From c22e815cb1e619f3ec1251c807a06c76ab5ad844 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Thu, 2 Sep 2021 12:58:44 -0700 Subject: [PATCH 01/11] feat(cwd-pane): Add a new trait to get the cwd of a given pid Co-authored-by: Quentin Rasmont --- Cargo.lock | 56 ++++++++++++++++++---------- zellij-server/Cargo.toml | 3 ++ zellij-server/src/os_input_output.rs | 20 ++++++++++ 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c2cdcd3ee..cd7f26779a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,11 +4,11 @@ version = 3 [[package]] name = "addr2line" -version = "0.16.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" dependencies = [ - "gimli 0.25.0", + "gimli 0.24.0", ] [[package]] @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] @@ -227,16 +227,16 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.61" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" +checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" dependencies = [ "addr2line", "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.26.0", + "object 0.24.0", "rustc-demangle", ] @@ -621,6 +621,26 @@ dependencies = [ "syn", ] +[[package]] +name = "darwin-libproc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc629b7cf42586fee31dae31f9ab73fa5ff5f0170016aa61be5fcbc12a90c516" +dependencies = [ + "darwin-libproc-sys", + "libc", + "memchr", +] + +[[package]] +name = "darwin-libproc-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef0aa083b94c54aa4cfd9bbfd37856714c139d1dc511af80270558c7ba3b4816" +dependencies = [ + "libc", +] + [[package]] name = "derivative" version = "2.2.0" @@ -897,9 +917,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.25.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" [[package]] name = "gloo-timers" @@ -1188,9 +1208,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "memmap2" @@ -1325,12 +1345,9 @@ dependencies = [ [[package]] name = "object" -version = "0.26.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" -dependencies = [ - "memchr", -] +checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" [[package]] name = "once_cell" @@ -1675,9 +1692,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" dependencies = [ "aho-corasick", "memchr", @@ -2655,6 +2672,7 @@ dependencies = [ "cassowary", "chrono", "daemonize", + "darwin-libproc", "insta", "log", "serde_json", diff --git a/zellij-server/Cargo.toml b/zellij-server/Cargo.toml index fe56b74244..7dd8600908 100644 --- a/zellij-server/Cargo.toml +++ b/zellij-server/Cargo.toml @@ -23,6 +23,9 @@ log = "0.4.14" typetag = "0.1.7" chrono = "0.4.19" +[target.'cfg(target_os = "macos")'.dependencies] +darwin-libproc = "0.2.0" + [dev-dependencies] insta = "1.6.0" diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 05980805f6..78cb597a22 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -1,9 +1,13 @@ +#[cfg(target_os = "macos")] +use darwin_libproc; + use std::env; use std::os::unix::io::RawFd; use std::os::unix::process::CommandExt; use std::path::PathBuf; use std::process::{Child, Command}; use std::sync::{Arc, Mutex}; +use std::fs; use zellij_utils::{async_std, interprocess, libc, nix, signal_hook, zellij_tile}; @@ -247,6 +251,8 @@ pub trait ServerOsApi: Send + Sync { /// Update the receiver socket for the client fn update_receiver(&mut self, stream: LocalSocketStream); fn load_palette(&self) -> Palette; + /// Returns the current working directory for a given pid + fn get_cwd(&self, pid: RawFd) -> Option; } impl ServerOsApi for ServerOsInputOutput { @@ -336,6 +342,20 @@ impl ServerOsApi for ServerOsInputOutput { fn load_palette(&self) -> Palette { default_palette() } + #[cfg(target_os = "macos")] + fn get_cwd(&self, pid: RawFd) -> Option { + match darwin_libproc::pid_cwd(pid) { + Ok(cwd) => Some(cwd), + Err(_) => None, + } + } + #[cfg(target_os = "linux")] + fn get_cwd(&self, pid: RawFd) -> Option { + match fs::read_link(format!("/proc/{}/cwd", pid)) { + Ok(cwd) => Some(cwd), + Err(_) => None, + } + } } impl Clone for Box { From 9dee9c3cd8a75d2ef62afac89150a81725da591f Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Thu, 2 Sep 2021 13:37:53 -0700 Subject: [PATCH 02/11] feat(cwd-pane): Allow for setting the cwd when spawning a new terminal Co-authored-by: Quentin Rasmont --- zellij-server/src/os_input_output.rs | 9 +++++++-- zellij-utils/src/input/command.rs | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 78cb597a22..4a0790093f 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -100,6 +100,10 @@ fn handle_command_exit(mut child: Child) { /// `orig_termios`. /// fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, Pid) { + let current_dir = cmd.cwd + .or_else(|| env::current_dir().ok()) + .unwrap_or_else(|| PathBuf::from(env::var("HOME").unwrap())); + let (pid_primary, pid_secondary): (RawFd, Pid) = { match forkpty(None, Some(&orig_termios)) { Ok(fork_pty_res) => { @@ -109,6 +113,7 @@ fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, P ForkResult::Child => { let child = unsafe { Command::new(cmd.command) + .current_dir(current_dir) .args(&cmd.args) .pre_exec(|| -> std::io::Result<()> { // this is the "unsafe" part, for more details please see: @@ -164,14 +169,14 @@ pub fn spawn_terminal( .into_os_string() .into_string() .expect("Not valid Utf8 Encoding")]; - RunCommand { command, args } + RunCommand { command, args, cwd: None } } Some(TerminalAction::RunCommand(command)) => command, None => { let command = PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")); let args = vec![]; - RunCommand { command, args } + RunCommand { command, args, cwd: None } } }; diff --git a/zellij-utils/src/input/command.rs b/zellij-utils/src/input/command.rs index 2054f208d4..e03afb23bc 100644 --- a/zellij-utils/src/input/command.rs +++ b/zellij-utils/src/input/command.rs @@ -15,6 +15,8 @@ pub struct RunCommand { pub command: PathBuf, #[serde(default)] pub args: Vec, + #[serde(default)] + pub cwd: Option, } /// Intermediate representation @@ -25,6 +27,8 @@ pub struct RunCommandAction { #[serde(default)] pub args: Vec, #[serde(default)] + pub cwd: Option, + #[serde(default)] pub direction: Option, } @@ -33,6 +37,7 @@ impl From for RunCommand { RunCommand { command: action.command, args: action.args, + cwd: action.cwd } } } From 8d187aded39cdc8842240c72be6f1174cea15565 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Thu, 2 Sep 2021 13:38:23 -0700 Subject: [PATCH 03/11] feat(cwd-pane): Add an active_pane field to the Pty struct Co-authored-by: Quentin Rasmont --- zellij-server/src/pty.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index e28729b72f..3d1d2dfe60 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -54,6 +54,7 @@ impl From<&PtyInstruction> for PtyContext { } pub(crate) struct Pty { + pub active_pane: Option, pub bus: Bus, pub id_to_child_pid: HashMap, debug_to_file: bool, @@ -208,6 +209,7 @@ fn stream_terminal_bytes( impl Pty { pub fn new(bus: Bus, debug_to_file: bool) -> Self { Pty { + active_pane: None, bus, id_to_child_pid: HashMap::new(), debug_to_file, @@ -315,6 +317,9 @@ impl Pty { self.close_pane(id); }); } + pub fn set_active_pane(&mut self, pane_id: Option) { + self.active_pane = pane_id; + } } impl Drop for Pty { From 6a63bb5e8dce8d8c5e1220fa6330cfa91d87e88d Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Fri, 3 Sep 2021 08:51:37 -0700 Subject: [PATCH 04/11] feat(cwd-pane): Update Pty with Tab's active pane id Co-authored-by: Quentin Rasmont --- zellij-server/src/pty.rs | 5 ++ zellij-server/src/tab.rs | 105 +++++++++++++++++++++---------------- zellij-utils/src/errors.rs | 1 + 3 files changed, 65 insertions(+), 46 deletions(-) diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 3d1d2dfe60..85abbdd379 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -33,6 +33,7 @@ pub(crate) enum PtyInstruction { SpawnTerminal(Option), SpawnTerminalVertically(Option), SpawnTerminalHorizontally(Option), + UpdateActivePane(Option), NewTab(Option, Option), ClosePane(PaneId), CloseTab(Vec), @@ -45,6 +46,7 @@ impl From<&PtyInstruction> for PtyContext { PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal, PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically, PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally, + PtyInstruction::UpdateActivePane(_) => PtyContext::UpdateActivePane, PtyInstruction::ClosePane(_) => PtyContext::ClosePane, PtyInstruction::CloseTab(_) => PtyContext::CloseTab, PtyInstruction::NewTab(..) => PtyContext::NewTab, @@ -87,6 +89,9 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: LayoutFromYaml) { .send_to_screen(ScreenInstruction::HorizontalSplit(PaneId::Terminal(pid))) .unwrap(); } + PtyInstruction::UpdateActivePane(pane_id) => { + pty.set_active_pane(pane_id); + } PtyInstruction::NewTab(terminal_action, tab_layout) => { let merged_layout = layout.template.clone().insert_tab_layout(tab_layout); pty.spawn_terminals_for_layout(merged_layout.into(), terminal_action.clone()); diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs index 16e196a1d5..9f81e7f711 100644 --- a/zellij-server/src/tab.rs +++ b/zellij-server/src/tab.rs @@ -295,6 +295,13 @@ impl Tab { } } + fn set_active_terminal(&mut self, pane_id: Option) { + self.active_terminal = pane_id; + self.senders + .send_to_pty(PtyInstruction::UpdateActivePane(self.active_terminal)) + .unwrap(); + } + pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec, tab_index: usize) { // TODO: this should be an attribute on Screen instead of full_screen_ws let free_space = PaneGeom::default(); @@ -388,7 +395,7 @@ impl Tab { self.set_pane_frames(self.draw_pane_frames); // This is the end of the nasty viewport hack... // FIXME: Active / new / current terminal, should be pane - self.active_terminal = self.panes.iter().map(|(id, _)| id.to_owned()).next(); + self.set_active_terminal(self.panes.iter().map(|(id, _)| id.to_owned()).next()); self.render(); } pub fn new_pane(&mut self, pid: PaneId) { @@ -461,7 +468,7 @@ impl Tab { } } } - self.active_terminal = Some(pid); + self.set_active_terminal(Some(pid)); self.render(); } pub fn horizontal_split(&mut self, pid: PaneId) { @@ -490,7 +497,7 @@ impl Tab { ); active_pane.set_geom(top_winsize); self.panes.insert(pid, Box::new(new_terminal)); - self.active_terminal = Some(pid); + self.set_active_terminal(Some(pid)); self.relayout_tab(Direction::Vertical); self.render(); } @@ -519,7 +526,7 @@ impl Tab { active_pane.set_geom(left_winsize); self.panes.insert(pid, Box::new(new_terminal)); } - self.active_terminal = Some(pid); + self.set_active_terminal(Some(pid)); self.relayout_tab(Direction::Horizontal); self.render(); } @@ -1739,16 +1746,15 @@ impl Tab { } let active_terminal_id = self.get_active_pane_id().unwrap(); let terminal_ids: Vec = self.get_selectable_panes().map(|(&pid, _)| pid).collect(); // TODO: better, no allocations - let first_terminal = terminal_ids.get(0).unwrap(); let active_terminal_id_position = terminal_ids .iter() .position(|id| id == &active_terminal_id) .unwrap(); - if let Some(next_terminal) = terminal_ids.get(active_terminal_id_position + 1) { - self.active_terminal = Some(*next_terminal); - } else { - self.active_terminal = Some(*first_terminal); - } + let active_terminal = terminal_ids.get(active_terminal_id_position + 1) + .or_else(|| terminal_ids.get(0)) + .map(|id| *id); + + self.set_active_terminal(active_terminal); self.render(); } pub fn focus_next_pane(&mut self) { @@ -1767,16 +1773,16 @@ impl Tab { a_pane.y().cmp(&b_pane.y()) } }); - let first_pane = panes.get(0).unwrap(); let active_pane_position = panes .iter() .position(|(id, _)| *id == &active_pane_id) // TODO: better .unwrap(); - if let Some(next_pane) = panes.get(active_pane_position + 1) { - self.active_terminal = Some(*next_pane.0); - } else { - self.active_terminal = Some(*first_pane.0); - } + + let active_terminal = panes.get(active_pane_position + 1) + .or_else(|| panes.get(0)) + .map(|p| *p.0); + + self.set_active_terminal(active_terminal); self.render(); } pub fn focus_previous_pane(&mut self) { @@ -1800,11 +1806,13 @@ impl Tab { .iter() .position(|(id, _)| *id == &active_pane_id) // TODO: better .unwrap(); - if active_pane_position == 0 { - self.active_terminal = Some(*last_pane.0); + + let active_terminal = if active_pane_position == 0 { + Some(*last_pane.0) } else { - self.active_terminal = Some(*panes.get(active_pane_position - 1).unwrap().0); - } + Some(*panes.get(active_pane_position - 1).unwrap().0) + }; + self.set_active_terminal(active_terminal); self.render(); } // returns a boolean that indicates whether the focus moved @@ -1816,7 +1824,7 @@ impl Tab { return false; } let active_terminal = self.get_active_pane(); - if let Some(active) = active_terminal { + let updated_active_terminal = if let Some(active) = active_terminal { let terminals = self.get_selectable_panes(); let next_index = terminals .enumerate() @@ -1835,17 +1843,18 @@ impl Tab { let next_active_pane = self.panes.get_mut(&p).unwrap(); next_active_pane.set_should_render(true); - self.active_terminal = Some(p); + self.set_active_terminal(Some(p)); self.render(); return true; } None => { - self.active_terminal = Some(active.pid()); + Some(active.pid()) } } } else { - self.active_terminal = Some(active_terminal.unwrap().pid()); - } + Some(active_terminal.unwrap().pid()) + }; + self.set_active_terminal(updated_active_terminal); false } pub fn move_focus_down(&mut self) { @@ -1856,7 +1865,7 @@ impl Tab { return; } let active_terminal = self.get_active_pane(); - if let Some(active) = active_terminal { + let updated_active_terminal = if let Some(active) = active_terminal { let terminals = self.get_selectable_panes(); let next_index = terminals .enumerate() @@ -1875,15 +1884,16 @@ impl Tab { let next_active_pane = self.panes.get_mut(&p).unwrap(); next_active_pane.set_should_render(true); - self.active_terminal = Some(p); + Some(p) } None => { - self.active_terminal = Some(active.pid()); + Some(active.pid()) } } } else { - self.active_terminal = Some(active_terminal.unwrap().pid()); - } + Some(active_terminal.unwrap().pid()) + }; + self.set_active_terminal(updated_active_terminal); self.render(); } pub fn move_focus_up(&mut self) { @@ -1894,7 +1904,7 @@ impl Tab { return; } let active_terminal = self.get_active_pane(); - if let Some(active) = active_terminal { + let updated_active_terminal = if let Some(active) = active_terminal { let terminals = self.get_selectable_panes(); let next_index = terminals .enumerate() @@ -1913,15 +1923,16 @@ impl Tab { let next_active_pane = self.panes.get_mut(&p).unwrap(); next_active_pane.set_should_render(true); - self.active_terminal = Some(p); + Some(p) } None => { - self.active_terminal = Some(active.pid()); + Some(active.pid()) } } } else { - self.active_terminal = Some(active_terminal.unwrap().pid()); - } + Some(active_terminal.unwrap().pid()) + }; + self.set_active_terminal(updated_active_terminal); self.render(); } // returns a boolean that indicates whether the focus moved @@ -1933,7 +1944,7 @@ impl Tab { return false; } let active_terminal = self.get_active_pane(); - if let Some(active) = active_terminal { + let updated_active_terminal = if let Some(active) = active_terminal { let terminals = self.get_selectable_panes(); let next_index = terminals .enumerate() @@ -1952,17 +1963,18 @@ impl Tab { let next_active_pane = self.panes.get_mut(&p).unwrap(); next_active_pane.set_should_render(true); - self.active_terminal = Some(p); + self.set_active_terminal(Some(p)); self.render(); return true; } None => { - self.active_terminal = Some(active.pid()); + Some(active.pid()) } } } else { - self.active_terminal = Some(active_terminal.unwrap().pid()); - } + Some(active_terminal.unwrap().pid()) + }; + self.set_active_terminal(updated_active_terminal); false } fn horizontal_borders(&self, terminals: &[PaneId]) -> HashSet { @@ -1981,6 +1993,7 @@ impl Tab { borders }) } + fn panes_to_the_left_between_aligning_borders(&self, id: PaneId) -> Option> { if let Some(terminal) = self.panes.get(&id) { let upper_close_border = terminal.y(); @@ -2107,7 +2120,7 @@ impl Tab { if let Some(pane) = self.panes.get_mut(&id) { pane.set_selectable(selectable); if self.get_active_pane_id() == Some(id) && !selectable { - self.active_terminal = self.next_active_pane(&self.get_pane_ids()) + self.set_active_terminal(self.next_active_pane(&self.get_pane_ids())); } } self.render(); @@ -2128,7 +2141,7 @@ impl Tab { self.panes.remove(&id); if self.active_terminal == Some(id) { let next_active_pane = self.next_active_pane(&panes); - self.active_terminal = next_active_pane; + self.set_active_terminal(next_active_pane); } self.relayout_tab(Direction::Horizontal); return; @@ -2140,7 +2153,7 @@ impl Tab { self.panes.remove(&id); if self.active_terminal == Some(id) { let next_active_pane = self.next_active_pane(&panes); - self.active_terminal = next_active_pane; + self.set_active_terminal(next_active_pane); } self.relayout_tab(Direction::Horizontal); return; @@ -2152,7 +2165,7 @@ impl Tab { self.panes.remove(&id); if self.active_terminal == Some(id) { let next_active_pane = self.next_active_pane(&panes); - self.active_terminal = next_active_pane; + self.set_active_terminal(next_active_pane); } self.relayout_tab(Direction::Vertical); return; @@ -2164,7 +2177,7 @@ impl Tab { self.panes.remove(&id); if self.active_terminal == Some(id) { let next_active_pane = self.next_active_pane(&panes); - self.active_terminal = next_active_pane; + self.set_active_terminal(next_active_pane); } self.relayout_tab(Direction::Vertical); return; @@ -2286,7 +2299,7 @@ impl Tab { } fn focus_pane_at(&mut self, point: &Position) { if let Some(clicked_pane) = self.get_pane_id_at(point) { - self.active_terminal = Some(clicked_pane); + self.set_active_terminal(Some(clicked_pane)); self.render(); } } diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 65a54c5600..87c3bb4dcf 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -237,6 +237,7 @@ pub enum PtyContext { SpawnTerminal, SpawnTerminalVertically, SpawnTerminalHorizontally, + UpdateActivePane, NewTab, ClosePane, CloseTab, From c2b86db88a2f9f11a59f167c7d870b16280192d7 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Fri, 3 Sep 2021 16:17:13 -0700 Subject: [PATCH 05/11] feat(cwd-pane): Refactor spawn_terminal to use cwd by default Co-authored-by: Quentin Rasmont --- Cargo.lock | 1 + zellij-server/Cargo.toml | 1 + zellij-server/src/os_input_output.rs | 135 ++++++++++++++++++--------- zellij-server/src/pty.rs | 55 ++++++++--- 4 files changed, 135 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd7f26779a..7bd709ac9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2669,6 +2669,7 @@ dependencies = [ "ansi_term 0.12.1", "async-trait", "base64", + "byteorder", "cassowary", "chrono", "daemonize", diff --git a/zellij-server/Cargo.toml b/zellij-server/Cargo.toml index 7dd8600908..1c8c986b64 100644 --- a/zellij-server/Cargo.toml +++ b/zellij-server/Cargo.toml @@ -12,6 +12,7 @@ license = "MIT" ansi_term = "0.12.1" async-trait = "0.1.50" base64 = "0.13.0" +byteorder = "1.4.3" daemonize = "0.4.1" serde_json = "1.0" unicode-width = "0.1.8" diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 4a0790093f..695b8f9d15 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -14,7 +14,7 @@ use zellij_utils::{async_std, interprocess, libc, nix, signal_hook, zellij_tile} use async_std::fs::File as AsyncFile; use async_std::os::unix::io::FromRawFd; use interprocess::local_socket::LocalSocketStream; -use nix::pty::{forkpty, Winsize}; +use nix::pty::{forkpty, ForkptyResult, Winsize}; use nix::sys::signal::{kill, Signal}; use nix::sys::termios; use nix::sys::wait::waitpid; @@ -31,6 +31,7 @@ use zellij_utils::{ shared::default_palette, }; +use byteorder::{BigEndian, ByteOrder}; use async_std::io::ReadExt; pub use async_trait::async_trait; @@ -96,49 +97,99 @@ fn handle_command_exit(mut child: Child) { } } +fn handle_fork_pty(fork_pty_res: ForkptyResult, cmd: RunCommand, parent_fd: RawFd, child_fd: RawFd) -> (RawFd, Pid, RawFd) { + let pid_primary = fork_pty_res.master; + let (pid_secondary, pid_shell) = match fork_pty_res.fork_result { + ForkResult::Parent { child } => { + //fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl"); + let pid_shell: u32 = read_from_pipe(parent_fd, child_fd); + (child, pid_shell) + }, + ForkResult::Child => { + let child = unsafe { + let command = &mut Command::new(cmd.command); + if let Some(current_dir) = cmd.cwd { + command.current_dir(current_dir); + } + command + .args(&cmd.args) + .pre_exec(|| -> std::io::Result<()> { + // this is the "unsafe" part, for more details please see: + // https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#notes-and-safety + unistd::setpgid(Pid::from_raw(0), Pid::from_raw(0)) + .expect("failed to create a new process group"); + Ok(()) + }) + .spawn() + .expect("failed to spawn") + + }; + unistd::tcsetpgrp(0, Pid::from_raw(child.id() as i32)) + .expect("faled to set child's forceground process group"); + write_to_pipe(child.id() as u32, parent_fd, child_fd); + handle_command_exit(child); + ::std::process::exit(0); + } + }; + (pid_primary, pid_secondary, pid_shell as i32) +} + /// Spawns a new terminal from the parent terminal with [`termios`](termios::Termios) /// `orig_termios`. /// -fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, Pid) { - let current_dir = cmd.cwd - .or_else(|| env::current_dir().ok()) - .unwrap_or_else(|| PathBuf::from(env::var("HOME").unwrap())); - - let (pid_primary, pid_secondary): (RawFd, Pid) = { +fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, Pid, RawFd) { + // Create a pipe to allow the child the communicate the shell's pid to it's + // parent. + let (parent_fd, child_fd) = unistd::pipe().expect("failed to create pipe"); + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = { match forkpty(None, Some(&orig_termios)) { Ok(fork_pty_res) => { - let pid_primary = fork_pty_res.master; - let pid_secondary = match fork_pty_res.fork_result { - ForkResult::Parent { child } => child, - ForkResult::Child => { - let child = unsafe { - Command::new(cmd.command) - .current_dir(current_dir) - .args(&cmd.args) - .pre_exec(|| -> std::io::Result<()> { - // this is the "unsafe" part, for more details please see: - // https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#notes-and-safety - unistd::setpgid(Pid::from_raw(0), Pid::from_raw(0)) - .expect("failed to create a new process group"); - Ok(()) - }) - .spawn() - .expect("failed to spawn") - }; - unistd::tcsetpgrp(0, Pid::from_raw(child.id() as i32)) - .expect("faled to set child's forceground process group"); - handle_command_exit(child); - ::std::process::exit(0); - } - }; - (pid_primary, pid_secondary) + handle_fork_pty(fork_pty_res, cmd, parent_fd, child_fd) } Err(e) => { panic!("failed to fork {:?}", e); } } }; - (pid_primary, pid_secondary) + (pid_primary, pid_secondary, pid_shell) +} + +/// Write to a pipe given both file descriptors +/// +/// # Panics +/// +/// This function will panic if a close operation on one of the file descriptors fails or if the +/// write operation fails. +fn write_to_pipe(data: u32, parent_fd: RawFd, child_fd: RawFd) { + let mut buff = [0; 4]; + BigEndian::write_u32(&mut buff, data); + unistd::close(parent_fd).expect("Write: couldn't close parent_fd"); + match unistd::write(child_fd, &buff) { + Ok(_) => {} + Err(e) => { + panic!("Write operation failed: {:?}", e); + } + } + unistd::close(child_fd).expect("Write: couldn't close child_fd"); +} + +/// Read from a pipe given both file descriptors +/// +/// # Panics +/// +/// This function will panic if a close operation on one of the file descriptors fails or if the +/// read operation fails. +fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> u32 { + let mut buffer = [0; 4]; + unistd::close(child_fd).expect("Read: couldn't close child_fd"); + match unistd::read(parent_fd, &mut buffer) { + Ok(_) => {} + Err(e) => { + panic!("Read operation failed: {:?}", e); + } + } + unistd::close(parent_fd).expect("Read: couldn't close parent_fd"); + u32::from_be_bytes(buffer) } /// If a [`TerminalAction::OpenFile(file)`] is given, the text editor specified by environment variable `EDITOR` @@ -154,11 +205,11 @@ fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, P /// This function will panic if both the `EDITOR` and `VISUAL` environment variables are not /// set. pub fn spawn_terminal( - terminal_action: Option, + terminal_action: TerminalAction, orig_termios: termios::Termios, -) -> (RawFd, Pid) { +) -> (RawFd, Pid, RawFd) { let cmd = match terminal_action { - Some(TerminalAction::OpenFile(file_to_open)) => { + TerminalAction::OpenFile(file_to_open) => { if env::var("EDITOR").is_err() && env::var("VISUAL").is_err() { panic!("Can't edit files if an editor is not defined. To fix: define the EDITOR or VISUAL environment variables with the path to your editor (eg. /usr/bin/vim)"); } @@ -171,13 +222,7 @@ pub fn spawn_terminal( .expect("Not valid Utf8 Encoding")]; RunCommand { command, args, cwd: None } } - Some(TerminalAction::RunCommand(command)) => command, - None => { - let command = - PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")); - let args = vec![]; - RunCommand { command, args, cwd: None } - } + TerminalAction::RunCommand(command) => command, }; handle_terminal(cmd, orig_termios) @@ -224,7 +269,7 @@ pub trait ServerOsApi: Send + Sync { /// Sets the size of the terminal associated to file descriptor `fd`. fn set_terminal_size_using_fd(&self, fd: RawFd, cols: u16, rows: u16); /// Spawn a new terminal, with a terminal action. - fn spawn_terminal(&self, terminal_action: Option) -> (RawFd, Pid); + fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, RawFd); /// Read bytes from the standard output of the virtual terminal referred to by `fd`. fn read_from_tty_stdout(&self, fd: RawFd, buf: &mut [u8]) -> Result; /// Creates an `AsyncReader` that can be used to read from `fd` in an async context @@ -266,7 +311,7 @@ impl ServerOsApi for ServerOsInputOutput { set_terminal_size_using_fd(fd, cols, rows); } } - fn spawn_terminal(&self, terminal_action: Option) -> (RawFd, Pid) { + fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, RawFd) { let orig_termios = self.orig_termios.lock().unwrap(); spawn_terminal(terminal_action, orig_termios.clone()) } diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 85abbdd379..e4cfc6e5c2 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -11,21 +11,28 @@ use async_std::{ task::{self, JoinHandle}, }; use std::{ + env, collections::HashMap, os::unix::io::RawFd, + path::PathBuf, time::{Duration, Instant}, }; use zellij_utils::{ async_std, errors::{get_current_ctx, ContextType, PtyContext}, input::{ - command::TerminalAction, + command::{RunCommand, TerminalAction}, layout::{Layout, LayoutFromYaml, Run, TabLayout}, }, logging::debug_to_file, }; pub type VteBytes = Vec; +#[derive(Debug)] +pub struct ChildId { + child: Pid, + shell: RawFd +} /// Instructions related to PTYs (pseudoterminals). #[derive(Clone, Debug)] @@ -58,7 +65,7 @@ impl From<&PtyInstruction> for PtyContext { pub(crate) struct Pty { pub active_pane: Option, pub bus: Bus, - pub id_to_child_pid: HashMap, + pub id_to_child_pid: HashMap, debug_to_file: bool, task_handles: HashMap>, } @@ -221,8 +228,22 @@ impl Pty { task_handles: HashMap::new(), } } + pub fn get_default_terminal(&self) -> TerminalAction { + TerminalAction::RunCommand(RunCommand { + args: vec![], + command: PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")), + cwd: self.active_pane + .and_then(|pane| match pane { + PaneId::Plugin(..) => None, + PaneId::Terminal(id) => self.id_to_child_pid.get(&id).map(|id| id.shell), + }) + .and_then(|id| self.bus.os_input.as_ref().map(|input| input.get_cwd(id))) + .flatten() + }) + } pub fn spawn_terminal(&mut self, terminal_action: Option) -> RawFd { - let (pid_primary, pid_secondary): (RawFd, Pid) = self + let terminal_action = terminal_action.unwrap_or_else(|| self.get_default_terminal()); + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = self .bus .os_input .as_mut() @@ -235,7 +256,10 @@ impl Pty { self.debug_to_file, ); self.task_handles.insert(pid_primary, task_handle); - self.id_to_child_pid.insert(pid_primary, pid_secondary); + self.id_to_child_pid.insert(pid_primary, ChildId { + child: pid_secondary, + shell: pid_shell + }); pid_primary } pub fn spawn_terminals_for_layout( @@ -243,29 +267,36 @@ impl Pty { layout: Layout, default_shell: Option, ) { + let default_shell = default_shell.unwrap_or_else(|| self.get_default_terminal()); let extracted_run_instructions = layout.extract_run_instructions(); let mut new_pane_pids = vec![]; for run_instruction in extracted_run_instructions { match run_instruction { Some(Run::Command(command)) => { let cmd = TerminalAction::RunCommand(command); - let (pid_primary, pid_secondary): (RawFd, Pid) = self + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = self .bus .os_input .as_mut() .unwrap() - .spawn_terminal(Some(cmd)); - self.id_to_child_pid.insert(pid_primary, pid_secondary); + .spawn_terminal(cmd); + self.id_to_child_pid.insert(pid_primary, ChildId { + child: pid_secondary, + shell: pid_shell + }); new_pane_pids.push(pid_primary); } None => { - let (pid_primary, pid_secondary): (RawFd, Pid) = self + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = self .bus .os_input .as_mut() .unwrap() .spawn_terminal(default_shell.clone()); - self.id_to_child_pid.insert(pid_primary, pid_secondary); + self.id_to_child_pid.insert(pid_primary, ChildId { + child: pid_secondary, + shell: pid_shell + }); new_pane_pids.push(pid_primary); } // Investigate moving plugin loading to here. @@ -292,10 +323,10 @@ impl Pty { pub fn close_pane(&mut self, id: PaneId) { match id { PaneId::Terminal(id) => { - let child_pid = self.id_to_child_pid.remove(&id).unwrap(); + let pids = self.id_to_child_pid.remove(&id).unwrap(); let handle = self.task_handles.remove(&id).unwrap(); task::block_on(async { - self.bus.os_input.as_mut().unwrap().kill(child_pid).unwrap(); + self.bus.os_input.as_mut().unwrap().kill(pids.child).unwrap(); let timeout = Duration::from_millis(100); match async_timeout(timeout, handle.cancel()).await { Ok(_) => {} @@ -304,7 +335,7 @@ impl Pty { .os_input .as_mut() .unwrap() - .force_kill(child_pid) + .force_kill(pids.child) .unwrap(); } }; From 695297237af2aa502632aee523bd274467566da8 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Fri, 3 Sep 2021 16:22:30 -0700 Subject: [PATCH 06/11] feat(cwd-pane): Fix tests and lints Co-authored-by: Quentin Rasmont --- zellij-server/src/tab.rs | 2 +- zellij-server/src/unit/screen_tests.rs | 6 +++++- zellij-server/src/unit/tab_tests.rs | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs index 9f81e7f711..55f7108d55 100644 --- a/zellij-server/src/tab.rs +++ b/zellij-server/src/tab.rs @@ -1752,7 +1752,7 @@ impl Tab { .unwrap(); let active_terminal = terminal_ids.get(active_terminal_id_position + 1) .or_else(|| terminal_ids.get(0)) - .map(|id| *id); + .copied(); self.set_active_terminal(active_terminal); self.render(); diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 2d08088625..3a4574fbab 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -5,6 +5,7 @@ use crate::{ thread_bus::Bus, SessionState, }; +use std::path::PathBuf; use std::sync::{Arc, RwLock}; use zellij_utils::input::command::TerminalAction; use zellij_utils::input::layout::LayoutTemplate; @@ -28,7 +29,7 @@ impl ServerOsApi for FakeInputOutput { fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { // noop } - fn spawn_terminal(&self, _file_to_open: Option) -> (RawFd, Pid) { + fn spawn_terminal(&self, _file_to_open: TerminalAction) -> (RawFd, Pid, RawFd) { unimplemented!() } fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result { @@ -73,6 +74,9 @@ impl ServerOsApi for FakeInputOutput { fn load_palette(&self) -> Palette { unimplemented!() } + fn get_cwd(&self, _pid: RawFd) -> Option { + unimplemented!() + } } fn create_new_screen(size: Size) -> Screen { diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/unit/tab_tests.rs index ea96df627f..29e42057f9 100644 --- a/zellij-server/src/unit/tab_tests.rs +++ b/zellij-server/src/unit/tab_tests.rs @@ -6,6 +6,7 @@ use crate::{ thread_bus::ThreadSenders, SessionState, }; +use std::path::PathBuf; use std::sync::{Arc, RwLock}; use zellij_utils::input::layout::LayoutTemplate; use zellij_utils::pane_size::Size; @@ -27,7 +28,7 @@ impl ServerOsApi for FakeInputOutput { fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { // noop } - fn spawn_terminal(&self, _file_to_open: Option) -> (RawFd, Pid) { + fn spawn_terminal(&self, _file_to_open: TerminalAction) -> (RawFd, Pid, RawFd) { unimplemented!() } fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result { @@ -72,6 +73,9 @@ impl ServerOsApi for FakeInputOutput { fn load_palette(&self) -> Palette { unimplemented!() } + fn get_cwd(&self, _pid: RawFd) -> Option { + unimplemented!() + } } fn create_new_tab(size: Size) -> Tab { From 5b1f9702885248a2860fbd18ce9520e6418eafbc Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Sat, 4 Sep 2021 09:08:10 -0700 Subject: [PATCH 07/11] feat(cwd-pane): Fix formatting --- zellij-server/src/os_input_output.rs | 24 +++++++----- zellij-server/src/pty.rs | 57 +++++++++++++++++----------- zellij-server/src/tab.rs | 22 ++++------- zellij-utils/src/input/command.rs | 2 +- 4 files changed, 58 insertions(+), 47 deletions(-) diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 695b8f9d15..185f15f8cd 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -2,12 +2,12 @@ use darwin_libproc; use std::env; +use std::fs; use std::os::unix::io::RawFd; use std::os::unix::process::CommandExt; use std::path::PathBuf; use std::process::{Child, Command}; use std::sync::{Arc, Mutex}; -use std::fs; use zellij_utils::{async_std, interprocess, libc, nix, signal_hook, zellij_tile}; @@ -31,9 +31,9 @@ use zellij_utils::{ shared::default_palette, }; -use byteorder::{BigEndian, ByteOrder}; use async_std::io::ReadExt; pub use async_trait::async_trait; +use byteorder::{BigEndian, ByteOrder}; pub use nix::unistd::Pid; @@ -97,14 +97,19 @@ fn handle_command_exit(mut child: Child) { } } -fn handle_fork_pty(fork_pty_res: ForkptyResult, cmd: RunCommand, parent_fd: RawFd, child_fd: RawFd) -> (RawFd, Pid, RawFd) { +fn handle_fork_pty( + fork_pty_res: ForkptyResult, + cmd: RunCommand, + parent_fd: RawFd, + child_fd: RawFd, +) -> (RawFd, Pid, RawFd) { let pid_primary = fork_pty_res.master; let (pid_secondary, pid_shell) = match fork_pty_res.fork_result { ForkResult::Parent { child } => { //fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl"); let pid_shell: u32 = read_from_pipe(parent_fd, child_fd); (child, pid_shell) - }, + } ForkResult::Child => { let child = unsafe { let command = &mut Command::new(cmd.command); @@ -122,7 +127,6 @@ fn handle_fork_pty(fork_pty_res: ForkptyResult, cmd: RunCommand, parent_fd: RawF }) .spawn() .expect("failed to spawn") - }; unistd::tcsetpgrp(0, Pid::from_raw(child.id() as i32)) .expect("faled to set child's forceground process group"); @@ -143,9 +147,7 @@ fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, P let (parent_fd, child_fd) = unistd::pipe().expect("failed to create pipe"); let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = { match forkpty(None, Some(&orig_termios)) { - Ok(fork_pty_res) => { - handle_fork_pty(fork_pty_res, cmd, parent_fd, child_fd) - } + Ok(fork_pty_res) => handle_fork_pty(fork_pty_res, cmd, parent_fd, child_fd), Err(e) => { panic!("failed to fork {:?}", e); } @@ -220,7 +222,11 @@ pub fn spawn_terminal( .into_os_string() .into_string() .expect("Not valid Utf8 Encoding")]; - RunCommand { command, args, cwd: None } + RunCommand { + command, + args, + cwd: None, + } } TerminalAction::RunCommand(command) => command, }; diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index e4cfc6e5c2..328de19cd9 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -11,8 +11,8 @@ use async_std::{ task::{self, JoinHandle}, }; use std::{ - env, collections::HashMap, + env, os::unix::io::RawFd, path::PathBuf, time::{Duration, Instant}, @@ -31,7 +31,7 @@ pub type VteBytes = Vec; #[derive(Debug)] pub struct ChildId { child: Pid, - shell: RawFd + shell: RawFd, } /// Instructions related to PTYs (pseudoterminals). @@ -232,13 +232,14 @@ impl Pty { TerminalAction::RunCommand(RunCommand { args: vec![], command: PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")), - cwd: self.active_pane + cwd: self + .active_pane .and_then(|pane| match pane { PaneId::Plugin(..) => None, PaneId::Terminal(id) => self.id_to_child_pid.get(&id).map(|id| id.shell), }) .and_then(|id| self.bus.os_input.as_ref().map(|input| input.get_cwd(id))) - .flatten() + .flatten(), }) } pub fn spawn_terminal(&mut self, terminal_action: Option) -> RawFd { @@ -256,10 +257,13 @@ impl Pty { self.debug_to_file, ); self.task_handles.insert(pid_primary, task_handle); - self.id_to_child_pid.insert(pid_primary, ChildId { - child: pid_secondary, - shell: pid_shell - }); + self.id_to_child_pid.insert( + pid_primary, + ChildId { + child: pid_secondary, + shell: pid_shell, + }, + ); pid_primary } pub fn spawn_terminals_for_layout( @@ -274,16 +278,15 @@ impl Pty { match run_instruction { Some(Run::Command(command)) => { let cmd = TerminalAction::RunCommand(command); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = self - .bus - .os_input - .as_mut() - .unwrap() - .spawn_terminal(cmd); - self.id_to_child_pid.insert(pid_primary, ChildId { - child: pid_secondary, - shell: pid_shell - }); + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = + self.bus.os_input.as_mut().unwrap().spawn_terminal(cmd); + self.id_to_child_pid.insert( + pid_primary, + ChildId { + child: pid_secondary, + shell: pid_shell, + }, + ); new_pane_pids.push(pid_primary); } None => { @@ -293,10 +296,13 @@ impl Pty { .as_mut() .unwrap() .spawn_terminal(default_shell.clone()); - self.id_to_child_pid.insert(pid_primary, ChildId { - child: pid_secondary, - shell: pid_shell - }); + self.id_to_child_pid.insert( + pid_primary, + ChildId { + child: pid_secondary, + shell: pid_shell, + }, + ); new_pane_pids.push(pid_primary); } // Investigate moving plugin loading to here. @@ -326,7 +332,12 @@ impl Pty { let pids = self.id_to_child_pid.remove(&id).unwrap(); let handle = self.task_handles.remove(&id).unwrap(); task::block_on(async { - self.bus.os_input.as_mut().unwrap().kill(pids.child).unwrap(); + self.bus + .os_input + .as_mut() + .unwrap() + .kill(pids.child) + .unwrap(); let timeout = Duration::from_millis(100); match async_timeout(timeout, handle.cancel()).await { Ok(_) => {} diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs index 55f7108d55..4cebccc042 100644 --- a/zellij-server/src/tab.rs +++ b/zellij-server/src/tab.rs @@ -1750,7 +1750,8 @@ impl Tab { .iter() .position(|id| id == &active_terminal_id) .unwrap(); - let active_terminal = terminal_ids.get(active_terminal_id_position + 1) + let active_terminal = terminal_ids + .get(active_terminal_id_position + 1) .or_else(|| terminal_ids.get(0)) .copied(); @@ -1778,7 +1779,8 @@ impl Tab { .position(|(id, _)| *id == &active_pane_id) // TODO: better .unwrap(); - let active_terminal = panes.get(active_pane_position + 1) + let active_terminal = panes + .get(active_pane_position + 1) .or_else(|| panes.get(0)) .map(|p| *p.0); @@ -1847,9 +1849,7 @@ impl Tab { self.render(); return true; } - None => { - Some(active.pid()) - } + None => Some(active.pid()), } } else { Some(active_terminal.unwrap().pid()) @@ -1886,9 +1886,7 @@ impl Tab { Some(p) } - None => { - Some(active.pid()) - } + None => Some(active.pid()), } } else { Some(active_terminal.unwrap().pid()) @@ -1925,9 +1923,7 @@ impl Tab { Some(p) } - None => { - Some(active.pid()) - } + None => Some(active.pid()), } } else { Some(active_terminal.unwrap().pid()) @@ -1967,9 +1963,7 @@ impl Tab { self.render(); return true; } - None => { - Some(active.pid()) - } + None => Some(active.pid()), } } else { Some(active_terminal.unwrap().pid()) diff --git a/zellij-utils/src/input/command.rs b/zellij-utils/src/input/command.rs index e03afb23bc..debd5bc59a 100644 --- a/zellij-utils/src/input/command.rs +++ b/zellij-utils/src/input/command.rs @@ -37,7 +37,7 @@ impl From for RunCommand { RunCommand { command: action.command, args: action.args, - cwd: action.cwd + cwd: action.cwd, } } } From 1653cab0381ac5a863cbcd4511a77cb0c9aa9aa5 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Mon, 6 Sep 2021 22:18:58 -0700 Subject: [PATCH 08/11] feat(cwd-pane): Refactor child pid fetching to handle errors better Instead of panicking when transfering the process id of the forked child command we just return an empty process id. --- zellij-server/src/os_input_output.rs | 77 +++++++++++----------------- zellij-server/src/pty.rs | 12 +++-- 2 files changed, 37 insertions(+), 52 deletions(-) diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 185f15f8cd..713a341784 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -102,12 +102,11 @@ fn handle_fork_pty( cmd: RunCommand, parent_fd: RawFd, child_fd: RawFd, -) -> (RawFd, Pid, RawFd) { +) -> (RawFd, Pid, Option) { let pid_primary = fork_pty_res.master; let (pid_secondary, pid_shell) = match fork_pty_res.fork_result { ForkResult::Parent { child } => { - //fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl"); - let pid_shell: u32 = read_from_pipe(parent_fd, child_fd); + let pid_shell = read_from_pipe(parent_fd, child_fd); (child, pid_shell) } ForkResult::Child => { @@ -130,22 +129,22 @@ fn handle_fork_pty( }; unistd::tcsetpgrp(0, Pid::from_raw(child.id() as i32)) .expect("faled to set child's forceground process group"); - write_to_pipe(child.id() as u32, parent_fd, child_fd); + write_to_pipe(child.id(), parent_fd, child_fd); handle_command_exit(child); ::std::process::exit(0); } }; - (pid_primary, pid_secondary, pid_shell as i32) + (pid_primary, pid_secondary, pid_shell.map(|pid| Pid::from_raw(pid as i32))) } /// Spawns a new terminal from the parent terminal with [`termios`](termios::Termios) /// `orig_termios`. /// -fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, Pid, RawFd) { +fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, Pid, Option) { // Create a pipe to allow the child the communicate the shell's pid to it's // parent. let (parent_fd, child_fd) = unistd::pipe().expect("failed to create pipe"); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = { + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = { match forkpty(None, Some(&orig_termios)) { Ok(fork_pty_res) => handle_fork_pty(fork_pty_res, cmd, parent_fd, child_fd), Err(e) => { @@ -157,41 +156,31 @@ fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, P } /// Write to a pipe given both file descriptors -/// -/// # Panics -/// -/// This function will panic if a close operation on one of the file descriptors fails or if the -/// write operation fails. fn write_to_pipe(data: u32, parent_fd: RawFd, child_fd: RawFd) { let mut buff = [0; 4]; BigEndian::write_u32(&mut buff, data); - unistd::close(parent_fd).expect("Write: couldn't close parent_fd"); - match unistd::write(child_fd, &buff) { - Ok(_) => {} - Err(e) => { - panic!("Write operation failed: {:?}", e); - } + if let Err(_) = unistd::close(parent_fd) { + return; } - unistd::close(child_fd).expect("Write: couldn't close child_fd"); + if let Err(_) = unistd::write(child_fd, &buff) { + return; + } + unistd::close(child_fd).unwrap_or_default(); } /// Read from a pipe given both file descriptors -/// -/// # Panics -/// -/// This function will panic if a close operation on one of the file descriptors fails or if the -/// read operation fails. -fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> u32 { +fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> Option { let mut buffer = [0; 4]; - unistd::close(child_fd).expect("Read: couldn't close child_fd"); - match unistd::read(parent_fd, &mut buffer) { - Ok(_) => {} - Err(e) => { - panic!("Read operation failed: {:?}", e); - } + if let Err(_) = unistd::close(child_fd) { + return None; + } + if let Err(_) = unistd::read(parent_fd, &mut buffer) { + return None; } - unistd::close(parent_fd).expect("Read: couldn't close parent_fd"); - u32::from_be_bytes(buffer) + if let Err(_) = unistd::close(parent_fd) { + return None; + } + Some(u32::from_be_bytes(buffer)) } /// If a [`TerminalAction::OpenFile(file)`] is given, the text editor specified by environment variable `EDITOR` @@ -209,7 +198,7 @@ fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> u32 { pub fn spawn_terminal( terminal_action: TerminalAction, orig_termios: termios::Termios, -) -> (RawFd, Pid, RawFd) { +) -> (RawFd, Pid, Option) { let cmd = match terminal_action { TerminalAction::OpenFile(file_to_open) => { if env::var("EDITOR").is_err() && env::var("VISUAL").is_err() { @@ -275,7 +264,7 @@ pub trait ServerOsApi: Send + Sync { /// Sets the size of the terminal associated to file descriptor `fd`. fn set_terminal_size_using_fd(&self, fd: RawFd, cols: u16, rows: u16); /// Spawn a new terminal, with a terminal action. - fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, RawFd); + fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, Option); /// Read bytes from the standard output of the virtual terminal referred to by `fd`. fn read_from_tty_stdout(&self, fd: RawFd, buf: &mut [u8]) -> Result; /// Creates an `AsyncReader` that can be used to read from `fd` in an async context @@ -308,7 +297,7 @@ pub trait ServerOsApi: Send + Sync { fn update_receiver(&mut self, stream: LocalSocketStream); fn load_palette(&self) -> Palette; /// Returns the current working directory for a given pid - fn get_cwd(&self, pid: RawFd) -> Option; + fn get_cwd(&self, pid: Pid) -> Option; } impl ServerOsApi for ServerOsInputOutput { @@ -317,7 +306,7 @@ impl ServerOsApi for ServerOsInputOutput { set_terminal_size_using_fd(fd, cols, rows); } } - fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, RawFd) { + fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, Option) { let orig_termios = self.orig_termios.lock().unwrap(); spawn_terminal(terminal_action, orig_termios.clone()) } @@ -399,18 +388,12 @@ impl ServerOsApi for ServerOsInputOutput { default_palette() } #[cfg(target_os = "macos")] - fn get_cwd(&self, pid: RawFd) -> Option { - match darwin_libproc::pid_cwd(pid) { - Ok(cwd) => Some(cwd), - Err(_) => None, - } + fn get_cwd(&self, pid: Pid) -> Option { + darwin_libproc::pid_cwd(pid.as_raw()).ok() } #[cfg(target_os = "linux")] - fn get_cwd(&self, pid: RawFd) -> Option { - match fs::read_link(format!("/proc/{}/cwd", pid)) { - Ok(cwd) => Some(cwd), - Err(_) => None, - } + fn get_cwd(&self, pid: Pid) -> Option { + fs::read_link(format!("/proc/{}/cwd", pid)).ok() } } diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 328de19cd9..903e1b2a0d 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -30,8 +30,10 @@ use zellij_utils::{ pub type VteBytes = Vec; #[derive(Debug)] pub struct ChildId { + /// Process id of the parent containing the shell child: Pid, - shell: RawFd, + /// Process id of the shell running inside the parent process + shell: Option, } /// Instructions related to PTYs (pseudoterminals). @@ -236,7 +238,7 @@ impl Pty { .active_pane .and_then(|pane| match pane { PaneId::Plugin(..) => None, - PaneId::Terminal(id) => self.id_to_child_pid.get(&id).map(|id| id.shell), + PaneId::Terminal(id) => self.id_to_child_pid.get(&id).and_then(|id| id.shell), }) .and_then(|id| self.bus.os_input.as_ref().map(|input| input.get_cwd(id))) .flatten(), @@ -244,7 +246,7 @@ impl Pty { } pub fn spawn_terminal(&mut self, terminal_action: Option) -> RawFd { let terminal_action = terminal_action.unwrap_or_else(|| self.get_default_terminal()); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = self + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = self .bus .os_input .as_mut() @@ -278,7 +280,7 @@ impl Pty { match run_instruction { Some(Run::Command(command)) => { let cmd = TerminalAction::RunCommand(command); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = self.bus.os_input.as_mut().unwrap().spawn_terminal(cmd); self.id_to_child_pid.insert( pid_primary, @@ -290,7 +292,7 @@ impl Pty { new_pane_pids.push(pid_primary); } None => { - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, RawFd) = self + let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = self .bus .os_input .as_mut() From 5f13c9520cc828203ebe9aa23c1a04c55781017b Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Mon, 6 Sep 2021 22:37:07 -0700 Subject: [PATCH 09/11] feat(cwd-pane): Add non Linux/MacOS targets for the get_cwd method. This will allow Zellij to compile on non Linux/MacOS targets without having an inherited cwd. --- zellij-server/src/os_input_output.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 713a341784..7afbc8c7f3 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -395,6 +395,10 @@ impl ServerOsApi for ServerOsInputOutput { fn get_cwd(&self, pid: Pid) -> Option { fs::read_link(format!("/proc/{}/cwd", pid)).ok() } + #[cfg(all(not(target_os = "linux"), not(target_os = "macos")))] + fn get_cwd(&self, _pid: Pid) -> Option { + None + } } impl Clone for Box { From db65a0d88313b5c94c3d6b4f3a6668df22899533 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Mon, 6 Sep 2021 23:49:40 -0700 Subject: [PATCH 10/11] feat(cwd-pane): Refactor spawn_terminal method to use ChildId struct. The spawn_terminal methods been refactored to use the ChildId struct in order to clarify what the Pid's returned by it are. The documentation for the ChildId struct was improved as well. --- zellij-server/src/os_input_output.rs | 46 +++++++++++++++++++--------- zellij-server/src/pty.rs | 43 ++++++-------------------- 2 files changed, 40 insertions(+), 49 deletions(-) diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 7afbc8c7f3..5a0d1a7580 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -102,7 +102,7 @@ fn handle_fork_pty( cmd: RunCommand, parent_fd: RawFd, child_fd: RawFd, -) -> (RawFd, Pid, Option) { +) -> (RawFd, ChildId) { let pid_primary = fork_pty_res.master; let (pid_secondary, pid_shell) = match fork_pty_res.fork_result { ForkResult::Parent { child } => { @@ -134,25 +134,29 @@ fn handle_fork_pty( ::std::process::exit(0); } }; - (pid_primary, pid_secondary, pid_shell.map(|pid| Pid::from_raw(pid as i32))) + + ( + pid_primary, + ChildId { + primary: pid_secondary, + shell: pid_shell.map(|pid| Pid::from_raw(pid as i32)), + }, + ) } /// Spawns a new terminal from the parent terminal with [`termios`](termios::Termios) /// `orig_termios`. /// -fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, Pid, Option) { +fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, ChildId) { // Create a pipe to allow the child the communicate the shell's pid to it's // parent. let (parent_fd, child_fd) = unistd::pipe().expect("failed to create pipe"); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = { - match forkpty(None, Some(&orig_termios)) { - Ok(fork_pty_res) => handle_fork_pty(fork_pty_res, cmd, parent_fd, child_fd), - Err(e) => { - panic!("failed to fork {:?}", e); - } + match forkpty(None, Some(&orig_termios)) { + Ok(fork_pty_res) => handle_fork_pty(fork_pty_res, cmd, parent_fd, child_fd), + Err(e) => { + panic!("failed to fork {:?}", e); } - }; - (pid_primary, pid_secondary, pid_shell) + } } /// Write to a pipe given both file descriptors @@ -198,7 +202,7 @@ fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> Option { pub fn spawn_terminal( terminal_action: TerminalAction, orig_termios: termios::Termios, -) -> (RawFd, Pid, Option) { +) -> (RawFd, ChildId) { let cmd = match terminal_action { TerminalAction::OpenFile(file_to_open) => { if env::var("EDITOR").is_err() && env::var("VISUAL").is_err() { @@ -263,8 +267,10 @@ impl AsyncReader for RawFdAsyncReader { pub trait ServerOsApi: Send + Sync { /// Sets the size of the terminal associated to file descriptor `fd`. fn set_terminal_size_using_fd(&self, fd: RawFd, cols: u16, rows: u16); - /// Spawn a new terminal, with a terminal action. - fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, Option); + /// Spawn a new terminal, with a terminal action. The returned tuple contains the master file + /// descriptor of the forked psuedo terminal and a [ChildId] struct containing process id's for + /// the forked child process. + fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, ChildId); /// Read bytes from the standard output of the virtual terminal referred to by `fd`. fn read_from_tty_stdout(&self, fd: RawFd, buf: &mut [u8]) -> Result; /// Creates an `AsyncReader` that can be used to read from `fd` in an async context @@ -306,7 +312,7 @@ impl ServerOsApi for ServerOsInputOutput { set_terminal_size_using_fd(fd, cols, rows); } } - fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, Pid, Option) { + fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, ChildId) { let orig_termios = self.orig_termios.lock().unwrap(); spawn_terminal(terminal_action, orig_termios.clone()) } @@ -416,3 +422,13 @@ pub fn get_server_os_input() -> Result { send_instructions_to_client: Arc::new(Mutex::new(None)), }) } + +/// Process id's for forked terminals +#[derive(Debug)] +pub struct ChildId { + /// Primary process id of a forked terminal + pub primary: Pid, + /// Process id of the command running inside the forked terminal, usually a shell. The primary + /// field is it's parent process id. + pub shell: Option, +} diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 903e1b2a0d..c68572580f 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -1,5 +1,5 @@ use crate::{ - os_input_output::{AsyncReader, Pid, ServerOsApi}, + os_input_output::{AsyncReader, ChildId, ServerOsApi}, panes::PaneId, screen::ScreenInstruction, thread_bus::{Bus, ThreadSenders}, @@ -28,13 +28,6 @@ use zellij_utils::{ }; pub type VteBytes = Vec; -#[derive(Debug)] -pub struct ChildId { - /// Process id of the parent containing the shell - child: Pid, - /// Process id of the shell running inside the parent process - shell: Option, -} /// Instructions related to PTYs (pseudoterminals). #[derive(Clone, Debug)] @@ -246,7 +239,7 @@ impl Pty { } pub fn spawn_terminal(&mut self, terminal_action: Option) -> RawFd { let terminal_action = terminal_action.unwrap_or_else(|| self.get_default_terminal()); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = self + let (pid_primary, child_id): (RawFd, ChildId) = self .bus .os_input .as_mut() @@ -259,13 +252,7 @@ impl Pty { self.debug_to_file, ); self.task_handles.insert(pid_primary, task_handle); - self.id_to_child_pid.insert( - pid_primary, - ChildId { - child: pid_secondary, - shell: pid_shell, - }, - ); + self.id_to_child_pid.insert(pid_primary, child_id); pid_primary } pub fn spawn_terminals_for_layout( @@ -280,31 +267,19 @@ impl Pty { match run_instruction { Some(Run::Command(command)) => { let cmd = TerminalAction::RunCommand(command); - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = + let (pid_primary, child_id): (RawFd, ChildId) = self.bus.os_input.as_mut().unwrap().spawn_terminal(cmd); - self.id_to_child_pid.insert( - pid_primary, - ChildId { - child: pid_secondary, - shell: pid_shell, - }, - ); + self.id_to_child_pid.insert(pid_primary, child_id); new_pane_pids.push(pid_primary); } None => { - let (pid_primary, pid_secondary, pid_shell): (RawFd, Pid, Option) = self + let (pid_primary, child_id): (RawFd, ChildId) = self .bus .os_input .as_mut() .unwrap() .spawn_terminal(default_shell.clone()); - self.id_to_child_pid.insert( - pid_primary, - ChildId { - child: pid_secondary, - shell: pid_shell, - }, - ); + self.id_to_child_pid.insert(pid_primary, child_id); new_pane_pids.push(pid_primary); } // Investigate moving plugin loading to here. @@ -338,7 +313,7 @@ impl Pty { .os_input .as_mut() .unwrap() - .kill(pids.child) + .kill(pids.primary) .unwrap(); let timeout = Duration::from_millis(100); match async_timeout(timeout, handle.cancel()).await { @@ -348,7 +323,7 @@ impl Pty { .os_input .as_mut() .unwrap() - .force_kill(pids.child) + .force_kill(pids.primary) .unwrap(); } }; From 6adddce734c465760857fa5e766b2195da91a742 Mon Sep 17 00:00:00 2001 From: Jesse Tuchsen Date: Mon, 6 Sep 2021 23:59:20 -0700 Subject: [PATCH 11/11] feat(cwd-pane): Fix tests/lints --- zellij-server/src/os_input_output.rs | 10 +++++----- zellij-server/src/unit/screen_tests.rs | 6 +++--- zellij-server/src/unit/tab_tests.rs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 5a0d1a7580..e24b24b41a 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -163,10 +163,10 @@ fn handle_terminal(cmd: RunCommand, orig_termios: termios::Termios) -> (RawFd, C fn write_to_pipe(data: u32, parent_fd: RawFd, child_fd: RawFd) { let mut buff = [0; 4]; BigEndian::write_u32(&mut buff, data); - if let Err(_) = unistd::close(parent_fd) { + if unistd::close(parent_fd).is_err() { return; } - if let Err(_) = unistd::write(child_fd, &buff) { + if unistd::write(child_fd, &buff).is_err() { return; } unistd::close(child_fd).unwrap_or_default(); @@ -175,13 +175,13 @@ fn write_to_pipe(data: u32, parent_fd: RawFd, child_fd: RawFd) { /// Read from a pipe given both file descriptors fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> Option { let mut buffer = [0; 4]; - if let Err(_) = unistd::close(child_fd) { + if unistd::close(child_fd).is_err() { return None; } - if let Err(_) = unistd::read(parent_fd, &mut buffer) { + if unistd::read(parent_fd, &mut buffer).is_err() { return None; } - if let Err(_) = unistd::close(parent_fd) { + if unistd::close(parent_fd).is_err() { return None; } Some(u32::from_be_bytes(buffer)) diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 3a4574fbab..f0abebd6d3 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -1,7 +1,7 @@ use super::{Screen, ScreenInstruction}; use crate::zellij_tile::data::{ModeInfo, Palette}; use crate::{ - os_input_output::{AsyncReader, Pid, ServerOsApi}, + os_input_output::{AsyncReader, ChildId, Pid, ServerOsApi}, thread_bus::Bus, SessionState, }; @@ -29,7 +29,7 @@ impl ServerOsApi for FakeInputOutput { fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { // noop } - fn spawn_terminal(&self, _file_to_open: TerminalAction) -> (RawFd, Pid, RawFd) { + fn spawn_terminal(&self, _file_to_open: TerminalAction) -> (RawFd, ChildId) { unimplemented!() } fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result { @@ -74,7 +74,7 @@ impl ServerOsApi for FakeInputOutput { fn load_palette(&self) -> Palette { unimplemented!() } - fn get_cwd(&self, _pid: RawFd) -> Option { + fn get_cwd(&self, _pid: Pid) -> Option { unimplemented!() } } diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/unit/tab_tests.rs index 29e42057f9..de5c106704 100644 --- a/zellij-server/src/unit/tab_tests.rs +++ b/zellij-server/src/unit/tab_tests.rs @@ -1,7 +1,7 @@ use super::Tab; use crate::zellij_tile::data::{ModeInfo, Palette}; use crate::{ - os_input_output::{AsyncReader, Pid, ServerOsApi}, + os_input_output::{AsyncReader, ChildId, Pid, ServerOsApi}, panes::PaneId, thread_bus::ThreadSenders, SessionState, @@ -28,7 +28,7 @@ impl ServerOsApi for FakeInputOutput { fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { // noop } - fn spawn_terminal(&self, _file_to_open: TerminalAction) -> (RawFd, Pid, RawFd) { + fn spawn_terminal(&self, _file_to_open: TerminalAction) -> (RawFd, ChildId) { unimplemented!() } fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result { @@ -73,7 +73,7 @@ impl ServerOsApi for FakeInputOutput { fn load_palette(&self) -> Palette { unimplemented!() } - fn get_cwd(&self, _pid: RawFd) -> Option { + fn get_cwd(&self, _pid: Pid) -> Option { unimplemented!() } }