refactor(screen): more multiple-users groundwork (#788)
* refactor(screen): support multiple mirrored clients * style(fmt): make rustfmt happy * style(clippy): make clippy happy * whitespace * github, y u no update CI?! * is this a cache issue? * is it the checkout cache? * no cache at all? * Debug * fix gototab * decoment * gototab none in wasm_vm * gototab none in wasm_vm * the fun never ends * style(fmt): make rustfmt happy
This commit is contained in:
parent
4fa55dbfde
commit
a99354a155
7 changed files with 680 additions and 513 deletions
|
|
@ -338,7 +338,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
let mode = mode_info.mode;
|
let mode = mode_info.mode;
|
||||||
session_data
|
session_data
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ChangeMode(mode_info.clone()))
|
.send_to_screen(ScreenInstruction::ChangeMode(mode_info.clone(), client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
session_data
|
session_data
|
||||||
.senders
|
.senders
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,19 @@ use zellij_utils::{
|
||||||
|
|
||||||
pub type VteBytes = Vec<u8>;
|
pub type VteBytes = Vec<u8>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum ClientOrTabIndex {
|
||||||
|
ClientId(ClientId),
|
||||||
|
TabIndex(usize),
|
||||||
|
}
|
||||||
|
|
||||||
/// Instructions related to PTYs (pseudoterminals).
|
/// Instructions related to PTYs (pseudoterminals).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) enum PtyInstruction {
|
pub(crate) enum PtyInstruction {
|
||||||
SpawnTerminal(Option<TerminalAction>),
|
SpawnTerminal(Option<TerminalAction>, ClientOrTabIndex),
|
||||||
SpawnTerminalVertically(Option<TerminalAction>),
|
SpawnTerminalVertically(Option<TerminalAction>, ClientId),
|
||||||
SpawnTerminalHorizontally(Option<TerminalAction>),
|
SpawnTerminalHorizontally(Option<TerminalAction>, ClientId),
|
||||||
UpdateActivePane(Option<PaneId>),
|
UpdateActivePane(Option<PaneId>, ClientId),
|
||||||
NewTab(Option<TerminalAction>, Option<TabLayout>, ClientId),
|
NewTab(Option<TerminalAction>, Option<TabLayout>, ClientId),
|
||||||
ClosePane(PaneId),
|
ClosePane(PaneId),
|
||||||
CloseTab(Vec<PaneId>),
|
CloseTab(Vec<PaneId>),
|
||||||
|
|
@ -45,10 +51,10 @@ pub(crate) enum PtyInstruction {
|
||||||
impl From<&PtyInstruction> for PtyContext {
|
impl From<&PtyInstruction> for PtyContext {
|
||||||
fn from(pty_instruction: &PtyInstruction) -> Self {
|
fn from(pty_instruction: &PtyInstruction) -> Self {
|
||||||
match *pty_instruction {
|
match *pty_instruction {
|
||||||
PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal,
|
PtyInstruction::SpawnTerminal(..) => PtyContext::SpawnTerminal,
|
||||||
PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically,
|
PtyInstruction::SpawnTerminalVertically(..) => PtyContext::SpawnTerminalVertically,
|
||||||
PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally,
|
PtyInstruction::SpawnTerminalHorizontally(..) => PtyContext::SpawnTerminalHorizontally,
|
||||||
PtyInstruction::UpdateActivePane(_) => PtyContext::UpdateActivePane,
|
PtyInstruction::UpdateActivePane(..) => PtyContext::UpdateActivePane,
|
||||||
PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
|
PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
|
||||||
PtyInstruction::CloseTab(_) => PtyContext::CloseTab,
|
PtyInstruction::CloseTab(_) => PtyContext::CloseTab,
|
||||||
PtyInstruction::NewTab(..) => PtyContext::NewTab,
|
PtyInstruction::NewTab(..) => PtyContext::NewTab,
|
||||||
|
|
@ -58,7 +64,7 @@ impl From<&PtyInstruction> for PtyContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Pty {
|
pub(crate) struct Pty {
|
||||||
pub active_pane: Option<PaneId>,
|
pub active_panes: HashMap<ClientId, PaneId>,
|
||||||
pub bus: Bus<PtyInstruction>,
|
pub bus: Bus<PtyInstruction>,
|
||||||
pub id_to_child_pid: HashMap<RawFd, ChildId>,
|
pub id_to_child_pid: HashMap<RawFd, ChildId>,
|
||||||
debug_to_file: bool,
|
debug_to_file: bool,
|
||||||
|
|
@ -72,29 +78,40 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: LayoutFromYaml) {
|
||||||
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
|
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Pty((&event).into()));
|
err_ctx.add_call(ContextType::Pty((&event).into()));
|
||||||
match event {
|
match event {
|
||||||
PtyInstruction::SpawnTerminal(terminal_action) => {
|
PtyInstruction::SpawnTerminal(terminal_action, client_or_tab_index) => {
|
||||||
let pid = pty.spawn_terminal(terminal_action);
|
let pid = pty.spawn_terminal(terminal_action, client_or_tab_index);
|
||||||
pty.bus
|
pty.bus
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::NewPane(PaneId::Terminal(pid)))
|
.send_to_screen(ScreenInstruction::NewPane(
|
||||||
|
PaneId::Terminal(pid),
|
||||||
|
client_or_tab_index,
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
PtyInstruction::SpawnTerminalVertically(terminal_action) => {
|
PtyInstruction::SpawnTerminalVertically(terminal_action, client_id) => {
|
||||||
let pid = pty.spawn_terminal(terminal_action);
|
let pid =
|
||||||
|
pty.spawn_terminal(terminal_action, ClientOrTabIndex::ClientId(client_id));
|
||||||
pty.bus
|
pty.bus
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::VerticalSplit(PaneId::Terminal(pid)))
|
.send_to_screen(ScreenInstruction::VerticalSplit(
|
||||||
|
PaneId::Terminal(pid),
|
||||||
|
client_id,
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
PtyInstruction::SpawnTerminalHorizontally(terminal_action) => {
|
PtyInstruction::SpawnTerminalHorizontally(terminal_action, client_id) => {
|
||||||
let pid = pty.spawn_terminal(terminal_action);
|
let pid =
|
||||||
|
pty.spawn_terminal(terminal_action, ClientOrTabIndex::ClientId(client_id));
|
||||||
pty.bus
|
pty.bus
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::HorizontalSplit(PaneId::Terminal(pid)))
|
.send_to_screen(ScreenInstruction::HorizontalSplit(
|
||||||
|
PaneId::Terminal(pid),
|
||||||
|
client_id,
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
PtyInstruction::UpdateActivePane(pane_id) => {
|
PtyInstruction::UpdateActivePane(pane_id, client_id) => {
|
||||||
pty.set_active_pane(pane_id);
|
pty.set_active_pane(pane_id, client_id);
|
||||||
}
|
}
|
||||||
PtyInstruction::NewTab(terminal_action, tab_layout, client_id) => {
|
PtyInstruction::NewTab(terminal_action, tab_layout, client_id) => {
|
||||||
let tab_name = tab_layout.as_ref().and_then(|layout| {
|
let tab_name = tab_layout.as_ref().and_then(|layout| {
|
||||||
|
|
@ -115,11 +132,14 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: LayoutFromYaml) {
|
||||||
// clear current name at first
|
// clear current name at first
|
||||||
pty.bus
|
pty.bus
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::UpdateTabName(vec![0]))
|
.send_to_screen(ScreenInstruction::UpdateTabName(vec![0], client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
pty.bus
|
pty.bus
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::UpdateTabName(tab_name.into_bytes()))
|
.send_to_screen(ScreenInstruction::UpdateTabName(
|
||||||
|
tab_name.into_bytes(),
|
||||||
|
client_id,
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -229,11 +249,14 @@ fn stream_terminal_bytes(
|
||||||
}
|
}
|
||||||
async_send_to_screen(senders.clone(), ScreenInstruction::Render).await;
|
async_send_to_screen(senders.clone(), ScreenInstruction::Render).await;
|
||||||
|
|
||||||
// this is a little hacky, and is because the tests end the file as soon as
|
// we send ClosePane here so that the screen knows to close this tab if the process
|
||||||
// we read everything, rather than hanging until there is new data
|
// inside the terminal exited on its own (eg. the user typed "exit<ENTER>" inside a
|
||||||
// a better solution would be to fix the test fakes, but this will do for now
|
// bash shell)
|
||||||
async_send_to_screen(senders, ScreenInstruction::ClosePane(PaneId::Terminal(pid)))
|
async_send_to_screen(
|
||||||
.await;
|
senders,
|
||||||
|
ScreenInstruction::ClosePane(PaneId::Terminal(pid), None),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -241,29 +264,40 @@ fn stream_terminal_bytes(
|
||||||
impl Pty {
|
impl Pty {
|
||||||
pub fn new(bus: Bus<PtyInstruction>, debug_to_file: bool) -> Self {
|
pub fn new(bus: Bus<PtyInstruction>, debug_to_file: bool) -> Self {
|
||||||
Pty {
|
Pty {
|
||||||
active_pane: None,
|
active_panes: HashMap::new(),
|
||||||
bus,
|
bus,
|
||||||
id_to_child_pid: HashMap::new(),
|
id_to_child_pid: HashMap::new(),
|
||||||
debug_to_file,
|
debug_to_file,
|
||||||
task_handles: HashMap::new(),
|
task_handles: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_default_terminal(&self) -> TerminalAction {
|
pub fn get_default_terminal(&self, client_id: Option<ClientId>) -> TerminalAction {
|
||||||
TerminalAction::RunCommand(RunCommand {
|
TerminalAction::RunCommand(RunCommand {
|
||||||
args: vec![],
|
args: vec![],
|
||||||
command: PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")),
|
command: PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")),
|
||||||
cwd: self
|
cwd: client_id
|
||||||
.active_pane
|
.and_then(|client_id| self.active_panes.get(&client_id))
|
||||||
.and_then(|pane| match pane {
|
.and_then(|pane| match pane {
|
||||||
PaneId::Plugin(..) => None,
|
PaneId::Plugin(..) => None,
|
||||||
PaneId::Terminal(id) => self.id_to_child_pid.get(&id).and_then(|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)))
|
.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<TerminalAction>) -> RawFd {
|
pub fn spawn_terminal(
|
||||||
let terminal_action = terminal_action.unwrap_or_else(|| self.get_default_terminal());
|
&mut self,
|
||||||
|
terminal_action: Option<TerminalAction>,
|
||||||
|
client_or_tab_index: ClientOrTabIndex,
|
||||||
|
) -> RawFd {
|
||||||
|
let terminal_action = match client_or_tab_index {
|
||||||
|
ClientOrTabIndex::ClientId(client_id) => {
|
||||||
|
terminal_action.unwrap_or_else(|| self.get_default_terminal(Some(client_id)))
|
||||||
|
}
|
||||||
|
ClientOrTabIndex::TabIndex(_) => {
|
||||||
|
terminal_action.unwrap_or_else(|| self.get_default_terminal(None))
|
||||||
|
}
|
||||||
|
};
|
||||||
let (pid_primary, child_id): (RawFd, ChildId) = self
|
let (pid_primary, child_id): (RawFd, ChildId) = self
|
||||||
.bus
|
.bus
|
||||||
.os_input
|
.os_input
|
||||||
|
|
@ -286,7 +320,8 @@ impl Pty {
|
||||||
default_shell: Option<TerminalAction>,
|
default_shell: Option<TerminalAction>,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
) {
|
) {
|
||||||
let default_shell = default_shell.unwrap_or_else(|| self.get_default_terminal());
|
let default_shell =
|
||||||
|
default_shell.unwrap_or_else(|| self.get_default_terminal(Some(client_id)));
|
||||||
let extracted_run_instructions = layout.extract_run_instructions();
|
let extracted_run_instructions = layout.extract_run_instructions();
|
||||||
let mut new_pane_pids = vec![];
|
let mut new_pane_pids = vec![];
|
||||||
for run_instruction in extracted_run_instructions {
|
for run_instruction in extracted_run_instructions {
|
||||||
|
|
@ -368,8 +403,10 @@ impl Pty {
|
||||||
self.close_pane(id);
|
self.close_pane(id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pub fn set_active_pane(&mut self, pane_id: Option<PaneId>) {
|
pub fn set_active_pane(&mut self, pane_id: Option<PaneId>, client_id: ClientId) {
|
||||||
self.active_pane = pane_id;
|
if let Some(pane_id) = pane_id {
|
||||||
|
self.active_panes.insert(client_id, pane_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@ use std::sync::{Arc, RwLock};
|
||||||
use zellij_utils::zellij_tile::data::Event;
|
use zellij_utils::zellij_tile::data::Event;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
os_input_output::ServerOsApi, pty::PtyInstruction, screen::ScreenInstruction,
|
os_input_output::ServerOsApi,
|
||||||
wasm_vm::PluginInstruction, ServerInstruction, SessionMetaData, SessionState,
|
pty::{ClientOrTabIndex, PtyInstruction},
|
||||||
|
screen::ScreenInstruction,
|
||||||
|
wasm_vm::PluginInstruction,
|
||||||
|
ServerInstruction, SessionMetaData, SessionState,
|
||||||
};
|
};
|
||||||
use zellij_utils::{
|
use zellij_utils::{
|
||||||
channels::SenderWithContext,
|
channels::SenderWithContext,
|
||||||
|
|
@ -34,17 +37,17 @@ fn route_action(
|
||||||
Action::ToggleTab => {
|
Action::ToggleTab => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ToggleTab)
|
.send_to_screen(ScreenInstruction::ToggleTab(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::Write(val) => {
|
Action::Write(val) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ClearScroll)
|
.send_to_screen(ScreenInstruction::ClearScroll(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::WriteCharacter(val))
|
.send_to_screen(ScreenInstruction::WriteCharacter(val, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::SwitchToMode(mode) => {
|
Action::SwitchToMode(mode) => {
|
||||||
|
|
@ -61,11 +64,10 @@ fn route_action(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ChangeMode(get_mode_info(
|
.send_to_screen(ScreenInstruction::ChangeMode(
|
||||||
mode,
|
get_mode_info(mode, palette, session.capabilities),
|
||||||
palette,
|
client_id,
|
||||||
session.capabilities,
|
))
|
||||||
)))
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
|
|
@ -74,103 +76,103 @@ fn route_action(
|
||||||
}
|
}
|
||||||
Action::Resize(direction) => {
|
Action::Resize(direction) => {
|
||||||
let screen_instr = match direction {
|
let screen_instr = match direction {
|
||||||
Direction::Left => ScreenInstruction::ResizeLeft,
|
Direction::Left => ScreenInstruction::ResizeLeft(client_id),
|
||||||
Direction::Right => ScreenInstruction::ResizeRight,
|
Direction::Right => ScreenInstruction::ResizeRight(client_id),
|
||||||
Direction::Up => ScreenInstruction::ResizeUp,
|
Direction::Up => ScreenInstruction::ResizeUp(client_id),
|
||||||
Direction::Down => ScreenInstruction::ResizeDown,
|
Direction::Down => ScreenInstruction::ResizeDown(client_id),
|
||||||
};
|
};
|
||||||
session.senders.send_to_screen(screen_instr).unwrap();
|
session.senders.send_to_screen(screen_instr).unwrap();
|
||||||
}
|
}
|
||||||
Action::SwitchFocus => {
|
Action::SwitchFocus => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::SwitchFocus)
|
.send_to_screen(ScreenInstruction::SwitchFocus(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::FocusNextPane => {
|
Action::FocusNextPane => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::FocusNextPane)
|
.send_to_screen(ScreenInstruction::FocusNextPane(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::FocusPreviousPane => {
|
Action::FocusPreviousPane => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::FocusPreviousPane)
|
.send_to_screen(ScreenInstruction::FocusPreviousPane(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::MoveFocus(direction) => {
|
Action::MoveFocus(direction) => {
|
||||||
let screen_instr = match direction {
|
let screen_instr = match direction {
|
||||||
Direction::Left => ScreenInstruction::MoveFocusLeft,
|
Direction::Left => ScreenInstruction::MoveFocusLeft(client_id),
|
||||||
Direction::Right => ScreenInstruction::MoveFocusRight,
|
Direction::Right => ScreenInstruction::MoveFocusRight(client_id),
|
||||||
Direction::Up => ScreenInstruction::MoveFocusUp,
|
Direction::Up => ScreenInstruction::MoveFocusUp(client_id),
|
||||||
Direction::Down => ScreenInstruction::MoveFocusDown,
|
Direction::Down => ScreenInstruction::MoveFocusDown(client_id),
|
||||||
};
|
};
|
||||||
session.senders.send_to_screen(screen_instr).unwrap();
|
session.senders.send_to_screen(screen_instr).unwrap();
|
||||||
}
|
}
|
||||||
Action::MoveFocusOrTab(direction) => {
|
Action::MoveFocusOrTab(direction) => {
|
||||||
let screen_instr = match direction {
|
let screen_instr = match direction {
|
||||||
Direction::Left => ScreenInstruction::MoveFocusLeftOrPreviousTab,
|
Direction::Left => ScreenInstruction::MoveFocusLeftOrPreviousTab(client_id),
|
||||||
Direction::Right => ScreenInstruction::MoveFocusRightOrNextTab,
|
Direction::Right => ScreenInstruction::MoveFocusRightOrNextTab(client_id),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
session.senders.send_to_screen(screen_instr).unwrap();
|
session.senders.send_to_screen(screen_instr).unwrap();
|
||||||
}
|
}
|
||||||
Action::MovePane(direction) => {
|
Action::MovePane(direction) => {
|
||||||
let screen_instr = match direction {
|
let screen_instr = match direction {
|
||||||
Direction::Left => ScreenInstruction::MovePaneLeft,
|
Direction::Left => ScreenInstruction::MovePaneLeft(client_id),
|
||||||
Direction::Right => ScreenInstruction::MovePaneRight,
|
Direction::Right => ScreenInstruction::MovePaneRight(client_id),
|
||||||
Direction::Up => ScreenInstruction::MovePaneUp,
|
Direction::Up => ScreenInstruction::MovePaneUp(client_id),
|
||||||
Direction::Down => ScreenInstruction::MovePaneDown,
|
Direction::Down => ScreenInstruction::MovePaneDown(client_id),
|
||||||
};
|
};
|
||||||
session.senders.send_to_screen(screen_instr).unwrap();
|
session.senders.send_to_screen(screen_instr).unwrap();
|
||||||
}
|
}
|
||||||
Action::ScrollUp => {
|
Action::ScrollUp => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ScrollUp)
|
.send_to_screen(ScreenInstruction::ScrollUp(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::ScrollUpAt(point) => {
|
Action::ScrollUpAt(point) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ScrollUpAt(point))
|
.send_to_screen(ScreenInstruction::ScrollUpAt(point, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::ScrollDown => {
|
Action::ScrollDown => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ScrollDown)
|
.send_to_screen(ScreenInstruction::ScrollDown(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::ScrollDownAt(point) => {
|
Action::ScrollDownAt(point) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ScrollDownAt(point))
|
.send_to_screen(ScreenInstruction::ScrollDownAt(point, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::ScrollToBottom => {
|
Action::ScrollToBottom => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ScrollToBottom)
|
.send_to_screen(ScreenInstruction::ScrollToBottom(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::PageScrollUp => {
|
Action::PageScrollUp => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::PageScrollUp)
|
.send_to_screen(ScreenInstruction::PageScrollUp(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::PageScrollDown => {
|
Action::PageScrollDown => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::PageScrollDown)
|
.send_to_screen(ScreenInstruction::PageScrollDown(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::ToggleFocusFullscreen => {
|
Action::ToggleFocusFullscreen => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ToggleActiveTerminalFullscreen)
|
.send_to_screen(ScreenInstruction::ToggleActiveTerminalFullscreen(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::TogglePaneFrames => {
|
Action::TogglePaneFrames => {
|
||||||
|
|
@ -182,31 +184,43 @@ fn route_action(
|
||||||
Action::NewPane(direction) => {
|
Action::NewPane(direction) => {
|
||||||
let shell = session.default_shell.clone();
|
let shell = session.default_shell.clone();
|
||||||
let pty_instr = match direction {
|
let pty_instr = match direction {
|
||||||
Some(Direction::Left) => PtyInstruction::SpawnTerminalVertically(shell),
|
Some(Direction::Left) => PtyInstruction::SpawnTerminalVertically(shell, client_id),
|
||||||
Some(Direction::Right) => PtyInstruction::SpawnTerminalVertically(shell),
|
Some(Direction::Right) => PtyInstruction::SpawnTerminalVertically(shell, client_id),
|
||||||
Some(Direction::Up) => PtyInstruction::SpawnTerminalHorizontally(shell),
|
Some(Direction::Up) => PtyInstruction::SpawnTerminalHorizontally(shell, client_id),
|
||||||
Some(Direction::Down) => PtyInstruction::SpawnTerminalHorizontally(shell),
|
Some(Direction::Down) => {
|
||||||
|
PtyInstruction::SpawnTerminalHorizontally(shell, client_id)
|
||||||
|
}
|
||||||
// No direction specified - try to put it in the biggest available spot
|
// No direction specified - try to put it in the biggest available spot
|
||||||
None => PtyInstruction::SpawnTerminal(shell),
|
None => PtyInstruction::SpawnTerminal(shell, ClientOrTabIndex::ClientId(client_id)),
|
||||||
};
|
};
|
||||||
session.senders.send_to_pty(pty_instr).unwrap();
|
session.senders.send_to_pty(pty_instr).unwrap();
|
||||||
}
|
}
|
||||||
Action::Run(command) => {
|
Action::Run(command) => {
|
||||||
let run_cmd = Some(TerminalAction::RunCommand(command.clone().into()));
|
let run_cmd = Some(TerminalAction::RunCommand(command.clone().into()));
|
||||||
let pty_instr = match command.direction {
|
let pty_instr = match command.direction {
|
||||||
Some(Direction::Left) => PtyInstruction::SpawnTerminalVertically(run_cmd),
|
Some(Direction::Left) => {
|
||||||
Some(Direction::Right) => PtyInstruction::SpawnTerminalVertically(run_cmd),
|
PtyInstruction::SpawnTerminalVertically(run_cmd, client_id)
|
||||||
Some(Direction::Up) => PtyInstruction::SpawnTerminalHorizontally(run_cmd),
|
}
|
||||||
Some(Direction::Down) => PtyInstruction::SpawnTerminalHorizontally(run_cmd),
|
Some(Direction::Right) => {
|
||||||
|
PtyInstruction::SpawnTerminalVertically(run_cmd, client_id)
|
||||||
|
}
|
||||||
|
Some(Direction::Up) => {
|
||||||
|
PtyInstruction::SpawnTerminalHorizontally(run_cmd, client_id)
|
||||||
|
}
|
||||||
|
Some(Direction::Down) => {
|
||||||
|
PtyInstruction::SpawnTerminalHorizontally(run_cmd, client_id)
|
||||||
|
}
|
||||||
// No direction specified - try to put it in the biggest available spot
|
// No direction specified - try to put it in the biggest available spot
|
||||||
None => PtyInstruction::SpawnTerminal(run_cmd),
|
None => {
|
||||||
|
PtyInstruction::SpawnTerminal(run_cmd, ClientOrTabIndex::ClientId(client_id))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
session.senders.send_to_pty(pty_instr).unwrap();
|
session.senders.send_to_pty(pty_instr).unwrap();
|
||||||
}
|
}
|
||||||
Action::CloseFocus => {
|
Action::CloseFocus => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::CloseFocusedPane)
|
.send_to_screen(ScreenInstruction::CloseFocusedPane(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::NewTab(tab_layout) => {
|
Action::NewTab(tab_layout) => {
|
||||||
|
|
@ -219,37 +233,37 @@ fn route_action(
|
||||||
Action::GoToNextTab => {
|
Action::GoToNextTab => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::SwitchTabNext)
|
.send_to_screen(ScreenInstruction::SwitchTabNext(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::GoToPreviousTab => {
|
Action::GoToPreviousTab => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::SwitchTabPrev)
|
.send_to_screen(ScreenInstruction::SwitchTabPrev(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::ToggleActiveSyncTab => {
|
Action::ToggleActiveSyncTab => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::ToggleActiveSyncTab)
|
.send_to_screen(ScreenInstruction::ToggleActiveSyncTab(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::CloseTab => {
|
Action::CloseTab => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::CloseTab)
|
.send_to_screen(ScreenInstruction::CloseTab(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::GoToTab(i) => {
|
Action::GoToTab(i) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::GoToTab(i))
|
.send_to_screen(ScreenInstruction::GoToTab(i, Some(client_id)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::TabNameInput(c) => {
|
Action::TabNameInput(c) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::UpdateTabName(c))
|
.send_to_screen(ScreenInstruction::UpdateTabName(c, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::Quit => {
|
Action::Quit => {
|
||||||
|
|
@ -267,25 +281,25 @@ fn route_action(
|
||||||
Action::LeftClick(point) => {
|
Action::LeftClick(point) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::LeftClick(point))
|
.send_to_screen(ScreenInstruction::LeftClick(point, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::MouseRelease(point) => {
|
Action::MouseRelease(point) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::MouseRelease(point))
|
.send_to_screen(ScreenInstruction::MouseRelease(point, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::MouseHold(point) => {
|
Action::MouseHold(point) => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::MouseHold(point))
|
.send_to_screen(ScreenInstruction::MouseHold(point, client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::Copy => {
|
Action::Copy => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::Copy)
|
.send_to_screen(ScreenInstruction::Copy(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::NoOp => {}
|
Action::NoOp => {}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -95,19 +95,16 @@ fn pane_content_offset(position_and_size: &PaneGeom, viewport: &Viewport) -> (us
|
||||||
(columns_offset, rows_offset)
|
(columns_offset, rows_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Output {
|
pub struct Output {
|
||||||
pub client_render_instructions: HashMap<ClientId, String>,
|
pub client_render_instructions: HashMap<ClientId, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
pub fn new(client_ids: &HashSet<ClientId>) -> Self {
|
pub fn add_clients(&mut self, client_ids: &HashSet<ClientId>) {
|
||||||
let mut client_render_instructions = HashMap::new();
|
|
||||||
for client_id in client_ids {
|
for client_id in client_ids {
|
||||||
client_render_instructions.insert(*client_id, String::new());
|
self.client_render_instructions
|
||||||
}
|
.insert(*client_id, String::new());
|
||||||
Output {
|
|
||||||
client_render_instructions,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn push_str_to_all_clients(&mut self, to_push: &str) {
|
pub fn push_str_to_all_clients(&mut self, to_push: &str) {
|
||||||
|
|
@ -134,7 +131,6 @@ pub(crate) struct Tab {
|
||||||
should_clear_display_before_rendering: bool,
|
should_clear_display_before_rendering: bool,
|
||||||
pub mode_info: ModeInfo,
|
pub mode_info: ModeInfo,
|
||||||
pub colors: Palette,
|
pub colors: Palette,
|
||||||
pub is_active: bool,
|
|
||||||
connected_clients: HashSet<ClientId>,
|
connected_clients: HashSet<ClientId>,
|
||||||
draw_pane_frames: bool,
|
draw_pane_frames: bool,
|
||||||
pending_vte_events: HashMap<RawFd, Vec<VteBytes>>,
|
pending_vte_events: HashMap<RawFd, Vec<VteBytes>>,
|
||||||
|
|
@ -335,7 +331,6 @@ impl Tab {
|
||||||
colors,
|
colors,
|
||||||
draw_pane_frames,
|
draw_pane_frames,
|
||||||
pending_vte_events: HashMap::new(),
|
pending_vte_events: HashMap::new(),
|
||||||
is_active: true,
|
|
||||||
connected_clients,
|
connected_clients,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -800,14 +795,20 @@ impl Tab {
|
||||||
resize_pty!(pane, self.os_api);
|
resize_pty!(pane, self.os_api);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn render(&mut self) -> Option<Output> {
|
pub fn render(&mut self, output: &mut Output) {
|
||||||
if self.connected_clients.is_empty() || self.active_terminal.is_none() {
|
if self.connected_clients.is_empty() || self.active_terminal.is_none() {
|
||||||
return None;
|
return;
|
||||||
}
|
}
|
||||||
self.senders
|
for connected_client in self.connected_clients.iter() {
|
||||||
.send_to_pty(PtyInstruction::UpdateActivePane(self.active_terminal))
|
// TODO: move this out of the render function
|
||||||
.unwrap();
|
self.senders
|
||||||
let mut output = Output::new(&self.connected_clients);
|
.send_to_pty(PtyInstruction::UpdateActivePane(
|
||||||
|
self.active_terminal,
|
||||||
|
*connected_client,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
output.add_clients(&self.connected_clients);
|
||||||
let mut boundaries = Boundaries::new(self.viewport);
|
let mut boundaries = Boundaries::new(self.viewport);
|
||||||
let hide_cursor = "\u{1b}[?25l";
|
let hide_cursor = "\u{1b}[?25l";
|
||||||
output.push_str_to_all_clients(hide_cursor);
|
output.push_str_to_all_clients(hide_cursor);
|
||||||
|
|
@ -878,7 +879,6 @@ impl Tab {
|
||||||
output.push_str_to_all_clients(hide_cursor);
|
output.push_str_to_all_clients(hide_cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(output)
|
|
||||||
}
|
}
|
||||||
fn get_panes(&self) -> impl Iterator<Item = (&PaneId, &Box<dyn Pane>)> {
|
fn get_panes(&self) -> impl Iterator<Item = (&PaneId, &Box<dyn Pane>)> {
|
||||||
self.panes.iter()
|
self.panes.iter()
|
||||||
|
|
@ -2409,6 +2409,7 @@ impl Tab {
|
||||||
// if we reached here, this is either the last pane or there's some sort of
|
// if we reached here, this is either the last pane or there's some sort of
|
||||||
// configuration error (eg. we're trying to close a pane surrounded by fixed panes)
|
// configuration error (eg. we're trying to close a pane surrounded by fixed panes)
|
||||||
self.panes.remove(&id);
|
self.panes.remove(&id);
|
||||||
|
self.active_terminal = None;
|
||||||
self.resize_whole_tab(self.display_area);
|
self.resize_whole_tab(self.display_area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2587,7 +2588,8 @@ impl Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_selection_to_clipboard(&self, selection: &str) {
|
fn write_selection_to_clipboard(&self, selection: &str) {
|
||||||
let mut output = Output::new(&self.connected_clients);
|
let mut output = Output::default();
|
||||||
|
output.add_clients(&self.connected_clients);
|
||||||
output.push_str_to_all_clients(&format!(
|
output.push_str_to_all_clients(&format!(
|
||||||
"\u{1b}]52;c;{}\u{1b}\\",
|
"\u{1b}]52;c;{}\u{1b}\\",
|
||||||
base64::encode(selection)
|
base64::encode(selection)
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ fn open_new_tab() {
|
||||||
|
|
||||||
assert_eq!(screen.tabs.len(), 2, "Screen now has two tabs");
|
assert_eq!(screen.tabs.len(), 2, "Screen now has two tabs");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab switched to new tab"
|
"Active tab switched to new tab"
|
||||||
);
|
);
|
||||||
|
|
@ -132,10 +132,10 @@ pub fn switch_to_prev_tab() {
|
||||||
|
|
||||||
new_tab(&mut screen, 1);
|
new_tab(&mut screen, 1);
|
||||||
new_tab(&mut screen, 2);
|
new_tab(&mut screen, 2);
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
0,
|
0,
|
||||||
"Active tab switched to previous tab"
|
"Active tab switched to previous tab"
|
||||||
);
|
);
|
||||||
|
|
@ -151,11 +151,11 @@ pub fn switch_to_next_tab() {
|
||||||
|
|
||||||
new_tab(&mut screen, 1);
|
new_tab(&mut screen, 1);
|
||||||
new_tab(&mut screen, 2);
|
new_tab(&mut screen, 2);
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
screen.switch_tab_next();
|
screen.switch_tab_next(1);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab switched to next tab"
|
"Active tab switched to next tab"
|
||||||
);
|
);
|
||||||
|
|
@ -171,11 +171,11 @@ pub fn close_tab() {
|
||||||
|
|
||||||
new_tab(&mut screen, 1);
|
new_tab(&mut screen, 1);
|
||||||
new_tab(&mut screen, 2);
|
new_tab(&mut screen, 2);
|
||||||
screen.close_tab();
|
screen.close_tab(1);
|
||||||
|
|
||||||
assert_eq!(screen.tabs.len(), 1, "Only one tab left");
|
assert_eq!(screen.tabs.len(), 1, "Only one tab left");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
0,
|
0,
|
||||||
"Active tab switched to previous tab"
|
"Active tab switched to previous tab"
|
||||||
);
|
);
|
||||||
|
|
@ -197,13 +197,13 @@ pub fn close_the_middle_tab() {
|
||||||
.values()
|
.values()
|
||||||
.map(|t| (t.index, t.position, t.name.clone(), t.get_pane_ids()))
|
.map(|t| (t.index, t.position, t.name.clone(), t.get_pane_ids()))
|
||||||
.collect::<Vec<_>>());
|
.collect::<Vec<_>>());
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
dbg!(screen
|
dbg!(screen
|
||||||
.tabs
|
.tabs
|
||||||
.values()
|
.values()
|
||||||
.map(|t| (t.index, t.position, t.name.clone(), t.get_pane_ids()))
|
.map(|t| (t.index, t.position, t.name.clone(), t.get_pane_ids()))
|
||||||
.collect::<Vec<_>>());
|
.collect::<Vec<_>>());
|
||||||
screen.close_tab();
|
screen.close_tab(1);
|
||||||
dbg!(screen
|
dbg!(screen
|
||||||
.tabs
|
.tabs
|
||||||
.values()
|
.values()
|
||||||
|
|
@ -212,7 +212,7 @@ pub fn close_the_middle_tab() {
|
||||||
|
|
||||||
assert_eq!(screen.tabs.len(), 2, "Two tabs left");
|
assert_eq!(screen.tabs.len(), 2, "Two tabs left");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab switched to previous tab"
|
"Active tab switched to previous tab"
|
||||||
);
|
);
|
||||||
|
|
@ -229,11 +229,11 @@ fn move_focus_left_at_left_screen_edge_changes_tab() {
|
||||||
new_tab(&mut screen, 1);
|
new_tab(&mut screen, 1);
|
||||||
new_tab(&mut screen, 2);
|
new_tab(&mut screen, 2);
|
||||||
new_tab(&mut screen, 3);
|
new_tab(&mut screen, 3);
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
screen.move_focus_left_or_previous_tab();
|
screen.move_focus_left_or_previous_tab(1);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
0,
|
0,
|
||||||
"Active tab switched to previous"
|
"Active tab switched to previous"
|
||||||
);
|
);
|
||||||
|
|
@ -250,11 +250,11 @@ fn move_focus_right_at_right_screen_edge_changes_tab() {
|
||||||
new_tab(&mut screen, 1);
|
new_tab(&mut screen, 1);
|
||||||
new_tab(&mut screen, 2);
|
new_tab(&mut screen, 2);
|
||||||
new_tab(&mut screen, 3);
|
new_tab(&mut screen, 3);
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
screen.move_focus_right_or_next_tab();
|
screen.move_focus_right_or_next_tab(1);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
2,
|
2,
|
||||||
"Active tab switched to next"
|
"Active tab switched to next"
|
||||||
);
|
);
|
||||||
|
|
@ -270,19 +270,19 @@ pub fn toggle_to_previous_tab_simple() {
|
||||||
|
|
||||||
new_tab(&mut screen, 1);
|
new_tab(&mut screen, 1);
|
||||||
new_tab(&mut screen, 2);
|
new_tab(&mut screen, 2);
|
||||||
screen.go_to_tab(1);
|
screen.go_to_tab(1, 1);
|
||||||
screen.go_to_tab(2);
|
screen.go_to_tab(2, 1);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
0,
|
0,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
@ -301,38 +301,38 @@ pub fn toggle_to_previous_tab_create_tabs_only() {
|
||||||
new_tab(&mut screen, 3);
|
new_tab(&mut screen, 3);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(1)],
|
&vec![0, 1],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(2)],
|
&vec![0, 2],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
2,
|
2,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(1)],
|
&vec![0, 1],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
@ -352,84 +352,84 @@ pub fn toggle_to_previous_tab_delete() {
|
||||||
new_tab(&mut screen, 4); // 3
|
new_tab(&mut screen, 4); // 3
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(1), Some(2)],
|
&vec![0, 1, 2],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
3,
|
3,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(1), Some(3)],
|
&vec![0, 1, 3],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
2,
|
2,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(1), Some(2)],
|
&vec![0, 1, 2],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
3,
|
3,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(1), Some(3)],
|
&vec![0, 1, 3],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
2,
|
2,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
screen.switch_tab_prev();
|
screen.switch_tab_prev(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(3), Some(2)],
|
&vec![0, 3, 2],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.close_tab();
|
screen.close_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(3)],
|
&vec![0, 3],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
1,
|
1,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.toggle_tab();
|
screen.toggle_tab(1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.get_active_tab().unwrap().position,
|
screen.get_active_tab(1).unwrap().position,
|
||||||
2,
|
2,
|
||||||
"Active tab toggler to previous tab"
|
"Active tab toggler to previous tab"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
screen.tab_history,
|
screen.tab_history.get(&1).unwrap(),
|
||||||
vec![None, Some(0), Some(2)],
|
&vec![0, 2],
|
||||||
"Tab history is invalid"
|
"Tab history is invalid"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use zellij_tile::data::{Event, EventType, PluginIds};
|
||||||
use crate::{
|
use crate::{
|
||||||
logging_pipe::LoggingPipe,
|
logging_pipe::LoggingPipe,
|
||||||
panes::PaneId,
|
panes::PaneId,
|
||||||
pty::PtyInstruction,
|
pty::{ClientOrTabIndex, PtyInstruction},
|
||||||
screen::ScreenInstruction,
|
screen::ScreenInstruction,
|
||||||
thread_bus::{Bus, ThreadSenders},
|
thread_bus::{Bus, ThreadSenders},
|
||||||
};
|
};
|
||||||
|
|
@ -60,6 +60,7 @@ pub(crate) struct PluginEnv {
|
||||||
pub senders: ThreadSenders,
|
pub senders: ThreadSenders,
|
||||||
pub wasi_env: WasiEnv,
|
pub wasi_env: WasiEnv,
|
||||||
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
|
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
|
||||||
|
pub tab_index: usize,
|
||||||
plugin_own_data_dir: PathBuf,
|
plugin_own_data_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,6 +209,7 @@ fn start_plugin(
|
||||||
wasi_env,
|
wasi_env,
|
||||||
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
||||||
plugin_own_data_dir,
|
plugin_own_data_dir,
|
||||||
|
tab_index,
|
||||||
};
|
};
|
||||||
|
|
||||||
let zellij = zellij_exports(store, &plugin_env);
|
let zellij = zellij_exports(store, &plugin_env);
|
||||||
|
|
@ -293,16 +295,17 @@ fn host_open_file(plugin_env: &PluginEnv) {
|
||||||
let path: PathBuf = wasi_read_object(&plugin_env.wasi_env);
|
let path: PathBuf = wasi_read_object(&plugin_env.wasi_env);
|
||||||
plugin_env
|
plugin_env
|
||||||
.senders
|
.senders
|
||||||
.send_to_pty(PtyInstruction::SpawnTerminal(Some(
|
.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
TerminalAction::OpenFile(path),
|
Some(TerminalAction::OpenFile(path)),
|
||||||
)))
|
ClientOrTabIndex::TabIndex(plugin_env.tab_index),
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn host_switch_tab_to(plugin_env: &PluginEnv, tab_idx: u32) {
|
fn host_switch_tab_to(plugin_env: &PluginEnv, tab_idx: u32) {
|
||||||
plugin_env
|
plugin_env
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::GoToTab(tab_idx))
|
.send_to_screen(ScreenInstruction::GoToTab(tab_idx, None)) // this is a hack, we should be able to return the client id here
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue