Problem
In split diff view, syntax highlighting often fails on the side that has fewer lines (typically the "old" / removed side), while the other side with more lines highlights correctly.
Root Cause
The DiffRenderable.buildSplitView() method reconstructs two separate content strings for the left and right CodeRenderable instances:
const preLeftContent = leftLogicalLines.map((l) => l.content).join('\n')
const preRightContent = rightLogicalLines.map((l) => l.content).join('\n')
Each CodeRenderable runs tree-sitter independently on its fragment. When one side has very few lines (e.g., 3-4 removed lines), tree-sitter receives incomplete/invalid code like:
</box>
<KeybindingBar />
<GlobalKeyHandler />
This isn't valid TSX — there's a closing tag without an opening tag, standalone components without a return statement or function wrapper. Tree-sitter can't parse it correctly, so no syntax tokens are emitted and the text renders unstyled.
Meanwhile, the other side might have 30+ lines of complete JSX that tree-sitter can successfully parse.
Expected Behavior
Both sides of a split diff should have correct syntax highlighting, regardless of how many lines each side has.
Suggested Fix
Instead of passing only the diff-visible lines to tree-sitter, the DiffRenderable could:
- Reconstruct the full old/new file content from the diff (context lines + removed/added lines can reconstruct both versions)
- Run tree-sitter on the complete file content for each side
- Map the highlighting results back to only the diff-visible lines
This is how editors like VS Code handle diff syntax highlighting — they highlight the full file and then render only the relevant lines in the diff view.
An alternative (simpler but less complete) approach would be to pad the tree-sitter input with additional context beyond what's shown in the diff, to give the parser more syntactic structure to work with.
Environment
- OpenTUI core: installed via npm
- Using
<diff> component in Solid.js with view="split", filetype="tsx", and a SyntaxStyle
- Default git diff context of 3 lines (
-U3)
Reproduction
Any diff where one side has significantly fewer lines than the other, especially when the removed/added code is a small fragment (like closing tags, short component declarations) without enough surrounding structure for tree-sitter to identify the language.
Problem
In split diff view, syntax highlighting often fails on the side that has fewer lines (typically the "old" / removed side), while the other side with more lines highlights correctly.
Root Cause
The
DiffRenderable.buildSplitView()method reconstructs two separate content strings for the left and rightCodeRenderableinstances:Each
CodeRenderableruns tree-sitter independently on its fragment. When one side has very few lines (e.g., 3-4 removed lines), tree-sitter receives incomplete/invalid code like:This isn't valid TSX — there's a closing tag without an opening tag, standalone components without a
returnstatement or function wrapper. Tree-sitter can't parse it correctly, so no syntax tokens are emitted and the text renders unstyled.Meanwhile, the other side might have 30+ lines of complete JSX that tree-sitter can successfully parse.
Expected Behavior
Both sides of a split diff should have correct syntax highlighting, regardless of how many lines each side has.
Suggested Fix
Instead of passing only the diff-visible lines to tree-sitter, the
DiffRenderablecould:This is how editors like VS Code handle diff syntax highlighting — they highlight the full file and then render only the relevant lines in the diff view.
An alternative (simpler but less complete) approach would be to pad the tree-sitter input with additional context beyond what's shown in the diff, to give the parser more syntactic structure to work with.
Environment
<diff>component in Solid.js withview="split",filetype="tsx", and aSyntaxStyle-U3)Reproduction
Any diff where one side has significantly fewer lines than the other, especially when the removed/added code is a small fragment (like closing tags, short component declarations) without enough surrounding structure for tree-sitter to identify the language.