summaryrefslogtreecommitdiffstats
path: root/zellij-server/src
diff options
context:
space:
mode:
Diffstat (limited to 'zellij-server/src')
-rw-r--r--zellij-server/src/os_input_output.rs177
-rw-r--r--zellij-server/src/pty.rs63
-rw-r--r--zellij-server/src/tab.rs115
-rw-r--r--zellij-server/src/unit/screen_tests.rs8
-rw-r--r--zellij-server/src/unit/tab_tests.rs8
5 files changed, 247 insertions, 124 deletions
diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs
index 05980805f..e24b24b41 100644
--- a/zellij-server/src/os_input_output.rs
+++ b/zellij-server/src/os_input_output.rs
@@ -1,4 +1,8 @@
+#[cfg(target_os = "macos")]
+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;
@@ -10,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;
@@ -29,6 +33,7 @@ use zellij_utils::{
use async_std::io::ReadExt;
pub use async_trait::async_trait;
+use byteorder::{BigEndian, ByteOrder};
pub use nix::unistd::Pid;
@@ -92,44 +97,94 @@ fn handle_command_exit(mut child: Child) {
}
}
+fn handle_fork_pty(
+ fork_pty_res: ForkptyResult,
+ cmd: RunCommand,
+ parent_fd: RawFd,
+ child_fd: RawFd,
+) -> (RawFd, ChildId) {
+ let pid_primary = fork_pty_res.master;
+ let (pid_secondary, pid_shell) = match fork_pty_res.fork_result {
+ ForkResult::Parent { child } => {
+ let pid_shell = 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(), parent_fd, child_fd);
+ handle_command_exit(child);
+ ::std::process::exit(0);
+ }
+ };
+
+ (
+ 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) {
- let (pid_primary, pid_secondary): (RawFd, Pid) = {
- 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)
- .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)
- }
- Err(e) => {
- panic!("failed to fork {:?}", e);
- }
+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");
+ 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)
+ }
+}
+
+/// Write to a pipe given both file descriptors
+fn write_to_pipe(data: u32, parent_fd: RawFd, child_fd: RawFd) {
+ let mut buff = [0; 4];
+ BigEndian::write_u32(&mut buff, data);
+ if unistd::close(parent_fd).is_err() {
+ return;
+ }
+ if unistd::write(child_fd, &buff).is_err() {
+ return;
+ }
+ unistd::close(child_fd).unwrap_or_default();
+}
+
+/// Read from a pipe given both file descriptors
+fn read_from_pipe(parent_fd: RawFd, child_fd: RawFd) -> Option<u32> {
+ let mut buffer = [0; 4];
+ if unistd::close(child_fd).is_err() {
+ return None;
+ }
+ if unistd::read(parent_fd, &mut buffer).is_err() {
+ return None;
+ }
+ if unistd::close(parent_fd).is_err() {
+ return None;
+ }
+ Some(u32::from_be_bytes(buffer))
}
/// If a [`TerminalAction::OpenFile(file)`] is given, the text editor specified by environment variable `EDITOR`
@@ -145,11 +200,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<TerminalAction>,
+ terminal_action: TerminalAction,
orig_termios: termios::Termios,
-) -> (RawFd, Pid) {
+) -> (RawFd, ChildId) {
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)");
}
@@ -160,15 +215,13 @@ pub fn spawn_terminal(
.into_os_string()
.into_string()
.expect("Not valid Utf8 Encoding")];
- RunCommand { command, args }
- }
- 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,
+ }
}
+ TerminalAction::RunCommand(command) => command,
};
handle_terminal(cmd, orig_termios)
@@ -214,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: Option<TerminalAction>) -> (RawFd, Pid);
+ /// 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<usize, nix::Error>;
/// Creates an `AsyncReader` that can be used to read from `fd` in an async context
@@ -247,6 +302,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: Pid) -> Option<PathBuf>;
}
impl ServerOsApi for ServerOsInputOutput {
@@ -255,7 +312,7 @@ impl ServerOsApi for ServerOsInputOutput {
set_terminal_size_using_fd(fd, cols, rows);
}
}
- fn spawn_terminal(&self, terminal_action: Option<TerminalAction>) -> (RawFd, Pid) {
+ fn spawn_terminal(&self, terminal_action: TerminalAction) -> (RawFd, ChildId) {
let orig_termios = self.orig_termios.lock().unwrap();
spawn_terminal(terminal_action, orig_termios.clone())
}
@@ -336,6 +393,18 @@ impl ServerOsApi for ServerOsInputOutput {
fn load_palette(&self) -> Palette {
default_palette()
}
+ #[cfg(target_os = "macos")]
+ fn get_cwd(&self, pid: Pid) -> Option<PathBuf> {
+ darwin_libproc::pid_cwd(pid.as_raw()).ok()
+ }
+ #[cfg(target_os = "linux")]
+ fn get_cwd(&self, pid: Pid) -> Option<PathBuf> {
+ 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<PathBuf> {
+ None
+ }
}
impl Clone for Box<dyn ServerOsApi> {
@@ -353,3 +422,13 @@ pub fn get_server_os_input() -> Result<ServerOsInputOutput, nix::Error> {
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<Pid>,
+}
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 {
diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs
index ba8a8c88b..dafb28639 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<PaneId>) {
+ 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<RawFd>, tab_index: usize) {
// TODO: this should be an attribute on Screen instead of full_screen_ws
let free_space = PaneGeom::default();
@@ -393,7 +400,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) {
@@ -466,7 +473,7 @@ impl Tab {
}
}
}
- self.active_terminal = Some(pid);
+ self.set_active_terminal(Some(pid));
self.render();
}
pub fn horizontal_split(&mut self, pid: PaneId) {
@@ -495,7 +502,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();
}
@@ -524,7 +531,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();
}
@@ -1757,16 +1764,16 @@ impl Tab {
}
let active_terminal_id = self.get_active_pane_id().unwrap();
let terminal_ids: Vec<PaneId> = 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))
+ .copied();
+
+ self.set_active_terminal(active_terminal);
self.render();
}
pub fn focus_next_pane(&mut self) {
@@ -1785,16 +1792,17 @@ 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) {
@@ -1818,11 +1826,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
@@ -1834,7 +1844,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()
@@ -1853,17 +1863,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);
+ self.set_active_terminal(Some(p));
self.render();
return true;
}
- None => {
- self.active_terminal = Some(active.pid());
- }
+ None => 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) {
@@ -1874,7 +1883,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()
@@ -1893,15 +1902,14 @@ impl Tab {
let next_active_pane = self.panes.get_mut(&p).unwrap();
next_active_pane.set_should_render(true);
- self.active_terminal = Some(p);
- }
- None => {
- self.active_terminal = Some(active.pid());
+ Some(p)
}
+ None => 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) {
@@ -1912,7 +1920,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()
@@ -1931,15 +1939,14 @@ impl Tab {
let next_active_pane = self.panes.get_mut(&p).unwrap();
next_active_pane.set_should_render(true);
- self.active_terminal = Some(p);
- }
- None => {
- self.active_terminal = Some(active.pid());
+ Some(p)
}
+ None => 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
@@ -1951,7 +1958,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()
@@ -1970,17 +1977,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);
+ self.set_active_terminal(Some(p));
self.render();
return true;
}
- None => {
- self.active_terminal = Some(active.pid());
- }
+ None => 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<usize> {
@@ -1999,6 +2005,7 @@ impl Tab {
borders
})
}
+
fn panes_to_the_left_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
if let Some(terminal) = self.panes.get(&id) {
let upper_close_border = terminal.y();
@@ -2125,7 +2132,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 {