summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/pty.rs
diff options
context:
space:
mode:
authorspacemaison <tuchsen@protonmail.com>2021-09-10 08:35:06 -0700
committerGitHub <noreply@github.com>2021-09-10 17:35:06 +0200
commit4f94f95c90a0b5c2cb3992533cec40cc55f05983 (patch)
tree006824300f43717d08862eeb8ebb08c151dd62c4 /zellij-server/src/pty.rs
parent26a970a7d8a0f3703124ab3bb57cff4d296a2e33 (diff)
feat(cwd-pane): Keeping the cwd when opening new panes (#691)
* feat(cwd-pane): Add a new trait to get the cwd of a given pid Co-authored-by: Quentin Rasmont <qrasmont@gmail.com> * feat(cwd-pane): Allow for setting the cwd when spawning a new terminal Co-authored-by: Quentin Rasmont <qrasmont@gmail.com> * feat(cwd-pane): Add an active_pane field to the Pty struct Co-authored-by: Quentin Rasmont <qrasmont@gmail.com> * feat(cwd-pane): Update Pty with Tab's active pane id Co-authored-by: Quentin Rasmont <qrasmont@gmail.com> * feat(cwd-pane): Refactor spawn_terminal to use cwd by default Co-authored-by: Quentin Rasmont <qrasmont@gmail.com> * feat(cwd-pane): Fix tests and lints Co-authored-by: Quentin Rasmont <qrasmont@gmail.com> * feat(cwd-pane): Fix formatting * 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. * 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. * 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. * feat(cwd-pane): Fix tests/lints Co-authored-by: Jesse Tuchsen <not@disclosing> Co-authored-by: Quentin Rasmont <qrasmont@gmail.com>
Diffstat (limited to 'zellij-server/src/pty.rs')
-rw-r--r--zellij-server/src/pty.rs63
1 files changed, 46 insertions, 17 deletions
diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs
index e28729b72..c68572580 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},
@@ -12,14 +12,16 @@ use async_std::{
};
use std::{
collections::HashMap,
+ env,
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,
@@ -33,6 +35,7 @@ pub(crate) enum PtyInstruction {
SpawnTerminal(Option<TerminalAction>),
SpawnTerminalVertically(Option<TerminalAction>),
SpawnTerminalHorizontally(Option<TerminalAction>),
+ UpdateActivePane(Option<PaneId>),
NewTab(Option<TerminalAction>, Option<TabLayout>),
ClosePane(PaneId),
CloseTab(Vec<PaneId>),
@@ -45,6 +48,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,
@@ -54,8 +58,9 @@ impl From<&PtyInstruction> for PtyContext {
}
pub(crate) struct Pty {
+ pub active_pane: Option<PaneId>,
pub bus: Bus<PtyInstruction>,
- pub id_to_child_pid: HashMap<RawFd, Pid>,
+ pub id_to_child_pid: HashMap<RawFd, ChildId>,
debug_to_file: bool,
task_handles: HashMap<RawFd, JoinHandle<()>>,
}
@@ -86,6 +91,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());
@@ -208,14 +216,30 @@ fn stream_terminal_bytes(
impl Pty {
pub fn new(bus: Bus<PtyInstruction>, debug_to_file: bool) -> Self {
Pty {
+ active_pane: None,
bus,
id_to_child_pid: HashMap::new(),
debug_to_file,
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).and_then(|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<TerminalAction>) -> RawFd {
- let (pid_primary, pid_secondary): (RawFd, Pid) = self
+ let terminal_action = terminal_action.unwrap_or_else(|| self.get_default_terminal());
+ let (pid_primary, child_id): (RawFd, ChildId) = self
.bus
.os_input
.as_mut()
@@ -228,7 +252,7 @@ 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, child_id);
pid_primary
}
pub fn spawn_terminals_for_layout(
@@ -236,29 +260,26 @@ impl Pty {
layout: Layout,
default_shell: Option<TerminalAction>,
) {
+ 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
- .bus
- .os_input
- .as_mut()
- .unwrap()
- .spawn_terminal(Some(cmd));
- self.id_to_child_pid.insert(pid_primary, pid_secondary);
+ 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, child_id);
new_pane_pids.push(pid_primary);
}
None => {
- let (pid_primary, pid_secondary): (RawFd, Pid) = 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, pid_secondary);
+ self.id_to_child_pid.insert(pid_primary, child_id);
new_pane_pids.push(pid_primary);
}
// Investigate moving plugin loading to here.
@@ -285,10 +306,15 @@ 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.primary)
+ .unwrap();
let timeout = Duration::from_millis(100);
match async_timeout(timeout, handle.cancel()).await {
Ok(_) => {}
@@ -297,7 +323,7 @@ impl Pty {
.os_input
.as_mut()
.unwrap()
- .force_kill(child_pid)
+ .force_kill(pids.primary)
.unwrap();
}
};
@@ -315,6 +341,9 @@ impl Pty {
self.close_pane(id);
});
}
+ pub fn set_active_pane(&mut self, pane_id: Option<PaneId>) {
+ self.active_pane = pane_id;
+ }
}
impl Drop for Pty {