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
The opt-in CJK terminal cell-width correction experiment (Settings → Experiments) currently exhibits a 1-frame glyph-size shift on tab switch when the visible pane size changes. Tracks #164 follow-up work.
Repro
Settings → Terminal → set Font family to a CJK monospaced font where W and 가 measure the same advance (e.g. D2Coding, Sarasa Mono K, IA Writer Mono V)
Open at least two sessions and switch between tabs while their panes differ in size
Expected: tab swap is a clean cut between rendered buffers.
Actual: 1 frame at the natural W advance is visible mid-swap — characters look briefly larger ("커졌다가") before snapping back to the halved cell width.
Root cause
Frame-by-frame inspection of a screen capture confirmed the transient. The portal target div hosting xterm moves limbo → pane body on tab activation. ResizeObserver fires → fitAddon.fit() → core._renderService.handleResize → DomRenderer._updateDimensions:
resets cell.width to the raw W advance (× dpr). The addon's post-fit patchTerminalCellMeasurements reapplies the halved value, but a paint can occur in between, producing the visible jump.
What we tried (all kept the transient)
Module-level measurement memo + fast-path early return on cached + already-at-target. Avoided redundant widthCache.clear + recalibrateDefaultSpacing rounds but did not close the resize-time gap.
_charSizeService.width getter intercept via Object.defineProperty so xterm's _updateDimensions would read the halved value from the start. Behavior unchanged in app.
renderer.handleResize wrap (call original, then applyCellWidth(target) in the same sync tick before next paint). Behavior unchanged in app.
term.options.letterSpacing public option (with dpr correction since xterm folds it into device.cell.width not the CSS value). Behavior unchanged in app.
Possible next steps
Replace the xterm.js DOM renderer with a forked variant whose _updateDimensions reads the half-cell target as the canonical char width.
Replace fitAddon with a custom fit that does not call core._renderService.clear() when only the surrounding pane size changes.
Investigate whether a requestAnimationFrame deferral of the patch reapply could collapse into the same paint as xterm's resize repaint (instead of one extra paint after).
Render the terminal at the actual pane dimensions while in limbo (currently fixed 800×600) so tab activation does not trigger a resize.
Workaround
The toggle ships off by default. Users hitting the original D2Coding-style misalignment can opt in and accept the flicker; the Experiments row description spells out the limitation.
Summary
The opt-in CJK terminal cell-width correction experiment (Settings → Experiments) currently exhibits a 1-frame glyph-size shift on tab switch when the visible pane size changes. Tracks #164 follow-up work.
Repro
Font familyto a CJK monospaced font whereWand가measure the same advance (e.g.D2Coding,Sarasa Mono K,IA Writer Mono V)Expected: tab swap is a clean cut between rendered buffers.
Actual: 1 frame at the natural
Wadvance is visible mid-swap — characters look briefly larger ("커졌다가") before snapping back to the halved cell width.Root cause
Frame-by-frame inspection of a screen capture confirmed the transient. The portal target div hosting xterm moves limbo → pane body on tab activation.
ResizeObserverfires →fitAddon.fit()→core._renderService.handleResize→DomRenderer._updateDimensions:resets
cell.widthto the rawWadvance (× dpr). The addon's post-fitpatchTerminalCellMeasurementsreapplies the halved value, but a paint can occur in between, producing the visible jump.What we tried (all kept the transient)
widthCache.clear+recalibrateDefaultSpacingrounds but did not close the resize-time gap._charSizeService.widthgetter intercept viaObject.definePropertyso xterm's_updateDimensionswould read the halved value from the start. Behavior unchanged in app.renderer.handleResizewrap (call original, thenapplyCellWidth(target)in the same sync tick before next paint). Behavior unchanged in app.term.options.letterSpacingpublic option (withdprcorrection since xterm folds it intodevice.cell.widthnot the CSS value). Behavior unchanged in app.Possible next steps
xterm.jsDOM renderer with a forked variant whose_updateDimensionsreads the half-cell target as the canonical char width.fitAddonwith a custom fit that does not callcore._renderService.clear()when only the surrounding pane size changes.requestAnimationFramedeferral of the patch reapply could collapse into the same paint as xterm's resize repaint (instead of one extra paint after).Workaround
The toggle ships off by default. Users hitting the original D2Coding-style misalignment can opt in and accept the flicker; the Experiments row description spells out the limitation.
References
src/lib/terminal-cjk-cell-width-addon.ts,src/components/Terminal.tsx,src/components/SettingsModal.tsx