Skip to content

Commit b64fa4f

Browse files
authored
fix(tui): Enable mouse capture for all terminals to restore scroll functionality (#11487)
## Summary Fixes the scrolling issue reported in #11434 where users couldn't scroll through task logs with their mouse on Windows (especially in VSCode's terminal). ### Problem PR #11418 introduced VSCode terminal detection that skipped `EnableMouseCapture` to prevent mouse event leakage to stdout. However, without mouse capture enabled, crossterm doesn't receive mouse scroll events—the terminal emulator consumes them for its own scrollback buffer instead. ### Solution - Remove VSCode terminal detection entirely - Always enable mouse capture on startup for all terminals - Rely on the proper cleanup code (already in place from #11444) to disable mouse capture on exit This restores mouse scroll functionality while the existing cleanup code handles: - Windows-specific `DisableMouseCapture` requirements - Panic handler terminal state restoration
1 parent fa0a461 commit b64fa4f

File tree

1 file changed

+7
-76
lines changed
  • crates/turborepo-ui/src/tui

1 file changed

+7
-76
lines changed

crates/turborepo-ui/src/tui/app.rs

Lines changed: 7 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -915,19 +915,6 @@ pub fn terminal_big_enough() -> Result<bool, Error> {
915915
Ok(width >= MIN_WIDTH && height >= MIN_HEIGHT)
916916
}
917917

918-
/// Detects if the current terminal is VSCode's integrated terminal.
919-
///
920-
/// VSCode's terminal is based on xterm.js and has issues with mouse capture -
921-
/// it can leak mouse events into child process stdout, causing garbage output.
922-
/// We detect VSCode to disable mouse capture and prevent this issue.
923-
fn is_vscode_terminal() -> bool {
924-
// Primary detection: TERM_PROGRAM is the most reliable indicator
925-
// VSCode sets TERM_PROGRAM=vscode in its integrated terminal
926-
std::env::var("TERM_PROGRAM")
927-
.map(|v| v.eq_ignore_ascii_case("vscode"))
928-
.unwrap_or(false)
929-
}
930-
931918
/// Configures terminal for rendering App
932919
#[tracing::instrument]
933920
fn startup(color_config: ColorConfig) -> io::Result<Terminal<CrosstermBackend<Stdout>>> {
@@ -939,19 +926,13 @@ fn startup(color_config: ColorConfig) -> io::Result<Terminal<CrosstermBackend<St
939926
// Ensure all pending writes are flushed before we switch to alternative screen
940927
stdout.flush()?;
941928

942-
// VSCode's terminal (xterm.js) has issues with mouse capture - it can leak
943-
// mouse events into child process stdout. Disable mouse capture for VSCode.
944-
if is_vscode_terminal() {
945-
crossterm::execute!(stdout, crossterm::terminal::EnterAlternateScreen)?;
946-
} else {
947-
crossterm::execute!(
948-
stdout,
949-
crossterm::event::EnableMouseCapture,
950-
crossterm::terminal::EnterAlternateScreen
951-
)?;
952-
// Track that mouse capture was enabled (important for Windows cleanup)
953-
super::panic_handler::set_mouse_capture_enabled();
954-
}
929+
crossterm::execute!(
930+
stdout,
931+
crossterm::event::EnableMouseCapture,
932+
crossterm::terminal::EnterAlternateScreen
933+
)?;
934+
// Track that mouse capture was enabled (important for Windows cleanup)
935+
super::panic_handler::set_mouse_capture_enabled();
955936

956937
// Mark TUI as active so panic handler knows to restore terminal state
957938
super::panic_handler::set_tui_active();
@@ -1210,7 +1191,6 @@ fn view<W>(app: &mut App<W>, f: &mut Frame) {
12101191

12111192
#[cfg(test)]
12121193
mod test {
1213-
use serial_test::serial;
12141194
use tempfile::tempdir;
12151195
use turbopath::AbsoluteSystemPathBuf;
12161196

@@ -2400,53 +2380,4 @@ mod test {
24002380

24012381
Ok(())
24022382
}
2403-
2404-
// Note: This test modifies the TERM_PROGRAM environment variable, which is
2405-
// process-global state. It must run serially to avoid interference with other
2406-
// tests that read TERM_PROGRAM (e.g., startup(), ColorConfig::rainbow()).
2407-
#[test]
2408-
#[serial]
2409-
fn test_is_vscode_terminal_detection() {
2410-
// Save original value to restore later
2411-
let original = std::env::var("TERM_PROGRAM").ok();
2412-
2413-
// SAFETY: Environment variable modification is safe here because this test
2414-
// runs serially (via #[serial]) and restores the original value on cleanup.
2415-
unsafe {
2416-
// Test: VSCode detection (lowercase)
2417-
std::env::set_var("TERM_PROGRAM", "vscode");
2418-
assert!(
2419-
is_vscode_terminal(),
2420-
"should detect VSCode when TERM_PROGRAM=vscode"
2421-
);
2422-
2423-
// Test: VSCode detection (mixed case)
2424-
std::env::set_var("TERM_PROGRAM", "VSCode");
2425-
assert!(is_vscode_terminal(), "should detect VSCode with mixed case");
2426-
2427-
// Test: Non-VSCode terminal
2428-
std::env::set_var("TERM_PROGRAM", "iTerm.app");
2429-
assert!(!is_vscode_terminal(), "should not detect iTerm as VSCode");
2430-
2431-
// Test: Empty value
2432-
std::env::set_var("TERM_PROGRAM", "");
2433-
assert!(
2434-
!is_vscode_terminal(),
2435-
"should not detect empty string as VSCode"
2436-
);
2437-
2438-
// Test: Unset variable
2439-
std::env::remove_var("TERM_PROGRAM");
2440-
assert!(
2441-
!is_vscode_terminal(),
2442-
"should not detect VSCode when TERM_PROGRAM is unset"
2443-
);
2444-
2445-
// Restore original value
2446-
match original {
2447-
Some(val) => std::env::set_var("TERM_PROGRAM", val),
2448-
None => std::env::remove_var("TERM_PROGRAM"),
2449-
}
2450-
}
2451-
}
24522383
}

0 commit comments

Comments
 (0)