feat: stack pane action (#4255)
* refactor: group placement properties * add stackpane cli and keybinding * add test * refactor: move spawn vertically/horizontally to spawnterminal * fix tests and cleanups * some cleanups and minor fixes * more cleanups * add stack action to the UI * style(fmt): rustfmt * fix serialization * add to default config * fix e2e tests * style(fmt): rustfmt * fix cli * fix tests * docs(changelog): add PR
This commit is contained in:
parent
02a0d055b6
commit
ca0048bdcb
44 changed files with 1202 additions and 863 deletions
|
|
@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||||
* feat: web-client, allowing users to share sessions in the browser (https://github.com/zellij-org/zellij/pull/4242)
|
* feat: web-client, allowing users to share sessions in the browser (https://github.com/zellij-org/zellij/pull/4242)
|
||||||
* performance: consolidate renders (https://github.com/zellij-org/zellij/pull/4245)
|
* performance: consolidate renders (https://github.com/zellij-org/zellij/pull/4245)
|
||||||
* feat: add plugin API to replace a pane with another existing pane (https://github.com/zellij-org/zellij/pull/4246)
|
* feat: add plugin API to replace a pane with another existing pane (https://github.com/zellij-org/zellij/pull/4246)
|
||||||
|
* feat: add "stack" keybinding and CLI action to add a stacked pane to the current pane (https://github.com/zellij-org/zellij/pull/4255)
|
||||||
|
|
||||||
## [0.42.2] - 2025-04-15
|
## [0.42.2] - 2025-04-15
|
||||||
* refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082)
|
* refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ keybinds clear-defaults=true {{
|
||||||
bind "n" {{ NewPane; SwitchToMode "Locked"; }}
|
bind "n" {{ NewPane; SwitchToMode "Locked"; }}
|
||||||
bind "d" {{ NewPane "Down"; SwitchToMode "Locked"; }}
|
bind "d" {{ NewPane "Down"; SwitchToMode "Locked"; }}
|
||||||
bind "r" {{ NewPane "Right"; SwitchToMode "Locked"; }}
|
bind "r" {{ NewPane "Right"; SwitchToMode "Locked"; }}
|
||||||
|
bind "s" {{ NewPane "stacked"; SwitchToMode "Locked"; }}
|
||||||
bind "x" {{ CloseFocus; SwitchToMode "Locked"; }}
|
bind "x" {{ CloseFocus; SwitchToMode "Locked"; }}
|
||||||
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Locked"; }}
|
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Locked"; }}
|
||||||
bind "z" {{ TogglePaneFrames; SwitchToMode "Locked"; }}
|
bind "z" {{ TogglePaneFrames; SwitchToMode "Locked"; }}
|
||||||
|
|
@ -244,6 +245,7 @@ keybinds clear-defaults=true {{
|
||||||
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
||||||
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
||||||
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
||||||
|
bind "s" {{ NewPane "stacked"; SwitchToMode "Normal"; }}
|
||||||
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
||||||
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
||||||
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
||||||
|
|
@ -468,6 +470,7 @@ keybinds clear-defaults=true {{
|
||||||
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
||||||
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
||||||
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
||||||
|
bind "s" {{ NewPane "stacked"; SwitchToMode "Normal"; }}
|
||||||
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
||||||
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
||||||
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
||||||
|
|
@ -663,6 +666,7 @@ keybinds clear-defaults=true {{
|
||||||
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
||||||
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
||||||
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
||||||
|
bind "s" {{ NewPane "stacked"; SwitchToMode "Normal"; }}
|
||||||
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
||||||
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
||||||
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
||||||
|
|
@ -865,6 +869,7 @@ keybinds clear-defaults=true {{
|
||||||
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
||||||
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
||||||
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
||||||
|
bind "s" {{ NewPane "stacked"; SwitchToMode "Normal"; }}
|
||||||
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
||||||
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
||||||
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
||||||
|
|
@ -1042,6 +1047,7 @@ keybinds clear-defaults=true {{
|
||||||
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
bind "n" {{ NewPane; SwitchToMode "Normal"; }}
|
||||||
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }}
|
||||||
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }}
|
||||||
|
bind "s" {{ NewPane "stacked"; SwitchToMode "Normal"; }}
|
||||||
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
bind "x" {{ CloseFocus; SwitchToMode "Normal"; }}
|
||||||
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }}
|
||||||
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }}
|
||||||
|
|
|
||||||
|
|
@ -1276,6 +1276,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<KeyWithModifier
|
||||||
(s("Toggle Embed"), s("Embed"), single_action_key(&km, &[A::TogglePaneEmbedOrFloating, TO_NORMAL])),
|
(s("Toggle Embed"), s("Embed"), single_action_key(&km, &[A::TogglePaneEmbedOrFloating, TO_NORMAL])),
|
||||||
(s("Split Right"), s("Right"), single_action_key(&km, &[A::NewPane(Some(Direction::Right), None, false), TO_NORMAL])),
|
(s("Split Right"), s("Right"), single_action_key(&km, &[A::NewPane(Some(Direction::Right), None, false), TO_NORMAL])),
|
||||||
(s("Split Down"), s("Down"), single_action_key(&km, &[A::NewPane(Some(Direction::Down), None, false), TO_NORMAL])),
|
(s("Split Down"), s("Down"), single_action_key(&km, &[A::NewPane(Some(Direction::Down), None, false), TO_NORMAL])),
|
||||||
|
(s("Stack"), s("Stack"), single_action_key(&km, &[A::NewStackedPane(None, None), TO_NORMAL])),
|
||||||
(s("Select pane"), s("Select"), to_basemode_key),
|
(s("Select pane"), s("Select"), to_basemode_key),
|
||||||
]} else if mi.mode == IM::Tab {
|
]} else if mi.mode == IM::Tab {
|
||||||
// With the default bindings, "Move focus" for tabs is tricky: It binds all the arrow keys
|
// With the default bindings, "Move focus" for tabs is tricky: It binds all the arrow keys
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ fn main() {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
pinned,
|
pinned,
|
||||||
|
stacked,
|
||||||
})) = opts.command
|
})) = opts.command
|
||||||
{
|
{
|
||||||
let cwd = cwd.or_else(|| std::env::current_dir().ok());
|
let cwd = cwd.or_else(|| std::env::current_dir().ok());
|
||||||
|
|
@ -59,6 +60,7 @@ fn main() {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
pinned,
|
pinned,
|
||||||
|
stacked,
|
||||||
};
|
};
|
||||||
commands::send_action_to_session(command_cli_action, opts.session, config);
|
commands::send_action_to_session(command_cli_action, opts.session, config);
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
|
@ -77,6 +79,7 @@ fn main() {
|
||||||
})) = opts.command
|
})) = opts.command
|
||||||
{
|
{
|
||||||
let cwd = None;
|
let cwd = None;
|
||||||
|
let stacked = false;
|
||||||
let command_cli_action = CliAction::NewPane {
|
let command_cli_action = CliAction::NewPane {
|
||||||
command: vec![],
|
command: vec![],
|
||||||
plugin: Some(url),
|
plugin: Some(url),
|
||||||
|
|
@ -94,6 +97,7 @@ fn main() {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
pinned,
|
pinned,
|
||||||
|
stacked,
|
||||||
};
|
};
|
||||||
commands::send_action_to_session(command_cli_action, opts.session, config);
|
commands::send_action_to_session(command_cli_action, opts.session, config);
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
|
|
||||||
|
|
@ -1045,7 +1045,6 @@ pub fn resize_terminal_window() {
|
||||||
name: "wait for terminal to be resized and app to be re-rendered",
|
name: "wait for terminal to be resized and app to be re-rendered",
|
||||||
instruction: |remote_terminal: RemoteTerminal| -> bool {
|
instruction: |remote_terminal: RemoteTerminal| -> bool {
|
||||||
let mut step_is_complete = false;
|
let mut step_is_complete = false;
|
||||||
eprintln!("current_snapshot: {}", remote_terminal.current_snapshot());
|
|
||||||
if remote_terminal.cursor_position_is(53, 2) && remote_terminal.ctrl_plus_appears()
|
if remote_terminal.cursor_position_is(53, 2) && remote_terminal.ctrl_plus_appears()
|
||||||
{
|
{
|
||||||
// size has been changed
|
// size has been changed
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,72 @@ impl TiledPanes {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn add_pane_to_stack_of_active_pane(
|
||||||
|
&mut self,
|
||||||
|
pane_id: PaneId,
|
||||||
|
mut pane: Box<dyn Pane>,
|
||||||
|
client_id: ClientId,
|
||||||
|
) {
|
||||||
|
let mut pane_grid = TiledPaneGrid::new(
|
||||||
|
&mut self.panes,
|
||||||
|
&self.panes_to_hide,
|
||||||
|
*self.display_area.borrow(),
|
||||||
|
*self.viewport.borrow(),
|
||||||
|
);
|
||||||
|
let Some(active_pane_id) = self.active_panes.get(&client_id) else {
|
||||||
|
log::error!("Could not find active pane id for client_id");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let pane_id_is_stacked = pane_grid
|
||||||
|
.get_pane_geom(active_pane_id)
|
||||||
|
.map(|p| p.is_stacked())
|
||||||
|
.unwrap_or(false);
|
||||||
|
if !pane_id_is_stacked {
|
||||||
|
let _ = pane_grid.make_pane_stacked(&active_pane_id);
|
||||||
|
}
|
||||||
|
match pane_grid.make_room_in_stack_of_pane_id_for_pane(active_pane_id) {
|
||||||
|
Ok(new_pane_geom) => {
|
||||||
|
pane.set_geom(new_pane_geom);
|
||||||
|
self.panes.insert(pane_id, pane);
|
||||||
|
self.set_force_render(); // TODO: why do we need this?
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to add pane to stack: {}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_pane_to_stack_of_pane_id(
|
||||||
|
&mut self,
|
||||||
|
pane_id: PaneId,
|
||||||
|
mut pane: Box<dyn Pane>,
|
||||||
|
root_pane_id: PaneId,
|
||||||
|
) {
|
||||||
|
let mut pane_grid = TiledPaneGrid::new(
|
||||||
|
&mut self.panes,
|
||||||
|
&self.panes_to_hide,
|
||||||
|
*self.display_area.borrow(),
|
||||||
|
*self.viewport.borrow(),
|
||||||
|
);
|
||||||
|
let pane_id_is_stacked = pane_grid
|
||||||
|
.get_pane_geom(&root_pane_id)
|
||||||
|
.map(|p| p.is_stacked())
|
||||||
|
.unwrap_or(false);
|
||||||
|
if !pane_id_is_stacked {
|
||||||
|
let _ = pane_grid.make_pane_stacked(&root_pane_id);
|
||||||
|
}
|
||||||
|
match pane_grid.make_room_in_stack_of_pane_id_for_pane(&root_pane_id) {
|
||||||
|
Ok(new_pane_geom) => {
|
||||||
|
pane.set_geom(new_pane_geom);
|
||||||
|
self.panes.insert(pane_id, pane);
|
||||||
|
self.set_force_render(); // TODO: why do we need this?
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to add pane to stack: {}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn fixed_pane_geoms(&self) -> Vec<Viewport> {
|
pub fn fixed_pane_geoms(&self) -> Vec<Viewport> {
|
||||||
self.panes
|
self.panes
|
||||||
.values()
|
.values()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 6878
|
expression: "format!(\"{:#?}\",\nnew_tab_event).replace(&format!(\"{:?}\", temp_folder.path()), \"\\\"CWD\\\"\")"
|
||||||
expression: "format!(\"{:#?}\",\n new_tab_event).replace(&format!(\"{:?}\", temp_folder.path()),\n \"\\\"CWD\\\"\")"
|
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
SpawnTerminal(
|
SpawnTerminal(
|
||||||
|
|
@ -29,8 +28,7 @@ Some(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
None,
|
NoPreference,
|
||||||
None,
|
|
||||||
true,
|
true,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4557
|
|
||||||
expression: "format!(\"{:#?}\", new_tab_event)"
|
expression: "format!(\"{:#?}\", new_tab_event)"
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -26,11 +25,10 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
None,
|
||||||
true,
|
Floating(
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4479
|
|
||||||
expression: "format!(\"{:#?}\", new_tab_event)"
|
expression: "format!(\"{:#?}\", new_tab_event)"
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -26,11 +25,10 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
None,
|
||||||
false,
|
Tiled(
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 3996
|
expression: "format!(\"{:#?}\",\nnew_tab_event).replace(&format!(\"{:?}\", temp_folder.path()), \"\\\"CWD\\\"\")"
|
||||||
expression: "format!(\"{:#?}\",\n new_tab_event).replace(&format!(\"{:?}\", temp_folder.path()),\n \"\\\"CWD\\\"\")"
|
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
SpawnTerminal(
|
SpawnTerminal(
|
||||||
|
|
@ -23,13 +22,12 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
Some(
|
Some(
|
||||||
"Editing: /path/to/my/file.rs",
|
"Editing: /path/to/my/file.rs",
|
||||||
),
|
),
|
||||||
|
Floating(
|
||||||
None,
|
None,
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4078
|
expression: "format!(\"{:#?}\",\nnew_tab_event).replace(&format!(\"{:?}\", temp_folder.path()), \"\\\"CWD\\\"\")"
|
||||||
expression: "format!(\"{:#?}\",\n new_tab_event).replace(&format!(\"{:?}\", temp_folder.path()),\n \"\\\"CWD\\\"\")"
|
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
SpawnTerminal(
|
SpawnTerminal(
|
||||||
|
|
@ -23,13 +22,12 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
Some(
|
Some(
|
||||||
"Editing: /path/to/my/file.rs",
|
"Editing: /path/to/my/file.rs",
|
||||||
),
|
),
|
||||||
|
Tiled(
|
||||||
None,
|
None,
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4243
|
expression: "format!(\"{:#?}\",\nnew_tab_event).replace(&format!(\"{:?}\", temp_folder.path()), \"\\\"CWD\\\"\")"
|
||||||
expression: "format!(\"{:#?}\",\n new_tab_event).replace(&format!(\"{:?}\", temp_folder.path()),\n \"\\\"CWD\\\"\")"
|
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
SpawnTerminal(
|
SpawnTerminal(
|
||||||
|
|
@ -25,13 +24,12 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
Some(
|
Some(
|
||||||
"Editing: /path/to/my/file.rs",
|
"Editing: /path/to/my/file.rs",
|
||||||
),
|
),
|
||||||
|
Floating(
|
||||||
None,
|
None,
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4161
|
expression: "format!(\"{:#?}\",\nnew_tab_event).replace(&format!(\"{:?}\", temp_folder.path()), \"\\\"CWD\\\"\")"
|
||||||
expression: "format!(\"{:#?}\",\n new_tab_event).replace(&format!(\"{:?}\", temp_folder.path()),\n \"\\\"CWD\\\"\")"
|
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
SpawnTerminal(
|
SpawnTerminal(
|
||||||
|
|
@ -25,13 +24,12 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
Some(
|
Some(
|
||||||
"Editing: /path/to/my/file.rs",
|
"Editing: /path/to/my/file.rs",
|
||||||
),
|
),
|
||||||
|
Tiled(
|
||||||
None,
|
None,
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4401
|
|
||||||
expression: "format!(\"{:#?}\", new_tab_event)"
|
expression: "format!(\"{:#?}\", new_tab_event)"
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -19,11 +18,10 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
None,
|
||||||
true,
|
Floating(
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 4323
|
|
||||||
expression: "format!(\"{:#?}\", new_tab_event)"
|
expression: "format!(\"{:#?}\", new_tab_event)"
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -19,11 +18,10 @@ Some(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Some(
|
None,
|
||||||
false,
|
Tiled(
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
ClientId(
|
ClientId(
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use super::PluginInstruction;
|
||||||
use crate::background_jobs::BackgroundJob;
|
use crate::background_jobs::BackgroundJob;
|
||||||
use crate::plugins::plugin_map::PluginEnv;
|
use crate::plugins::plugin_map::PluginEnv;
|
||||||
use crate::plugins::wasm_bridge::handle_plugin_crash;
|
use crate::plugins::wasm_bridge::handle_plugin_crash;
|
||||||
use crate::pty::{ClientTabIndexOrPaneId, PtyInstruction};
|
use crate::pty::{ClientTabIndexOrPaneId, NewPanePlacement, PtyInstruction};
|
||||||
use crate::route::route_action;
|
use crate::route::route_action;
|
||||||
use crate::ServerInstruction;
|
use crate::ServerInstruction;
|
||||||
use async_std::task;
|
use async_std::task;
|
||||||
|
|
@ -744,14 +744,12 @@ fn open_file_near_plugin(
|
||||||
OriginatingPlugin::new(env.plugin_id, env.client_id, context),
|
OriginatingPlugin::new(env.plugin_id, env.client_id, context),
|
||||||
);
|
);
|
||||||
let title = format!("Editing: {}", open_file_payload.path.display());
|
let title = format!("Editing: {}", open_file_payload.path.display());
|
||||||
let should_float = false;
|
|
||||||
let start_suppressed = false;
|
let start_suppressed = false;
|
||||||
let open_file = TerminalAction::OpenFile(open_file_payload);
|
let open_file = TerminalAction::OpenFile(open_file_payload);
|
||||||
let pty_instr = PtyInstruction::SpawnTerminal(
|
let pty_instr = PtyInstruction::SpawnTerminal(
|
||||||
Some(open_file),
|
Some(open_file),
|
||||||
Some(should_float),
|
|
||||||
Some(title),
|
Some(title),
|
||||||
None,
|
NewPanePlacement::default(),
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
||||||
);
|
);
|
||||||
|
|
@ -774,14 +772,12 @@ fn open_file_floating_near_plugin(
|
||||||
OriginatingPlugin::new(env.plugin_id, env.client_id, context),
|
OriginatingPlugin::new(env.plugin_id, env.client_id, context),
|
||||||
);
|
);
|
||||||
let title = format!("Editing: {}", open_file_payload.path.display());
|
let title = format!("Editing: {}", open_file_payload.path.display());
|
||||||
let should_float = true;
|
|
||||||
let start_suppressed = false;
|
let start_suppressed = false;
|
||||||
let open_file = TerminalAction::OpenFile(open_file_payload);
|
let open_file = TerminalAction::OpenFile(open_file_payload);
|
||||||
let pty_instr = PtyInstruction::SpawnTerminal(
|
let pty_instr = PtyInstruction::SpawnTerminal(
|
||||||
Some(open_file),
|
Some(open_file),
|
||||||
Some(should_float),
|
|
||||||
Some(title),
|
Some(title),
|
||||||
floating_pane_coordinates,
|
NewPanePlacement::Floating(floating_pane_coordinates),
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
||||||
);
|
);
|
||||||
|
|
@ -834,7 +830,6 @@ fn open_terminal(env: &PluginEnv, cwd: PathBuf) {
|
||||||
|
|
||||||
fn open_terminal_near_plugin(env: &PluginEnv, cwd: PathBuf) {
|
fn open_terminal_near_plugin(env: &PluginEnv, cwd: PathBuf) {
|
||||||
let cwd = env.plugin_cwd.join(cwd);
|
let cwd = env.plugin_cwd.join(cwd);
|
||||||
let should_float = false;
|
|
||||||
let mut default_shell = env.default_shell.clone().unwrap_or_else(|| {
|
let mut default_shell = env.default_shell.clone().unwrap_or_else(|| {
|
||||||
TerminalAction::RunCommand(RunCommand {
|
TerminalAction::RunCommand(RunCommand {
|
||||||
command: env.path_to_default_shell.clone(),
|
command: env.path_to_default_shell.clone(),
|
||||||
|
|
@ -845,9 +840,8 @@ fn open_terminal_near_plugin(env: &PluginEnv, cwd: PathBuf) {
|
||||||
default_shell.change_cwd(cwd);
|
default_shell.change_cwd(cwd);
|
||||||
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(default_shell),
|
Some(default_shell),
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
None,
|
NewPanePlacement::Tiled(None),
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
||||||
));
|
));
|
||||||
|
|
@ -881,7 +875,6 @@ fn open_terminal_floating_near_plugin(
|
||||||
floating_pane_coordinates: Option<FloatingPaneCoordinates>,
|
floating_pane_coordinates: Option<FloatingPaneCoordinates>,
|
||||||
) {
|
) {
|
||||||
let cwd = env.plugin_cwd.join(cwd);
|
let cwd = env.plugin_cwd.join(cwd);
|
||||||
let should_float = true;
|
|
||||||
let mut default_shell = env.default_shell.clone().unwrap_or_else(|| {
|
let mut default_shell = env.default_shell.clone().unwrap_or_else(|| {
|
||||||
TerminalAction::RunCommand(RunCommand {
|
TerminalAction::RunCommand(RunCommand {
|
||||||
command: env.path_to_default_shell.clone(),
|
command: env.path_to_default_shell.clone(),
|
||||||
|
|
@ -892,9 +885,8 @@ fn open_terminal_floating_near_plugin(
|
||||||
let name = None;
|
let name = None;
|
||||||
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(default_shell),
|
Some(default_shell),
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
floating_pane_coordinates,
|
NewPanePlacement::Floating(floating_pane_coordinates),
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
||||||
));
|
));
|
||||||
|
|
@ -1021,7 +1013,6 @@ fn open_command_pane_near_plugin(
|
||||||
let hold_on_close = true;
|
let hold_on_close = true;
|
||||||
let hold_on_start = false;
|
let hold_on_start = false;
|
||||||
let name = None;
|
let name = None;
|
||||||
let should_float = false;
|
|
||||||
let run_command_action = RunCommandAction {
|
let run_command_action = RunCommandAction {
|
||||||
command,
|
command,
|
||||||
args,
|
args,
|
||||||
|
|
@ -1038,9 +1029,8 @@ fn open_command_pane_near_plugin(
|
||||||
let run_cmd = TerminalAction::RunCommand(run_command_action.into());
|
let run_cmd = TerminalAction::RunCommand(run_command_action.into());
|
||||||
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(run_cmd),
|
Some(run_cmd),
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
None,
|
NewPanePlacement::Tiled(None),
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
||||||
));
|
));
|
||||||
|
|
@ -1090,7 +1080,6 @@ fn open_command_pane_floating_near_plugin(
|
||||||
let hold_on_close = true;
|
let hold_on_close = true;
|
||||||
let hold_on_start = false;
|
let hold_on_start = false;
|
||||||
let name = None;
|
let name = None;
|
||||||
let should_float = true;
|
|
||||||
let run_command_action = RunCommandAction {
|
let run_command_action = RunCommandAction {
|
||||||
command,
|
command,
|
||||||
args,
|
args,
|
||||||
|
|
@ -1107,9 +1096,8 @@ fn open_command_pane_floating_near_plugin(
|
||||||
let run_cmd = TerminalAction::RunCommand(run_command_action.into());
|
let run_cmd = TerminalAction::RunCommand(run_command_action.into());
|
||||||
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(run_cmd),
|
Some(run_cmd),
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
floating_pane_coordinates,
|
NewPanePlacement::Floating(floating_pane_coordinates),
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
|
||||||
));
|
));
|
||||||
|
|
@ -1177,9 +1165,8 @@ fn open_command_pane_background(
|
||||||
let run_cmd = TerminalAction::RunCommand(run_command_action.into());
|
let run_cmd = TerminalAction::RunCommand(run_command_action.into());
|
||||||
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
let _ = env.senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(run_cmd),
|
Some(run_cmd),
|
||||||
None,
|
|
||||||
name,
|
name,
|
||||||
None,
|
NewPanePlacement::default(),
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
ClientTabIndexOrPaneId::ClientId(env.client_id),
|
ClientTabIndexOrPaneId::ClientId(env.client_id),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use nix::unistd::Pid;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{collections::HashMap, os::unix::io::RawFd, path::PathBuf};
|
use std::{collections::HashMap, os::unix::io::RawFd, path::PathBuf};
|
||||||
use zellij_utils::{
|
use zellij_utils::{
|
||||||
data::{Event, FloatingPaneCoordinates, OriginatingPlugin},
|
data::{Direction, Event, FloatingPaneCoordinates, OriginatingPlugin},
|
||||||
errors::prelude::*,
|
errors::prelude::*,
|
||||||
errors::{ContextType, PtyContext},
|
errors::{ContextType, PtyContext},
|
||||||
input::{
|
input::{
|
||||||
|
|
@ -37,26 +37,95 @@ pub enum ClientTabIndexOrPaneId {
|
||||||
PaneId(PaneId),
|
PaneId(PaneId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move elsewhere
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum NewPanePlacement {
|
||||||
|
NoPreference,
|
||||||
|
Tiled(Option<Direction>),
|
||||||
|
Floating(Option<FloatingPaneCoordinates>),
|
||||||
|
InPlace {
|
||||||
|
pane_id_to_replace: Option<PaneId>,
|
||||||
|
close_replaced_pane: bool,
|
||||||
|
},
|
||||||
|
Stacked(Option<PaneId>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for NewPanePlacement {
|
||||||
|
fn default() -> Self {
|
||||||
|
NewPanePlacement::NoPreference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewPanePlacement {
|
||||||
|
pub fn with_floating_pane_coordinates(
|
||||||
|
floating_pane_coordinates: Option<FloatingPaneCoordinates>,
|
||||||
|
) -> Self {
|
||||||
|
NewPanePlacement::Floating(floating_pane_coordinates)
|
||||||
|
}
|
||||||
|
pub fn with_should_be_in_place(
|
||||||
|
self,
|
||||||
|
should_be_in_place: bool,
|
||||||
|
close_replaced_pane: bool,
|
||||||
|
) -> Self {
|
||||||
|
if should_be_in_place {
|
||||||
|
NewPanePlacement::InPlace {
|
||||||
|
pane_id_to_replace: None,
|
||||||
|
close_replaced_pane,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn with_pane_id_to_replace(
|
||||||
|
pane_id_to_replace: Option<PaneId>,
|
||||||
|
close_replaced_pane: bool,
|
||||||
|
) -> Self {
|
||||||
|
NewPanePlacement::InPlace {
|
||||||
|
pane_id_to_replace,
|
||||||
|
close_replaced_pane,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn should_float(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
NewPanePlacement::Floating(_) => Some(true),
|
||||||
|
NewPanePlacement::Tiled(_) => Some(false),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn floating_pane_coordinates(&self) -> Option<FloatingPaneCoordinates> {
|
||||||
|
match self {
|
||||||
|
NewPanePlacement::Floating(floating_pane_coordinates) => {
|
||||||
|
floating_pane_coordinates.clone()
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn should_stack(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
NewPanePlacement::Stacked(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn id_of_stack_root(&self) -> Option<PaneId> {
|
||||||
|
match self {
|
||||||
|
NewPanePlacement::Stacked(id) => *id,
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Instructions related to PTYs (pseudoterminals).
|
/// Instructions related to PTYs (pseudoterminals).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PtyInstruction {
|
pub enum PtyInstruction {
|
||||||
SpawnTerminal(
|
SpawnTerminal(
|
||||||
Option<TerminalAction>,
|
Option<TerminalAction>,
|
||||||
Option<bool>,
|
|
||||||
Option<String>,
|
Option<String>,
|
||||||
Option<FloatingPaneCoordinates>,
|
NewPanePlacement,
|
||||||
bool, // start suppressed
|
bool, // start suppressed
|
||||||
ClientTabIndexOrPaneId,
|
ClientTabIndexOrPaneId,
|
||||||
), // bool (if Some) is
|
), // bool (if Some) is
|
||||||
// should_float, String is an optional pane name
|
// should_float, String is an optional pane name
|
||||||
OpenInPlaceEditor(PathBuf, Option<usize>, ClientTabIndexOrPaneId), // Option<usize> is the optional line number
|
OpenInPlaceEditor(PathBuf, Option<usize>, ClientTabIndexOrPaneId), // Option<usize> is the optional line number
|
||||||
SpawnTerminalVertically(Option<TerminalAction>, Option<String>, ClientId), // String is an
|
|
||||||
// optional pane
|
|
||||||
// name
|
|
||||||
// bool is start_suppressed
|
|
||||||
SpawnTerminalHorizontally(Option<TerminalAction>, Option<String>, ClientId), // String is an
|
|
||||||
// optional pane
|
|
||||||
// name
|
|
||||||
UpdateActivePane(Option<PaneId>, ClientId),
|
UpdateActivePane(Option<PaneId>, ClientId),
|
||||||
GoToTab(TabIndex, ClientId),
|
GoToTab(TabIndex, ClientId),
|
||||||
NewTab(
|
NewTab(
|
||||||
|
|
@ -114,8 +183,6 @@ impl From<&PtyInstruction> for PtyContext {
|
||||||
match *pty_instruction {
|
match *pty_instruction {
|
||||||
PtyInstruction::SpawnTerminal(..) => PtyContext::SpawnTerminal,
|
PtyInstruction::SpawnTerminal(..) => PtyContext::SpawnTerminal,
|
||||||
PtyInstruction::OpenInPlaceEditor(..) => PtyContext::OpenInPlaceEditor,
|
PtyInstruction::OpenInPlaceEditor(..) => PtyContext::OpenInPlaceEditor,
|
||||||
PtyInstruction::SpawnTerminalVertically(..) => PtyContext::SpawnTerminalVertically,
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(..) => PtyContext::SpawnTerminalHorizontally,
|
|
||||||
PtyInstruction::UpdateActivePane(..) => PtyContext::UpdateActivePane,
|
PtyInstruction::UpdateActivePane(..) => PtyContext::UpdateActivePane,
|
||||||
PtyInstruction::GoToTab(..) => PtyContext::GoToTab,
|
PtyInstruction::GoToTab(..) => PtyContext::GoToTab,
|
||||||
PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
|
PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
|
||||||
|
|
@ -153,9 +220,8 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
||||||
match event {
|
match event {
|
||||||
PtyInstruction::SpawnTerminal(
|
PtyInstruction::SpawnTerminal(
|
||||||
terminal_action,
|
terminal_action,
|
||||||
should_float,
|
|
||||||
name,
|
name,
|
||||||
floating_pane_coordinates,
|
new_pane_placement,
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
client_or_tab_index,
|
client_or_tab_index,
|
||||||
) => {
|
) => {
|
||||||
|
|
@ -235,10 +301,9 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
||||||
.send_to_screen(ScreenInstruction::NewPane(
|
.send_to_screen(ScreenInstruction::NewPane(
|
||||||
PaneId::Terminal(pid),
|
PaneId::Terminal(pid),
|
||||||
pane_title,
|
pane_title,
|
||||||
should_float,
|
|
||||||
hold_for_command,
|
hold_for_command,
|
||||||
invoked_with,
|
invoked_with,
|
||||||
floating_pane_coordinates,
|
new_pane_placement,
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
client_or_tab_index,
|
client_or_tab_index,
|
||||||
))
|
))
|
||||||
|
|
@ -253,10 +318,9 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
||||||
.send_to_screen(ScreenInstruction::NewPane(
|
.send_to_screen(ScreenInstruction::NewPane(
|
||||||
PaneId::Terminal(*terminal_id),
|
PaneId::Terminal(*terminal_id),
|
||||||
pane_title,
|
pane_title,
|
||||||
should_float,
|
|
||||||
hold_for_command,
|
hold_for_command,
|
||||||
invoked_with,
|
invoked_with,
|
||||||
floating_pane_coordinates,
|
new_pane_placement,
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
client_or_tab_index,
|
client_or_tab_index,
|
||||||
))
|
))
|
||||||
|
|
@ -390,144 +454,6 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PtyInstruction::SpawnTerminalVertically(terminal_action, name, client_id) => {
|
|
||||||
let err_context =
|
|
||||||
|| format!("failed to spawn terminal vertically for client {client_id}");
|
|
||||||
|
|
||||||
let (hold_on_close, run_command, pane_title) = match &terminal_action {
|
|
||||||
Some(TerminalAction::RunCommand(run_command)) => (
|
|
||||||
run_command.hold_on_close,
|
|
||||||
Some(run_command.clone()),
|
|
||||||
Some(name.unwrap_or_else(|| run_command.to_string())),
|
|
||||||
),
|
|
||||||
_ => (false, None, name),
|
|
||||||
};
|
|
||||||
match pty
|
|
||||||
.spawn_terminal(terminal_action, ClientTabIndexOrPaneId::ClientId(client_id))
|
|
||||||
.with_context(err_context)
|
|
||||||
{
|
|
||||||
Ok((pid, starts_held)) => {
|
|
||||||
let hold_for_command = if starts_held { run_command } else { None };
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::VerticalSplit(
|
|
||||||
PaneId::Terminal(pid),
|
|
||||||
pane_title,
|
|
||||||
hold_for_command,
|
|
||||||
client_id,
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
},
|
|
||||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
|
||||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
|
||||||
let hold_for_command = None; // we do not hold an "error" pane
|
|
||||||
if hold_on_close {
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::VerticalSplit(
|
|
||||||
PaneId::Terminal(*terminal_id),
|
|
||||||
pane_title,
|
|
||||||
hold_for_command,
|
|
||||||
client_id,
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
if let Some(run_command) = run_command {
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::PtyBytes(
|
|
||||||
*terminal_id,
|
|
||||||
format!(
|
|
||||||
"Command not found: {}",
|
|
||||||
run_command.command.display()
|
|
||||||
)
|
|
||||||
.as_bytes()
|
|
||||||
.to_vec(),
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::HoldPane(
|
|
||||||
PaneId::Terminal(*terminal_id),
|
|
||||||
Some(2), // exit status
|
|
||||||
run_command,
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => Err::<(), _>(err).non_fatal(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(terminal_action, name, client_id) => {
|
|
||||||
let err_context =
|
|
||||||
|| format!("failed to spawn terminal horizontally for client {client_id}");
|
|
||||||
|
|
||||||
let (hold_on_close, run_command, pane_title) = match &terminal_action {
|
|
||||||
Some(TerminalAction::RunCommand(run_command)) => (
|
|
||||||
run_command.hold_on_close,
|
|
||||||
Some(run_command.clone()),
|
|
||||||
Some(name.unwrap_or_else(|| run_command.to_string())),
|
|
||||||
),
|
|
||||||
_ => (false, None, name),
|
|
||||||
};
|
|
||||||
match pty
|
|
||||||
.spawn_terminal(terminal_action, ClientTabIndexOrPaneId::ClientId(client_id))
|
|
||||||
.with_context(err_context)
|
|
||||||
{
|
|
||||||
Ok((pid, starts_held)) => {
|
|
||||||
let hold_for_command = if starts_held { run_command } else { None };
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::HorizontalSplit(
|
|
||||||
PaneId::Terminal(pid),
|
|
||||||
pane_title,
|
|
||||||
hold_for_command,
|
|
||||||
client_id,
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
},
|
|
||||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
|
||||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
|
||||||
if hold_on_close {
|
|
||||||
let hold_for_command = None; // we do not hold an "error" pane
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::HorizontalSplit(
|
|
||||||
PaneId::Terminal(*terminal_id),
|
|
||||||
pane_title,
|
|
||||||
hold_for_command,
|
|
||||||
client_id,
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
if let Some(run_command) = run_command {
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::PtyBytes(
|
|
||||||
*terminal_id,
|
|
||||||
format!(
|
|
||||||
"Command not found: {}",
|
|
||||||
run_command.command.display()
|
|
||||||
)
|
|
||||||
.as_bytes()
|
|
||||||
.to_vec(),
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
pty.bus
|
|
||||||
.senders
|
|
||||||
.send_to_screen(ScreenInstruction::HoldPane(
|
|
||||||
PaneId::Terminal(*terminal_id),
|
|
||||||
Some(2), // exit status
|
|
||||||
run_command,
|
|
||||||
))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => Err::<(), _>(err).non_fatal(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PtyInstruction::UpdateActivePane(pane_id, client_id) => {
|
PtyInstruction::UpdateActivePane(pane_id, client_id) => {
|
||||||
pty.set_active_pane(pane_id, client_id);
|
pty.set_active_pane(pane_id, client_id);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
os_input_output::ServerOsApi,
|
os_input_output::ServerOsApi,
|
||||||
panes::PaneId,
|
panes::PaneId,
|
||||||
plugins::PluginInstruction,
|
plugins::PluginInstruction,
|
||||||
pty::{ClientTabIndexOrPaneId, PtyInstruction},
|
pty::{ClientTabIndexOrPaneId, NewPanePlacement, PtyInstruction},
|
||||||
screen::ScreenInstruction,
|
screen::ScreenInstruction,
|
||||||
ServerInstruction, SessionMetaData, SessionState,
|
ServerInstruction, SessionMetaData, SessionState,
|
||||||
};
|
};
|
||||||
|
|
@ -257,30 +257,13 @@ pub(crate) fn route_action(
|
||||||
},
|
},
|
||||||
Action::NewPane(direction, name, start_suppressed) => {
|
Action::NewPane(direction, name, start_suppressed) => {
|
||||||
let shell = default_shell.clone();
|
let shell = default_shell.clone();
|
||||||
let pty_instr = match direction {
|
senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(Direction::Left) => {
|
|
||||||
PtyInstruction::SpawnTerminalVertically(shell, name, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Right) => {
|
|
||||||
PtyInstruction::SpawnTerminalVertically(shell, name, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Up) => {
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(shell, name, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Down) => {
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(shell, name, client_id)
|
|
||||||
},
|
|
||||||
// No direction specified - try to put it in the biggest available spot
|
|
||||||
None => PtyInstruction::SpawnTerminal(
|
|
||||||
shell,
|
shell,
|
||||||
None,
|
|
||||||
name,
|
name,
|
||||||
None,
|
NewPanePlacement::Tiled(direction),
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
ClientTabIndexOrPaneId::ClientId(client_id),
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
),
|
));
|
||||||
};
|
|
||||||
senders.send_to_pty(pty_instr).with_context(err_context)?;
|
|
||||||
},
|
},
|
||||||
Action::EditFile(
|
Action::EditFile(
|
||||||
open_file_payload,
|
open_file_payload,
|
||||||
|
|
@ -292,25 +275,8 @@ pub(crate) fn route_action(
|
||||||
) => {
|
) => {
|
||||||
let title = format!("Editing: {}", open_file_payload.path.display());
|
let title = format!("Editing: {}", open_file_payload.path.display());
|
||||||
let open_file = TerminalAction::OpenFile(open_file_payload);
|
let open_file = TerminalAction::OpenFile(open_file_payload);
|
||||||
let pty_instr = match (split_direction, should_float, should_open_in_place) {
|
let pty_instr = if should_open_in_place {
|
||||||
(Some(Direction::Left), false, false) => {
|
match pane_id {
|
||||||
PtyInstruction::SpawnTerminalVertically(Some(open_file), Some(title), client_id)
|
|
||||||
},
|
|
||||||
(Some(Direction::Right), false, false) => {
|
|
||||||
PtyInstruction::SpawnTerminalVertically(Some(open_file), Some(title), client_id)
|
|
||||||
},
|
|
||||||
(Some(Direction::Up), false, false) => PtyInstruction::SpawnTerminalHorizontally(
|
|
||||||
Some(open_file),
|
|
||||||
Some(title),
|
|
||||||
client_id,
|
|
||||||
),
|
|
||||||
(Some(Direction::Down), false, false) => PtyInstruction::SpawnTerminalHorizontally(
|
|
||||||
Some(open_file),
|
|
||||||
Some(title),
|
|
||||||
client_id,
|
|
||||||
),
|
|
||||||
// open terminal in place
|
|
||||||
(_, _, true) => match pane_id {
|
|
||||||
Some(pane_id) => PtyInstruction::SpawnInPlaceTerminal(
|
Some(pane_id) => PtyInstruction::SpawnInPlaceTerminal(
|
||||||
Some(open_file),
|
Some(open_file),
|
||||||
Some(title),
|
Some(title),
|
||||||
|
|
@ -323,17 +289,19 @@ pub(crate) fn route_action(
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::ClientId(client_id),
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
),
|
),
|
||||||
},
|
}
|
||||||
// Open either floating terminal if we were asked with should_float or defer
|
} else {
|
||||||
// placement to screen
|
PtyInstruction::SpawnTerminal(
|
||||||
(None, _, _) | (_, true, _) => PtyInstruction::SpawnTerminal(
|
|
||||||
Some(open_file),
|
Some(open_file),
|
||||||
Some(should_float),
|
|
||||||
Some(title),
|
Some(title),
|
||||||
floating_pane_coordinates,
|
if should_float {
|
||||||
|
NewPanePlacement::Floating(floating_pane_coordinates)
|
||||||
|
} else {
|
||||||
|
NewPanePlacement::Tiled(split_direction)
|
||||||
|
},
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
ClientTabIndexOrPaneId::ClientId(client_id),
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
),
|
)
|
||||||
};
|
};
|
||||||
senders.send_to_pty(pty_instr).with_context(err_context)?;
|
senders.send_to_pty(pty_instr).with_context(err_context)?;
|
||||||
},
|
},
|
||||||
|
|
@ -368,16 +336,14 @@ pub(crate) fn route_action(
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
},
|
},
|
||||||
Action::NewFloatingPane(run_command, name, floating_pane_coordinates) => {
|
Action::NewFloatingPane(run_command, name, floating_pane_coordinates) => {
|
||||||
let should_float = true;
|
|
||||||
let run_cmd = run_command
|
let run_cmd = run_command
|
||||||
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
|
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
|
||||||
.or_else(|| default_shell.clone());
|
.or_else(|| default_shell.clone());
|
||||||
senders
|
senders
|
||||||
.send_to_pty(PtyInstruction::SpawnTerminal(
|
.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
run_cmd,
|
run_cmd,
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
floating_pane_coordinates,
|
NewPanePlacement::Floating(floating_pane_coordinates),
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::ClientId(client_id),
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
))
|
))
|
||||||
|
|
@ -410,35 +376,46 @@ pub(crate) fn route_action(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Action::NewTiledPane(direction, run_command, name) => {
|
Action::NewStackedPane(run_command, name) => {
|
||||||
let should_float = false;
|
|
||||||
let run_cmd = run_command
|
let run_cmd = run_command
|
||||||
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
|
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
|
||||||
.or_else(|| default_shell.clone());
|
.or_else(|| default_shell.clone());
|
||||||
let pty_instr = match direction {
|
match pane_id {
|
||||||
Some(Direction::Left) => {
|
Some(pane_id) => {
|
||||||
PtyInstruction::SpawnTerminalVertically(run_cmd, name, client_id)
|
senders
|
||||||
},
|
.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(Direction::Right) => {
|
|
||||||
PtyInstruction::SpawnTerminalVertically(run_cmd, name, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Up) => {
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(run_cmd, name, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Down) => {
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(run_cmd, name, client_id)
|
|
||||||
},
|
|
||||||
// No direction specified - try to put it in the biggest available spot
|
|
||||||
None => PtyInstruction::SpawnTerminal(
|
|
||||||
run_cmd,
|
run_cmd,
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
None,
|
NewPanePlacement::Stacked(Some(pane_id)),
|
||||||
|
false,
|
||||||
|
ClientTabIndexOrPaneId::PaneId(pane_id),
|
||||||
|
))
|
||||||
|
.with_context(err_context)?;
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
senders
|
||||||
|
.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
|
run_cmd,
|
||||||
|
name,
|
||||||
|
NewPanePlacement::Stacked(None),
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::ClientId(client_id),
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
),
|
))
|
||||||
};
|
.with_context(err_context)?;
|
||||||
senders.send_to_pty(pty_instr).with_context(err_context)?;
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Action::NewTiledPane(direction, run_command, name) => {
|
||||||
|
let run_cmd = run_command
|
||||||
|
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
|
||||||
|
.or_else(|| default_shell.clone());
|
||||||
|
let _ = senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
|
run_cmd,
|
||||||
|
name,
|
||||||
|
NewPanePlacement::Tiled(direction),
|
||||||
|
false,
|
||||||
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
|
));
|
||||||
},
|
},
|
||||||
Action::TogglePaneEmbedOrFloating => {
|
Action::TogglePaneEmbedOrFloating => {
|
||||||
senders
|
senders
|
||||||
|
|
@ -465,30 +442,13 @@ pub(crate) fn route_action(
|
||||||
},
|
},
|
||||||
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 _ = senders.send_to_pty(PtyInstruction::SpawnTerminal(
|
||||||
Some(Direction::Left) => {
|
|
||||||
PtyInstruction::SpawnTerminalVertically(run_cmd, None, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Right) => {
|
|
||||||
PtyInstruction::SpawnTerminalVertically(run_cmd, None, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Up) => {
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(run_cmd, None, client_id)
|
|
||||||
},
|
|
||||||
Some(Direction::Down) => {
|
|
||||||
PtyInstruction::SpawnTerminalHorizontally(run_cmd, None, client_id)
|
|
||||||
},
|
|
||||||
// No direction specified - try to put it in the biggest available spot
|
|
||||||
None => PtyInstruction::SpawnTerminal(
|
|
||||||
run_cmd,
|
run_cmd,
|
||||||
None,
|
None,
|
||||||
None,
|
NewPanePlacement::Tiled(command.direction),
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
ClientTabIndexOrPaneId::ClientId(client_id),
|
ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
),
|
));
|
||||||
};
|
|
||||||
senders.send_to_pty(pty_instr).with_context(err_context)?;
|
|
||||||
},
|
},
|
||||||
Action::CloseFocus => {
|
Action::CloseFocus => {
|
||||||
senders
|
senders
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ use crate::{
|
||||||
panes::sixel::SixelImageStore,
|
panes::sixel::SixelImageStore,
|
||||||
panes::PaneId,
|
panes::PaneId,
|
||||||
plugins::{PluginId, PluginInstruction, PluginRenderAsset},
|
plugins::{PluginId, PluginInstruction, PluginRenderAsset},
|
||||||
pty::{get_default_shell, ClientTabIndexOrPaneId, PtyInstruction, VteBytes},
|
pty::{get_default_shell, ClientTabIndexOrPaneId, NewPanePlacement, PtyInstruction, VteBytes},
|
||||||
tab::{SuppressedPanes, Tab},
|
tab::{SuppressedPanes, Tab},
|
||||||
thread_bus::Bus,
|
thread_bus::Bus,
|
||||||
ui::{
|
ui::{
|
||||||
|
|
@ -138,7 +138,6 @@ macro_rules! active_tab_and_connected_client_id {
|
||||||
}
|
}
|
||||||
|
|
||||||
type InitialTitle = String;
|
type InitialTitle = String;
|
||||||
type ShouldFloat = bool;
|
|
||||||
type HoldForCommand = Option<RunCommand>;
|
type HoldForCommand = Option<RunCommand>;
|
||||||
|
|
||||||
/// Instructions that can be sent to the [`Screen`].
|
/// Instructions that can be sent to the [`Screen`].
|
||||||
|
|
@ -151,10 +150,9 @@ pub enum ScreenInstruction {
|
||||||
NewPane(
|
NewPane(
|
||||||
PaneId,
|
PaneId,
|
||||||
Option<InitialTitle>,
|
Option<InitialTitle>,
|
||||||
Option<ShouldFloat>,
|
|
||||||
HoldForCommand,
|
HoldForCommand,
|
||||||
Option<Run>, // invoked with
|
Option<Run>, // invoked with
|
||||||
Option<FloatingPaneCoordinates>,
|
NewPanePlacement,
|
||||||
bool, // start suppressed
|
bool, // start suppressed
|
||||||
ClientTabIndexOrPaneId,
|
ClientTabIndexOrPaneId,
|
||||||
),
|
),
|
||||||
|
|
@ -3335,10 +3333,9 @@ pub(crate) fn screen_thread_main(
|
||||||
ScreenInstruction::NewPane(
|
ScreenInstruction::NewPane(
|
||||||
pid,
|
pid,
|
||||||
initial_pane_title,
|
initial_pane_title,
|
||||||
should_float,
|
|
||||||
hold_for_command,
|
hold_for_command,
|
||||||
invoked_with,
|
invoked_with,
|
||||||
floating_pane_coordinates,
|
new_pane_placement,
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
client_or_tab_index,
|
client_or_tab_index,
|
||||||
) => {
|
) => {
|
||||||
|
|
@ -3347,11 +3344,10 @@ pub(crate) fn screen_thread_main(
|
||||||
active_tab_and_connected_client_id!(screen, client_id, |tab: &mut Tab, client_id: ClientId| {
|
active_tab_and_connected_client_id!(screen, client_id, |tab: &mut Tab, client_id: ClientId| {
|
||||||
tab.new_pane(pid,
|
tab.new_pane(pid,
|
||||||
initial_pane_title,
|
initial_pane_title,
|
||||||
should_float,
|
|
||||||
invoked_with,
|
invoked_with,
|
||||||
floating_pane_coordinates,
|
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
true,
|
true,
|
||||||
|
new_pane_placement,
|
||||||
Some(client_id)
|
Some(client_id)
|
||||||
)
|
)
|
||||||
}, ?);
|
}, ?);
|
||||||
|
|
@ -3374,11 +3370,10 @@ pub(crate) fn screen_thread_main(
|
||||||
active_tab.new_pane(
|
active_tab.new_pane(
|
||||||
pid,
|
pid,
|
||||||
initial_pane_title,
|
initial_pane_title,
|
||||||
should_float,
|
|
||||||
invoked_with,
|
invoked_with,
|
||||||
floating_pane_coordinates,
|
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
true,
|
true,
|
||||||
|
new_pane_placement,
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
if let Some(hold_for_command) = hold_for_command {
|
if let Some(hold_for_command) = hold_for_command {
|
||||||
|
|
@ -3397,11 +3392,10 @@ pub(crate) fn screen_thread_main(
|
||||||
tab.new_pane(
|
tab.new_pane(
|
||||||
pid,
|
pid,
|
||||||
initial_pane_title,
|
initial_pane_title,
|
||||||
should_float,
|
|
||||||
invoked_with,
|
invoked_with,
|
||||||
floating_pane_coordinates,
|
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
true,
|
true,
|
||||||
|
new_pane_placement,
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
if let Some(hold_for_command) = hold_for_command {
|
if let Some(hold_for_command) = hold_for_command {
|
||||||
|
|
@ -4659,9 +4653,28 @@ pub(crate) fn screen_thread_main(
|
||||||
should_focus_plugin,
|
should_focus_plugin,
|
||||||
client_id,
|
client_id,
|
||||||
) => {
|
) => {
|
||||||
|
let close_replaced_pane = false; // TODO: support this
|
||||||
|
let mut new_pane_placement = NewPanePlacement::default();
|
||||||
|
let maybe_should_float = should_float;
|
||||||
|
let should_be_tiled = maybe_should_float.map(|f| !f).unwrap_or(false);
|
||||||
|
let should_float = maybe_should_float.unwrap_or(false);
|
||||||
|
if floating_pane_coordinates.is_some() || should_float {
|
||||||
|
new_pane_placement = NewPanePlacement::with_floating_pane_coordinates(
|
||||||
|
floating_pane_coordinates.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if should_be_tiled {
|
||||||
|
new_pane_placement = NewPanePlacement::Tiled(None);
|
||||||
|
}
|
||||||
|
if should_be_in_place {
|
||||||
|
new_pane_placement = NewPanePlacement::with_pane_id_to_replace(
|
||||||
|
pane_id_to_replace,
|
||||||
|
close_replaced_pane,
|
||||||
|
);
|
||||||
|
}
|
||||||
if screen.active_tab_indices.is_empty() && tab_index.is_none() {
|
if screen.active_tab_indices.is_empty() && tab_index.is_none() {
|
||||||
pending_events_waiting_for_client.push(ScreenInstruction::AddPlugin(
|
pending_events_waiting_for_client.push(ScreenInstruction::AddPlugin(
|
||||||
should_float,
|
maybe_should_float,
|
||||||
should_be_in_place,
|
should_be_in_place,
|
||||||
run_plugin_or_alias,
|
run_plugin_or_alias,
|
||||||
pane_title,
|
pane_title,
|
||||||
|
|
@ -4718,11 +4731,10 @@ pub(crate) fn screen_thread_main(
|
||||||
active_tab.new_pane(
|
active_tab.new_pane(
|
||||||
PaneId::Plugin(plugin_id),
|
PaneId::Plugin(plugin_id),
|
||||||
Some(pane_title),
|
Some(pane_title),
|
||||||
should_float,
|
|
||||||
Some(run_plugin),
|
Some(run_plugin),
|
||||||
floating_pane_coordinates,
|
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
should_focus_plugin.unwrap_or(true),
|
should_focus_plugin.unwrap_or(true),
|
||||||
|
new_pane_placement,
|
||||||
Some(client_id),
|
Some(client_id),
|
||||||
)
|
)
|
||||||
}, ?);
|
}, ?);
|
||||||
|
|
@ -4732,11 +4744,10 @@ pub(crate) fn screen_thread_main(
|
||||||
active_tab.new_pane(
|
active_tab.new_pane(
|
||||||
PaneId::Plugin(plugin_id),
|
PaneId::Plugin(plugin_id),
|
||||||
Some(pane_title),
|
Some(pane_title),
|
||||||
should_float,
|
|
||||||
Some(run_plugin),
|
Some(run_plugin),
|
||||||
None,
|
|
||||||
start_suppressed,
|
start_suppressed,
|
||||||
should_focus_plugin.unwrap_or(true),
|
should_focus_plugin.unwrap_or(true),
|
||||||
|
new_pane_placement,
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ use crate::{
|
||||||
panes::{FloatingPanes, TiledPanes},
|
panes::{FloatingPanes, TiledPanes},
|
||||||
panes::{LinkHandler, PaneId, PluginPane, TerminalPane},
|
panes::{LinkHandler, PaneId, PluginPane, TerminalPane},
|
||||||
plugins::PluginInstruction,
|
plugins::PluginInstruction,
|
||||||
pty::{ClientTabIndexOrPaneId, PtyInstruction, VteBytes},
|
pty::{ClientTabIndexOrPaneId, NewPanePlacement, PtyInstruction, VteBytes},
|
||||||
thread_bus::ThreadSenders,
|
thread_bus::ThreadSenders,
|
||||||
ClientId, ServerInstruction,
|
ClientId, ServerInstruction,
|
||||||
};
|
};
|
||||||
|
|
@ -1238,7 +1238,6 @@ impl Tab {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let name = None;
|
let name = None;
|
||||||
let should_float = true;
|
|
||||||
let client_id_or_tab_index = match client_id {
|
let client_id_or_tab_index = match client_id {
|
||||||
Some(client_id) => ClientTabIndexOrPaneId::ClientId(client_id),
|
Some(client_id) => ClientTabIndexOrPaneId::ClientId(client_id),
|
||||||
None => ClientTabIndexOrPaneId::TabIndex(self.index),
|
None => ClientTabIndexOrPaneId::TabIndex(self.index),
|
||||||
|
|
@ -1246,9 +1245,8 @@ impl Tab {
|
||||||
let should_start_suppressed = false;
|
let should_start_suppressed = false;
|
||||||
let instruction = PtyInstruction::SpawnTerminal(
|
let instruction = PtyInstruction::SpawnTerminal(
|
||||||
default_shell,
|
default_shell,
|
||||||
Some(should_float),
|
|
||||||
name,
|
name,
|
||||||
None,
|
NewPanePlacement::Floating(None),
|
||||||
should_start_suppressed,
|
should_start_suppressed,
|
||||||
client_id_or_tab_index,
|
client_id_or_tab_index,
|
||||||
);
|
);
|
||||||
|
|
@ -1266,21 +1264,81 @@ impl Tab {
|
||||||
&mut self,
|
&mut self,
|
||||||
pid: PaneId,
|
pid: PaneId,
|
||||||
initial_pane_title: Option<String>,
|
initial_pane_title: Option<String>,
|
||||||
should_float: Option<bool>,
|
|
||||||
invoked_with: Option<Run>,
|
invoked_with: Option<Run>,
|
||||||
floating_pane_coordinates: Option<FloatingPaneCoordinates>,
|
start_suppressed: bool,
|
||||||
|
should_focus_pane: bool,
|
||||||
|
new_pane_placement: NewPanePlacement,
|
||||||
|
client_id: Option<ClientId>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match new_pane_placement {
|
||||||
|
NewPanePlacement::NoPreference => self.new_no_preference_pane(
|
||||||
|
pid,
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
start_suppressed,
|
||||||
|
should_focus_pane,
|
||||||
|
client_id,
|
||||||
|
),
|
||||||
|
NewPanePlacement::Tiled(None) => self.new_tiled_pane(
|
||||||
|
pid,
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
start_suppressed,
|
||||||
|
should_focus_pane,
|
||||||
|
client_id,
|
||||||
|
),
|
||||||
|
NewPanePlacement::Tiled(Some(direction)) => {
|
||||||
|
if let Some(client_id) = client_id {
|
||||||
|
if direction == Direction::Left || direction == Direction::Right {
|
||||||
|
self.vertical_split(pid, initial_pane_title, client_id)?;
|
||||||
|
} else {
|
||||||
|
self.horizontal_split(pid, initial_pane_title, client_id)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
NewPanePlacement::Floating(floating_pane_coordinates) => self.new_floating_pane(
|
||||||
|
pid,
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
start_suppressed,
|
||||||
|
should_focus_pane,
|
||||||
|
floating_pane_coordinates,
|
||||||
|
),
|
||||||
|
NewPanePlacement::InPlace {
|
||||||
|
pane_id_to_replace,
|
||||||
|
close_replaced_pane,
|
||||||
|
} => self.new_in_place_pane(
|
||||||
|
pid,
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
start_suppressed,
|
||||||
|
should_focus_pane,
|
||||||
|
pane_id_to_replace,
|
||||||
|
close_replaced_pane,
|
||||||
|
client_id,
|
||||||
|
),
|
||||||
|
NewPanePlacement::Stacked(pane_id_to_stack_under) => self.new_stacked_pane(
|
||||||
|
pid,
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
start_suppressed,
|
||||||
|
should_focus_pane,
|
||||||
|
pane_id_to_stack_under,
|
||||||
|
client_id,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_no_preference_pane(
|
||||||
|
&mut self,
|
||||||
|
pid: PaneId,
|
||||||
|
initial_pane_title: Option<String>,
|
||||||
|
invoked_with: Option<Run>,
|
||||||
start_suppressed: bool,
|
start_suppressed: bool,
|
||||||
should_focus_pane: bool,
|
should_focus_pane: bool,
|
||||||
client_id: Option<ClientId>,
|
client_id: Option<ClientId>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let err_context = || format!("failed to create new pane with id {pid:?}");
|
let err_context = || format!("failed to create new pane with id {pid:?}");
|
||||||
if should_focus_pane {
|
|
||||||
match should_float {
|
|
||||||
Some(true) => self.show_floating_panes(),
|
|
||||||
Some(false) => self.hide_floating_panes(),
|
|
||||||
None => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
self.close_down_to_max_terminals()
|
self.close_down_to_max_terminals()
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let mut new_pane = match pid {
|
let mut new_pane = match pid {
|
||||||
|
|
@ -1357,23 +1415,340 @@ impl Tab {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if should_focus_pane {
|
} else if should_focus_pane {
|
||||||
if self.floating_panes.panes_are_visible() {
|
if self.floating_panes.panes_are_visible() {
|
||||||
self.add_floating_pane(new_pane, pid, floating_pane_coordinates, true)
|
self.add_floating_pane(new_pane, pid, None, true)
|
||||||
} else {
|
} else {
|
||||||
self.add_tiled_pane(new_pane, pid, client_id)
|
self.add_tiled_pane(new_pane, pid, client_id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match should_float {
|
|
||||||
Some(true) => {
|
|
||||||
self.add_floating_pane(new_pane, pid, floating_pane_coordinates, false)
|
|
||||||
},
|
|
||||||
Some(false) => self.add_tiled_pane(new_pane, pid, client_id),
|
|
||||||
None => {
|
|
||||||
if self.floating_panes.panes_are_visible() {
|
if self.floating_panes.panes_are_visible() {
|
||||||
self.add_floating_pane(new_pane, pid, floating_pane_coordinates, false)
|
self.add_floating_pane(new_pane, pid, None, false)
|
||||||
} else {
|
} else {
|
||||||
self.add_tiled_pane(new_pane, pid, client_id)
|
self.add_tiled_pane(new_pane, pid, client_id)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_tiled_pane(
|
||||||
|
&mut self,
|
||||||
|
pid: PaneId,
|
||||||
|
initial_pane_title: Option<String>,
|
||||||
|
invoked_with: Option<Run>,
|
||||||
|
start_suppressed: bool,
|
||||||
|
should_focus_pane: bool,
|
||||||
|
client_id: Option<ClientId>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let err_context = || format!("failed to create new pane with id {pid:?}");
|
||||||
|
if should_focus_pane {
|
||||||
|
self.hide_floating_panes();
|
||||||
|
}
|
||||||
|
self.close_down_to_max_terminals()
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let mut new_pane = match pid {
|
||||||
|
PaneId::Terminal(term_pid) => {
|
||||||
|
let next_terminal_position = self.get_next_terminal_position();
|
||||||
|
Box::new(TerminalPane::new(
|
||||||
|
term_pid,
|
||||||
|
PaneGeom::default(), // this will be filled out later
|
||||||
|
self.style,
|
||||||
|
next_terminal_position,
|
||||||
|
String::new(),
|
||||||
|
self.link_handler.clone(),
|
||||||
|
self.character_cell_size.clone(),
|
||||||
|
self.sixel_image_store.clone(),
|
||||||
|
self.terminal_emulator_colors.clone(),
|
||||||
|
self.terminal_emulator_color_codes.clone(),
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
self.debug,
|
||||||
|
self.arrow_fonts,
|
||||||
|
self.styled_underlines,
|
||||||
|
self.explicitly_disable_kitty_keyboard_protocol,
|
||||||
|
)) as Box<dyn Pane>
|
||||||
},
|
},
|
||||||
|
PaneId::Plugin(plugin_pid) => {
|
||||||
|
Box::new(PluginPane::new(
|
||||||
|
plugin_pid,
|
||||||
|
PaneGeom::default(), // this will be filled out later
|
||||||
|
self.senders
|
||||||
|
.to_plugin
|
||||||
|
.as_ref()
|
||||||
|
.with_context(err_context)?
|
||||||
|
.clone(),
|
||||||
|
initial_pane_title.unwrap_or("".to_owned()),
|
||||||
|
String::new(),
|
||||||
|
self.sixel_image_store.clone(),
|
||||||
|
self.terminal_emulator_colors.clone(),
|
||||||
|
self.terminal_emulator_color_codes.clone(),
|
||||||
|
self.link_handler.clone(),
|
||||||
|
self.character_cell_size.clone(),
|
||||||
|
self.connected_clients.borrow().iter().copied().collect(),
|
||||||
|
self.style,
|
||||||
|
invoked_with,
|
||||||
|
self.debug,
|
||||||
|
self.arrow_fonts,
|
||||||
|
self.styled_underlines,
|
||||||
|
)) as Box<dyn Pane>
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if start_suppressed {
|
||||||
|
// this pane needs to start in the background (suppressed), only accessible if a plugin takes it out
|
||||||
|
// of there in one way or another
|
||||||
|
// we need to do some bookkeeping for this pane, namely setting its geom and
|
||||||
|
// content_offset so that things will appear properly in the terminal - we set it to
|
||||||
|
// the default geom of the first floating pane - this is just in order to give it some
|
||||||
|
// reasonable size, when it is shown - if needed - it will be given the proper geom as if it were
|
||||||
|
// resized
|
||||||
|
let viewport = { self.viewport.borrow().clone() };
|
||||||
|
let new_pane_geom = half_size_middle_geom(&viewport, 0);
|
||||||
|
new_pane.set_active_at(Instant::now());
|
||||||
|
new_pane.set_geom(new_pane_geom);
|
||||||
|
new_pane.set_content_offset(Offset::frame(1));
|
||||||
|
resize_pty!(
|
||||||
|
new_pane,
|
||||||
|
self.os_api,
|
||||||
|
self.senders,
|
||||||
|
self.character_cell_size
|
||||||
|
)
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let is_scrollback_editor = false;
|
||||||
|
self.suppressed_panes
|
||||||
|
.insert(pid, (is_scrollback_editor, new_pane));
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.add_tiled_pane(new_pane, pid, client_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_floating_pane(
|
||||||
|
&mut self,
|
||||||
|
pid: PaneId,
|
||||||
|
initial_pane_title: Option<String>,
|
||||||
|
invoked_with: Option<Run>,
|
||||||
|
start_suppressed: bool,
|
||||||
|
should_focus_pane: bool,
|
||||||
|
floating_pane_coordinates: Option<FloatingPaneCoordinates>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let err_context = || format!("failed to create new pane with id {pid:?}");
|
||||||
|
if should_focus_pane {
|
||||||
|
self.show_floating_panes();
|
||||||
|
}
|
||||||
|
self.close_down_to_max_terminals()
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let mut new_pane = match pid {
|
||||||
|
PaneId::Terminal(term_pid) => {
|
||||||
|
let next_terminal_position = self.get_next_terminal_position();
|
||||||
|
Box::new(TerminalPane::new(
|
||||||
|
term_pid,
|
||||||
|
PaneGeom::default(), // this will be filled out later
|
||||||
|
self.style,
|
||||||
|
next_terminal_position,
|
||||||
|
String::new(),
|
||||||
|
self.link_handler.clone(),
|
||||||
|
self.character_cell_size.clone(),
|
||||||
|
self.sixel_image_store.clone(),
|
||||||
|
self.terminal_emulator_colors.clone(),
|
||||||
|
self.terminal_emulator_color_codes.clone(),
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
self.debug,
|
||||||
|
self.arrow_fonts,
|
||||||
|
self.styled_underlines,
|
||||||
|
self.explicitly_disable_kitty_keyboard_protocol,
|
||||||
|
)) as Box<dyn Pane>
|
||||||
|
},
|
||||||
|
PaneId::Plugin(plugin_pid) => {
|
||||||
|
Box::new(PluginPane::new(
|
||||||
|
plugin_pid,
|
||||||
|
PaneGeom::default(), // this will be filled out later
|
||||||
|
self.senders
|
||||||
|
.to_plugin
|
||||||
|
.as_ref()
|
||||||
|
.with_context(err_context)?
|
||||||
|
.clone(),
|
||||||
|
initial_pane_title.unwrap_or("".to_owned()),
|
||||||
|
String::new(),
|
||||||
|
self.sixel_image_store.clone(),
|
||||||
|
self.terminal_emulator_colors.clone(),
|
||||||
|
self.terminal_emulator_color_codes.clone(),
|
||||||
|
self.link_handler.clone(),
|
||||||
|
self.character_cell_size.clone(),
|
||||||
|
self.connected_clients.borrow().iter().copied().collect(),
|
||||||
|
self.style,
|
||||||
|
invoked_with,
|
||||||
|
self.debug,
|
||||||
|
self.arrow_fonts,
|
||||||
|
self.styled_underlines,
|
||||||
|
)) as Box<dyn Pane>
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if start_suppressed {
|
||||||
|
// this pane needs to start in the background (suppressed), only accessible if a plugin takes it out
|
||||||
|
// of there in one way or another
|
||||||
|
// we need to do some bookkeeping for this pane, namely setting its geom and
|
||||||
|
// content_offset so that things will appear properly in the terminal - we set it to
|
||||||
|
// the default geom of the first floating pane - this is just in order to give it some
|
||||||
|
// reasonable size, when it is shown - if needed - it will be given the proper geom as if it were
|
||||||
|
// resized
|
||||||
|
let viewport = { self.viewport.borrow().clone() };
|
||||||
|
let new_pane_geom = half_size_middle_geom(&viewport, 0);
|
||||||
|
new_pane.set_active_at(Instant::now());
|
||||||
|
new_pane.set_geom(new_pane_geom);
|
||||||
|
new_pane.set_content_offset(Offset::frame(1));
|
||||||
|
resize_pty!(
|
||||||
|
new_pane,
|
||||||
|
self.os_api,
|
||||||
|
self.senders,
|
||||||
|
self.character_cell_size
|
||||||
|
)
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let is_scrollback_editor = false;
|
||||||
|
self.suppressed_panes
|
||||||
|
.insert(pid, (is_scrollback_editor, new_pane));
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.add_floating_pane(new_pane, pid, floating_pane_coordinates, should_focus_pane)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_in_place_pane(
|
||||||
|
&mut self,
|
||||||
|
pid: PaneId,
|
||||||
|
initial_pane_title: Option<String>,
|
||||||
|
invoked_with: Option<Run>,
|
||||||
|
start_suppressed: bool,
|
||||||
|
should_focus_pane: bool,
|
||||||
|
pane_id_to_replace: Option<PaneId>,
|
||||||
|
close_replaced_pane: bool,
|
||||||
|
client_id: Option<ClientId>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match (pane_id_to_replace, client_id) {
|
||||||
|
(Some(pane_id_to_replace), _) => {
|
||||||
|
self.suppress_pane_and_replace_with_pid(
|
||||||
|
pane_id_to_replace,
|
||||||
|
pid,
|
||||||
|
close_replaced_pane,
|
||||||
|
invoked_with,
|
||||||
|
)?;
|
||||||
|
},
|
||||||
|
(None, Some(client_id)) => match self.get_active_pane_id(client_id) {
|
||||||
|
Some(active_pane_id) => {
|
||||||
|
self.suppress_pane_and_replace_with_pid(
|
||||||
|
active_pane_id,
|
||||||
|
pid,
|
||||||
|
close_replaced_pane,
|
||||||
|
invoked_with,
|
||||||
|
)?;
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
log::error!("Cannot find active pane");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
log::error!("Must have pane id to replace or client id to start pane in place>");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if let Some(initial_pane_title) = initial_pane_title {
|
||||||
|
let _ = self.rename_pane(initial_pane_title.as_bytes().to_vec(), pid);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn new_stacked_pane(
|
||||||
|
&mut self,
|
||||||
|
pid: PaneId,
|
||||||
|
initial_pane_title: Option<String>,
|
||||||
|
invoked_with: Option<Run>,
|
||||||
|
start_suppressed: bool,
|
||||||
|
should_focus_pane: bool,
|
||||||
|
pane_id_to_stack_under: Option<PaneId>,
|
||||||
|
client_id: Option<ClientId>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let err_context = || format!("failed to create new pane with id {pid:?}");
|
||||||
|
if should_focus_pane {
|
||||||
|
self.hide_floating_panes();
|
||||||
|
}
|
||||||
|
self.close_down_to_max_terminals()
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let mut new_pane = match pid {
|
||||||
|
PaneId::Terminal(term_pid) => {
|
||||||
|
let next_terminal_position = self.get_next_terminal_position();
|
||||||
|
Box::new(TerminalPane::new(
|
||||||
|
term_pid,
|
||||||
|
PaneGeom::default(), // this will be filled out later
|
||||||
|
self.style,
|
||||||
|
next_terminal_position,
|
||||||
|
String::new(),
|
||||||
|
self.link_handler.clone(),
|
||||||
|
self.character_cell_size.clone(),
|
||||||
|
self.sixel_image_store.clone(),
|
||||||
|
self.terminal_emulator_colors.clone(),
|
||||||
|
self.terminal_emulator_color_codes.clone(),
|
||||||
|
initial_pane_title,
|
||||||
|
invoked_with,
|
||||||
|
self.debug,
|
||||||
|
self.arrow_fonts,
|
||||||
|
self.styled_underlines,
|
||||||
|
self.explicitly_disable_kitty_keyboard_protocol,
|
||||||
|
)) as Box<dyn Pane>
|
||||||
|
},
|
||||||
|
PaneId::Plugin(plugin_pid) => {
|
||||||
|
Box::new(PluginPane::new(
|
||||||
|
plugin_pid,
|
||||||
|
PaneGeom::default(), // this will be filled out later
|
||||||
|
self.senders
|
||||||
|
.to_plugin
|
||||||
|
.as_ref()
|
||||||
|
.with_context(err_context)?
|
||||||
|
.clone(),
|
||||||
|
initial_pane_title.unwrap_or("".to_owned()),
|
||||||
|
String::new(),
|
||||||
|
self.sixel_image_store.clone(),
|
||||||
|
self.terminal_emulator_colors.clone(),
|
||||||
|
self.terminal_emulator_color_codes.clone(),
|
||||||
|
self.link_handler.clone(),
|
||||||
|
self.character_cell_size.clone(),
|
||||||
|
self.connected_clients.borrow().iter().copied().collect(),
|
||||||
|
self.style,
|
||||||
|
invoked_with,
|
||||||
|
self.debug,
|
||||||
|
self.arrow_fonts,
|
||||||
|
self.styled_underlines,
|
||||||
|
)) as Box<dyn Pane>
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if start_suppressed {
|
||||||
|
// this pane needs to start in the background (suppressed), only accessible if a plugin takes it out
|
||||||
|
// of there in one way or another
|
||||||
|
// we need to do some bookkeeping for this pane, namely setting its geom and
|
||||||
|
// content_offset so that things will appear properly in the terminal - we set it to
|
||||||
|
// the default geom of the first floating pane - this is just in order to give it some
|
||||||
|
// reasonable size, when it is shown - if needed - it will be given the proper geom as if it were
|
||||||
|
// resized
|
||||||
|
let viewport = { self.viewport.borrow().clone() };
|
||||||
|
let new_pane_geom = half_size_middle_geom(&viewport, 0);
|
||||||
|
new_pane.set_active_at(Instant::now());
|
||||||
|
new_pane.set_geom(new_pane_geom);
|
||||||
|
new_pane.set_content_offset(Offset::frame(1));
|
||||||
|
resize_pty!(
|
||||||
|
new_pane,
|
||||||
|
self.os_api,
|
||||||
|
self.senders,
|
||||||
|
self.character_cell_size
|
||||||
|
)
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let is_scrollback_editor = false;
|
||||||
|
self.suppressed_panes
|
||||||
|
.insert(pid, (is_scrollback_editor, new_pane));
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
if let Some(pane_id_to_stack_under) = pane_id_to_stack_under {
|
||||||
|
// TODO: also focus pane if should_focus_pane? in cases where we did this from the CLI in an unfocused
|
||||||
|
// pane...
|
||||||
|
self.add_stacked_pane_to_pane_id(new_pane, pid, pane_id_to_stack_under)
|
||||||
|
} else if let Some(client_id) = client_id {
|
||||||
|
self.add_stacked_pane_to_active_pane(new_pane, pid, client_id)
|
||||||
|
} else {
|
||||||
|
log::error!("Must have client id or pane id to stack pane");
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4653,6 +5028,38 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
pub fn add_stacked_pane_to_pane_id(
|
||||||
|
&mut self,
|
||||||
|
pane: Box<dyn Pane>,
|
||||||
|
pane_id: PaneId,
|
||||||
|
root_pane_id: PaneId,
|
||||||
|
) -> Result<()> {
|
||||||
|
if self.tiled_panes.fullscreen_is_active() {
|
||||||
|
self.tiled_panes.unset_fullscreen();
|
||||||
|
}
|
||||||
|
self.tiled_panes
|
||||||
|
.add_pane_to_stack_of_pane_id(pane_id, pane, root_pane_id);
|
||||||
|
self.set_should_clear_display_before_rendering();
|
||||||
|
self.tiled_panes.expand_pane_in_stack(pane_id); // so that it will get focused by all
|
||||||
|
// clients
|
||||||
|
self.swap_layouts.set_is_tiled_damaged();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn add_stacked_pane_to_active_pane(
|
||||||
|
&mut self,
|
||||||
|
pane: Box<dyn Pane>,
|
||||||
|
pane_id: PaneId,
|
||||||
|
client_id: ClientId,
|
||||||
|
) -> Result<()> {
|
||||||
|
if self.tiled_panes.fullscreen_is_active() {
|
||||||
|
self.tiled_panes.unset_fullscreen();
|
||||||
|
}
|
||||||
|
self.tiled_panes
|
||||||
|
.add_pane_to_stack_of_active_pane(pane_id, pane, client_id);
|
||||||
|
self.tiled_panes.focus_pane(pane_id, client_id);
|
||||||
|
self.swap_layouts.set_is_tiled_damaged();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
pub fn request_plugin_permissions(&mut self, pid: u32, permissions: Option<PluginPermission>) {
|
pub fn request_plugin_permissions(&mut self, pid: u32, permissions: Option<PluginPermission>) {
|
||||||
let mut should_focus_pane = false;
|
let mut should_focus_pane = false;
|
||||||
if let Some(plugin_pane) = self
|
if let Some(plugin_pane) = self
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
01 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
02 (C): │ │
|
||||||
|
03 (C): │ │
|
||||||
|
04 (C): │ │
|
||||||
|
05 (C): │ │
|
||||||
|
06 (C): │ │
|
||||||
|
07 (C): │ │
|
||||||
|
08 (C): │ │
|
||||||
|
09 (C): │ │
|
||||||
|
10 (C): │ │
|
||||||
|
11 (C): │ │
|
||||||
|
12 (C): │ │
|
||||||
|
13 (C): │ │
|
||||||
|
14 (C): │ │
|
||||||
|
15 (C): │ │
|
||||||
|
16 (C): │ │
|
||||||
|
17 (C): │ │
|
||||||
|
18 (C): │ │
|
||||||
|
19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,7 @@
|
||||||
use super::Tab;
|
use super::Tab;
|
||||||
use crate::pane_groups::PaneGroups;
|
use crate::pane_groups::PaneGroups;
|
||||||
use crate::panes::sixel::SixelImageStore;
|
use crate::panes::sixel::SixelImageStore;
|
||||||
|
use crate::pty::NewPanePlacement;
|
||||||
use crate::screen::CopyOptions;
|
use crate::screen::CopyOptions;
|
||||||
use crate::{
|
use crate::{
|
||||||
os_input_output::{AsyncReader, Pid, ServerOsApi},
|
os_input_output::{AsyncReader, Pid, ServerOsApi},
|
||||||
|
|
@ -625,7 +626,15 @@ fn split_largest_pane() {
|
||||||
let mut tab = create_new_tab(size, stacked_resize);
|
let mut tab = create_new_tab(size, stacked_resize);
|
||||||
for i in 2..5 {
|
for i in 2..5 {
|
||||||
let new_pane_id = PaneId::Terminal(i);
|
let new_pane_id = PaneId::Terminal(i);
|
||||||
tab.new_pane(new_pane_id, None, None, None, None, false, true, Some(1))
|
tab.new_pane(
|
||||||
|
new_pane_id,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
|
Some(1),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(tab.tiled_panes.panes.len(), 4, "The tab has four panes");
|
assert_eq!(tab.tiled_panes.panes.len(), 4, "The tab has four panes");
|
||||||
|
|
@ -838,10 +847,9 @@ pub fn cannot_split_largest_pane_when_there_is_no_room() {
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -888,7 +896,15 @@ pub fn toggle_focused_pane_fullscreen() {
|
||||||
let mut tab = create_new_tab(size, stacked_resize);
|
let mut tab = create_new_tab(size, stacked_resize);
|
||||||
for i in 2..5 {
|
for i in 2..5 {
|
||||||
let new_pane_id = PaneId::Terminal(i);
|
let new_pane_id = PaneId::Terminal(i);
|
||||||
tab.new_pane(new_pane_id, None, None, None, None, false, true, Some(1))
|
tab.new_pane(
|
||||||
|
new_pane_id,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
|
Some(1),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
tab.toggle_active_pane_fullscreen(1);
|
tab.toggle_active_pane_fullscreen(1);
|
||||||
|
|
@ -964,7 +980,15 @@ pub fn toggle_focused_pane_fullscreen_with_stacked_resizes() {
|
||||||
let mut tab = create_new_tab(size, stacked_resize);
|
let mut tab = create_new_tab(size, stacked_resize);
|
||||||
for i in 2..5 {
|
for i in 2..5 {
|
||||||
let new_pane_id = PaneId::Terminal(i);
|
let new_pane_id = PaneId::Terminal(i);
|
||||||
tab.new_pane(new_pane_id, None, None, None, None, false, true, Some(1))
|
tab.new_pane(
|
||||||
|
new_pane_id,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
|
Some(1),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
tab.toggle_active_pane_fullscreen(1);
|
tab.toggle_active_pane_fullscreen(1);
|
||||||
|
|
@ -1044,10 +1068,9 @@ fn switch_to_next_pane_fullscreen() {
|
||||||
PaneId::Terminal(1),
|
PaneId::Terminal(1),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1056,10 +1079,9 @@ fn switch_to_next_pane_fullscreen() {
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1068,10 +1090,9 @@ fn switch_to_next_pane_fullscreen() {
|
||||||
PaneId::Terminal(3),
|
PaneId::Terminal(3),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1080,10 +1101,9 @@ fn switch_to_next_pane_fullscreen() {
|
||||||
PaneId::Terminal(4),
|
PaneId::Terminal(4),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1121,10 +1141,9 @@ fn switch_to_prev_pane_fullscreen() {
|
||||||
PaneId::Terminal(1),
|
PaneId::Terminal(1),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1133,10 +1152,9 @@ fn switch_to_prev_pane_fullscreen() {
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1145,10 +1163,9 @@ fn switch_to_prev_pane_fullscreen() {
|
||||||
PaneId::Terminal(3),
|
PaneId::Terminal(3),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1157,10 +1174,9 @@ fn switch_to_prev_pane_fullscreen() {
|
||||||
PaneId::Terminal(4),
|
PaneId::Terminal(4),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -14758,10 +14774,9 @@ fn correctly_resize_frameless_panes_on_pane_close() {
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
plugins::PluginInstruction,
|
plugins::PluginInstruction,
|
||||||
pty::{ClientTabIndexOrPaneId, PtyInstruction},
|
pty::{ClientTabIndexOrPaneId, NewPanePlacement, PtyInstruction},
|
||||||
};
|
};
|
||||||
use zellij_utils::ipc::PixelDimensions;
|
use zellij_utils::ipc::PixelDimensions;
|
||||||
|
|
||||||
|
|
@ -1235,10 +1235,9 @@ fn switch_to_tab_with_fullscreen() {
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1359,10 +1358,9 @@ fn attach_after_first_tab_closed() {
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::default(),
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1385,22 +1383,20 @@ fn open_new_floating_pane_with_custom_coordinates() {
|
||||||
|
|
||||||
new_tab(&mut screen, 1, 0);
|
new_tab(&mut screen, 1, 0);
|
||||||
let active_tab = screen.get_active_tab_mut(1).unwrap();
|
let active_tab = screen.get_active_tab_mut(1).unwrap();
|
||||||
let should_float = Some(true);
|
|
||||||
active_tab
|
active_tab
|
||||||
.new_pane(
|
.new_pane(
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
should_float,
|
|
||||||
None,
|
None,
|
||||||
Some(FloatingPaneCoordinates {
|
false,
|
||||||
|
true,
|
||||||
|
NewPanePlacement::Floating(Some(FloatingPaneCoordinates {
|
||||||
x: Some(SplitSize::Percent(10)),
|
x: Some(SplitSize::Percent(10)),
|
||||||
y: Some(SplitSize::Fixed(5)),
|
y: Some(SplitSize::Fixed(5)),
|
||||||
width: Some(SplitSize::Percent(1)),
|
width: Some(SplitSize::Percent(1)),
|
||||||
height: Some(SplitSize::Fixed(2)),
|
height: Some(SplitSize::Fixed(2)),
|
||||||
pinned: None,
|
pinned: None,
|
||||||
}),
|
})),
|
||||||
false,
|
|
||||||
true,
|
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1421,22 +1417,20 @@ fn open_new_floating_pane_with_custom_coordinates_exceeding_viewport() {
|
||||||
|
|
||||||
new_tab(&mut screen, 1, 0);
|
new_tab(&mut screen, 1, 0);
|
||||||
let active_tab = screen.get_active_tab_mut(1).unwrap();
|
let active_tab = screen.get_active_tab_mut(1).unwrap();
|
||||||
let should_float = Some(true);
|
|
||||||
active_tab
|
active_tab
|
||||||
.new_pane(
|
.new_pane(
|
||||||
PaneId::Terminal(2),
|
PaneId::Terminal(2),
|
||||||
None,
|
None,
|
||||||
should_float,
|
|
||||||
None,
|
None,
|
||||||
Some(FloatingPaneCoordinates {
|
false,
|
||||||
|
true,
|
||||||
|
NewPanePlacement::Floating(Some(FloatingPaneCoordinates {
|
||||||
x: Some(SplitSize::Fixed(122)),
|
x: Some(SplitSize::Fixed(122)),
|
||||||
y: Some(SplitSize::Fixed(21)),
|
y: Some(SplitSize::Fixed(21)),
|
||||||
width: Some(SplitSize::Fixed(10)),
|
width: Some(SplitSize::Fixed(10)),
|
||||||
height: Some(SplitSize::Fixed(10)),
|
height: Some(SplitSize::Fixed(10)),
|
||||||
pinned: None,
|
pinned: None,
|
||||||
}),
|
})),
|
||||||
false,
|
|
||||||
true,
|
|
||||||
Some(1),
|
Some(1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1611,17 +1605,15 @@ fn group_panes_following_focus() {
|
||||||
|
|
||||||
{
|
{
|
||||||
let active_tab = screen.get_active_tab_mut(client_id).unwrap();
|
let active_tab = screen.get_active_tab_mut(client_id).unwrap();
|
||||||
let should_float = Some(false);
|
|
||||||
for i in 2..5 {
|
for i in 2..5 {
|
||||||
active_tab
|
active_tab
|
||||||
.new_pane(
|
.new_pane(
|
||||||
PaneId::Terminal(i),
|
PaneId::Terminal(i),
|
||||||
None,
|
None,
|
||||||
should_float,
|
|
||||||
None,
|
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::Tiled(None),
|
||||||
Some(client_id),
|
Some(client_id),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1670,17 +1662,15 @@ fn break_group_with_mouse() {
|
||||||
|
|
||||||
{
|
{
|
||||||
let active_tab = screen.get_active_tab_mut(client_id).unwrap();
|
let active_tab = screen.get_active_tab_mut(client_id).unwrap();
|
||||||
let should_float = Some(false);
|
|
||||||
for i in 2..5 {
|
for i in 2..5 {
|
||||||
active_tab
|
active_tab
|
||||||
.new_pane(
|
.new_pane(
|
||||||
PaneId::Terminal(i),
|
PaneId::Terminal(i),
|
||||||
None,
|
None,
|
||||||
should_float,
|
|
||||||
None,
|
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
NewPanePlacement::Tiled(None),
|
||||||
Some(client_id),
|
Some(client_id),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -2596,6 +2586,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() {
|
||||||
width: None,
|
width: None,
|
||||||
height: None,
|
height: None,
|
||||||
pinned: None,
|
pinned: None,
|
||||||
|
stacked: false,
|
||||||
};
|
};
|
||||||
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
||||||
|
|
@ -2640,6 +2631,7 @@ pub fn send_cli_new_pane_action_with_split_direction() {
|
||||||
width: None,
|
width: None,
|
||||||
height: None,
|
height: None,
|
||||||
pinned: None,
|
pinned: None,
|
||||||
|
stacked: false,
|
||||||
};
|
};
|
||||||
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
||||||
|
|
@ -2684,6 +2676,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() {
|
||||||
width: None,
|
width: None,
|
||||||
height: None,
|
height: None,
|
||||||
pinned: None,
|
pinned: None,
|
||||||
|
stacked: false,
|
||||||
};
|
};
|
||||||
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
||||||
|
|
@ -2694,7 +2687,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|instruction| match instruction {
|
.find(|instruction| match instruction {
|
||||||
PtyInstruction::SpawnTerminalVertically(..) => true,
|
PtyInstruction::SpawnTerminal(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
@ -2739,6 +2732,7 @@ pub fn send_cli_new_pane_action_with_floating_pane_and_coordinates() {
|
||||||
width: Some("20%".to_owned()),
|
width: Some("20%".to_owned()),
|
||||||
height: None,
|
height: None,
|
||||||
pinned: None,
|
pinned: None,
|
||||||
|
stacked: false,
|
||||||
};
|
};
|
||||||
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
||||||
---
|
---
|
||||||
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some(false), Some("Editing: /file/to/edit"), None, false, ClientId(10)), Exit]
|
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled(None), false, ClientId(10)), Exit]
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
||||||
---
|
---
|
||||||
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: Some(100), cwd: Some("."), originating_plugin: None })), Some(false), Some("Editing: /file/to/edit"), None, false, ClientId(10)), Exit]
|
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: Some(100), cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled(None), false, ClientId(10)), Exit]
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
||||||
---
|
---
|
||||||
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminalHorizontally(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), 10), Exit]
|
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled(Some(Down)), false, ClientId(10)), Exit]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
assertion_line: 2339
|
|
||||||
expression: "format!(\"{:?}\", new_pane_instruction)"
|
expression: "format!(\"{:?}\", new_pane_instruction)"
|
||||||
---
|
---
|
||||||
Some(SpawnTerminalVertically(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), None, 10))
|
Some(SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), None, Tiled(Some(Right)), false, ClientId(10)))
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
||||||
---
|
---
|
||||||
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, Some(false), None, None, false, ClientId(10)), Exit]
|
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, None, Tiled(None), false, ClientId(10)), Exit]
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
||||||
---
|
---
|
||||||
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), Some(true), None, Some(FloatingPaneCoordinates { x: Some(Fixed(10)), y: None, width: Some(Percent(20)), height: None, pinned: None }), false, ClientId(10)), Exit]
|
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), None, Floating(Some(FloatingPaneCoordinates { x: Some(Fixed(10)), y: None, width: Some(Percent(20)), height: None, pinned: None })), false, ClientId(10)), Exit]
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: zellij-server/src/./unit/screen_tests.rs
|
source: zellij-server/src/./unit/screen_tests.rs
|
||||||
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
|
||||||
---
|
---
|
||||||
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminalVertically(None, None, 10), Exit]
|
[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, None, Tiled(Some(Right)), false, ClientId(10)), Exit]
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ keybinds {
|
||||||
bind "n" { NewPane; SwitchToMode "Normal"; }
|
bind "n" { NewPane; SwitchToMode "Normal"; }
|
||||||
bind "d" { NewPane "Down"; SwitchToMode "Normal"; }
|
bind "d" { NewPane "Down"; SwitchToMode "Normal"; }
|
||||||
bind "r" { NewPane "Right"; SwitchToMode "Normal"; }
|
bind "r" { NewPane "Right"; SwitchToMode "Normal"; }
|
||||||
|
bind "s" { NewPane "stacked"; SwitchToMode "Normal"; }
|
||||||
bind "x" { CloseFocus; SwitchToMode "Normal"; }
|
bind "x" { CloseFocus; SwitchToMode "Normal"; }
|
||||||
bind "f" { ToggleFocusFullscreen; SwitchToMode "Normal"; }
|
bind "f" { ToggleFocusFullscreen; SwitchToMode "Normal"; }
|
||||||
bind "z" { TogglePaneFrames; SwitchToMode "Normal"; }
|
bind "z" { TogglePaneFrames; SwitchToMode "Normal"; }
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,7 @@ pub enum ActionName {
|
||||||
MouseEvent = 86,
|
MouseEvent = 86,
|
||||||
TogglePaneInGroup = 87,
|
TogglePaneInGroup = 87,
|
||||||
ToggleGroupMarking = 88,
|
ToggleGroupMarking = 88,
|
||||||
|
NewStackedPane = 89,
|
||||||
}
|
}
|
||||||
impl ActionName {
|
impl ActionName {
|
||||||
/// String value of the enum field names used in the ProtoBuf definition.
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
|
|
@ -569,6 +570,7 @@ impl ActionName {
|
||||||
ActionName::MouseEvent => "MouseEvent",
|
ActionName::MouseEvent => "MouseEvent",
|
||||||
ActionName::TogglePaneInGroup => "TogglePaneInGroup",
|
ActionName::TogglePaneInGroup => "TogglePaneInGroup",
|
||||||
ActionName::ToggleGroupMarking => "ToggleGroupMarking",
|
ActionName::ToggleGroupMarking => "ToggleGroupMarking",
|
||||||
|
ActionName::NewStackedPane => "NewStackedPane",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
|
|
@ -660,6 +662,7 @@ impl ActionName {
|
||||||
"MouseEvent" => Some(Self::MouseEvent),
|
"MouseEvent" => Some(Self::MouseEvent),
|
||||||
"TogglePaneInGroup" => Some(Self::TogglePaneInGroup),
|
"TogglePaneInGroup" => Some(Self::TogglePaneInGroup),
|
||||||
"ToggleGroupMarking" => Some(Self::ToggleGroupMarking),
|
"ToggleGroupMarking" => Some(Self::ToggleGroupMarking),
|
||||||
|
"NewStackedPane" => Some(Self::NewStackedPane),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,15 @@ pub enum Sessions {
|
||||||
/// Whether to pin a floating pane so that it is always on top
|
/// Whether to pin a floating pane so that it is always on top
|
||||||
#[clap(long, requires("floating"))]
|
#[clap(long, requires("floating"))]
|
||||||
pinned: Option<bool>,
|
pinned: Option<bool>,
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
conflicts_with("floating"),
|
||||||
|
conflicts_with("direction"),
|
||||||
|
value_parser,
|
||||||
|
default_value("false"),
|
||||||
|
takes_value(false)
|
||||||
|
)]
|
||||||
|
stacked: bool,
|
||||||
},
|
},
|
||||||
/// Load a plugin
|
/// Load a plugin
|
||||||
#[clap(visible_alias = "p")]
|
#[clap(visible_alias = "p")]
|
||||||
|
|
@ -602,6 +611,15 @@ pub enum CliAction {
|
||||||
/// Whether to pin a floating pane so that it is always on top
|
/// Whether to pin a floating pane so that it is always on top
|
||||||
#[clap(long, requires("floating"))]
|
#[clap(long, requires("floating"))]
|
||||||
pinned: Option<bool>,
|
pinned: Option<bool>,
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
conflicts_with("floating"),
|
||||||
|
conflicts_with("direction"),
|
||||||
|
value_parser,
|
||||||
|
default_value("false"),
|
||||||
|
takes_value(false)
|
||||||
|
)]
|
||||||
|
stacked: bool,
|
||||||
},
|
},
|
||||||
/// Open the specified file in a new zellij pane with your default EDITOR
|
/// Open the specified file in a new zellij pane with your default EDITOR
|
||||||
Edit {
|
Edit {
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,8 @@ pub enum Action {
|
||||||
/// Open a new pane in place of the focused one, suppressing it instead
|
/// Open a new pane in place of the focused one, suppressing it instead
|
||||||
NewInPlacePane(Option<RunCommandAction>, Option<String>), // String is an
|
NewInPlacePane(Option<RunCommandAction>, Option<String>), // String is an
|
||||||
// optional pane
|
// optional pane
|
||||||
|
NewStackedPane(Option<RunCommandAction>, Option<String>), // String is an
|
||||||
|
// optional pane
|
||||||
// name
|
// name
|
||||||
/// Embed focused pane in tab if floating or float focused pane if embedded
|
/// Embed focused pane in tab if floating or float focused pane if embedded
|
||||||
TogglePaneEmbedOrFloating,
|
TogglePaneEmbedOrFloating,
|
||||||
|
|
@ -362,6 +364,7 @@ impl Action {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
pinned,
|
pinned,
|
||||||
|
stacked,
|
||||||
} => {
|
} => {
|
||||||
let current_dir = get_current_dir();
|
let current_dir = get_current_dir();
|
||||||
// cwd should only be specified in a plugin alias if it was explicitly given to us,
|
// cwd should only be specified in a plugin alias if it was explicitly given to us,
|
||||||
|
|
@ -443,6 +446,8 @@ impl Action {
|
||||||
)])
|
)])
|
||||||
} else if in_place {
|
} else if in_place {
|
||||||
Ok(vec![Action::NewInPlacePane(Some(run_command_action), name)])
|
Ok(vec![Action::NewInPlacePane(Some(run_command_action), name)])
|
||||||
|
} else if stacked {
|
||||||
|
Ok(vec![Action::NewStackedPane(Some(run_command_action), name)])
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![Action::NewTiledPane(
|
Ok(vec![Action::NewTiledPane(
|
||||||
direction,
|
direction,
|
||||||
|
|
@ -459,6 +464,8 @@ impl Action {
|
||||||
)])
|
)])
|
||||||
} else if in_place {
|
} else if in_place {
|
||||||
Ok(vec![Action::NewInPlacePane(None, name)])
|
Ok(vec![Action::NewInPlacePane(None, name)])
|
||||||
|
} else if stacked {
|
||||||
|
Ok(vec![Action::NewStackedPane(None, name)])
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![Action::NewTiledPane(direction, None, name)])
|
Ok(vec![Action::NewTiledPane(direction, None, name)])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -534,6 +534,8 @@ impl Action {
|
||||||
"NewPane" => {
|
"NewPane" => {
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
return Ok(Action::NewPane(None, None, false));
|
return Ok(Action::NewPane(None, None, false));
|
||||||
|
} else if string == "stacked" {
|
||||||
|
return Ok(Action::NewStackedPane(None, None));
|
||||||
} else {
|
} else {
|
||||||
let direction = Direction::from_str(string.as_str()).map_err(|_| {
|
let direction = Direction::from_str(string.as_str()).map_err(|_| {
|
||||||
ConfigError::new_kdl_error(
|
ConfigError::new_kdl_error(
|
||||||
|
|
@ -911,6 +913,48 @@ impl Action {
|
||||||
}
|
}
|
||||||
Some(node)
|
Some(node)
|
||||||
},
|
},
|
||||||
|
Action::NewStackedPane(run_command_action, name) => match run_command_action {
|
||||||
|
Some(run_command_action) => {
|
||||||
|
let mut node = KdlNode::new("Run");
|
||||||
|
let mut node_children = KdlDocument::new();
|
||||||
|
node.push(run_command_action.command.display().to_string());
|
||||||
|
for arg in &run_command_action.args {
|
||||||
|
node.push(arg.clone());
|
||||||
|
}
|
||||||
|
let mut stacked_node = KdlNode::new("stacked");
|
||||||
|
stacked_node.push(KdlValue::Bool(true));
|
||||||
|
node_children.nodes_mut().push(stacked_node);
|
||||||
|
if let Some(cwd) = &run_command_action.cwd {
|
||||||
|
let mut cwd_node = KdlNode::new("cwd");
|
||||||
|
cwd_node.push(cwd.display().to_string());
|
||||||
|
node_children.nodes_mut().push(cwd_node);
|
||||||
|
}
|
||||||
|
if run_command_action.hold_on_start {
|
||||||
|
let mut hos_node = KdlNode::new("hold_on_start");
|
||||||
|
hos_node.push(KdlValue::Bool(true));
|
||||||
|
node_children.nodes_mut().push(hos_node);
|
||||||
|
}
|
||||||
|
if !run_command_action.hold_on_close {
|
||||||
|
let mut hoc_node = KdlNode::new("hold_on_close");
|
||||||
|
hoc_node.push(KdlValue::Bool(false));
|
||||||
|
node_children.nodes_mut().push(hoc_node);
|
||||||
|
}
|
||||||
|
if let Some(name) = name {
|
||||||
|
let mut name_node = KdlNode::new("name");
|
||||||
|
name_node.push(name.clone());
|
||||||
|
node_children.nodes_mut().push(name_node);
|
||||||
|
}
|
||||||
|
if !node_children.nodes().is_empty() {
|
||||||
|
node.set_children(node_children);
|
||||||
|
}
|
||||||
|
Some(node)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let mut node = KdlNode::new("NewPane");
|
||||||
|
node.push("stacked");
|
||||||
|
Some(node)
|
||||||
|
},
|
||||||
|
},
|
||||||
Action::Detach => Some(KdlNode::new("Detach")),
|
Action::Detach => Some(KdlNode::new("Detach")),
|
||||||
Action::LaunchOrFocusPlugin(
|
Action::LaunchOrFocusPlugin(
|
||||||
run_plugin_or_alias,
|
run_plugin_or_alias,
|
||||||
|
|
@ -1557,6 +1601,9 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
|
||||||
let in_place = command_metadata
|
let in_place = command_metadata
|
||||||
.and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "in_place"))
|
.and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "in_place"))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
let stacked = command_metadata
|
||||||
|
.and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "stacked"))
|
||||||
|
.unwrap_or(false);
|
||||||
let run_command_action = RunCommandAction {
|
let run_command_action = RunCommandAction {
|
||||||
command: PathBuf::from(command),
|
command: PathBuf::from(command),
|
||||||
args,
|
args,
|
||||||
|
|
@ -1588,6 +1635,8 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
|
||||||
))
|
))
|
||||||
} else if in_place {
|
} else if in_place {
|
||||||
Ok(Action::NewInPlacePane(Some(run_command_action), name))
|
Ok(Action::NewInPlacePane(Some(run_command_action), name))
|
||||||
|
} else if stacked {
|
||||||
|
Ok(Action::NewStackedPane(Some(run_command_action), name))
|
||||||
} else {
|
} else {
|
||||||
Ok(Action::NewTiledPane(
|
Ok(Action::NewTiledPane(
|
||||||
direction,
|
direction,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ keybinds clear-defaults=true {
|
||||||
bind "p" { SwitchFocus; }
|
bind "p" { SwitchFocus; }
|
||||||
bind "Ctrl p" { SwitchToMode "normal"; }
|
bind "Ctrl p" { SwitchToMode "normal"; }
|
||||||
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
||||||
|
bind "s" { NewPane "stacked"; SwitchToMode "normal"; }
|
||||||
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
||||||
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ keybinds clear-defaults=true {
|
||||||
bind "p" { SwitchFocus; }
|
bind "p" { SwitchFocus; }
|
||||||
bind "Ctrl p" { SwitchToMode "normal"; }
|
bind "Ctrl p" { SwitchToMode "normal"; }
|
||||||
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
||||||
|
bind "s" { NewPane "stacked"; SwitchToMode "normal"; }
|
||||||
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
||||||
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ enum ActionName {
|
||||||
MouseEvent = 86;
|
MouseEvent = 86;
|
||||||
TogglePaneInGroup = 87;
|
TogglePaneInGroup = 87;
|
||||||
ToggleGroupMarking = 88;
|
ToggleGroupMarking = 88;
|
||||||
|
NewStackedPane = 89;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Position {
|
message Position {
|
||||||
|
|
|
||||||
|
|
@ -720,6 +720,10 @@ impl TryFrom<ProtobufAction> for Action {
|
||||||
plugin_id: None,
|
plugin_id: None,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
Some(ProtobufActionName::NewStackedPane) => match protobuf_action.optional_payload {
|
||||||
|
Some(_) => Err("NewStackedPane should not have a payload"),
|
||||||
|
None => Ok(Action::NewStackedPane(None, None)),
|
||||||
|
},
|
||||||
_ => Err("Unknown Action"),
|
_ => Err("Unknown Action"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1254,6 +1258,10 @@ impl TryFrom<Action> for ProtobufAction {
|
||||||
name: ProtobufActionName::ToggleGroupMarking as i32,
|
name: ProtobufActionName::ToggleGroupMarking as i32,
|
||||||
optional_payload: None,
|
optional_payload: None,
|
||||||
}),
|
}),
|
||||||
|
Action::NewStackedPane(..) => Ok(ProtobufAction {
|
||||||
|
name: ProtobufActionName::NewStackedPane as i32,
|
||||||
|
optional_payload: None,
|
||||||
|
}),
|
||||||
Action::NoOp
|
Action::NoOp
|
||||||
| Action::Confirm
|
| Action::Confirm
|
||||||
| Action::NewInPlacePane(..)
|
| Action::NewInPlacePane(..)
|
||||||
|
|
|
||||||
|
|
@ -1339,6 +1339,20 @@ Config {
|
||||||
Normal,
|
Normal,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
KeyWithModifier {
|
||||||
|
bare_key: Char(
|
||||||
|
's',
|
||||||
|
),
|
||||||
|
key_modifiers: {},
|
||||||
|
}: [
|
||||||
|
NewStackedPane(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
SwitchToMode(
|
||||||
|
Normal,
|
||||||
|
),
|
||||||
|
],
|
||||||
KeyWithModifier {
|
KeyWithModifier {
|
||||||
bare_key: Char(
|
bare_key: Char(
|
||||||
's',
|
's',
|
||||||
|
|
|
||||||
|
|
@ -1339,6 +1339,20 @@ Config {
|
||||||
Normal,
|
Normal,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
KeyWithModifier {
|
||||||
|
bare_key: Char(
|
||||||
|
's',
|
||||||
|
),
|
||||||
|
key_modifiers: {},
|
||||||
|
}: [
|
||||||
|
NewStackedPane(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
SwitchToMode(
|
||||||
|
Normal,
|
||||||
|
),
|
||||||
|
],
|
||||||
KeyWithModifier {
|
KeyWithModifier {
|
||||||
bare_key: Char(
|
bare_key: Char(
|
||||||
's',
|
's',
|
||||||
|
|
|
||||||
|
|
@ -1339,6 +1339,20 @@ Config {
|
||||||
Normal,
|
Normal,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
KeyWithModifier {
|
||||||
|
bare_key: Char(
|
||||||
|
's',
|
||||||
|
),
|
||||||
|
key_modifiers: {},
|
||||||
|
}: [
|
||||||
|
NewStackedPane(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
SwitchToMode(
|
||||||
|
Normal,
|
||||||
|
),
|
||||||
|
],
|
||||||
KeyWithModifier {
|
KeyWithModifier {
|
||||||
bare_key: Char(
|
bare_key: Char(
|
||||||
's',
|
's',
|
||||||
|
|
|
||||||
|
|
@ -1339,6 +1339,20 @@ Config {
|
||||||
Normal,
|
Normal,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
KeyWithModifier {
|
||||||
|
bare_key: Char(
|
||||||
|
's',
|
||||||
|
),
|
||||||
|
key_modifiers: {},
|
||||||
|
}: [
|
||||||
|
NewStackedPane(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
SwitchToMode(
|
||||||
|
Normal,
|
||||||
|
),
|
||||||
|
],
|
||||||
KeyWithModifier {
|
KeyWithModifier {
|
||||||
bare_key: Char(
|
bare_key: Char(
|
||||||
's',
|
's',
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue