Clear TODO backlog: --debug/--profile, codex selection, MCP orientation, perf
- Add --debug[=DIR] / --profile[=DIR] flags that write run artefacts
(patterm.log, events.jsonl, per-child raw PTY captures, CPU + heap
+ goroutine pprof) to a dir without polluting stdout/stderr.
- Strengthen vendor-TUI orientation in three places (MCP
initialize.instructions, the spawn_agent tool description, and
help('spawning')) to head off codex's habits of poking the Unix
socket via perl and shelling out to launch peers — both bypass
caller identity and produce orphaned top-level tabs.
- Fix click-and-drag text selection from alt-screen TUIs. Host SGR
mouse reporting now follows the focused child's screen side
instead of being permanently armed; alt-screen TUIs that need
mouse re-enable it themselves and the toggle is forwarded.
- Move drawSidebar() off the per-PTY-chunk hot path. Long claude
session resume was paying a full sidebar rebuild for every
scrolled chunk; the chrome ticker now drains a dirty flag at 60 Hz.
- Gate the per-chunk Title() CGO poll on a containsOSC scan so
codex/ratatui's many SGR-only chunks no longer pay a CGO call each.
This commit is contained in:
@@ -33,6 +33,14 @@ type viewportRenderer struct {
|
||||
// cache so the next drawSidebar repaints over the clobber.
|
||||
scrolled bool
|
||||
|
||||
// childOnAlt tracks whether the focused child has entered its
|
||||
// alternate screen (via ?47 / ?1047 / ?1049). Used to gate mouse-
|
||||
// tracking-mode forwarding to the host: filter on primary so
|
||||
// patterm's wheel-scrollback stays armed, forward on alt so codex
|
||||
// (which disables mouse) lets the user select text and vim (which
|
||||
// enables it) still gets mouse events.
|
||||
childOnAlt bool
|
||||
|
||||
// skipUTF8 is set when the current multi-byte UTF-8 character started
|
||||
// past the viewport's right edge. The starter byte was dropped, so
|
||||
// the remaining continuation bytes must be dropped too instead of
|
||||
@@ -65,6 +73,16 @@ func newViewportRenderer(l terminalLayout) *viewportRenderer {
|
||||
return vr
|
||||
}
|
||||
|
||||
// SetChildOnAlt seeds the renderer's view of the focused child's screen
|
||||
// side. Used when a new renderer is constructed for an already-running
|
||||
// child whose alt-screen transition we missed, so subsequent mouse-mode
|
||||
// toggles are filtered/forwarded according to the right side.
|
||||
func (vr *viewportRenderer) SetChildOnAlt(onAlt bool) {
|
||||
vr.mu.Lock()
|
||||
defer vr.mu.Unlock()
|
||||
vr.childOnAlt = onAlt
|
||||
}
|
||||
|
||||
func (vr *viewportRenderer) SetLayout(l terminalLayout) {
|
||||
vr.mu.Lock()
|
||||
defer vr.mu.Unlock()
|
||||
@@ -236,15 +254,36 @@ func (vr *viewportRenderer) emitCSI() {
|
||||
return
|
||||
}
|
||||
if isAltScreenMode(params) {
|
||||
// Track the child's screen side so we know whether to filter
|
||||
// or forward subsequent mouse-mode toggles. Entering alt
|
||||
// disables host mouse reporting by default so codex (and
|
||||
// any other alt-screen TUI that doesn't request mouse)
|
||||
// allows the user to click-drag to select text. Alt-screen
|
||||
// TUIs that want mouse (vim, less with -X) re-enable it
|
||||
// via ?1000h after switching to alt — the forwarder below
|
||||
// passes that through. Leaving alt re-arms host mouse for
|
||||
// primary-screen wheel-scrollback.
|
||||
wasAlt := vr.childOnAlt
|
||||
vr.childOnAlt = final == 'h'
|
||||
if !wasAlt && vr.childOnAlt {
|
||||
vr.pending.WriteString("\x1b[?1000l\x1b[?1006l")
|
||||
}
|
||||
if wasAlt && !vr.childOnAlt {
|
||||
vr.pending.WriteString("\x1b[?1000h\x1b[?1006h")
|
||||
}
|
||||
return
|
||||
}
|
||||
if isMouseTrackingMode(params) {
|
||||
// Patterm owns mouse reporting on the host so wheel events keep
|
||||
// flowing for scroll-viewport. The child's own emulator still
|
||||
// observes the mode set/reset (it processes the same bytes we
|
||||
// hand to ghostty_terminal_vt_write), so we know whether the
|
||||
// child wants mouse input — we just don't let it disarm our
|
||||
// host listener.
|
||||
// On the child's primary screen patterm owns mouse reporting so
|
||||
// wheel events keep flowing for in-pane scrollback — drop the
|
||||
// child's toggle. On the alt screen the child should be free
|
||||
// to enable mouse (vim, less) or disable it (codex); we forward
|
||||
// the toggle to the host so click-and-drag selection works for
|
||||
// alt-screen TUIs that don't want mouse, and mouse-aware ones
|
||||
// still see the events they need.
|
||||
if vr.childOnAlt {
|
||||
vr.pending.Write(vr.buf)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user