@@ -41,10 +41,45 @@ func InitTerminal() {
4141 // Small delay to allow any pending responses to arrive
4242 time .Sleep (20 * time .Millisecond )
4343 // Flush any pending terminal responses from stdin
44- FlushStdinWithTimeout (50 * time .Millisecond )
44+ // Increased timeout to 150ms to catch slower terminals
45+ FlushStdinWithTimeout (150 * time .Millisecond )
4546 }
4647}
4748
49+ // ResetTerminalAfterTUI cleans up terminal state after a TUI (like bubbletea) exits.
50+ // This prevents escape sequences from asynchronous terminal responses (cursor position
51+ // reports, OSC responses) from appearing in the output after the TUI closes.
52+ //
53+ // Should be called after any bubbletea program exits, especially when using alternate screen.
54+ func ResetTerminalAfterTUI () {
55+ if ! term .IsTerminal (int (os .Stdout .Fd ())) {
56+ return
57+ }
58+
59+ // 1. Disable terminal query modes that may have been enabled
60+ // These prevent the terminal from sending unsolicited responses
61+ fmt .Fprint (os .Stdout , "\033 [?1004l" ) // Disable focus reporting
62+ fmt .Fprint (os .Stdout , "\033 [?1003l" ) // Disable all mouse tracking
63+ fmt .Fprint (os .Stdout , "\033 [?1000l" ) // Disable X10 mouse tracking
64+ fmt .Fprint (os .Stdout , "\033 [?1006l" ) // Disable SGR mouse mode
65+ fmt .Fprint (os .Stdout , "\033 [?25h" ) // Show cursor (ensure it's visible)
66+
67+ // 2. Send a carriage return to ensure we're at the start of a line
68+ // This prevents partial escape sequences from appearing mid-line
69+ fmt .Fprint (os .Stdout , "\r " )
70+
71+ // 3. Allow time for terminal to process the reset commands
72+ time .Sleep (30 * time .Millisecond )
73+
74+ // 4. Flush stdin to catch any async responses that arrived during/after TUI exit
75+ // Use a longer timeout (150ms) to catch delayed responses from slow terminals
76+ // Common delayed responses:
77+ // - Cursor position reports (CPR): ^[[row;colR
78+ // - OSC responses: ^[]11;rgb:xxxx/xxxx/xxxx^[\
79+ // - Focus events: ^[[I or ^[[O
80+ FlushStdinWithTimeout (150 * time .Millisecond )
81+ }
82+
4883// FlushStdinWithTimeout reads and discards stdin for the specified duration.
4984// This catches asynchronous terminal responses (cursor position reports,
5085// OSC responses, focus events) that arrive after queries are sent.
0 commit comments