From dd47dba5b0ebdbe5e09fde489743104a8b8c9dfc Mon Sep 17 00:00:00 2001 From: Hare Date: Fri, 21 Aug 2026 13:36:03 +0900 Subject: [PATCH] feat: render bash ANSI colors in web console --- web/workspace/deno.json | 2 +- .../src/lib/workspace/console/AnsiText.svelte | 49 ++++ .../workspace/console/ConsoleLineItem.svelte | 17 +- .../src/lib/workspace/console/ansi.ts | 221 ++++++++++++++++++ .../console/worker-console.ui.test.ts | 11 +- web/workspace/test/console/ansi.test.ts | 78 +++++++ 6 files changed, 373 insertions(+), 5 deletions(-) create mode 100644 web/workspace/src/lib/workspace/console/AnsiText.svelte create mode 100644 web/workspace/src/lib/workspace/console/ansi.ts create mode 100644 web/workspace/test/console/ansi.test.ts diff --git a/web/workspace/deno.json b/web/workspace/deno.json index 4bcefbed..ee7b129a 100644 --- a/web/workspace/deno.json +++ b/web/workspace/deno.json @@ -6,7 +6,7 @@ "dev": "deno run -A npm:vite@7.2.7 dev", "dev:backend": "cd ../.. && cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787", "check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json", - "test": "deno test --allow-read=src,test --allow-env=LOG,VSCODE_TEXTMATE_DEBUG src/lib/workspace/auth/model.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/tasks.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts", + "test": "deno test --allow-read=src,test --allow-env=LOG,VSCODE_TEXTMATE_DEBUG src/lib/workspace/auth/model.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts test/console/ansi.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/tasks.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts", "build": "deno run -A npm:vite@7.2.7 build", "preview": "deno run -A npm:vite@7.2.7 preview" }, diff --git a/web/workspace/src/lib/workspace/console/AnsiText.svelte b/web/workspace/src/lib/workspace/console/AnsiText.svelte new file mode 100644 index 00000000..7d970e52 --- /dev/null +++ b/web/workspace/src/lib/workspace/console/AnsiText.svelte @@ -0,0 +1,49 @@ + + +{#each segments as segment} + {segment.text} +{/each} + + diff --git a/web/workspace/src/lib/workspace/console/ConsoleLineItem.svelte b/web/workspace/src/lib/workspace/console/ConsoleLineItem.svelte index 1d38cebb..b957efc3 100644 --- a/web/workspace/src/lib/workspace/console/ConsoleLineItem.svelte +++ b/web/workspace/src/lib/workspace/console/ConsoleLineItem.svelte @@ -1,4 +1,5 @@ \x1b]8;;\x07" + + "\x1b[2Ksafe\x00\x1b[31"; + const segments = ansiSegments(input); + + assertEquals( + segments.map((segment) => segment.text).join(""), + "safe", + ); + assert(!segments.some((segment) => segment.text.includes("\x1b"))); +});