You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug: invisible highlighting in light mode terminals #113
When trying to highlight text in the terminal (click-and-drag with the mouse), the highlight is not perceivable.
Expected behavior
For each theme, highlighting text in the terminal should use the same text color and background color as is adopted in the file editor for proper contrast.
Steps to reproduce
n/a
Environment
No response
Logs or screenshots
Additional context
No response
Before submitting
I searched existing issues and did not find a duplicate.
I have provided enough information to reproduce the issue.
Issue #113 will make terminal text selection visibly readable in every visual theme by defining one explicit selection foreground/background pair per theme and applying it consistently to the file editor and xterm terminal.
Current findings
src/ui/themes.mjs is the shared visual-theme registry and already owns each xterm palette.
src/ui/terminal.js passes the registry palette to xterm both at startup and when themes change.
xterm supports selectionBackground, selectionForeground, and selectionInactiveBackground, but the current palettes omit them.
src/ui/editor.js explicitly defines selection colors only for the custom dark Monaco theme; built-in Monaco themes currently rely on Monaco defaults.
Tasks
Extend the theme registry with explicit selection colors for all five themes.
Keep selection foreground/background values in the registry as the single source of truth.
Add the corresponding xterm selection fields, including inactive selection background.
Choose contrast-safe values for light and high-contrast themes, while preserving the existing dark-theme appearance.
Apply the same registry values to Monaco.
Define or extend the app-owned Monaco theme definitions so each visual theme uses the registry selection foreground/background pair rather than an implicit Monaco default.
Preserve editor content, diagnostics, cursor state, and theme switching behavior.
Keep xterm theme switching on the existing path.
Continue using terminalTheme at terminal creation and terminal.options.theme in setTheme().
Do not add CSS overrides or recreate the terminal.
Add regression coverage.
Extend scripts/e2e-settings-visual-theme.test.mjs (or add a focused test) to require selection fields for every theme and reject identical foreground/background pairs or a selection background equal to the terminal background.
Extend browser smoke coverage to select visible terminal text in light and high-contrast themes, verify the selection is rendered with a distinct non-transparent style, and verify switching themes updates the live terminal without losing content.
Acceptance criteria
Mouse-selected terminal text is perceivable in Light and High Contrast Light.
Selection remains readable in browser.cpp Dark, Dark, and High Contrast Dark.
Monaco and xterm use the same explicit selection foreground/background pair for the active theme.
Changing themes updates selection colors without reload or terminal recreation.
Automated tests catch missing selection fields and low-contrast/identical color pairs.
Verification
npm run lint
npm run build
npm run test:e2e
npm run test:browser:chrome when the local browser/Clang fixture is available
Canvas/DOM rendering can make browser assertions implementation-sensitive; the smoke test should verify the live xterm theme/rendered selection behavior rather than rely only on registry values.
No files are changed by this planning pass. Implementation should proceed on a feature branch and land through a PR referencing closes #113.
The implementation uses one project-owned selection pair per theme, shared by Monaco and xterm. Registry coverage enforces at least 4.5:1 contrast between selected text and its background. Browser smoke performs a real mouse drag in Light and High Contrast Light, then checks xterm's selected text and active selection theme values while confirming terminal content survives theme changes. It checks the live selection state and configured renderer colors rather than screenshot pixels, which would vary across xterm renderers.
The internal Monaco theme IDs are implementation details; persisted visual theme IDs remain unchanged. The PR will close this issue.
The PR did not fix the bug. See the attached screenshot, where the user has highlighted the Available commands: and g++ lines in the terminal but there is no visual indicator of highlight. The file editor's selection has light blue highlight behind black text so the terminal should have similar highlight according to the specs
Plan update for #113 after the reported failure of PR #114
The latest report says selections over “Available commands:” and “g++” in the terminal have no visible highlight, although the file editor shows a light-blue selection behind black text. PR #114 is merged, but its smoke test verified xterm's logical selection and theme options—not rendered visibility—so it did not establish that the bug was fixed.
Revised plan
Reproduce in the browser smoke test using the reported terminal content and light theme. Select the exact text with a real mouse interaction and record xterm's selected text, selection overlay elements, their non-zero rectangles, computed foreground/background colors, focus state, and screenshot.
Diagnose rendering before changing colors: if the logical selection exists but the overlay is absent, zero-sized, transparent, occluded, or clipped, trace the renderer/CSS/layout issue and fix that cause. Check both focused and unfocused selection paths.
Match the light terminal selection to the stated editor appearance: light-blue background with black selected text. Prefer deriving expected appearance from the editor's computed selection colors in the same browser over hard-coded guesses. Preserve stable/persisted theme IDs; ensure dark themes retain a clearly visible, readable selection.
Strengthen regression coverage. The browser test must fail when selection state exists without a visible overlay or visible screenshot change, and must check the selected text's foreground as well as the highlight. Use existing PNG tooling for a focused pixel-level comparison if DOM/style assertions alone cannot detect occlusion. Cover light and dark themes, then switch themes and reselect.
In the light theme, selecting the reported command and compiler lines visibly produces a light-blue highlight behind black text, comparable to the editor selection.
Browser regression coverage verifies rendered visibility (not only xterm selection state), geometry, and foreground/background appearance.
Dark-theme selection remains visible and readable; theme switching does not leave stale or invisible selection rendering.
Persisted theme IDs and stored user preferences remain compatible.
Assumption: “similar highlight” means visually comparable light blue and black, not exact pixel identity. The attached screenshot is not available in the issue API response; the text description above is the acceptance reference, and the browser smoke test can sample the editor's computed selection style.
The user has now attached the two screenshots referenced in the comment. They clarify the visual target: the editor shows a rounded light-blue selection behind dark text, while the selected terminal text has no visible highlight.
I updated the plan artifact at specs/issue-113-20261013-sdlc_planner-visible-terminal-selection.md to use those screenshots as the reference. The browser smoke acceptance now compares selected terminal pixels against adjacent unselected cells and checks for a clearly visible light-blue/dark-text result; exact pixel identity is not required.
Updated plan: make terminal selection visibly render
The screenshots confirm the acceptance target: the editor selection is rounded light blue behind dark text, while selecting Available commands: and g++ in the terminal paints no visible highlight. PR #114 checked xterm's logical selection and theme options, not rendered visibility.
Sync a feature branch to current main including merged PR fix(terminal): make selection visible across themes #114, reproduce in Chrome, and collect selected text, renderer/overlay geometry, computed colors, focus state, and before/after screenshots.
Diagnose the rendering stage first: check whether overlay elements exist, overlap selected cells, and are visible rather than transparent, clipped, or occluded. Inspect focused and unfocused behavior. Choose a fix based on the evidence.
Fix the cause so Light and High Contrast Light render a clearly visible light-blue highlight behind dark text, comparable to the editor screenshot. Preserve readable dark-theme selections, persisted theme IDs, and terminal contents through live theme changes.
Add a real-mouse-drag browser regression on the reported help text. Assert logical selected text, non-zero overlay geometry, computed colors, and visible screenshot/pixel differences from adjacent unselected cells. Cover Light, High Contrast Light, and theme switching; state-only assertions are insufficient.
Keep registry tests for configuration, then run lint, build, E2E, smoke script syntax check, and Chrome browser smoke. Include rendered evidence in the PR.
Acceptance: the selected Available commands: and g++ lines visibly show a light-blue highlight with dark text in Light theme; High Contrast Light remains perceivable; dark themes remain readable; browser tests fail when selection is logically present but visually absent. Exact pixel matching to Monaco is not specified; visually comparable is the target.
The detailed plan is in specs/issue-113-20261013-sdlc_planner-visible-terminal-selection.md. No code changes are included in this planning update.
Plan update: remove the light-theme terminal black strip (#113)
@kbuffardi reported: “the highlighting looks better now but both light modes are showing a weird black box in the terminal.”
Investigation findings
The strip is a new regression in the selection-rendering follow-up, not a missing Light/High Contrast Light color definition. Those themes configure a white terminal background.
The current workaround in src/ui/terminal.js calls xterm 6's private term._core._renderService.handleSelectionChanged(...) directly from public selection events, terminal mouseup, and theme changes.
xterm's own selection service instead queues selection redraws on an animation frame and routes them through its render service. The private direct call bypasses that scheduling and renderer coordination. It is the most likely source of a stale or partially repainted canvas/DOM region, but the fix will be selected only after reproducing the strip.
Implementation plan
Create a focused failing browser regression.
Start in Light and High Contrast Light with the terminal at the same size/scroll state as the report.
Run the real help command, mouse-select Available commands: and g++, then move focus away and switch themes.
Capture screenshots and sample the terminal's blank regions, including the lower viewport. The test must fail if a black/non-terminal-background rectangle remains after selection repaint, clearing selection, blur, or theme change.
Localize the renderer state before changing behavior.
Record the active xterm renderer, canvas/selection-layer bounds, selection range, viewport bounds, computed terminal background, and repaint timing for the failing sequence.
Compare the private direct refresh with xterm's normal queued selection redraw. Confirm whether the strip appears only with the direct refresh or also in xterm's native path.
Replace the unsafe repaint mechanism with the smallest supported flow.
Remove the direct dependency on xterm private internals if the native selection redraw now produces visible highlights.
If a follow-up repaint is still needed for a specific renderer, schedule it after xterm finalizes the range and use the narrowest renderer-compatible public behavior possible; do not invoke the private render service directly from every selection event.
Preserve the existing requirements: exact Monaco selection colors, visible inactive selection, live theme changes without clearing the selection, and all five themes.
Verify the complete visual state.
Keep the existing exact-color and selected-pixel checks.
Add assertions that all unselected terminal pixels—including the lower blank viewport—match the configured terminal background within screenshot tolerance, and that selection clearing/theme transitions remove stale paint.
Run npm run lint, npm run build, npm run test:e2e, node --check scripts/smoke-browser.mjs, and the Chrome smoke test.
Acceptance criteria
Light and High Contrast Light have no black strip or stale dark region before, during, or after selecting terminal text.
The terminal's non-selected viewport consistently paints its configured background.
Existing visible-selection coverage continues to pass across every theme and selection focus state.
The production terminal code no longer relies on an unguarded direct call to xterm's private render service unless browser evidence proves it is required and safe for every supported renderer.
No implementation files were changed during this investigation.
Revised plan: eliminate the light-theme terminal black strip (#113)
@kbuffardi requested an updated plan after two reviews identified gaps in the initial black-strip investigation. This replaces the prior plan. The detailed implementation plan is in specs/issue-113-20261013-sdlc_planner-visible-terminal-selection.md.
Evidence and scope
The regression appears after the visible-selection follow-up in Light and High Contrast Light, whose configured terminal backgrounds are white.
Current production code directly calls xterm 6 private render-service internals from public selection events, terminal mouseup, and theme changes.
This is a hypothesis, not a root-cause conclusion. The black strip may instead be canvas clearing, parent/CSS background exposure, terminal geometry, DPR, font-fit timing, or another renderer issue.
Automated scope is Chrome with the app’s active xterm default renderer. The app does not configure rendererType; any new renderer-specific branch must add that renderer to the smoke matrix. Edge/Brave/Chromium remain optional confidence runs.
Deterministic RED regression
Before changing production code, extend scripts/smoke-browser.mjs to reproduce the issue with:
A fixed Chrome viewport, forced DPR and 100% zoom, deterministic terminal-panel height, stable terminal rows/columns, stable xterm screen/cell geometry for two animation frames, and completed font readiness.
Page scroll reset to 0,0; terminal scroll positioned so real help output places Available commands: and g++ in known visible rows with known blank rows below.
The genuine terminal input path: focus terminal, type help, press Enter, wait for its actual buffer output, and real-CDP drag-select both target strings. Do not inject help output through a smoke hook.
Cell-aligned samples from known blank cells inside .xterm-screen, excluding text glyphs, selection cells, cursor, scrollbar, padding, and borders. Sampling must not depend on selection-overlay bounds.
Screenshots and assertions after each state separately: select, blur, retained-selection theme switch, clear, clear-then-theme-switch, and theme-switch-then-clear.
For Light and High Contrast Light, blank cells must match the configured terminal background within screenshot tolerance and must not be black. Selected cells must visibly differ from adjacent unselected cells. Existing all-theme exact Monaco/xterm selection-color and inactive-selection checks remain required.
Controlled diagnosis and decision gates
Run the exact same sequence with the private repaint disabled (native/public xterm behavior) and enabled, keeping browser binary, launch args, renderer, viewport, DPR, zoom, panel height, rows/columns, font readiness, scroll offset, output, mouse coordinates, and waits identical. Record computed backgrounds for #terminal-panel, #terminal-container, .xterm, .xterm-screen, canvas/rows layers, and .xterm-selection.
If native/public behavior passes the selection and blank-cell checks, remove the private direct render-service call.
If a public repaint is required, use the narrowest documented/public mechanism, such as a scheduled visible-row refresh after a theme update.
If diagnostics show CSS, parent, canvas, stacking, or clipping exposure, correct that specific layer.
Retain a private fallback only if same-run A/B evidence proves public and CSS alternatives cannot meet the contract. It must be isolated in one helper, guarded by affected renderer/browser/timing conditions, scheduled after selection geometry finalizes, documented with its removal condition, and never run unconditionally from every selection event, mouseup, and theme change.
Required guarantees and diagnostics
The final change must preserve exact Monaco-derived active and inactive selection colors for all five themes; visible inactive selections; terminal content, scroll state, and selection through live theme changes; persisted theme IDs; and real help drag selection.
The test must fail RED on the current reproduction before the fix, then pass GREEN afterward. On failure, save screenshots and JSON diagnostics with browser/version/headless mode, viewport, DPR, zoom, renderer, geometry, rows/columns, font metrics, page/terminal scroll, selection range/focus/theme, layer backgrounds, blank-cell coordinates, expected/actual colors, and common failing-region colors.
Validation and delivery
npm run lint
npm run build
npm run test:e2e
node --check scripts/smoke-browser.mjs
npm run test:browser:chrome
Implementation will start from current main on fix/terminal-selection-black-strip, preserve unrelated work, and be submitted in a PR containing closes #113, the A/B conclusion, supported renderer/browser scope, and diagnostic-artifact references.
No production code was changed in this planning update.
New reproduction evidence: black strip exists before selection
@kbuffardi attached a Light-theme startup screenshot showing the black strip at the bottom of the terminal before any terminal text has been selected. The welcome banner and prompt are visible, but the lower blank terminal region is black.
This changes the investigation order:
Do not treat the private selection repaint path as the immediate trigger. It may still be relevant to earlier selection behavior, but this screenshot proves the black strip can occur with no selection, blur, clear, or theme transition.
The RED regression must first assert blank, cell-aligned lower viewport cells immediately after terminal creation, initial fit(), and welcome-banner rendering—before typing or selecting anything.
Diagnose terminal geometry and background propagation first: compare #terminal-panel, #terminal-container, .xterm, .xterm-screen, and xterm canvas/rows-layer bounds and computed backgrounds against the configured terminal background. Capture terminal rows/columns, canvas CSS/pixel dimensions, DPR, panel height, and the exact blank-cell coordinates.
Then repeat the same blank-cell assertion after help, selection, blur, clear, and theme transitions to ensure a startup fix does not regress the selection requirements.
The black strip is now a baseline terminal-rendering/background defect, not only a selection-state defect. No production code changed in response to this evidence.
Activity
kbuffardi commentedon Oct 13, 2026
Implementation plan
Issue #113 will make terminal text selection visibly readable in every visual theme by defining one explicit selection foreground/background pair per theme and applying it consistently to the file editor and xterm terminal.
Current findings
src/ui/themes.mjsis the shared visual-theme registry and already owns each xterm palette.src/ui/terminal.jspasses the registry palette to xterm both at startup and when themes change.selectionBackground,selectionForeground, andselectionInactiveBackground, but the current palettes omit them.src/ui/editor.jsexplicitly defines selection colors only for the custom dark Monaco theme; built-in Monaco themes currently rely on Monaco defaults.Tasks
Extend the theme registry with explicit selection colors for all five themes.
Apply the same registry values to Monaco.
Keep xterm theme switching on the existing path.
terminalThemeat terminal creation andterminal.options.themeinsetTheme().Add regression coverage.
scripts/e2e-settings-visual-theme.test.mjs(or add a focused test) to require selection fields for every theme and reject identical foreground/background pairs or a selection background equal to the terminal background.Acceptance criteria
Verification
npm run lintnpm run buildnpm run test:e2enpm run test:browser:chromewhen the local browser/Clang fixture is availableRisks and decisions
No files are changed by this planning pass. Implementation should proceed on a feature branch and land through a PR referencing
closes #113.kbuffardi commentedon Oct 13, 2026
Plan review and decisions
@kbuffardi: “yes” to keeping the persisted theme IDs (
vs,vs-dark,hc-light, andhc-black) unchanged while mapping them to app-owned Monaco theme IDs.@kbuffardi: “implement this plan and raise a pr”.
The implementation uses one project-owned selection pair per theme, shared by Monaco and xterm. Registry coverage enforces at least 4.5:1 contrast between selected text and its background. Browser smoke performs a real mouse drag in Light and High Contrast Light, then checks xterm's selected text and active selection theme values while confirming terminal content survives theme changes. It checks the live selection state and configured renderer colors rather than screenshot pixels, which would vary across xterm renderers.
The internal Monaco theme IDs are implementation details; persisted visual theme IDs remain unchanged. The PR will close this issue.
kbuffardi commentedon Oct 13, 2026
The PR did not fix the bug. See the attached screenshot, where the user has highlighted the
Available commands:andg++lines in the terminal but there is no visual indicator of highlight. The file editor's selection has light blue highlight behind black text so the terminal should have similar highlight according to the specskbuffardi commentedon Oct 13, 2026
Plan update for #113 after the reported failure of PR #114
The latest report says selections over “Available commands:” and “g++” in the terminal have no visible highlight, although the file editor shows a light-blue selection behind black text. PR #114 is merged, but its smoke test verified xterm's logical selection and theme options—not rendered visibility—so it did not establish that the bug was fixed.
Revised plan
Acceptance criteria
Assumption: “similar highlight” means visually comparable light blue and black, not exact pixel identity. The attached screenshot is not available in the issue API response; the text description above is the acceptance reference, and the browser smoke test can sample the editor's computed selection style.
kbuffardi commentedon Oct 13, 2026
The user has now attached the two screenshots referenced in the comment. They clarify the visual target: the editor shows a rounded light-blue selection behind dark text, while the selected terminal text has no visible highlight.
I updated the plan artifact at specs/issue-113-20261013-sdlc_planner-visible-terminal-selection.md to use those screenshots as the reference. The browser smoke acceptance now compares selected terminal pixels against adjacent unselected cells and checks for a clearly visible light-blue/dark-text result; exact pixel identity is not required.
kbuffardi commentedon Oct 13, 2026
Updated plan: make terminal selection visibly render
The screenshots confirm the acceptance target: the editor selection is rounded light blue behind dark text, while selecting
Available commands:andg++in the terminal paints no visible highlight. PR #114 checked xterm's logical selection and theme options, not rendered visibility.Acceptance: the selected
Available commands:andg++lines visibly show a light-blue highlight with dark text in Light theme; High Contrast Light remains perceivable; dark themes remain readable; browser tests fail when selection is logically present but visually absent. Exact pixel matching to Monaco is not specified; visually comparable is the target.The detailed plan is in
specs/issue-113-20261013-sdlc_planner-visible-terminal-selection.md. No code changes are included in this planning update.kbuffardi commentedon Oct 13, 2026
@kbuffardi confirmed the implementation requirements during the plan review interview:
helpoutput with controlled terminal size/scroll state for stable reproduction ofAvailable commands:andg++.Implementation will target the merged PR #114 state, use renderer-specific handling only where required by the evidence, and retain theme IDs.
kbuffardi commentedon Oct 13, 2026
Plan update: remove the light-theme terminal black strip (#113)
@kbuffardi reported: “the highlighting looks better now but both light modes are showing a weird black box in the terminal.”
Investigation findings
src/ui/terminal.jscalls xterm 6's privateterm._core._renderService.handleSelectionChanged(...)directly from public selection events, terminalmouseup, and theme changes.Implementation plan
Create a focused failing browser regression.
helpcommand, mouse-selectAvailable commands:andg++, then move focus away and switch themes.Localize the renderer state before changing behavior.
Replace the unsafe repaint mechanism with the smallest supported flow.
Verify the complete visual state.
npm run lint,npm run build,npm run test:e2e,node --check scripts/smoke-browser.mjs, and the Chrome smoke test.Acceptance criteria
No implementation files were changed during this investigation.
kbuffardi commentedon Oct 13, 2026
Revised plan: eliminate the light-theme terminal black strip (#113)
@kbuffardi requested an updated plan after two reviews identified gaps in the initial black-strip investigation. This replaces the prior plan. The detailed implementation plan is in
specs/issue-113-20261013-sdlc_planner-visible-terminal-selection.md.Evidence and scope
mouseup, and theme changes.rendererType; any new renderer-specific branch must add that renderer to the smoke matrix. Edge/Brave/Chromium remain optional confidence runs.Deterministic RED regression
Before changing production code, extend
scripts/smoke-browser.mjsto reproduce the issue with:0,0; terminal scroll positioned so realhelpoutput placesAvailable commands:andg++in known visible rows with known blank rows below.help, press Enter, wait for its actual buffer output, and real-CDP drag-select both target strings. Do not inject help output through a smoke hook..xterm-screen, excluding text glyphs, selection cells, cursor, scrollbar, padding, and borders. Sampling must not depend on selection-overlay bounds.For Light and High Contrast Light, blank cells must match the configured terminal background within screenshot tolerance and must not be black. Selected cells must visibly differ from adjacent unselected cells. Existing all-theme exact Monaco/xterm selection-color and inactive-selection checks remain required.
Controlled diagnosis and decision gates
Run the exact same sequence with the private repaint disabled (native/public xterm behavior) and enabled, keeping browser binary, launch args, renderer, viewport, DPR, zoom, panel height, rows/columns, font readiness, scroll offset, output, mouse coordinates, and waits identical. Record computed backgrounds for
#terminal-panel,#terminal-container,.xterm,.xterm-screen, canvas/rows layers, and.xterm-selection.Required guarantees and diagnostics
The final change must preserve exact Monaco-derived active and inactive selection colors for all five themes; visible inactive selections; terminal content, scroll state, and selection through live theme changes; persisted theme IDs; and real
helpdrag selection.The test must fail RED on the current reproduction before the fix, then pass GREEN afterward. On failure, save screenshots and JSON diagnostics with browser/version/headless mode, viewport, DPR, zoom, renderer, geometry, rows/columns, font metrics, page/terminal scroll, selection range/focus/theme, layer backgrounds, blank-cell coordinates, expected/actual colors, and common failing-region colors.
Validation and delivery
npm run lintnpm run buildnpm run test:e2enode --check scripts/smoke-browser.mjsnpm run test:browser:chromeImplementation will start from current
mainonfix/terminal-selection-black-strip, preserve unrelated work, and be submitted in a PR containingcloses #113, the A/B conclusion, supported renderer/browser scope, and diagnostic-artifact references.No production code was changed in this planning update.
kbuffardi commentedon Oct 14, 2026
New reproduction evidence: black strip exists before selection
@kbuffardi attached a Light-theme startup screenshot showing the black strip at the bottom of the terminal before any terminal text has been selected. The welcome banner and prompt are visible, but the lower blank terminal region is black.
This changes the investigation order:
fit(), and welcome-banner rendering—before typing or selecting anything.#terminal-panel,#terminal-container,.xterm,.xterm-screen, and xterm canvas/rows-layer bounds and computed backgrounds against the configured terminal background. Capture terminal rows/columns, canvas CSS/pixel dimensions, DPR, panel height, and the exact blank-cell coordinates.help, selection, blur, clear, and theme transitions to ensure a startup fix does not regress the selection requirements.The black strip is now a baseline terminal-rendering/background defect, not only a selection-state defect. No production code changed in response to this evidence.
fix(terminal): inherit the themed viewport background