Skip to content

Commit 80ec7da

Browse files
committed
fixes
1 parent c563a89 commit 80ec7da

2 files changed

Lines changed: 40 additions & 4 deletions

File tree

cmd/push-validator/cmd_dashboard.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,10 @@ func runDashboardInteractive(opts dashboard.Options) error {
151151
return fmt.Errorf("dashboard error: %w", err)
152152
}
153153

154-
// Flush stale terminal responses (cursor position reports, focus events)
155-
// that arrive after bubbletea exits the alternate screen
156-
ui.FlushStdinWithTimeout(50 * time.Millisecond)
154+
// Clean up terminal state and flush any pending async responses
155+
// This prevents escape sequences (CPR, OSC responses, focus events)
156+
// from appearing in the output after the dashboard closes
157+
ui.ResetTerminalAfterTUI()
157158

158159
return nil
159160
}

internal/ui/terminal_init.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)