enhance(actions): replace ansi_up with first-party code (#38619)

Replaces the `ansi_up` dependency with first-party code and fixes a
number of bugs in turn.

- Faster rendering, around 7x for plain lines and 3x for colored ones.
- Render many SGR features like hyperlinks, blink, inverse, conceal,
strikethrough, overline, underline styles and underline color, including
`:` sub-parameters, which no longer swallow the codes after them.
- Drop OSC, DCS, SOS, PM and APC with their payload, ending them at BEL,
`ESC \` or the 8-bit ST. A truncated sequence is dropped instead of
corrupting a later line.
- A backspace moves the cursor back a column, so what follows overwrites
it, even across a style change.
- A style inside an OSC 8 label renders instead of leaking, and a
private CSI ending in `m` no longer resets the style.
- Log lines render as DOM nodes, never as markup, and only an `http(s)`
url becomes a link.
- Named colors render as CSS classes, only 24-bit color stays inline.
- Invisible text is now selectable, and the `z-index` workaround is
gone.

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
silverwind
2026-08-05 23:59:26 +02:00
committed by GitHub
parent 42e0c9eca4
commit 74804df4a5
11 changed files with 419 additions and 105 deletions
+31 -5
View File
@@ -16,15 +16,41 @@
text-decoration: underline;
text-decoration-style: dashed;
}
.console a:hover { color: var(--color-primary); }
.console a:hover {
color: var(--color-primary);
text-underline-position: auto; /* the global "a:hover" sets "under", which would shift the underline */
}
@keyframes blink-animation {
to {
visibility: hidden;
50% {
color: transparent;
}
}
/* ansi_up colors used in actions */
/* SGR attributes emitted by web_src/js/render/ansi.ts */
.ansi-bold { font-weight: var(--font-weight-semibold); }
.ansi-italic { font-style: italic; }
.ansi-blink { animation: blink-animation 1s step-end infinite; }
.ansi-faint { color: color-mix(in srgb, currentcolor 70%, transparent); }
.ansi-conceal { color: transparent; }
.ansi-inverse-fg { color: var(--color-console-bg); }
.ansi-inverse-bg { background-color: var(--color-console-fg); }
.ansi-underline { text-decoration-line: underline; }
.ansi-line-through { text-decoration-line: line-through; }
.ansi-overline { text-decoration-line: overline; }
.ansi-underline.ansi-line-through { text-decoration-line: underline line-through; }
.ansi-underline.ansi-overline { text-decoration-line: underline overline; }
.ansi-line-through.ansi-overline { text-decoration-line: line-through overline; }
.ansi-underline.ansi-line-through.ansi-overline { text-decoration-line: underline line-through overline; }
.ansi-double { text-decoration-style: double; }
.ansi-wavy { text-decoration-style: wavy; }
.ansi-dotted { text-decoration-style: dotted; }
.ansi-dashed { text-decoration-style: dashed; }
/* ANSI colors used in actions */
.ansi-black-fg { color: var(--color-ansi-black); }
.ansi-red-fg { color: var(--color-ansi-red); }
@@ -67,7 +93,7 @@
.term-fg2 { color: var(--color-ansi-bright-black); } /* faint (decreased intensity) - same as gray really */
.term-fg3 { font-style: italic; } /* italic */
.term-fg4 { text-decoration: underline; } /* underline */
.term-fg5 { animation: blink-animation 1s steps(3, start) infinite; } /* blink */
.term-fg5 { animation: blink-animation 1s step-end infinite; } /* blink */
.term-fg9 { text-decoration: line-through; } /* crossed-out */
.term-fg30 { color: var(--color-ansi-black); } /* black (but we can't use black, so a diff color) */