Repository navigation
Conversation
The bash tool's command was the one block of code in a session drawn as plain text, while write, edit and apply_patch already go through tree-sitter. It is now the same `<text>$ command</text>` as before, with each token a colored span, so it wraps, indents and fits the block exactly as the plain command does; only the colors differ. The text appears plain at once and takes its colors when the parser worker answers. Highlighting goes through a cache keyed by language and content (packages/tui/src/util/highlight-cache.ts), so a remounted transcript or a reopened session does not reparse every command. Identical concurrent requests share one round trip, a failed one is retried, and the cache holds at most 1000 entries or 4M characters. In the transcript red means a failed or rejected tool call, so the command is colored with a syntax style that never uses red (packages/tui/src/theme/tool-code.ts): every syntax slot that comes out red, or in the theme's error color, takes a non-red alternative, such as the function color for variables, commands and builtins. A test checks every built-in theme in dark and light. nvim-treesitter's bash query narrows its number, constant and shebang captures with `#lua-match?`, which web-tree-sitter does not evaluate, so every word came back as a number and every variable as a constant. packages/tui/src/util/bash-highlight.ts applies those patterns after the worker answers. It also drops the query's `@spell` captures: the theme colors spell as plain text, which turned every comment back to the text color. `syntax.bash: false` in tui.json restores the plain-text command.
Generic tool output was drawn as plain text, and nothing knows its type: a plugin tool returns a string and an MCP text result carries no content type, so a JSON result from `browser` read as a grey wall. `syntax.tool_output` in tui.json maps a tool name or glob (`browser`, `github_*`, `*`) to a language id, `auto` or `none`; an exact name wins over globs and the most specific glob over the rest (packages/tui/src/util/tool-output.ts). `auto` colors output that is a JSON object or array: a bounded sniff (bracket pair, at most 100,000 characters, one parse) whose answer is cached by content. Only output that is shown is sniffed or colored. Unset by default, so output stays plain as upstream draws it. The output is one text renderable whose content becomes the same text as colored chunks when the parser worker answers, so it wraps exactly as the plain text does (test/cli/tui/tool-output.test.tsx compares the frames at 40, 80 and 160 columns), and it uses the non-red tool-code palette, since red means a failed tool call. The whole output is highlighted, once and cached, even while the block is collapsed: a preview cut through the middle of a JSON value does not parse, so the preview takes the whole output's highlights that fall inside the part it shares with the output, and its ellipsis stays plain.
Contributor
|
The following comment was made by an LLM, it may be inaccurate: |
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 12, 2026
syntax.tool_output colors plugin and MCP tool output by tool name or glob, with a cached JSON sniff for auto (0ab6637); issue anomalyco#54957, PR anomalyco#54968; the plugin SDK content-type idea is kept as a future note; vt-252 on desktop and m4max. AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Tool: opencode 1.19.0-vt-227-dfb56f76c7 AI-Platform: linux AI-Harness: Vibeterm e6434eb AI-Session-ID: ses_ed1e2b932ffe6tTqhsOiGuYXRE
This was referenced Oct 14, 2026
Author
|
Closing: this targets the v1 TUI, which upstream now maintains for critical fixes only, so it is not going to be merged. The branch stays on Nowaker/opencode if anyone wants to pick it up. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note: I'm aware v1 is now the maintenance branch and new features go to v2 only. This PR is here for others to use, and I'll submit the v2 version once I've migrated my whole plugin system to it.
Issue for this PR
Closes #54957
Builds on the bash command coloring PR (#54704), whose highlight cache and non-red tool-code palette it uses; its commit is the first one here. Review only the second commit.
Type of change
What does this PR do?
Generic tool output (plugin and MCP tools, when output is shown) is drawn as plain text, and nothing knows its type: a plugin tool returns a string, and an MCP text result carries no content type. A JSON result reads as a grey wall.
syntax.tool_outputin tui.json maps a tool name or glob (browser,github_*,*) to a language id,autoornone. An exact name wins over globs, and the most specific glob over the rest (util/tool-output.ts). Unset by default, so output stays plain.autocolors output that is a JSON object or array: a bounded sniff (bracket pair, at most 100,000 characters, one parse), cached by content. Over 564 real generic outputs it costs about 6 µs per output cold and 2 µs warm.Possible follow-up: let a tool declare its output's content type, so no config is needed. For example a plugin
tool({ ..., output: { contentType: "application/json" } }), or an MCP result'smimeType, mapped to a language beforesyntax.tool_outputis consulted.How did you verify your code works?
bun typecheckin packages/tui and packages/opencode;bun test test/util test/config.test.tsx test/cli/tui test/tool-code-theme.test.ts: 129 pass.tool-output.test.tsxcompares plain and colored frames at 40, 80 and 160 columns; unit tests cover the glob precedence, the sniff and the preview highlights.browserJSON result and a plain-text result under"*": "auto": the screen text is byte-identical with the setting on and off; JSON keys, strings and numbers are colored in the collapsed preview; the plain-text result stays plain.Screenshots / recordings
p/elskeys in the property color,"/console/..."in the string color:Checklist
This PR is AI generated, but under direct supervision and on request of @Nowaker.