diff --git a/Makefile b/Makefile index d5fea23..479e7ac 100644 --- a/Makefile +++ b/Makefile @@ -901,10 +901,21 @@ SCHINIT_JOBS = $(wildcard etc/schinit/*.job) etc/schinit/README ETC_FILES = $(wildcard etc/*) ETC_PLAIN = $(filter-out etc/schinit,$(ETC_FILES)) -etc-install: $(SCHINIT_JOBS) $(ETC_PLAIN) - @mkdir -p $(SYSROOT)/etc/schinit +# The mark as characters, for anything that draws a logo into a terminal -- +# fastfetch takes it with --file-raw. Installed from docs/branding rather than +# copied into sysroot by hand, so there is one source and `make` keeps them in +# step; see docs/branding/README.md. +# +# The 50-column one, because that is what fits beside an info block on an +# 80-column console. The wider renderings are in the same directory for +# anything with more room. +LOGO_ASCII = docs/branding/Ascii/ascii_50.txt + +etc-install: $(SCHINIT_JOBS) $(ETC_PLAIN) $(LOGO_ASCII) + @mkdir -p $(SYSROOT)/etc/schinit $(SYSROOT)/usr/share/schos @cp $(ETC_PLAIN) $(SYSROOT)/etc/ @cp $(SCHINIT_JOBS) $(SYSROOT)/etc/schinit/ + @cp $(LOGO_ASCII) $(SYSROOT)/usr/share/schos/logo.txt @echo "installed $(words $(ETC_PLAIN)) /etc file(s) and $(words $(SCHINIT_JOBS)) schinit manifest(s)" sysroot-install: $(addprefix $(SYSROOT)/bin/, $(CMDS)) etc-install diff --git a/docs/architecture/graphics.md b/docs/architecture/graphics.md index 8901f68..da370fc 100644 --- a/docs/architecture/graphics.md +++ b/docs/architecture/graphics.md @@ -129,6 +129,23 @@ what makes an OS look like a hobby project. Everything still goes out the UART. The console still uses the 8×16 cell grid. Porting it onto the text layer and deleting the grid is open work. +Two things the ANSI parser got wrong until a large program nobody here wrote +exercised it properly: + +**`ESC[m` with no parameters is a reset**, and `sgr()` iterated its parameter +list — which is empty in that case, so the loop body never ran and the reset was +dropped. ECMA-48 says an omitted parameter takes its default and SGR's default +is 0. Programs emit the bare form constantly, so every colour set became +permanent; with a *background* colour that meant the whole console went +white-on-white and stayed there, which reads as a corrupted framebuffer rather +than a missing branch. + +**OSC sequences must be consumed even when they are ignored.** `ESC ]` was not a +state, so the payload printed as text and a hyperlinked path arrived as +`Disk (]8;;file:///\]8;;\)`. There is no window title to set here and no +hyperlink to follow, but discarding the body is not optional — the alternative +is printing somebody's URL into the middle of their output. + ### Input Keys reach both `/dev/input/eventN` and the tty line discipline, which is diff --git a/docs/branding/Ascii/ascii_100.txt b/docs/branding/Ascii/ascii_100.txt new file mode 100644 index 0000000..1c1bbfe --- /dev/null +++ b/docs/branding/Ascii/ascii_100.txt @@ -0,0 +1,57 @@ + + + + + + + + + + + + + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrxJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrYJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrYJJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrXJJJJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrcJJJJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrvJJJJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrxJJJJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrJJJJJJ + nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnYJJJJJJ + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzJJJJC + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzJJJ + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzY + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYOm + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY0mmm + CYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYQmmmmm + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYCmmmmmw + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYJmmmmmm + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYmmmmmm + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYZmmmmmw + JYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYOmmmmmw + QCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCQmmmmmw + 000000000000000000000000000000000000000000000000000000Ommmw + 000000000000000000000000000000000000000000000000000000Omm + 000000000000000000000000000000000000000000000000000000O + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmpk + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwkkk + mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwkkkkk + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwbkkkkhh + wwmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmdkkkkkh + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmdkkkkhh + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmpkkkkkh + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwkkkkkh + dppppppppppppppppppppppppppppppppppppppppppppppppppppppkkkkkha + bddddddddddddddddddddddddddddddddddddddddddddddddddddddkkkhh + bddddddddddddddddddddddddddddddddddddddddddddddddddddddkkh + dbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbk + + + + + + + + + diff --git a/docs/branding/Ascii/ascii_150.txt b/docs/branding/Ascii/ascii_150.txt new file mode 100644 index 0000000..52b2000 --- /dev/null +++ b/docs/branding/Ascii/ascii_150.txt @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLJ + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLJII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMJIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLKIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMKIIIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLJIIIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLJIIIIIIII + LMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLJIIIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLJIIIIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLKIIIIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMKIIIIIIIII + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLIIIIIIIII + KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJIIIIIIII + KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKIIIIIII + KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKIIIIIH + KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKIIII + KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKII + IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH + IJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGG + IJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGGGG + JIJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJHGGGGG + JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIHGGGGGGG + JIJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJHGGGGGGGGF + JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGGGGGGGGG + JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGGGGGGGGG + JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGGGGGGGGG + JIJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIHGGGGGGGGF + JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJHGGGGGGGGF + JIJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGGGGGGGGF + JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIGGGGGGGGF + HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGG + HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGF + HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGF + HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGG + + FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEE + FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEE + FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEE + GFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGEEEEEEEE + GFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFEEEEEEEED + GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEEEED + FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEEEED + FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEEEED + GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGEEEEEEEED + GFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEEEEED + GFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEEEED + FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFEEEEEEEED + EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED + EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED + EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED + EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED + EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE + + + + + + + + + + + + + diff --git a/docs/branding/Ascii/ascii_50.txt b/docs/branding/Ascii/ascii_50.txt new file mode 100644 index 0000000..aaad2d8 --- /dev/null +++ b/docs/branding/Ascii/ascii_50.txt @@ -0,0 +1,27 @@ + + + + + + + rrrrrrrrrrrrrrrrrrrrrrrrrrJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrYJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrXJJ + zzzzzzzzzzzzzzzzzzzzzzzzzzJC + JYYYYYYYYYYYYYYYYYYYYYYYYYJ + YYYYYYYYYYYYYYYYYYYYYYYYYJmm + YYYYYYYYYYYYYYYYYYYYYYYYYYmmm + YYYYYYYYYYYYYYYYYYYYYYYYYYmmm + 00000000000000000000000000Zmm + 00000000000000000000000000Zp + wmmmmmmmmmmmmmmmmmmmmmmmmmph + wmmmmmmmmmmmmmmmmmmmmmmmmmwkkh + mmmmmmmmmmmmmmmmmmmmmmmmmmkkh + mmmmmmmmmmmmmmmmmmmmmmmmmmkkh + ddddddddddddddddddddddddddkk + bbbbbbbbbbbbbbbbbbbbbbbbbb + + + + diff --git a/docs/branding/Ascii/ascii_68.txt b/docs/branding/Ascii/ascii_68.txt new file mode 100644 index 0000000..fa52cb9 --- /dev/null +++ b/docs/branding/Ascii/ascii_68.txt @@ -0,0 +1,37 @@ + + + + + + + + + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrnJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrxJJJ + jrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrJJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrYJJJ + rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrYJJJ + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzJJJC + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzJJ + JYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYQ + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYmm + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYmmmm + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYOmmmw + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY0mmmw + YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYJmmmm + 000000000000000000000000000000000000mmw + 000000000000000000000000000000000000m + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmb + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmdkk + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmpkkkh + mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwkkkh + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwkkkh + wmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmkkkh + dddddddddddddddddddddddddddddddddddbkk + dddddddddddddddddddddddddddddddddddbh + + + + + + diff --git a/docs/branding/README.md b/docs/branding/README.md index 0f86089..1626ef7 100644 --- a/docs/branding/README.md +++ b/docs/branding/README.md @@ -128,6 +128,25 @@ No screenshots of marks. No re-exports of re-exports: go back to the SVG. **SVG is the source of truth for every mark.** A raster is something generated from it, never edited. +## The mark as characters + +`Ascii/ascii_{50,68,100,150}.txt` — Shift rendered in text at four widths, named +for the column count they fit in. + +`make` installs the 50-column one as `/usr/share/schos/logo.txt`, because 50 is +what leaves room for an info block beside it on an 80-column console: + +```sh +fastfetch --file-raw /usr/share/schos/logo.txt +``` + +Installed from here rather than copied into `sysroot/` by hand, so there is one +source and the build keeps them in step. + +These are a *rendering* of the mark, not a second mark. If Shift changes they +are regenerated from it; they are not edited to taste, or the two drift and the +text one wins by being the one people see in a terminal. + ## What is in here, and why a raster is committed ``` diff --git a/kernel/core/console.c b/kernel/core/console.c index 35a3925..1f02def 100644 --- a/kernel/core/console.c +++ b/kernel/core/console.c @@ -217,7 +217,11 @@ static uint32 cons_bg = CONS_DEFAULT_BG; static int cons_bold = 0; // Escape parser state. -enum { E_NORMAL, E_ESC, E_CSI }; +// E_OSC and E_OSC_ESC exist for hyperlinks. A terminal that does not follow +// them must still *consume* them, or the URL is printed as text -- which is +// what "Disk (]8;;file:///\]8;;\): 4.6 MiB" was: fastfetch wrapping a path in +// OSC 8, and this console spelling it out. +enum { E_NORMAL, E_ESC, E_CSI, E_OSC, E_OSC_ESC }; static int esc_state = E_NORMAL; static int esc_parm[8]; static int esc_nparm; @@ -302,7 +306,19 @@ glyph_for(uint32 cp) static void sgr(void) { - for (int i = 0; i < esc_nparm; i++) { + // "ESC[m" with no parameters means ESC[0m -- reset -- and ECMA-48 says so for + // every CSI: an omitted parameter takes its default, and SGR's default is 0. + // + // This loop used to start at a count of zero and therefore do nothing, so a + // bare reset was silently dropped. Programs emit it constantly: fastfetch + // writes "\x1b[32m1%\x1b[m", and with the reset ignored everything after the + // first coloured character stayed green forever. Worse with background + // colours -- its palette swatch sets a white background and resets, so the + // whole console went white-on-white and stayed there, which looks like a + // corrupted framebuffer rather than a missing branch. + int nparm = esc_nparm ? esc_nparm : 1; // esc_parm[0] is already 0 + + for (int i = 0; i < nparm; i++) { int p = esc_parm[i]; if (p == 0) { @@ -392,6 +408,10 @@ gfx_feed(int c) for (int i = 0; i < 8; i++) esc_parm[i] = 0; return; } + if (c == ']') { // OSC: swallow it, see below + esc_state = E_OSC; + return; + } esc_state = E_NORMAL; if (c == 'c') { // RIS -- full reset cons_fg = CONS_DEFAULT_FG; @@ -400,6 +420,24 @@ gfx_feed(int c) } return; // other two-byte escapes: ignored + // An operating-system command runs until BEL or until ST (ESC \). Nothing + // here acts on one -- there is no window title to set and no hyperlink to + // follow -- but discarding the payload is not optional: the alternative is + // printing somebody's URL into the middle of their output. + case E_OSC: + if (c == '\a') { esc_state = E_NORMAL; return; } + if (c == '\x1b') { esc_state = E_OSC_ESC; return; } + return; + + case E_OSC_ESC: + // ESC \ ends it; ESC anything-else means the OSC was malformed and a new + // escape has started, so hand the byte to the ESC state rather than eating + // it. Dropping it would lose the sequence that follows. + if (c == '\\') { esc_state = E_NORMAL; return; } + esc_state = E_ESC; + gfx_feed(c); + return; + case E_CSI: if (c == '?') { esc_private = 1; return; } if (c >= '0' && c <= '9') {