Skip to content

Toggle bold and italic, apply them to a selection, and make selections inclusive - #2

Open
ptimmons wants to merge 2 commits into
benlong100:mainfrom
ptimmons:emphasis-toggle-and-selection
Open

ptimmons wants to merge 2 commits into
benlong100:mainfrom
ptimmons:emphasis-toggle-and-selection

Conversation

@ptimmons

Copy link
Copy Markdown

Two changes from running ZipEdit on a real Apple //e and in Virtual ]['s ][+ emulation. They are separate commits, and each one builds and passes on its own.

1. Bold and italic toggle, and apply to a selection

  • Toggle. A second Ctrl-B on a bold word used to give ****word****. Now each key reads the asterisk runs at both ends of the word (*x* is italic, **x** bold, ***x*** both) and removes its own markers if they are there, or adds them if not. Italic on ***word*** leaves **word**.
  • Selections. With text selected, Ctrl-B and Ctrl-I act on the selection instead of the word at the cursor. Markers just outside the selection count, and the selection stays on the same text afterwards so you can toggle again. On a selection, Tab/Ctrl-I ($89) always italicises, even at the start of a line.
  • Punctuation. A word's closing . , ; : ! ? ) " and opening ( " stay outside the markers, so word. becomes *word*.. Without this, **word**. could never toggle off.

2. A selection includes the character under the cursor

The cursor is a block drawn on a character, but selecting forwards stopped just before it, so the selection looked one character short. Both ends are now inclusive. A line break or the end of the document at the far end is still left out, so selecting to the end of a line and cutting doesn't join it to the next line.

One behaviour change: OA-Space (Ctrl-T on the ][+) now selects the character under the cursor immediately, so typing straight afterwards replaces that character.

This commit also fixes a redraw bug the change exposed: RENDER set half of AUXPTR before SELBOUNDS and half after, and the new code reads through AUXPTR. The first row filled with E as soon as Ctrl-T was pressed. The suite now checks for it.

Testing

  • Full suite: make test ran 326 checks. The two failures were a bug in one of the new tests, since fixed, and a missing Slovenian disk image (make LANG=sl disk had never been run on this clone). Both sections were re-run and pass: emphasis toggles 20/20, another language 15/15.
  • First commit on its own: the emphasis toggles, keyboard, editing operations and selection sections pass (48 checks).
  • 6502 simulation: the ][+ build's handlers were also run in a py65 harness against 58 documents, including selections over 255 bytes, a nearly full buffer, cut and copy, and the selection bounds RENDER paints.
  • Manual: the ][+ image was tried by hand in Virtual ][.

Not covered

  • The //e image has not been run on real hardware. Its manual test was blocked because macOS intercepts Cmd-Space before Virtual ][ sees OA-Space. The suite sends OA-Space through AppleScript, and that part passes.
  • Speed. The emulator can't show whether Ctrl-B, Ctrl-I or selecting feel slower on a real machine.

Cost and scope

  • Size. The //e binary grows from 11,158 to 12,167 bytes, and its text buffer (in aux) is unchanged. The ][+ binary grows by three pages, from 10,240 to 11,264 bytes. That build's buffer starts right after the code, so it is 3,072 bytes smaller.
  • Versioning. Nothing is bumped. The changelog entries are under a new ## Unreleased heading for you to place.
  • Known gap, unchanged. Adding markers still doesn't re-wrap the line, so a line can run past the margin until it is reflowed. That was already the case before this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Kyp6u8xbp9NKD5AasYzejn

ptimmons and others added 2 commits September 15, 2026 10:29
Reported from a real //e: a second Ctrl-B on a bold word made ****word****
instead of taking the bold off, and with text selected both keys still went
to the word at the cursor.

Bold and italic share the asterisk, so a span's emphasis is read off the
marker runs at its two ends. With n the shorter run, bold is on at n >= 2 and
italic when n is odd, so *x*, **x** and ***x*** are italic, bold and both.
Each key takes its markers off when its effect is on and puts them on
otherwise. One asterisk is as good as another, so every edit is made at the
span's outer edges and nothing has to find the inner end of a run.

With a selection, the span is the selection, widened over any markers
touching it, and the selection is left on the same text afterwards so another
key toggles again. Otherwise it is the word at the cursor less a closing
. , ; : ! ? ) " and an opening ( ", which stay outside the markers: without
that, **word**. could never toggle off. A span of nothing but markers is
empty emphasis and the cursor goes back between them. An insert that would
not fit does nothing, rather than half an edit the walk back would miscount.

$89 is Tab in leading whitespace, but a selection now makes it italic
wherever the selection starts.

Verified in a py65 harness driving the ][+ build's handlers directly, 43
documents including 300-byte selections and a nearly full buffer, and by a
new "emphasis toggles" section in the suite.

The new code is about 880 bytes. The //e's buffer is in aux and does not
notice; the ][+ buffer starts after the code and is three pages smaller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kyp6u8xbp9NKD5AasYzejn
Reported from Virtual ]['s ][+ emulation: selecting forwards stopped one
character short. The cursor is a block drawn ON a character, but the selection
ran from the anchor up to the cursor, so the block sat on a letter a cut was
going to leave behind.

Both ends are inclusive now. SELRANGE still measures the half-open run;
SELEND says whether the character at the far end belongs too, which it does
unless it is a line break or the end of the document -- neither is drawn, and
a cut that took a break would join two lines nobody saw selected. SELBOUNDS
adds it for the renderer and SELGRAB for everything that consumes a
selection: cut, copy, delete, typing or pasting over it, and emphasis.

The selection stays contiguous. A backward selection's extra character is one
more byte after the gap; a forward one's is the byte just past it, so SELGRAB
steps the cursor over it and the run is before the gap again. COPYSEL steps
back, since a copy should not move the cursor.

RENDER set AUXPTR's low byte before calling SELBOUNDS and its high byte after,
and SELEND reads through AUXPTR. The walk then started part way into a page,
stepped over the gap without landing on GAPBEG, and drew the gap's $E5 poison
as a row of E -- reported the moment Ctrl-T selected a character straight
away. AUXPTR is now set after SELBOUNDS, and the suite checks the first row
right after OA-Space.

A consequence worth knowing: OA-Space (Ctrl-T on the ][+) now selects the
character under the cursor at once, so typing straight after replaces it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kyp6u8xbp9NKD5AasYzejn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant