Put the cursor home when the screen is cleared
A screen with nothing on it and a cursor half way down it is not a cleared screen: the next thing written lands where the last thing happened to leave off, at a position whose meaning was just erased. The shell's clear did exactly that, and left the next line one row below wherever it had been. Both halves were missing. consoleClearScreen blanks the cells and does not touch cursorRow or cursorColumn, and 2J on a terminal empties the screen without moving anything - H is what puts the cursor at the top. Life and Snake never showed this because they follow their clear with an explicit 1;1H of their own. They were working around it, which is why the bug survived until a command cleared the screen and then let somebody type. The attribute is deliberately not reset. Clearing is about what is on the screen rather than how the next thing will be drawn, and a program that chose a colour and then cleared still wants that colour - which is what a terminal does too. Two checks in video.sh, and they took two goes to make independent. The first pointed at the row where the letter lands when the cursor is NOT homed, so removing the clear and removing the homing failed the same pair and neither said which. The second now looks at a row nothing writes to either way - and at a letter whose ink actually reaches the pixel it reads, which "two" did not, so it passed on a screen that had never been cleared. 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
553882d28d
commit
0e0731e2b1
+17
-1
@@ -1071,7 +1071,23 @@ uint8_t OutputHandler(uint8_t DataByte, uint8_t Address) {
|
||||
case CONSOLE_COMMAND:
|
||||
if (DataByte == CONSOLE_COMMAND_CLEAR) {
|
||||
consoleClearScreen(0);
|
||||
consoleTellTerminal("\033[2J");
|
||||
// ---- And the cursor goes home ----
|
||||
//
|
||||
// A screen with nothing on it and a cursor half way down it is not a cleared
|
||||
// screen: the next thing written lands where the last thing happened to
|
||||
// leave off, which is a position that no longer means anything because
|
||||
// whatever gave it meaning has just been erased.
|
||||
//
|
||||
// The attribute is deliberately NOT reset. Clearing is about what is on the
|
||||
// screen and not about how the next thing will be drawn - a program that
|
||||
// chose a colour and then cleared still wants that colour, the same as on a
|
||||
// terminal, where 2J does not touch the graphics state either.
|
||||
cursorRow = 0;
|
||||
cursorColumn = 0;
|
||||
consoleCursorMoved();
|
||||
// 2J empties it and H is what puts the cursor at the top. A terminal given
|
||||
// only the first does exactly what this device did before this comment.
|
||||
consoleTellTerminal("\033[2J\033[H");
|
||||
}
|
||||
// Anything else does nothing. A command block reserved for later should be
|
||||
// quiet rather than fatal, the same as the screen's spare registers.
|
||||
|
||||
@@ -694,7 +694,7 @@ Three more registers, because that is how this machine talks to everything else.
|
||||
| --- | --- |
|
||||
| 0x03 | Cursor row. Read and write. |
|
||||
| 0x04 | Cursor column. Read and write. |
|
||||
| 0x05 | Command. Write 1 to clear the screen. |
|
||||
| 0x05 | Command. Write 1 to clear the screen, which also puts the cursor at the top left. |
|
||||
| 0x06 | Attribute. Read and write. |
|
||||
|
||||
**A cursor is shown only when it is asked for**, with bit 2 of the Control port, and status bit 4 says whether one is being shown. Off is the right default for a machine: a program painting its own screen does not want something blinking in the middle of it, and a system that reads lines from a person turns it on.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[2J[1;1H #
|
||||
[2J[H[1;1H #
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[2J[1;1H #
|
||||
[2J[H[1;1H #
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CosmOS
|
||||
> loaded, starting at 4000
|
||||
> [2J[1;1H #
|
||||
> [2J[H[1;1H #
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CosmOS
|
||||
> loaded, starting at 4000
|
||||
> [2J[1;1H #
|
||||
> [2J[H[1;1H #
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CosmOS
|
||||
> loaded, starting at 4000
|
||||
> [2J[1;1H+----------------+
|
||||
> [2J[H[1;1H+----------------+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|
||||
@@ -4,7 +4,7 @@ CosmOS ready.
|
||||
> echo and loud again
|
||||
and loud again
|
||||
and quiet again at the end
|
||||
> [2J> typed by hand
|
||||
> [2J[H> typed by hand
|
||||
> halted
|
||||
Execution halted.
|
||||
[exit 0]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CosmOS
|
||||
startup.sh is there but does not begin with #!, so it was not run
|
||||
> [2J> typed by hand
|
||||
> [2J[H> typed by hand
|
||||
> halted
|
||||
Execution halted.
|
||||
[exit 0]
|
||||
|
||||
@@ -718,6 +718,32 @@ TOTAL="$(grep -oE 'after [0-9]+' "$BUILD/poller.out" | grep -oE '[0-9]+')"
|
||||
&& result ok "and the flag comes down when looked at" "$TOTAL cycles, so three frames passed" \
|
||||
|| result no "and the flag comes down when looked at" "$TOTAL cycles, too few to be three frames"
|
||||
|
||||
# ---- Clearing puts the cursor back at the top ----
|
||||
#
|
||||
# A screen with nothing on it and a cursor half way down it is not a cleared screen. This
|
||||
# writes three lines, clears, and writes one letter: it has to land in the very first cell.
|
||||
# Before the cursor was homed it landed on the fourth row, on a screen that no longer had
|
||||
# anything on the first three to justify it.
|
||||
{ printf '#Program\nstart:\n'
|
||||
say "AAA"; emit 10
|
||||
say "AAA"; emit 10
|
||||
say "AAA"; emit 10
|
||||
port 0x05 0x01
|
||||
say "X"
|
||||
epilogue
|
||||
} | run clearhome || exit 1
|
||||
inked clearhome 2 1 \
|
||||
&& result ok "clearing puts the cursor home" "the next letter landed in the first cell" \
|
||||
|| result no "clearing puts the cursor home" "nothing at 2,1"
|
||||
# And the three lines really are gone, so the check above is about the cursor rather than
|
||||
# about a clear that did nothing.
|
||||
# The SECOND row, which nothing writes to either way - so this fails when the clear did not
|
||||
# clear and passes whether or not the cursor was homed. Pointed at the fourth row it failed
|
||||
# for the same reason as the check above, which is a second check that says nothing.
|
||||
papered clearhome 2 9 \
|
||||
&& result ok "and the screen really was cleared" "the second row is empty" \
|
||||
|| result no "and the screen really was cleared" "there is still ink on the second row"
|
||||
|
||||
# And what scrolled off the top is still in the map, which is scrollback nothing had to keep.
|
||||
{ printf '#Program\nstart:\n'
|
||||
say "A"
|
||||
|
||||
Reference in New Issue
Block a user