Tab finishes a word somebody started

The first word of a line, against the shell's fifteen commands. One match goes in
with a space after it, because a word that can only be one thing is finished.
Several are folded into their longest common prefix and that goes in, which is
the most that can be said without guessing which was meant - and if that adds
nothing, the matches are listed and the line put back underneath.

THE LINE COMING BACK IS THE HALF I EXPECTED TO BE HARD and it was already
solved. The prompt has been reprinted somewhere else entirely, so the editor's
idea of where the line begins is wrong - but editAnchor works that out backwards
from where printing ended, precisely so it survives the screen moving. Listing is
a redraw it already knew how to do.

editInsert became editPut, a routine, because completing a word puts in several
characters and every one of them is that. Which cost a bug immediately: the old
inline code left the insertion point in A, and a RET puts A back to what the
caller had.

Two more bugs worth naming, both mine and both the same shape - a pointer that
had moved:

THE CANDIDATE'S START HAS TO BE KEPT. The comparison walks DP3 through the name
as it matches, so by the time a match is declared, DP3 points at the part AFTER
what was typed - and that is what got copied. "he" completed to "he" because the
answer taken was "lp".

AND THE INSERTION STOPS AT OR PAST, not exactly equal. With the wrong answer the
two counters passed each other and the loop ran off the end of the buffer,
filling the line with whatever was next in memory. They cannot pass each other
now, and the branch stays, because the cheaper failure is worth nothing.

MY OWN TEST HAD A HOLE and breaking the code found it. The later-word case
pressed Tab after a space, where there is nothing to finish anyway, so it passed
whether or not the shell checked which word it was on. It types "echo he" now,
which would become "echo help" if it did not.

The assembler's label table went past 1024 and is doubled. A ceiling reached
once will be reached again, and it is pointers into source already in memory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-01 17:43:48 -04:00
co-authored by Claude Opus 5
parent 749fef8ce2
commit bb065fe221
7 changed files with 615 additions and 45 deletions
+21
View File
@@ -299,6 +299,7 @@ line can be moved about in at all.
| Backspace | Take out the character before the cursor. |
| Delete | Take out the one under it. |
| Up, Down | Walk back through the last eight lines, and forward again. |
| Tab | Finish the word being typed, if there is only one thing it could be. |
| Return | Finish the line, wherever the cursor happens to be sitting. |
Anything typed goes in where the cursor is, so a word left out of the middle of a line is
@@ -312,6 +313,26 @@ line, and nowhere for a history to live. Now the console delivers keys and says
about what they mean, the same way it reports what a drive is and says nothing about what
should be on it, and the shell decides.
### Finishing A Word:
Tab finishes the **first** word of a line against the shell's own commands. One match goes in
with a space after it, because a word that can only be one thing is finished. Several are
folded into their longest common prefix and that goes in, which is the most that can be said
without guessing which was meant - and if that adds nothing, because what is typed is already
as far as they all agree, the matches are listed and the line put back underneath.
Nothing typed and nothing matching both do nothing, quietly. Finishing an argument rather
than a command is not built yet.
**This is the same wall the history was behind.** A shell that never sees a keystroke has no
moment at which somebody has typed half a word - the terminal hands over finished lines - so
there is nothing to press Tab at. What made it possible was moving the line editing into the
system, and everything since has been downstream of that one decision.
The commands are walkable because they are **packed**: fifteen names, each ending in the zero
that says where the next begins. The dispatch is a chain of comparisons and cannot be walked,
so the names have to be data as well as code, and `make test` checks that the two agree.
### The History:
The last eight lines are kept, and Up walks back through them. It is a ring: a ninth line