Skip to content

vscode: terminal renders corrupted and cursor lands at top after window reactivation #1052

Description

@amrmelsayed

Symptom

When the VSCode window loses focus (alt-tab to another app, lock screen, second monitor switch, etc.) and the user returns to the Codev terminal pane, one of two things happens:

  1. Cursor renders at the wrong location — typed input lands near the top of the terminal pane instead of in the prompt area at the bottom where the cursor should be.
  2. Rendering corruption — the status bar / INSERT line stack up and partially overlay each other; old TUI frames bleed into new ones; the visual state of the terminal looks distorted until something forces a redraw (resize, focus toggle, manual refresh).

The two symptoms appear together or one without the other. Screenshots below show both in the same affected pane.

Reproduction

  1. Open a builder or architect terminal in VSCode (any Codev terminal pane backed by the shellper PTY relayed through Tower).
  2. Let the TUI (Claude Code's UI, or any full-screen alt-screen TUI) render normally.
  3. Switch focus away from the VSCode window — alt-tab to another app, lock the screen, or move to a different desktop / monitor. Wait at least a few seconds.
  4. Return focus to the VSCode window and click into the terminal pane.
  5. Type any character.

Expected: the character renders in the prompt area at the bottom of the terminal where the cursor was.
Actual: the character renders near the top of the terminal pane and / or the visible TUI state shows stacking overlapping render lines from prior frames.

Workarounds (none satisfying)

  • Resizing the VSCode window forces a full TUI redraw and clears the corruption — slow and disruptive.
  • Manually triggering the editor's terminal "clear" command — destroys the visible history.
  • Closing and reopening the terminal tab — destroys the connection.

Screenshots

Screenshot 1 — distorted TUI: stacked INSERT lines (─INSERTe──m▶▶tautotmodeoon, INSERT─C▶▶ auto mode on), the Musing… line garbled, cursor visible near the top by check #861's scope instead of in the empty prompt area below.

Image

Screenshot 2 — typed input rendering at the top of the terminal in what should be chat history (multi-line description text appearing as overlay), pasted file path drawing across older content, empty prompt unchanged at the bottom.

Image

Suspected area

This is a VSCode-side terminal rendering / state-sync issue, not (apparently) a Tower / shellper PTY bug. Several plausible mechanisms, none verified:

  1. xterm.js cursor-position desync. VSCode's terminal uses xterm.js. When the WebView loses and regains focus, xterm.js's internal cursor-position state may drift from where the PTY thinks the cursor is. Subsequent keystrokes land at xterm.js's tracked position, not the PTY's actual cursor location.
  2. WebSocket reconnect / replay race during window inactivity. When the VSCode window is hidden or inactive, the OS may throttle the WebView's network or timers. The Tower → VSCode WebSocket may briefly disconnect or pause draining. On reactivation, the accumulated output replays in a way that confuses xterm.js. This is adjacent to but distinct from the PR tower + vscode: fix terminal freeze (oversized-replay storm) and blank-on-open #1050 / tower + vscode: terminal freeze from oversized-replay reconnect storm (unbounded no-newline buffers + client backpressure loop) #1047 terminal-freeze fix — that issue was sustained CPU saturation, this one is a transient render-state corruption on focus change.
  3. Connect-time replay path interacting with window-visibility events. PR tower + vscode: fix terminal freeze (oversized-replay storm) and blank-on-open #1050 added a post-connect repaint nudge to address the blank-pane-on-open case (same-size resize as no-op). The same nudge may need to fire on window reactivation (onDidChangeWindowState) even when no reconnect happened — to force a known-clean redraw after long periods of background output accumulation in an unfocused WebView.
  4. TUI escape sequence interleaving during overload. Drop-not-reconnect (also from PR tower + vscode: fix terminal freeze (oversized-replay storm) and blank-on-open #1050) keeps the WebSocket alive but drops live output frames under overload. If a partial escape sequence is dropped mid-frame, xterm.js may end up in an inconsistent ANSI parser state. Returning to the window then displays the broken state until a manual redraw.

Reproduction context for the investigator

Per the screenshots, the affected pane is the architect terminal (Claude Code TUI). Reproducible reliably on the architect's daily-driver setup. Worth checking whether builder terminals exhibit the same symptom (same code path) or only the architect's pane (some architect-specific routing).

VSCode version, OS, multi-monitor configuration, and external-display refresh-rate variance probably matter for narrowing this down.

Suggested protocol

PIR. Root cause is ambiguous (four plausible mechanisms above, none verified). Investigation phase needed before a fix shape is obvious. Dev-approval gate is load-bearing because the fix is visual and reproducible-only-in-real-VSCode — PR diff alone cannot verify it works.

Related

Out of scope

  • Tower-side PTY behavior — PTY content reaching Tower is correct; the issue is between Tower's WS relay and VSCode's xterm.js renderer.
  • The terminal-freeze / oversized-replay class of bug (already fixed in tower + vscode: fix terminal freeze (oversized-replay storm) and blank-on-open #1050).
  • TUIs running in other terminal applications (iTerm2, Terminal.app) — those use a real PTY path, not the Tower-relayed WS path, and are not in scope here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/terminalArea: Terminal-specific (PTY, vscode terminal pane)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions