The console draws a tab instead of dropping it
consoleDraw gave meanings to newline, carriage return and backspace and dropped every other byte below the first glyph. A tab was one of those, so it left no mark on the screen at all - while the same byte went down the serial line, where a host terminal laid it out perfectly. That is why a tab separated file read correctly and displayed wrongly. Type and More were never at fault: they hand the file's bytes to the console unchanged, and the console is where the tabs stopped. An assembler symbol table came out with its fields run together. A tab now moves the cursor to the next stop, eight columns apart, and wraps when the next stop would reach or pass the last column - which is what an ordinary character does at the edge, rather than a rule only tabs obey. It MOVES rather than writing spaces, the way a terminal does: a carriage return followed by a tab steps over what is on the line and leaves it. Kept in the console rather than expanded by Type, More, and every future program that prints text. Three checks in video.sh, each of which fails on a different mistake: a tab renders the same screen as the spaces it stands for, one that runs off the edge renders the same screen as a newline, and sixteen letters tabbed across still have their ink - which is the one that fails if a tab is implemented by writing spaces. Verified with break.sh both ways. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
7dca141aae
commit
019c93a587
@@ -332,6 +332,31 @@ static void consoleDraw(uint8_t byte) {
|
||||
consoleCursorMoved();
|
||||
}
|
||||
return;
|
||||
case '\t': {
|
||||
// ---- A tab moves the cursor and marks nothing ----
|
||||
//
|
||||
// The byte reaches standard output either way, so anything reading the serial
|
||||
// line has always seen tabs and a host terminal has always laid them out. The
|
||||
// screen dropped them, which is why a tab separated file - an assembler symbol
|
||||
// table, say - came out of Type or More as its fields run together.
|
||||
//
|
||||
// MOVING RATHER THAN WRITING SPACES is what a terminal does, and the difference
|
||||
// shows the moment anything is already on the line: a tab that wrote blanks
|
||||
// would rub out what it passed over.
|
||||
//
|
||||
// Eight columns is the conventional stop and the one everything that prints a
|
||||
// tab assumes. Reaching or passing the right edge wraps, which is what an
|
||||
// ordinary character does at the edge - the alternative, stopping in the last
|
||||
// column, invents a rule that only tabs obey.
|
||||
int stop = (cursorColumn / CONSOLE_TAB_WIDTH + 1) * CONSOLE_TAB_WIDTH;
|
||||
if (stop >= videoColumns()) {
|
||||
consoleNewLine();
|
||||
} else {
|
||||
cursorColumn = (uint8_t)stop;
|
||||
}
|
||||
consoleCursorMoved();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -227,6 +227,12 @@
|
||||
// like afterwards and what was typed before are the system's business - see the shell,
|
||||
// which edits its own line - exactly as what is on a disk is the system's business and what
|
||||
// a drive IS belongs to the machine.
|
||||
// How far apart the console's tab stops are, on the screen. The serial line is not this
|
||||
// device's business - a host terminal lays a tab out with whatever it was configured for -
|
||||
// but the character screen has to be told, and eight is what everything that prints a tab
|
||||
// expects.
|
||||
#define CONSOLE_TAB_WIDTH 8
|
||||
|
||||
#define CONSOLE_KEY_UP 0x80
|
||||
#define CONSOLE_KEY_DOWN 0x81
|
||||
#define CONSOLE_KEY_LEFT 0x82
|
||||
|
||||
Reference in New Issue
Block a user