diff --git a/yazi-adapter/src/mux.rs b/yazi-adapter/src/mux.rs index 167a2b5f..a59e4594 100644 --- a/yazi-adapter/src/mux.rs +++ b/yazi-adapter/src/mux.rs @@ -20,6 +20,37 @@ impl Mux { Cow::Borrowed(s) } } + + pub fn tmux_has_csi_u() -> bool { + let output = time!( + "Querying tmux for CSI u support", + std::process::Command::new("tmux") + .args(["display-message", "-p", "#{extended-keys},#{extended-keys-format}"]) + .output() + ); + + match output { + Ok(o) if o.status.success() => { + // Success case: The command ran and exited with code 0. + let stdout = String::from_utf8_lossy(&o.stdout); + stdout.trim() == "on,csi-u" + } + Ok(o) => { + // Execution Error: The command ran but failed. + error!( + "Querying tmux for CSI u support failed with status {:?}: {}", + o.status, + String::from_utf8_lossy(&o.stderr) + ); + false + } + Err(e) => { + // Spawn Error: The command could not be started. + error!("Failed to spawn `tmux display-message` for CSI u query: {}", e); + false + } + } + } pub fn tmux_passthrough() { let output = time!( diff --git a/yazi-fm/src/term.rs b/yazi-fm/src/term.rs index 8c92431c..ce332f42 100644 --- a/yazi-fm/src/term.rs +++ b/yazi-fm/src/term.rs @@ -30,23 +30,54 @@ impl Term { yazi_adapter::Mux::tmux_passthrough(); } - execute!( - TTY.writer(), - yazi_term::If(!TMUX.get(), EnterAlternateScreen), - Print("\x1bP$q q\x1b\\"), // Request cursor shape (DECRQSS query for DECSCUSR) - Print(Mux::csi("\x1b[?12$p")), // Request cursor blink status (DECSET) - Print("\x1b[?u"), // Request keyboard enhancement flags (CSI u) - Print(Mux::csi("\x1b[0c")), // Request device attributes - yazi_term::If(TMUX.get(), EnterAlternateScreen), - EnableBracketedPaste, - yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), EnableMouseCapture), - )?; + let mut csi_u_supported = false; // This will hold the result of our detection. - let resp = Emulator::read_until_da1(); - Mux::tmux_drain()?; - yazi_term::RestoreCursor::store(&resp); + if TMUX.get() { + // --- TMUX-SPECIFIC LOGIC --- + // 1. Reliably detect CSI u support by querying tmux's own options. + csi_u_supported = Mux::tmux_has_csi_u(); - CSI_U.store(resp.contains("\x1b[?0u"), Ordering::Relaxed); + // 2. Send only the essential queries, skipping the problematic cursor ones. + execute!( + TTY.writer(), + Print(Mux::csi("\x1b[0c")), // Request device attributes + EnterAlternateScreen, + EnableBracketedPaste, + yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), EnableMouseCapture), + )?; + + // 3. Read the terminal's response, but do NOT call store(). + // This allows tmux's native alternate screen restoration to work. + Emulator::read_until_da1(); + Mux::tmux_drain()?; + + } else { + // --- ORIGINAL LOGIC FOR NON-TMUX TERMINALS --- + // 1. Send all original queries, as they may be supported by other terminals. + execute!( + TTY.writer(), + yazi_term::If(!TMUX.get(), EnterAlternateScreen), + Print("\x1bP$q q\x1b\\"), // Request cursor shape (DECRQSS query for DECSCUSR) + Print(Mux::csi("\x1b[?12$p")), // Request cursor blink status (DECSET) + Print("\x1b[?u"), // Request keyboard enhancement flags (CSI u) + Print(Mux::csi("\x1b[0c")), // Request device attributes + yazi_term::If(TMUX.get(), EnterAlternateScreen), + EnableBracketedPaste, + yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), EnableMouseCapture), + )?; + + // 2. Use the original logic to parse the response and store the cursor state. + let resp = Emulator::read_until_da1(); + Mux::tmux_drain()?; + yazi_term::RestoreCursor::store(&resp); + + // 3. Check the ANSI response for CSI u support, as before. + if resp.contains("\x1b[?0u") { + csi_u_supported = true; + } + } + + CSI_U.store(csi_u_supported, Ordering::Relaxed); if CSI_U.load(Ordering::Relaxed) { PushKeyboardEnhancementFlags( KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES