| // suspend TUI, stop stdin-reader to avoid SIGTTIN, run cmd on real TTY, resume
|
| async fn run_external(app: &mut App, cmdline: &str, _ui_tx: mpsc::Sender<UiInput>) -> bool {
|
| // Stop stdin reader so we don't read while backgrounded
|
| if let Some(h) = app.stdin_task.take() {
|
| h.abort();
|
| let _ = h.await;
|
| }
|
|
|
| // Leave alt-screen and show cursor
|
| let _ = std::io::Write::write_all(app.terminal.backend_mut(), b"\x1b[?1049l\x1b[?25h\x1b[0m");
|
| let _ = app.terminal.backend_mut().flush();
|
|
|
| // Restore cooked while external program runs.
|
| set_tty_cooked(&app.saved_termios);
|
|
|
| // Run synchronously.
|
| let status = std::process::Command::new("sh")
|
| .arg("-lc")
|
| .arg(cmdline)
|
| .status();
|
|
|
| // Re-enter alt-screen, hide cursor and restore RAW.
|
| let _ = std::io::Write::write_all(app.terminal.backend_mut(), b"\x1b[?1049h\x1b[?25l");
|
| let _ = app.terminal.backend_mut().flush();
|
|
|
| // Switch terminal back to RAW (so keystrokes are delivered immediately)
|
| set_tty_raw_from_saved(&app.saved_termios);
|
|
|
| // Re-apply winsize (external may have resized)
|
| if let Ok(sz) = app.terminal.size() {
|
| let area = ratatui::layout::Rect::new(0, 0, sz.width, sz.height);
|
| app.area = area;
|
| set_pty_winsize(&app.pty_master_cmd, area);
|
| if let Some(ref fd) = app.pty_master_ipc {
|
| set_pty_winsize(fd, area);
|
| }
|
| }
|
|
|
| // Redraw, refresh title and respawn stdin reader.
|
| app.force_redraw();
|
| app.update_osc_title_for_tab();
|
| spawn_stdin_reader(app);
|
|
|
| match status {
|
| Ok(st) => {
|
| let msg = if let Some(c) = st.code() {
|
| format!(":! {} exited with code {}", cmdline, c)
|
| } else {
|
| #[cfg(unix)]
|
| {
|
| use std::os::unix::process::ExitStatusExt;
|
| if let Some(sig) = st.signal() {
|
| format!(":! {} killed by signal {}", cmdline, sig)
|
| } else {
|
| format!(":! {} exited", cmdline)
|
| }
|
| }
|
| #[cfg(not(unix))]
|
| {
|
| format!(":! {} exited", cmdline)
|
| }
|
| };
|
| app.push_msg_plain(msg);
|
| }
|
| Err(e) => {
|
| app.push_msg_plain(format!(":! {} failed: {}", cmdline, e));
|
| }
|
| }
|
| false
|
| }
|