mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-07 15:32:11 +00:00
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:
@@ -5,6 +5,7 @@ import {showFomanticModal} from './fomantic/modal.ts';
|
||||
import {createElementFromHTML} from '../utils/dom.ts';
|
||||
import {html} from '../utils/html.ts';
|
||||
import {showGlobalErrorMessage} from './errors.ts';
|
||||
import {AnsiLineRenderer} from '../render/ansi.ts';
|
||||
|
||||
type LevelMap = Record<string, (message: string) => Toast | null>;
|
||||
|
||||
@@ -56,8 +57,56 @@ function initDevtestPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// shows every sequence web_src/js/render/ansi.ts renders. Lines whose output does not explain
|
||||
// itself are preceded by their own escaped source.
|
||||
function initDevtestAnsiRender(container: HTMLElement) {
|
||||
const esc = '\x1b';
|
||||
const cells = (count: number, cell: (index: number) => string, separator = '') =>
|
||||
Array.from({length: count}, (_value, index) => cell(index)).join(separator);
|
||||
const attr = (params: string, label: string) => `${esc}[${params}m${label}${esc}[m`;
|
||||
const withSource = (line: string) => [attr('2', line.replaceAll(esc, '\\e').replaceAll('\b', '\\b').replaceAll('\r', '\\r')), line];
|
||||
|
||||
const lines = [
|
||||
...Array.from({length: 16}, (_value, row) =>
|
||||
cells(16, (col) => `${esc}[38;5;${row * 16 + col}m${String(row * 16 + col).padStart(4)}${esc}[0m`)),
|
||||
' ',
|
||||
cells(16, (index) => `${esc}[48;5;${index}m ${String(index).padStart(3)} ${esc}[0m`),
|
||||
// truecolor, a gradient no palette index can express
|
||||
cells(77, (col) => `${esc}[48;2;${255 - col * 3};0;${col * 3}m${esc}[38;2;${col * 3};0;${255 - col * 3}m/${esc}[0m`),
|
||||
' ',
|
||||
[cells(10, (code) => attr(String(code), `SGR ${code}`), ' '), attr('53', 'SGR 53')].join(' '),
|
||||
' ',
|
||||
[
|
||||
cells(5, (index) => attr(`4:${index + 1}`, `SGR 4:${index + 1}`), ' '),
|
||||
attr('21', 'SGR 21'),
|
||||
`${esc}[4:3m${esc}[58;2;135;0;255mtruecolor underline${esc}[59m${esc}[4:0m`,
|
||||
`${esc}]8;;https://example.com${esc}\\${esc}[3mstyled${esc}[23m hyperlink${esc}]8;;${esc}\\`,
|
||||
].join(' '),
|
||||
' ',
|
||||
...withSource('Reading... 1%\rReading... 50%\rReading... 100%'),
|
||||
...withSource(`first${esc}[Ksecond${esc}[2Jthird`),
|
||||
...withSource(`cursor ${esc}[3Amovement, private ${esc}[?25lCSI, ${esc}]0;title${esc}\\titles, ${esc}Pquery${esc}\\strings, truncated${esc}[38;5;`),
|
||||
...withSource('Reading... 10%\b\b\b100%'),
|
||||
...withSource('<script>alert(1)</script> & "quotes", and a bare url https://example.com'),
|
||||
' ',
|
||||
`${esc}[31man unterminated color`,
|
||||
'carries into the following lines',
|
||||
`${esc}[0muntil something resets it`,
|
||||
];
|
||||
|
||||
const elConsole = createElementFromHTML(html`<div class="console tw-p-2 tw-whitespace-pre-wrap"></div>`);
|
||||
const ansi = new AnsiLineRenderer();
|
||||
for (const line of lines) {
|
||||
const el = document.createElement('div');
|
||||
ansi.renderLine(el, line);
|
||||
elConsole.append(el);
|
||||
}
|
||||
container.append(elConsole);
|
||||
}
|
||||
|
||||
export function initDevtest() {
|
||||
registerGlobalInitFunc('initDevtestPage', initDevtestPage);
|
||||
registerGlobalInitFunc('initDevtestAnsiRender', initDevtestAnsiRender);
|
||||
registerGlobalInitFunc('initDevtestDetailsErrorMessage', () => {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
showGlobalErrorMessage('showGlobalErrorMessage single message', 'warning');
|
||||
|
||||
Reference in New Issue
Block a user