tweaks to ANSI sequence (OSC) handling (#34964)
Fixes: #34604 Prompted by that I realized we do not correctly recognize both "ST" sequences we want to recognize, fix that.
This commit is contained in:
+27
-8
@@ -698,7 +698,8 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
|
||||
STATE_OTHER,
|
||||
STATE_ESCAPE,
|
||||
STATE_CSI,
|
||||
STATE_CSO,
|
||||
STATE_OSC,
|
||||
STATE_OSC_CLOSING,
|
||||
} state = STATE_OTHER;
|
||||
_cleanup_(memstream_done) MemStream m = {};
|
||||
size_t isz, shift[2] = {}, n_carriage_returns = 0;
|
||||
@@ -711,7 +712,7 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
|
||||
*
|
||||
* 1. Replaces TABs by 8 spaces
|
||||
* 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences
|
||||
* 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences
|
||||
* 3. Strips ANSI operating system sequences (OSC), i.e. ESC ']' … ST sequences
|
||||
* 4. Strip trailing \r characters (since they would "move the cursor", but have no
|
||||
* other effect).
|
||||
*
|
||||
@@ -719,7 +720,7 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
|
||||
* are any other special characters. Truncated ANSI sequences are left-as is too. This call is
|
||||
* supposed to suppress the most basic formatting noise, but nothing else.
|
||||
*
|
||||
* Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */
|
||||
* Why care for OSC sequences? Well, to undo what terminal_urlify() and friends generate. */
|
||||
|
||||
isz = _isz ? *_isz : strlen(*ibuf);
|
||||
|
||||
@@ -766,8 +767,8 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
|
||||
} else if (*i == '[') { /* ANSI CSI */
|
||||
state = STATE_CSI;
|
||||
begin = i + 1;
|
||||
} else if (*i == ']') { /* ANSI CSO */
|
||||
state = STATE_CSO;
|
||||
} else if (*i == ']') { /* ANSI OSC */
|
||||
state = STATE_OSC;
|
||||
begin = i + 1;
|
||||
} else {
|
||||
fputc('\x1B', f);
|
||||
@@ -793,17 +794,35 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
|
||||
|
||||
break;
|
||||
|
||||
case STATE_CSO:
|
||||
case STATE_OSC:
|
||||
assert(n_carriage_returns == 0);
|
||||
|
||||
/* There are three kinds of OSC terminators: \x07, \x1b\x5c or \x9c. We only support
|
||||
* the first two, because the last one is a valid UTF-8 codepoint and hence creates
|
||||
* an ambiguity (many Terminal emulators refuse to support it as well). */
|
||||
if (i >= *ibuf + isz || /* EOT … */
|
||||
(*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
|
||||
(!IN_SET(*i, '\x07', '\x1b') && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
|
||||
fputc('\x1B', f);
|
||||
fputc(']', f);
|
||||
advance_offsets(i - *ibuf, highlight, shift, 2);
|
||||
state = STATE_OTHER;
|
||||
i = begin-1;
|
||||
} else if (*i == '\a')
|
||||
} else if (*i == '\x07') /* Single character ST */
|
||||
state = STATE_OTHER;
|
||||
else if (*i == '\x1B')
|
||||
state = STATE_OSC_CLOSING;
|
||||
|
||||
break;
|
||||
|
||||
case STATE_OSC_CLOSING:
|
||||
if (i >= *ibuf + isz || /* EOT … */
|
||||
*i != '\x5c') { /* … or incomplete two-byte ST in sequence */
|
||||
fputc('\x1B', f);
|
||||
fputc(']', f);
|
||||
advance_offsets(i - *ibuf, highlight, shift, 2);
|
||||
state = STATE_OTHER;
|
||||
i = begin-1;
|
||||
} else if (*i == '\x5c')
|
||||
state = STATE_OTHER;
|
||||
|
||||
break;
|
||||
|
||||
@@ -1923,12 +1923,12 @@ int get_default_background_color(double *ret_red, double *ret_green, double *ret
|
||||
if (tcsetattr(STDIN_FILENO, TCSADRAIN, &new_termios) < 0)
|
||||
return -errno;
|
||||
|
||||
r = loop_write(STDOUT_FILENO, "\x1B]11;?\x07", SIZE_MAX);
|
||||
r = loop_write(STDOUT_FILENO, ANSI_OSC "11;?" ANSI_ST, SIZE_MAX);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
usec_t end = usec_add(now(CLOCK_MONOTONIC), 333 * USEC_PER_MSEC);
|
||||
char buf[STRLEN("\x1B]11;rgb:0/0/0\x07")]; /* shortest possible reply */
|
||||
char buf[STRLEN(ANSI_OSC "11;rgb:0/0/0" ANSI_ST)]; /* shortest possible reply */
|
||||
size_t buf_full = 0;
|
||||
BackgroundColorContext context = {};
|
||||
|
||||
|
||||
@@ -27,6 +27,16 @@
|
||||
#define ANSI_WINDOW_TITLE_PUSH "\x1b[22;2t"
|
||||
#define ANSI_WINDOW_TITLE_POP "\x1b[23;2t"
|
||||
|
||||
/* ANSI "string terminator" character ("ST"). Terminal emulators typically allow three different ones: 0x07,
|
||||
* 0x9c, and 0x1B 0x5C. We'll avoid 0x07 (BEL, aka ^G) since it might trigger unexpected TTY signal
|
||||
* handling. And we'll avoid 0x9c since that's also valid regular codepoint in UTF-8 and elsewhere, and
|
||||
* creates ambiguities. Because of that some terminal emulators explicitly choose not to support it. Hence we
|
||||
* use 0x1B 0x5c */
|
||||
#define ANSI_ST "\e\\"
|
||||
|
||||
/* The "operating system command" ("OSC") start sequence */
|
||||
#define ANSI_OSC "\e]"
|
||||
|
||||
bool isatty_safe(int fd);
|
||||
|
||||
int terminal_reset_defensive(int fd, bool switch_to_text);
|
||||
|
||||
Reference in New Issue
Block a user