feat(plugins): extensive plugin api (#2516)

* feat(plugins): add our entire API

* style(fmt): rustfmt

* fix(detach): make it work again
This commit is contained in:
Aram Drevekenin 2023-06-09 22:49:12 +02:00 committed by GitHub
parent 7f0b878520
commit 8485b1c296
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 5430 additions and 568 deletions

View file

@ -38,10 +38,10 @@ impl ZellijPlugin for State {
fn load(&mut self) {
subscribe(&[
EventType::InputReceived,
EventType::Key,
EventType::SystemClipboardFailure,
EventType::CustomMessage,
EventType::FileSystemCreate,
EventType::FileSystemRead,
EventType::FileSystemUpdate,
EventType::FileSystemDelete,
]);
@ -49,6 +49,142 @@ impl ZellijPlugin for State {
fn update(&mut self, event: Event) -> bool {
match &event {
Event::Key(key) => match key {
Key::Char('a') => {
switch_to_input_mode(&InputMode::Tab);
},
Key::Char('b') => {
new_tabs_with_layout(
"layout {
tab {
pane
pane
}
tab split_direction=\"vertical\" {
pane
pane
}
}",
);
},
Key::Char('c') => new_tab(),
Key::Char('d') => go_to_next_tab(),
Key::Char('e') => go_to_previous_tab(),
Key::Char('f') => {
let resize = Resize::Increase;
resize_focused_pane(resize)
},
Key::Char('g') => {
let resize = Resize::Increase;
let direction = Direction::Left;
resize_focused_pane_with_direction(resize, direction);
},
Key::Char('h') => focus_next_pane(),
Key::Char('i') => focus_previous_pane(),
Key::Char('j') => {
let direction = Direction::Left;
move_focus(direction)
},
Key::Char('k') => {
let direction = Direction::Left;
move_focus_or_tab(direction)
},
Key::Char('l') => detach(),
Key::Char('m') => edit_scrollback(),
Key::Char('n') => {
let bytes = vec![102, 111, 111];
write(bytes)
},
Key::Char('o') => {
let chars = "foo";
write_chars(chars);
},
Key::Char('p') => toggle_tab(),
Key::Char('q') => move_pane(),
Key::Char('r') => {
let direction = Direction::Left;
move_pane_with_direction(direction)
},
Key::Char('s') => clear_screen(),
Key::Char('t') => scroll_up(),
Key::Char('u') => scroll_down(),
Key::Char('v') => scroll_to_top(),
Key::Char('w') => scroll_to_bottom(),
Key::Char('x') => page_scroll_up(),
Key::Char('y') => page_scroll_down(),
Key::Char('z') => toggle_focus_fullscreen(),
Key::Char('1') => toggle_pane_frames(),
Key::Char('2') => toggle_pane_embed_or_eject(),
Key::Char('3') => undo_rename_pane(),
Key::Char('4') => close_focus(),
Key::Char('5') => toggle_active_tab_sync(),
Key::Char('6') => close_focused_tab(),
Key::Char('7') => undo_rename_tab(),
Key::Char('8') => quit_zellij(),
Key::Ctrl('a') => previous_swap_layout(),
Key::Ctrl('b') => next_swap_layout(),
Key::Ctrl('c') => {
let tab_name = "my tab name";
go_to_tab_name(tab_name)
},
Key::Ctrl('d') => {
let tab_name = "my tab name";
focus_or_create_tab(tab_name)
},
Key::Ctrl('e') => {
let tab_index = 2;
go_to_tab(tab_index)
},
Key::Ctrl('f') => {
let plugin_url = "file:/path/to/my/plugin.wasm";
start_or_reload_plugin(plugin_url)
},
Key::Ctrl('g') => {
open_file(std::path::PathBuf::from("/path/to/my/file.rs").as_path());
},
Key::Ctrl('h') => {
open_file_floating(std::path::PathBuf::from("/path/to/my/file.rs").as_path());
},
Key::Ctrl('i') => {
open_file_with_line(
std::path::PathBuf::from("/path/to/my/file.rs").as_path(),
42,
);
},
Key::Ctrl('j') => {
open_file_with_line_floating(
std::path::PathBuf::from("/path/to/my/file.rs").as_path(),
42,
);
},
Key::Ctrl('k') => {
open_terminal(std::path::PathBuf::from("/path/to/my/file.rs").as_path());
},
Key::Ctrl('l') => {
open_terminal_floating(
std::path::PathBuf::from("/path/to/my/file.rs").as_path(),
);
},
Key::Ctrl('m') => {
open_command_pane(
std::path::PathBuf::from("/path/to/my/file.rs").as_path(),
vec!["arg1".to_owned(), "arg2".to_owned()],
);
},
Key::Ctrl('n') => {
open_command_pane_floating(
std::path::PathBuf::from("/path/to/my/file.rs").as_path(),
vec!["arg1".to_owned(), "arg2".to_owned()],
);
},
Key::Ctrl('o') => {
switch_tab_to(1);
},
Key::Ctrl('p') => {
hide_self();
},
_ => {},
},
Event::CustomMessage(message, payload) => {
if message == "pong" {
self.received_payload = Some(payload.clone());

View file

@ -204,17 +204,7 @@ impl Search {
) -> Vec<SearchResult> {
let mut matches = vec![];
for ((file_name, line_number), line_entry) in &self.file_contents {
if line_entry.contains("struct") {
if line_entry.len() < 400 {
eprintln!("matching against: {:?}", line_entry)
} else {
eprintln!("matching again line that has struct but is very long")
}
}
if let Some((score, indices)) = matcher.fuzzy_indices(&line_entry, &search_term) {
if line_entry.contains("struct") {
eprintln!("score: {:?}", score)
}
matches.push(SearchResult::new_file_line(
score,
indices,
@ -222,10 +212,6 @@ impl Search {
line_entry.clone(),
*line_number,
));
} else {
if line_entry.contains("struct") {
eprintln!("no score!")
}
}
}
matches

View file

@ -778,6 +778,9 @@ fn init_session(
let store = get_store();
let layout = layout.clone();
let client_attributes = client_attributes.clone();
let default_shell = default_shell.clone();
let capabilities = capabilities.clone();
move || {
plugin_thread_main(
plugin_bus,
@ -787,6 +790,9 @@ fn init_session(
layout,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
)
.fatal()
}
@ -834,7 +840,7 @@ fn init_session(
to_plugin: Some(to_plugin),
to_pty_writer: Some(to_pty_writer),
to_background_jobs: Some(to_background_jobs),
to_server: None,
to_server: Some(to_server),
should_silently_fail: false,
},
capabilities,

View file

@ -14,13 +14,14 @@ use crate::{pty::PtyInstruction, thread_bus::Bus, ClientId, ServerInstruction};
use wasm_bridge::WasmBridge;
use zellij_utils::{
data::Event,
data::{Event, PluginCapabilities},
errors::{prelude::*, ContextType, PluginContext},
input::{
command::TerminalAction,
layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginLocation, TiledPaneLayout},
plugins::PluginsConfig,
},
ipc::ClientAttributes,
pane_size::Size,
};
@ -108,6 +109,9 @@ pub(crate) fn plugin_thread_main(
layout: Box<Layout>,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
) -> Result<()> {
info!("Wasm main thread starts");
@ -121,6 +125,10 @@ pub(crate) fn plugin_thread_main(
plugin_dir,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
layout.clone(),
);
loop {

View file

@ -22,8 +22,12 @@ use crate::{
use zellij_utils::{
consts::{VERSION, ZELLIJ_CACHE_DIR, ZELLIJ_SESSION_CACHE_DIR, ZELLIJ_TMP_DIR},
data::PluginCapabilities,
errors::prelude::*,
input::command::TerminalAction,
input::layout::Layout,
input::plugins::PluginConfig,
ipc::ClientAttributes,
pane_size::Size,
};
@ -165,6 +169,10 @@ pub struct PluginLoader<'a> {
wasm_blob_on_hd: Option<(Vec<u8>, PathBuf)>,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
}
impl<'a> PluginLoader<'a> {
@ -179,6 +187,10 @@ impl<'a> PluginLoader<'a> {
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<()> {
let err_context = || format!("failed to reload plugin {plugin_id} from memory");
let mut connected_clients: Vec<ClientId> =
@ -199,6 +211,10 @@ impl<'a> PluginLoader<'a> {
&plugin_dir,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
)?;
plugin_loader
.load_module_from_memory()
@ -234,6 +250,10 @@ impl<'a> PluginLoader<'a> {
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<()> {
let err_context = || format!("failed to start plugin {plugin_id} for client {client_id}");
let mut plugin_loader = PluginLoader::new(
@ -249,6 +269,10 @@ impl<'a> PluginLoader<'a> {
size,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
)?;
plugin_loader
.load_module_from_memory()
@ -284,6 +308,10 @@ impl<'a> PluginLoader<'a> {
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<()> {
let mut new_plugins = HashSet::new();
for plugin_id in plugin_map.lock().unwrap().plugin_ids() {
@ -301,6 +329,10 @@ impl<'a> PluginLoader<'a> {
&plugin_dir,
path_to_default_shell.clone(),
zellij_cwd.clone(),
capabilities.clone(),
client_attributes.clone(),
default_shell.clone(),
default_layout.clone(),
)?;
plugin_loader
.load_module_from_memory()
@ -329,6 +361,10 @@ impl<'a> PluginLoader<'a> {
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<()> {
let err_context = || format!("failed to reload plugin id {plugin_id}");
@ -350,6 +386,10 @@ impl<'a> PluginLoader<'a> {
&plugin_dir,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
)?;
plugin_loader
.compile_module()
@ -382,6 +422,10 @@ impl<'a> PluginLoader<'a> {
size: Size,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<Self> {
let plugin_own_data_dir = ZELLIJ_SESSION_CACHE_DIR
.join(Url::from(&plugin.location).to_string())
@ -404,6 +448,10 @@ impl<'a> PluginLoader<'a> {
wasm_blob_on_hd: None,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
})
}
pub fn new_from_existing_plugin_attributes(
@ -417,6 +465,10 @@ impl<'a> PluginLoader<'a> {
plugin_dir: &'a PathBuf,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<Self> {
let err_context = || "Failed to find existing plugin";
let (running_plugin, _subscriptions, _workers) = {
@ -446,6 +498,10 @@ impl<'a> PluginLoader<'a> {
size,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
)
}
pub fn new_from_different_client_id(
@ -459,6 +515,10 @@ impl<'a> PluginLoader<'a> {
plugin_dir: &'a PathBuf,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<Self> {
let err_context = || "Failed to find existing plugin";
let running_plugin = {
@ -489,6 +549,10 @@ impl<'a> PluginLoader<'a> {
size,
path_to_default_shell,
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
)
}
pub fn load_module_from_memory(&mut self) -> Result<Module> {
@ -721,6 +785,10 @@ impl<'a> PluginLoader<'a> {
&self.plugin_dir,
self.path_to_default_shell.clone(),
self.zellij_cwd.clone(),
self.capabilities.clone(),
self.client_attributes.clone(),
self.default_shell.clone(),
self.default_layout.clone(),
)?;
plugin_loader_for_client
.load_module_from_memory()
@ -804,6 +872,10 @@ impl<'a> PluginLoader<'a> {
plugin_own_data_dir: self.plugin_own_data_dir.clone(),
tab_index: self.tab_index,
path_to_default_shell: self.path_to_default_shell.clone(),
capabilities: self.capabilities.clone(),
client_attributes: self.client_attributes.clone(),
default_shell: self.default_shell.clone(),
default_layout: self.default_layout.clone(),
};
let subscriptions = Arc::new(Mutex::new(HashSet::new()));

View file

@ -13,7 +13,12 @@ use crate::{thread_bus::ThreadSenders, ClientId};
use zellij_utils::async_channel::Sender;
use zellij_utils::errors::prelude::*;
use zellij_utils::{
data::EventType, input::layout::RunPluginLocation, input::plugins::PluginConfig,
data::EventType,
data::PluginCapabilities,
input::command::TerminalAction,
input::layout::{Layout, RunPluginLocation},
input::plugins::PluginConfig,
ipc::ClientAttributes,
};
// the idea here is to provide atomicity when adding/removing plugins from the map (eg. when a new
@ -195,6 +200,10 @@ pub struct PluginEnv {
#[allow(dead_code)]
pub plugin_own_data_dir: PathBuf,
pub path_to_default_shell: PathBuf,
pub capabilities: PluginCapabilities,
pub client_attributes: ClientAttributes,
pub default_shell: Option<TerminalAction>,
pub default_layout: Box<Layout>,
}
impl PluginEnv {

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 387
assertion_line: 400
expression: "format!(\"{:#?}\", plugin_bytes_event)"
---
Some(
(
0,
1,
"Rows: 20, Cols: 121, Received events: [InputReceived, FileSystemRead([\"/host/test1\"])]\n\r",
"Rows: 20, Cols: 121, Received events: [FileSystemCreate([\"/host/test1\"])]\n\r",
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1387
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ClearScreen(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2010
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
CloseFocusedPane(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2118
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
CloseTab(
1,
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2685
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
DetachSession(
[
1,
],
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1063
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
EditScrollback(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 847
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
FocusNextPane(
1,
),
)

View file

@ -0,0 +1,19 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2388
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
GoToTabName(
"my tab name",
(
[],
[],
),
None,
true,
Some(
1,
),
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 901
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
FocusPreviousPane(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 632
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SwitchTabNext(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 687
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SwitchTabPrev(
1,
),
)

View file

@ -0,0 +1,13 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2442
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
GoToTab(
2,
Some(
1,
),
),
)

View file

@ -0,0 +1,19 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2334
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
GoToTabName(
"my tab name\n\r",
(
[],
[],
),
None,
false,
Some(
1,
),
),
)

View file

@ -0,0 +1,13 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 3306
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SuppressPane(
Plugin(
0,
),
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1009
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
MoveFocusLeftOrPreviousTab(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 955
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
MoveFocusLeft(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1279
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
MovePane(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1333
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
MovePaneLeft(
1,
),
)

View file

@ -0,0 +1,19 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 573
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
NewTab(
None,
None,
None,
[],
None,
(
[],
[],
),
1,
),
)

View file

@ -0,0 +1,60 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 521
expression: "format!(\"{:#?}\", second_new_tab_event)"
---
Some(
NewTab(
None,
None,
Some(
TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
children_are_stacked: false,
is_expanded_in_stack: false,
exclude_from_sync: None,
},
TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
children_are_stacked: false,
is_expanded_in_stack: false,
exclude_from_sync: None,
},
],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
children_are_stacked: false,
is_expanded_in_stack: false,
exclude_from_sync: None,
},
),
[],
None,
(
[],
[],
),
1,
),
)

View file

@ -0,0 +1,60 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 520
expression: "format!(\"{:#?}\", first_new_tab_event)"
---
Some(
NewTab(
None,
None,
Some(
TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
children_are_stacked: false,
is_expanded_in_stack: false,
exclude_from_sync: None,
},
TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
children_are_stacked: false,
is_expanded_in_stack: false,
exclude_from_sync: None,
},
],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
children_are_stacked: false,
is_expanded_in_stack: false,
exclude_from_sync: None,
},
),
[],
None,
(
[],
[],
),
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2280
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
NextSwapLayout(
1,
),
)

View file

@ -0,0 +1,30 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 3198
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
RunCommand(
RunCommand {
command: "/path/to/my/file.rs",
args: [
"arg1",
"arg2",
],
cwd: None,
hold_on_close: true,
hold_on_start: false,
},
),
),
Some(
true,
),
None,
ClientId(
1,
),
),
)

View file

@ -0,0 +1,30 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 3144
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
RunCommand(
RunCommand {
command: "/path/to/my/file.rs",
args: [
"arg1",
"arg2",
],
cwd: None,
hold_on_close: true,
hold_on_start: false,
},
),
),
Some(
false,
),
None,
ClientId(
1,
),
),
)

View file

@ -0,0 +1,25 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2820
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
OpenFile(
"/path/to/my/file.rs",
None,
None,
),
),
Some(
true,
),
Some(
"Editing: /path/to/my/file.rs",
),
ClientId(
1,
),
),
)

View file

@ -0,0 +1,25 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2874
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
OpenFile(
"/path/to/my/file.rs",
None,
None,
),
),
Some(
false,
),
Some(
"Editing: /path/to/my/file.rs",
),
ClientId(
1,
),
),
)

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2982
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
OpenFile(
"/path/to/my/file.rs",
Some(
42,
),
None,
),
),
Some(
true,
),
Some(
"Editing: /path/to/my/file.rs",
),
ClientId(
1,
),
),
)

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2927
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
OpenFile(
"/path/to/my/file.rs",
Some(
42,
),
None,
),
),
Some(
false,
),
Some(
"Editing: /path/to/my/file.rs",
),
ClientId(
1,
),
),
)

View file

@ -0,0 +1,25 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2820
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
OpenFile(
"/path/to/my/file.rs",
None,
None,
),
),
Some(
false,
),
Some(
"Editing: /path/to/my/file.rs",
),
ClientId(
1,
),
),
)

View file

@ -0,0 +1,29 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 3090
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
RunCommand(
RunCommand {
command: "",
args: [],
cwd: Some(
"/path/to/my/file.rs",
),
hold_on_close: false,
hold_on_start: false,
},
),
),
Some(
true,
),
None,
ClientId(
1,
),
),
)

View file

@ -0,0 +1,29 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 3036
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
SpawnTerminal(
Some(
RunCommand(
RunCommand {
command: "",
args: [],
cwd: Some(
"/path/to/my/file.rs",
),
hold_on_close: false,
hold_on_start: false,
},
),
),
Some(
false,
),
None,
ClientId(
1,
),
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1711
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
PageScrollDown(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1657
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
PageScrollUp(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2226
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
PreviousSwapLayout(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2631
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ClientExit(
1,
),
)

View file

@ -0,0 +1,15 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 742
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
Resize(
1,
ResizeStrategy {
resize: Increase,
direction: None,
invert_on_boundaries: true,
},
),
)

View file

@ -0,0 +1,17 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 793
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
Resize(
1,
ResizeStrategy {
resize: Increase,
direction: Some(
Left,
),
invert_on_boundaries: true,
},
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1495
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ScrollDown(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1603
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ScrollToBottom(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1549
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ScrollToTop(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1441
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ScrollUp(
1,
),
)

View file

@ -0,0 +1,13 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2496
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
StartOrReloadPluginPane(
File(
"/path/to/my/plugin.wasm",
),
None,
),
)

View file

@ -0,0 +1,79 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 455
expression: "format!(\"{:#?}\", switch_to_mode_event)"
---
Some(
ChangeMode(
ModeInfo {
mode: Tab,
keybinds: [],
style: Style {
colors: Palette {
source: Default,
theme_hue: Dark,
fg: EightBit(
0,
),
bg: EightBit(
0,
),
black: EightBit(
0,
),
red: EightBit(
0,
),
green: EightBit(
0,
),
yellow: EightBit(
0,
),
blue: EightBit(
0,
),
magenta: EightBit(
0,
),
cyan: EightBit(
0,
),
white: EightBit(
0,
),
orange: EightBit(
0,
),
gray: EightBit(
0,
),
purple: EightBit(
0,
),
gold: EightBit(
0,
),
silver: EightBit(
0,
),
pink: EightBit(
0,
),
brown: EightBit(
0,
),
},
rounded_corners: false,
hide_session_name: false,
},
capabilities: PluginCapabilities {
arrow_fonts: true,
},
session_name: Some(
"zellij-test",
),
},
1,
),
)

View file

@ -0,0 +1,13 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 3252
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
GoToTab(
1,
Some(
1,
),
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2064
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ToggleActiveSyncTab(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1765
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ToggleActiveTerminalFullscreen(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1902
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
TogglePaneEmbedOrFloating(
1,
),
)

View file

@ -0,0 +1,8 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1848
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
TogglePaneFrames,
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1225
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
ToggleTab(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1956
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
UndoRenamePane(
1,
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 2172
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
UndoRenameTab(
1,
),
)

View file

@ -0,0 +1,17 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1171
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
WriteCharacter(
[
102,
111,
111,
10,
13,
],
1,
),
)

View file

@ -0,0 +1,15 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1117
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
WriteCharacter(
[
102,
111,
111,
],
1,
),
)

View file

@ -21,12 +21,14 @@ use crate::{
};
use zellij_utils::{
consts::VERSION,
data::{Event, EventType},
data::{Event, EventType, PluginCapabilities},
errors::prelude::*,
input::{
layout::{RunPlugin, RunPluginLocation},
command::TerminalAction,
layout::{Layout, RunPlugin, RunPluginLocation},
plugins::PluginsConfig,
},
ipc::ClientAttributes,
pane_size::Size,
};
@ -50,6 +52,10 @@ pub struct WasmBridge {
path_to_default_shell: PathBuf,
watcher: Option<RecommendedWatcher>,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
}
impl WasmBridge {
@ -60,6 +66,10 @@ impl WasmBridge {
plugin_dir: PathBuf,
path_to_default_shell: PathBuf,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Self {
let plugin_map = Arc::new(Mutex::new(PluginMap::default()));
let connected_clients: Arc<Mutex<Vec<ClientId>>> = Arc::new(Mutex::new(vec![]));
@ -89,6 +99,10 @@ impl WasmBridge {
loading_plugins: HashMap::new(),
pending_plugin_reloads: HashSet::new(),
zellij_cwd,
capabilities,
client_attributes,
default_shell,
default_layout,
}
}
pub fn load_plugin(
@ -137,6 +151,10 @@ impl WasmBridge {
let connected_clients = self.connected_clients.clone();
let path_to_default_shell = self.path_to_default_shell.clone();
let zellij_cwd = self.zellij_cwd.clone();
let capabilities = self.capabilities.clone();
let client_attributes = self.client_attributes.clone();
let default_shell = self.default_shell.clone();
let default_layout = self.default_layout.clone();
async move {
let _ =
senders.send_to_background_jobs(BackgroundJob::AnimatePluginLoading(plugin_id));
@ -156,6 +174,10 @@ impl WasmBridge {
&mut loading_indication,
path_to_default_shell,
zellij_cwd.clone(),
capabilities,
client_attributes,
default_shell,
default_layout,
) {
Ok(_) => handle_plugin_successful_loading(&senders, plugin_id),
Err(e) => handle_plugin_loading_failure(
@ -217,6 +239,10 @@ impl WasmBridge {
let connected_clients = self.connected_clients.clone();
let path_to_default_shell = self.path_to_default_shell.clone();
let zellij_cwd = self.zellij_cwd.clone();
let capabilities = self.capabilities.clone();
let client_attributes = self.client_attributes.clone();
let default_shell = self.default_shell.clone();
let default_layout = self.default_layout.clone();
async move {
match PluginLoader::reload_plugin(
first_plugin_id,
@ -229,6 +255,10 @@ impl WasmBridge {
&mut loading_indication,
path_to_default_shell.clone(),
zellij_cwd.clone(),
capabilities.clone(),
client_attributes.clone(),
default_shell.clone(),
default_layout.clone(),
) {
Ok(_) => {
handle_plugin_successful_loading(&senders, first_plugin_id);
@ -249,6 +279,10 @@ impl WasmBridge {
&mut loading_indication,
path_to_default_shell.clone(),
zellij_cwd.clone(),
capabilities.clone(),
client_attributes.clone(),
default_shell.clone(),
default_layout.clone(),
) {
Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id),
Err(e) => handle_plugin_loading_failure(
@ -291,6 +325,10 @@ impl WasmBridge {
&mut loading_indication,
self.path_to_default_shell.clone(),
self.zellij_cwd.clone(),
self.capabilities.clone(),
self.client_attributes.clone(),
self.default_shell.clone(),
self.default_layout.clone(),
) {
Ok(_) => {
let _ = self

View file

@ -1,6 +1,7 @@
use super::PluginInstruction;
use crate::plugins::plugin_map::{PluginEnv, Subscriptions};
use crate::plugins::wasm_bridge::handle_plugin_crash;
use crate::route::route_action;
use log::{debug, warn};
use serde::{de::DeserializeOwned, Serialize};
use std::{
@ -14,23 +15,39 @@ use std::{
use wasmer::{imports, Function, ImportObject, Store, WasmerEnv};
use wasmer_wasi::WasiEnv;
use crate::{
panes::PaneId,
pty::{ClientOrTabIndex, PtyInstruction},
screen::ScreenInstruction,
};
use url::Url;
use crate::{panes::PaneId, screen::ScreenInstruction};
use zellij_utils::{
consts::VERSION,
data::{Event, EventType, PluginIds},
data::{Direction, Event, EventType, InputMode, PluginIds, Resize},
errors::prelude::*,
input::{
command::{RunCommand, TerminalAction},
actions::Action,
command::{RunCommand, RunCommandAction, TerminalAction},
layout::{Layout, RunPlugin, RunPluginLocation},
plugins::PluginType,
},
serde,
};
macro_rules! apply_action {
($action:ident, $error_message:ident, $env: ident) => {
if let Err(e) = route_action(
$action,
$env.plugin_env.client_id,
$env.plugin_env.senders.clone(),
$env.plugin_env.capabilities.clone(),
$env.plugin_env.client_attributes.clone(),
$env.plugin_env.default_shell.clone(),
$env.plugin_env.default_layout.clone(),
) {
log::error!("{}: {:?}", $error_message(), e);
}
};
}
pub fn zellij_exports(
store: &Store,
plugin_env: &PluginEnv,
@ -59,6 +76,8 @@ pub fn zellij_exports(
host_open_file_with_line_floating,
host_open_terminal,
host_open_terminal_floating,
host_open_command_pane,
host_open_command_pane_floating,
host_switch_tab_to,
host_set_timeout,
host_exec_cmd,
@ -66,6 +85,46 @@ pub fn zellij_exports(
host_post_message_to,
host_post_message_to_plugin,
host_hide_self,
host_switch_to_mode,
host_new_tabs_with_layout,
host_new_tab,
host_go_to_next_tab,
host_go_to_previous_tab,
host_resize,
host_resize_with_direction,
host_focus_next_pane,
host_focus_previous_pane,
host_move_focus,
host_move_focus_or_tab,
host_detach,
host_edit_scrollback,
host_write,
host_write_chars,
host_toggle_tab,
host_move_pane,
host_move_pane_with_direction,
host_clear_screen,
host_scroll_up,
host_scroll_down,
host_scroll_to_top,
host_scroll_to_bottom,
host_page_scroll_up,
host_page_scroll_down,
host_toggle_focus_fullscreen,
host_toggle_pane_frames,
host_toggle_pane_embed_or_eject,
host_undo_rename_pane,
host_close_focus,
host_toggle_active_tab_sync,
host_close_focused_tab,
host_undo_rename_tab,
host_quit_zellij,
host_previous_swap_layout,
host_next_swap_layout,
host_go_to_tab_name,
host_focus_or_create_tab,
host_go_to_tab,
host_start_or_reload_plugin,
}
}
@ -165,14 +224,16 @@ fn host_get_zellij_version(env: &ForeignFunctionEnv) {
fn host_open_file(env: &ForeignFunctionEnv) {
wasi_read_object::<PathBuf>(&env.plugin_env.wasi_env)
.and_then(|path| {
env.plugin_env
.senders
.send_to_pty(PtyInstruction::SpawnTerminal(
Some(TerminalAction::OpenFile(path, None, None)),
Some(false),
None,
ClientOrTabIndex::ClientId(env.plugin_env.client_id),
))
let error_msg = || {
format!(
"failed to open floating file in plugin {}",
env.plugin_env.name()
)
};
let floating = false;
let action = Action::EditFile(path, None, None, None, floating); // TODO: add cwd
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| {
format!(
@ -186,14 +247,11 @@ fn host_open_file(env: &ForeignFunctionEnv) {
fn host_open_file_floating(env: &ForeignFunctionEnv) {
wasi_read_object::<PathBuf>(&env.plugin_env.wasi_env)
.and_then(|path| {
env.plugin_env
.senders
.send_to_pty(PtyInstruction::SpawnTerminal(
Some(TerminalAction::OpenFile(path, None, None)),
Some(true),
None,
ClientOrTabIndex::ClientId(env.plugin_env.client_id),
))
let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name());
let floating = true;
let action = Action::EditFile(path, None, None, None, floating); // TODO: add cwd
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| {
format!(
@ -207,14 +265,11 @@ fn host_open_file_floating(env: &ForeignFunctionEnv) {
fn host_open_file_with_line(env: &ForeignFunctionEnv) {
wasi_read_object::<(PathBuf, usize)>(&env.plugin_env.wasi_env)
.and_then(|(path, line)| {
env.plugin_env
.senders
.send_to_pty(PtyInstruction::SpawnTerminal(
Some(TerminalAction::OpenFile(path, Some(line), None)), // TODO: add cwd
Some(false),
None,
ClientOrTabIndex::ClientId(env.plugin_env.client_id),
))
let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name());
let floating = false;
let action = Action::EditFile(path, Some(line), None, None, floating); // TODO: add cwd
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| {
format!(
@ -228,14 +283,11 @@ fn host_open_file_with_line(env: &ForeignFunctionEnv) {
fn host_open_file_with_line_floating(env: &ForeignFunctionEnv) {
wasi_read_object::<(PathBuf, usize)>(&env.plugin_env.wasi_env)
.and_then(|(path, line)| {
env.plugin_env
.senders
.send_to_pty(PtyInstruction::SpawnTerminal(
Some(TerminalAction::OpenFile(path, Some(line), None)), // TODO: add cwd
Some(true),
None,
ClientOrTabIndex::ClientId(env.plugin_env.client_id),
))
let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name());
let floating = true;
let action = Action::EditFile(path, Some(line), None, None, floating); // TODO: add cwd
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| {
format!(
@ -249,21 +301,24 @@ fn host_open_file_with_line_floating(env: &ForeignFunctionEnv) {
fn host_open_terminal(env: &ForeignFunctionEnv) {
wasi_read_object::<PathBuf>(&env.plugin_env.wasi_env)
.and_then(|path| {
env.plugin_env
.senders
.send_to_pty(PtyInstruction::SpawnTerminal(
Some(TerminalAction::RunCommand(
RunCommand::new(env.plugin_env.path_to_default_shell.clone())
.with_cwd(path),
)),
Some(false),
None,
ClientOrTabIndex::ClientId(env.plugin_env.client_id),
))
let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name());
let mut default_shell = env
.plugin_env
.default_shell
.clone()
.unwrap_or_else(|| TerminalAction::RunCommand(RunCommand::default()));
default_shell.change_cwd(path);
let run_command_action: Option<RunCommandAction> = match default_shell {
TerminalAction::RunCommand(run_command) => Some(run_command.into()),
_ => None,
};
let action = Action::NewTiledPane(None, run_command_action, None);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| {
format!(
"failed to open terminal on host from plugin {}",
"failed to open file on host from plugin {}",
env.plugin_env.name()
)
})
@ -273,27 +328,80 @@ fn host_open_terminal(env: &ForeignFunctionEnv) {
fn host_open_terminal_floating(env: &ForeignFunctionEnv) {
wasi_read_object::<PathBuf>(&env.plugin_env.wasi_env)
.and_then(|path| {
env.plugin_env
.senders
.send_to_pty(PtyInstruction::SpawnTerminal(
Some(TerminalAction::RunCommand(
RunCommand::new(env.plugin_env.path_to_default_shell.clone())
.with_cwd(path),
)),
Some(true),
None,
ClientOrTabIndex::ClientId(env.plugin_env.client_id),
))
let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name());
let mut default_shell = env
.plugin_env
.default_shell
.clone()
.unwrap_or_else(|| TerminalAction::RunCommand(RunCommand::default()));
default_shell.change_cwd(path);
let run_command_action: Option<RunCommandAction> = match default_shell {
TerminalAction::RunCommand(run_command) => Some(run_command.into()),
_ => None,
};
let action = Action::NewFloatingPane(run_command_action, None);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| {
format!(
"failed to open terminal on host from plugin {}",
"failed to open file on host from plugin {}",
env.plugin_env.name()
)
})
.non_fatal();
}
fn host_open_command_pane(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to run command in plugin {}", env.plugin_env.name());
wasi_read_object::<(PathBuf, Vec<String>)>(&env.plugin_env.wasi_env)
.and_then(|(command, args)| {
let cwd = None;
let direction = None;
let hold_on_close = true;
let hold_on_start = false;
let name = None;
let run_command_action = RunCommandAction {
command,
args,
cwd,
direction,
hold_on_close,
hold_on_start,
};
let action = Action::NewTiledPane(direction, Some(run_command_action), name);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.non_fatal();
}
fn host_open_command_pane_floating(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to run command in plugin {}", env.plugin_env.name());
wasi_read_object::<(PathBuf, Vec<String>)>(&env.plugin_env.wasi_env)
.and_then(|(command, args)| {
let cwd = None;
let direction = None;
let hold_on_close = true;
let hold_on_start = false;
let name = None;
let run_command_action = RunCommandAction {
command,
args,
cwd,
direction,
hold_on_close,
hold_on_start,
};
let action = Action::NewFloatingPane(Some(run_command_action), name);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.non_fatal();
}
fn host_switch_tab_to(env: &ForeignFunctionEnv, tab_idx: u32) {
env.plugin_env
.senders
@ -424,6 +532,422 @@ fn host_hide_self(env: &ForeignFunctionEnv) {
.fatal();
}
fn host_switch_to_mode(env: &ForeignFunctionEnv) {
wasi_read_object::<InputMode>(&env.plugin_env.wasi_env)
.and_then(|input_mode| {
let action = Action::SwitchToMode(input_mode);
let error_msg = || {
format!(
"failed to switch to mode in plugin {}",
env.plugin_env.name()
)
};
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(|| format!("failed to subscribe for plugin {}", env.plugin_env.name()))
.fatal();
}
fn host_new_tabs_with_layout(env: &ForeignFunctionEnv) {
wasi_read_string(&env.plugin_env.wasi_env)
.and_then(|raw_layout| {
Layout::from_str(
&raw_layout,
format!("Layout from plugin: {}", env.plugin_env.name()),
None,
None,
)
.map_err(|e| anyhow!("Failed to parse layout: {:?}", e))
}) // TODO: cwd?
.and_then(|layout| {
let mut tabs_to_open = vec![];
let tabs = layout.tabs();
if tabs.is_empty() {
let action = Action::NewTab(
layout.template.as_ref().map(|t| t.0.clone()),
layout.template.map(|t| t.1).unwrap_or_default(),
None,
None,
None,
);
tabs_to_open.push(action);
} else {
for (tab_name, tiled_pane_layout, floating_pane_layout) in layout.tabs() {
let action = Action::NewTab(
Some(tiled_pane_layout),
floating_pane_layout,
None,
None,
tab_name,
);
tabs_to_open.push(action);
}
}
for action in tabs_to_open {
let error_msg = || format!("Failed to create layout tab");
apply_action!(action, error_msg, env);
}
Ok(())
})
.non_fatal();
}
fn host_new_tab(env: &ForeignFunctionEnv) {
let action = Action::NewTab(None, vec![], None, None, None);
let error_msg = || format!("Failed to open new tab");
apply_action!(action, error_msg, env);
}
fn host_go_to_next_tab(env: &ForeignFunctionEnv) {
let action = Action::GoToNextTab;
let error_msg = || format!("Failed to go to next tab");
apply_action!(action, error_msg, env);
}
fn host_go_to_previous_tab(env: &ForeignFunctionEnv) {
let action = Action::GoToPreviousTab;
let error_msg = || format!("Failed to go to previous tab");
apply_action!(action, error_msg, env);
}
fn host_resize(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to resize in plugin {}", env.plugin_env.name());
wasi_read_object::<Resize>(&env.plugin_env.wasi_env)
.and_then(|resize| {
let action = Action::Resize(resize, None);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_resize_with_direction(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to resize in plugin {}", env.plugin_env.name());
wasi_read_object::<(Resize, Direction)>(&env.plugin_env.wasi_env)
.and_then(|(resize, direction)| {
let action = Action::Resize(resize, Some(direction));
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_focus_next_pane(env: &ForeignFunctionEnv) {
let action = Action::FocusNextPane;
let error_msg = || format!("Failed to focus next pane");
apply_action!(action, error_msg, env);
}
fn host_focus_previous_pane(env: &ForeignFunctionEnv) {
let action = Action::FocusPreviousPane;
let error_msg = || format!("Failed to focus previous pane");
apply_action!(action, error_msg, env);
}
fn host_move_focus(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to move focus in plugin {}", env.plugin_env.name());
wasi_read_object::<Direction>(&env.plugin_env.wasi_env)
.and_then(|direction| {
let action = Action::MoveFocus(direction);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_move_focus_or_tab(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to move focus in plugin {}", env.plugin_env.name());
wasi_read_object::<Direction>(&env.plugin_env.wasi_env)
.and_then(|direction| {
let action = Action::MoveFocusOrTab(direction);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_detach(env: &ForeignFunctionEnv) {
let action = Action::Detach;
let error_msg = || format!("Failed to detach");
apply_action!(action, error_msg, env);
}
fn host_edit_scrollback(env: &ForeignFunctionEnv) {
let action = Action::EditScrollback;
let error_msg = || format!("Failed to edit scrollback");
apply_action!(action, error_msg, env);
}
fn host_write(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to write in plugin {}", env.plugin_env.name());
wasi_read_object::<Vec<u8>>(&env.plugin_env.wasi_env)
.and_then(|bytes| {
let action = Action::Write(bytes);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_write_chars(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to write in plugin {}", env.plugin_env.name());
wasi_read_string(&env.plugin_env.wasi_env)
.and_then(|chars_to_write| {
let action = Action::WriteChars(chars_to_write);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_toggle_tab(env: &ForeignFunctionEnv) {
let action = Action::ToggleTab;
let error_msg = || format!("Failed to toggle tab");
apply_action!(action, error_msg, env);
}
fn host_move_pane(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to move pane in plugin {}", env.plugin_env.name());
let action = Action::MovePane(None);
apply_action!(action, error_msg, env);
}
fn host_move_pane_with_direction(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to move pane in plugin {}", env.plugin_env.name());
wasi_read_object::<Direction>(&env.plugin_env.wasi_env)
.and_then(|direction| {
let action = Action::MovePane(Some(direction));
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_clear_screen(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to clear screen in plugin {}", env.plugin_env.name());
let action = Action::ClearScreen;
apply_action!(action, error_msg, env);
}
fn host_scroll_up(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll up in plugin {}", env.plugin_env.name());
let action = Action::ScrollUp;
apply_action!(action, error_msg, env);
}
fn host_scroll_down(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll down in plugin {}", env.plugin_env.name());
let action = Action::ScrollDown;
apply_action!(action, error_msg, env);
}
fn host_scroll_to_top(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name());
let action = Action::ScrollToTop;
apply_action!(action, error_msg, env);
}
fn host_scroll_to_bottom(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name());
let action = Action::ScrollToBottom;
apply_action!(action, error_msg, env);
}
fn host_page_scroll_up(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name());
let action = Action::PageScrollUp;
apply_action!(action, error_msg, env);
}
fn host_page_scroll_down(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name());
let action = Action::PageScrollDown;
apply_action!(action, error_msg, env);
}
fn host_toggle_focus_fullscreen(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to toggle full screen in plugin {}",
env.plugin_env.name()
)
};
let action = Action::ToggleFocusFullscreen;
apply_action!(action, error_msg, env);
}
fn host_toggle_pane_frames(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to toggle full screen in plugin {}",
env.plugin_env.name()
)
};
let action = Action::TogglePaneFrames;
apply_action!(action, error_msg, env);
}
fn host_toggle_pane_embed_or_eject(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to toggle pane embed or eject in plugin {}",
env.plugin_env.name()
)
};
let action = Action::TogglePaneEmbedOrFloating;
apply_action!(action, error_msg, env);
}
fn host_undo_rename_pane(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to undo rename pane in plugin {}",
env.plugin_env.name()
)
};
let action = Action::UndoRenamePane;
apply_action!(action, error_msg, env);
}
fn host_close_focus(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to close focused pane in plugin {}",
env.plugin_env.name()
)
};
let action = Action::CloseFocus;
apply_action!(action, error_msg, env);
}
fn host_toggle_active_tab_sync(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to toggle active tab sync in plugin {}",
env.plugin_env.name()
)
};
let action = Action::ToggleActiveSyncTab;
apply_action!(action, error_msg, env);
}
fn host_close_focused_tab(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to close active tab in plugin {}",
env.plugin_env.name()
)
};
let action = Action::CloseTab;
apply_action!(action, error_msg, env);
}
fn host_undo_rename_tab(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to undo rename tab in plugin {}",
env.plugin_env.name()
)
};
let action = Action::UndoRenameTab;
apply_action!(action, error_msg, env);
}
fn host_quit_zellij(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to quit zellij in plugin {}", env.plugin_env.name());
let action = Action::Quit;
apply_action!(action, error_msg, env);
}
fn host_previous_swap_layout(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to switch swap layout in plugin {}",
env.plugin_env.name()
)
};
let action = Action::PreviousSwapLayout;
apply_action!(action, error_msg, env);
}
fn host_next_swap_layout(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to switch swap layout in plugin {}",
env.plugin_env.name()
)
};
let action = Action::NextSwapLayout;
apply_action!(action, error_msg, env);
}
fn host_go_to_tab_name(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to change tab in plugin {}", env.plugin_env.name());
wasi_read_string(&env.plugin_env.wasi_env)
.and_then(|tab_name| {
let create = false;
let action = Action::GoToTabName(tab_name, create);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_focus_or_create_tab(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to change or create tab in plugin {}",
env.plugin_env.name()
)
};
wasi_read_string(&env.plugin_env.wasi_env)
.and_then(|tab_name| {
let create = true;
let action = Action::GoToTabName(tab_name, create);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
fn host_go_to_tab(env: &ForeignFunctionEnv, tab_index: i32) {
let error_msg = || {
format!(
"failed to change tab focus in plugin {}",
env.plugin_env.name()
)
};
let action = Action::GoToTab(tab_index as u32);
apply_action!(action, error_msg, env);
}
fn host_start_or_reload_plugin(env: &ForeignFunctionEnv) {
let error_msg = || {
format!(
"failed to start or reload plugin in plugin {}",
env.plugin_env.name()
)
};
wasi_read_string(&env.plugin_env.wasi_env)
.and_then(|url| Url::parse(&url).map_err(|e| anyhow!("Failed to parse url: {}", e)))
.and_then(|url| {
let action = Action::StartOrReloadPlugin(url);
apply_action!(action, error_msg, env);
Ok(())
})
.with_context(error_msg)
.fatal();
}
// Custom panic handler for plugins.
//
// This is called when a panic occurs in a plugin. Since most panics will likely originate in the

View file

@ -1,6 +1,7 @@
use std::collections::VecDeque;
use std::sync::{Arc, RwLock};
use crate::thread_bus::ThreadSenders;
use crate::{
os_input_output::ServerOsApi,
plugins::PluginInstruction,
@ -10,25 +11,29 @@ use crate::{
};
use zellij_utils::{
channels::SenderWithContext,
data::{Direction, Event, ResizeStrategy},
data::{Direction, Event, PluginCapabilities, ResizeStrategy},
errors::prelude::*,
input::{
actions::{Action, SearchDirection, SearchOption},
command::TerminalAction,
get_mode_info,
layout::RunPluginLocation,
layout::{Layout, RunPluginLocation},
},
ipc::{
ClientAttributes, ClientToServerMsg, ExitReason, IpcReceiverWithContext, ServerToClientMsg,
},
ipc::{ClientToServerMsg, ExitReason, IpcReceiverWithContext, ServerToClientMsg},
};
use crate::ClientId;
pub(crate) fn route_action(
action: Action,
session: &SessionMetaData,
_os_input: &dyn ServerOsApi,
to_server: &SenderWithContext<ServerInstruction>,
client_id: ClientId,
senders: ThreadSenders,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
default_layout: Box<Layout>,
) -> Result<bool> {
let mut should_break = false;
let err_context = || format!("failed to route action for client {client_id}");
@ -39,8 +44,7 @@ pub(crate) fn route_action(
match action {
Action::MouseHoldLeft(..) | Action::MouseHoldRight(..) => {},
_ => {
session
.senders
senders
.send_to_plugin(PluginInstruction::Update(vec![(
None,
Some(client_id),
@ -52,81 +56,69 @@ pub(crate) fn route_action(
match action {
Action::ToggleTab => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ToggleTab(client_id))
.with_context(err_context)?;
},
Action::Write(val) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ClearScroll(client_id))
.with_context(err_context)?;
session
.senders
senders
.send_to_screen(ScreenInstruction::WriteCharacter(val, client_id))
.with_context(err_context)?;
},
Action::WriteChars(val) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ClearScroll(client_id))
.with_context(err_context)?;
let val = val.into_bytes();
session
.senders
senders
.send_to_screen(ScreenInstruction::WriteCharacter(val, client_id))
.with_context(err_context)?;
},
Action::SwitchToMode(mode) => {
let attrs = &session.client_attributes;
let attrs = &client_attributes;
// TODO: use the palette from the client and remove it from the server os api
// this is left here as a stop gap measure until we shift some code around
// to allow for this
// TODO: Need access to `ClientAttributes` here
session
.senders
senders
.send_to_plugin(PluginInstruction::Update(vec![(
None,
Some(client_id),
Event::ModeUpdate(get_mode_info(mode, attrs, session.capabilities)),
Event::ModeUpdate(get_mode_info(mode, attrs, capabilities)),
)]))
.with_context(err_context)?;
session
.senders
senders
.send_to_screen(ScreenInstruction::ChangeMode(
get_mode_info(mode, attrs, session.capabilities),
get_mode_info(mode, attrs, capabilities),
client_id,
))
.with_context(err_context)?;
session
.senders
senders
.send_to_screen(ScreenInstruction::Render)
.with_context(err_context)?;
},
Action::Resize(resize, direction) => {
let screen_instr =
ScreenInstruction::Resize(client_id, ResizeStrategy::new(resize, direction));
session
.senders
senders
.send_to_screen(screen_instr)
.with_context(err_context)?;
},
Action::SwitchFocus => {
session
.senders
senders
.send_to_screen(ScreenInstruction::SwitchFocus(client_id))
.with_context(err_context)?;
},
Action::FocusNextPane => {
session
.senders
senders
.send_to_screen(ScreenInstruction::FocusNextPane(client_id))
.with_context(err_context)?;
},
Action::FocusPreviousPane => {
session
.senders
senders
.send_to_screen(ScreenInstruction::FocusPreviousPane(client_id))
.with_context(err_context)?;
},
@ -137,8 +129,7 @@ pub(crate) fn route_action(
Direction::Up => ScreenInstruction::MoveFocusUp(client_id),
Direction::Down => ScreenInstruction::MoveFocusDown(client_id),
};
session
.senders
senders
.send_to_screen(screen_instr)
.with_context(err_context)?;
},
@ -149,8 +140,7 @@ pub(crate) fn route_action(
Direction::Up => ScreenInstruction::SwitchTabNext(client_id),
Direction::Down => ScreenInstruction::SwitchTabPrev(client_id),
};
session
.senders
senders
.send_to_screen(screen_instr)
.with_context(err_context)?;
},
@ -162,109 +152,92 @@ pub(crate) fn route_action(
Some(Direction::Down) => ScreenInstruction::MovePaneDown(client_id),
None => ScreenInstruction::MovePane(client_id),
};
session
.senders
senders
.send_to_screen(screen_instr)
.with_context(err_context)?;
},
Action::MovePaneBackwards => {
session
.senders
senders
.send_to_screen(ScreenInstruction::MovePaneBackwards(client_id))
.with_context(err_context)?;
},
Action::ClearScreen => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ClearScreen(client_id))
.with_context(err_context)?;
},
Action::DumpScreen(val, full) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::DumpScreen(val, client_id, full))
.with_context(err_context)?;
},
Action::EditScrollback => {
session
.senders
senders
.send_to_screen(ScreenInstruction::EditScrollback(client_id))
.with_context(err_context)?;
},
Action::ScrollUp => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ScrollUp(client_id))
.with_context(err_context)?;
},
Action::ScrollUpAt(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ScrollUpAt(point, client_id))
.with_context(err_context)?;
},
Action::ScrollDown => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ScrollDown(client_id))
.with_context(err_context)?;
},
Action::ScrollDownAt(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ScrollDownAt(point, client_id))
.with_context(err_context)?;
},
Action::ScrollToBottom => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ScrollToBottom(client_id))
.with_context(err_context)?;
},
Action::ScrollToTop => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ScrollToTop(client_id))
.with_context(err_context)?;
},
Action::PageScrollUp => {
session
.senders
senders
.send_to_screen(ScreenInstruction::PageScrollUp(client_id))
.with_context(err_context)?;
},
Action::PageScrollDown => {
session
.senders
senders
.send_to_screen(ScreenInstruction::PageScrollDown(client_id))
.with_context(err_context)?;
},
Action::HalfPageScrollUp => {
session
.senders
senders
.send_to_screen(ScreenInstruction::HalfPageScrollUp(client_id))
.with_context(err_context)?;
},
Action::HalfPageScrollDown => {
session
.senders
senders
.send_to_screen(ScreenInstruction::HalfPageScrollDown(client_id))
.with_context(err_context)?;
},
Action::ToggleFocusFullscreen => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ToggleActiveTerminalFullscreen(client_id))
.with_context(err_context)?;
},
Action::TogglePaneFrames => {
session
.senders
senders
.send_to_screen(ScreenInstruction::TogglePaneFrames)
.with_context(err_context)?;
},
Action::NewPane(direction, name) => {
let shell = session.default_shell.clone();
let shell = default_shell.clone();
let pty_instr = match direction {
Some(Direction::Left) => {
PtyInstruction::SpawnTerminalVertically(shell, name, client_id)
@ -286,10 +259,7 @@ pub(crate) fn route_action(
ClientOrTabIndex::ClientId(client_id),
),
};
session
.senders
.send_to_pty(pty_instr)
.with_context(err_context)?;
senders.send_to_pty(pty_instr).with_context(err_context)?;
},
Action::EditFile(path_to_file, line_number, cwd, split_direction, should_float) => {
let title = format!("Editing: {}", path_to_file.display());
@ -319,27 +289,22 @@ pub(crate) fn route_action(
ClientOrTabIndex::ClientId(client_id),
),
};
session
.senders
.send_to_pty(pty_instr)
.with_context(err_context)?;
senders.send_to_pty(pty_instr).with_context(err_context)?;
},
Action::SwitchModeForAllClients(input_mode) => {
let attrs = &session.client_attributes;
session
.senders
let attrs = &client_attributes;
senders
.send_to_plugin(PluginInstruction::Update(vec![(
None,
None,
Event::ModeUpdate(get_mode_info(input_mode, attrs, session.capabilities)),
Event::ModeUpdate(get_mode_info(input_mode, attrs, capabilities)),
)]))
.with_context(err_context)?;
session
.senders
senders
.send_to_screen(ScreenInstruction::ChangeModeForAllClients(get_mode_info(
input_mode,
attrs,
session.capabilities,
capabilities,
)))
.with_context(err_context)?;
},
@ -347,9 +312,8 @@ pub(crate) fn route_action(
let should_float = true;
let run_cmd = run_command
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
.or_else(|| session.default_shell.clone());
session
.senders
.or_else(|| default_shell.clone());
senders
.send_to_pty(PtyInstruction::SpawnTerminal(
run_cmd,
Some(should_float),
@ -362,7 +326,7 @@ pub(crate) fn route_action(
let should_float = false;
let run_cmd = run_command
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
.or_else(|| session.default_shell.clone());
.or_else(|| default_shell.clone());
let pty_instr = match direction {
Some(Direction::Left) => {
PtyInstruction::SpawnTerminalVertically(run_cmd, name, client_id)
@ -384,35 +348,28 @@ pub(crate) fn route_action(
ClientOrTabIndex::ClientId(client_id),
),
};
session
.senders
.send_to_pty(pty_instr)
.with_context(err_context)?;
senders.send_to_pty(pty_instr).with_context(err_context)?;
},
Action::TogglePaneEmbedOrFloating => {
session
.senders
senders
.send_to_screen(ScreenInstruction::TogglePaneEmbedOrFloating(client_id))
.with_context(err_context)?;
},
Action::ToggleFloatingPanes => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ToggleFloatingPanes(
client_id,
session.default_shell.clone(),
default_shell.clone(),
))
.with_context(err_context)?;
},
Action::PaneNameInput(c) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::UpdatePaneName(c, client_id))
.with_context(err_context)?;
},
Action::UndoRenamePane => {
session
.senders
senders
.send_to_screen(ScreenInstruction::UndoRenamePane(client_id))
.with_context(err_context)?;
},
@ -439,14 +396,10 @@ pub(crate) fn route_action(
ClientOrTabIndex::ClientId(client_id),
),
};
session
.senders
.send_to_pty(pty_instr)
.with_context(err_context)?;
senders.send_to_pty(pty_instr).with_context(err_context)?;
},
Action::CloseFocus => {
session
.senders
senders
.send_to_screen(ScreenInstruction::CloseFocusedPane(client_id))
.with_context(err_context)?;
},
@ -457,13 +410,12 @@ pub(crate) fn route_action(
swap_floating_layouts,
tab_name,
) => {
let shell = session.default_shell.clone();
let shell = default_shell.clone();
let swap_tiled_layouts =
swap_tiled_layouts.unwrap_or_else(|| session.layout.swap_tiled_layouts.clone());
swap_tiled_layouts.unwrap_or_else(|| default_layout.swap_tiled_layouts.clone());
let swap_floating_layouts = swap_floating_layouts
.unwrap_or_else(|| session.layout.swap_floating_layouts.clone());
session
.senders
.unwrap_or_else(|| default_layout.swap_floating_layouts.clone());
senders
.send_to_screen(ScreenInstruction::NewTab(
None,
shell,
@ -476,41 +428,35 @@ pub(crate) fn route_action(
.with_context(err_context)?;
},
Action::GoToNextTab => {
session
.senders
senders
.send_to_screen(ScreenInstruction::SwitchTabNext(client_id))
.with_context(err_context)?;
},
Action::GoToPreviousTab => {
session
.senders
senders
.send_to_screen(ScreenInstruction::SwitchTabPrev(client_id))
.with_context(err_context)?;
},
Action::ToggleActiveSyncTab => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ToggleActiveSyncTab(client_id))
.with_context(err_context)?;
},
Action::CloseTab => {
session
.senders
senders
.send_to_screen(ScreenInstruction::CloseTab(client_id))
.with_context(err_context)?;
},
Action::GoToTab(i) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::GoToTab(i, Some(client_id)))
.with_context(err_context)?;
},
Action::GoToTabName(name, create) => {
let shell = session.default_shell.clone();
let swap_tiled_layouts = session.layout.swap_tiled_layouts.clone();
let swap_floating_layouts = session.layout.swap_floating_layouts.clone();
session
.senders
let shell = default_shell.clone();
let swap_tiled_layouts = default_layout.swap_tiled_layouts.clone();
let swap_floating_layouts = default_layout.swap_floating_layouts.clone();
senders
.send_to_screen(ScreenInstruction::GoToTabName(
name,
(swap_tiled_layouts, swap_floating_layouts),
@ -521,106 +467,92 @@ pub(crate) fn route_action(
.with_context(err_context)?;
},
Action::TabNameInput(c) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::UpdateTabName(c, client_id))
.with_context(err_context)?;
},
Action::UndoRenameTab => {
session
.senders
senders
.send_to_screen(ScreenInstruction::UndoRenameTab(client_id))
.with_context(err_context)?;
},
Action::Quit => {
to_server
.send(ServerInstruction::ClientExit(client_id))
senders
.send_to_server(ServerInstruction::ClientExit(client_id))
.with_context(err_context)?;
should_break = true;
},
Action::Detach => {
to_server
.send(ServerInstruction::DetachSession(vec![client_id]))
senders
.send_to_server(ServerInstruction::DetachSession(vec![client_id]))
.with_context(err_context)?;
should_break = true;
},
Action::LeftClick(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::LeftClick(point, client_id))
.with_context(err_context)?;
},
Action::RightClick(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::RightClick(point, client_id))
.with_context(err_context)?;
},
Action::MiddleClick(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::MiddleClick(point, client_id))
.with_context(err_context)?;
},
Action::LeftMouseRelease(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::LeftMouseRelease(point, client_id))
.with_context(err_context)?;
},
Action::RightMouseRelease(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::RightMouseRelease(point, client_id))
.with_context(err_context)?;
},
Action::MiddleMouseRelease(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::MiddleMouseRelease(point, client_id))
.with_context(err_context)?;
},
Action::MouseHoldLeft(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::MouseHoldLeft(point, client_id))
.with_context(err_context)?;
},
Action::MouseHoldRight(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::MouseHoldRight(point, client_id))
.with_context(err_context)?;
},
Action::MouseHoldMiddle(point) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::MouseHoldMiddle(point, client_id))
.with_context(err_context)?;
},
Action::Copy => {
session
.senders
senders
.send_to_screen(ScreenInstruction::Copy(client_id))
.with_context(err_context)?;
},
Action::Confirm => {
session
.senders
senders
.send_to_screen(ScreenInstruction::ConfirmPrompt(client_id))
.with_context(err_context)?;
},
Action::Deny => {
session
.senders
senders
.send_to_screen(ScreenInstruction::DenyPrompt(client_id))
.with_context(err_context)?;
},
#[allow(clippy::single_match)]
Action::SkipConfirm(action) => match *action {
Action::Quit => {
to_server
.send(ServerInstruction::ClientExit(client_id))
senders
.send_to_server(ServerInstruction::ClientExit(client_id))
.with_context(err_context)?;
should_break = true;
},
@ -628,8 +560,7 @@ pub(crate) fn route_action(
},
Action::NoOp => {},
Action::SearchInput(c) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::UpdateSearch(c, client_id))
.with_context(err_context)?;
},
@ -638,8 +569,7 @@ pub(crate) fn route_action(
SearchDirection::Down => ScreenInstruction::SearchDown(client_id),
SearchDirection::Up => ScreenInstruction::SearchUp(client_id),
};
session
.senders
senders
.send_to_screen(instruction)
.with_context(err_context)?;
},
@ -651,41 +581,35 @@ pub(crate) fn route_action(
SearchOption::WholeWord => ScreenInstruction::SearchToggleWholeWord(client_id),
SearchOption::Wrap => ScreenInstruction::SearchToggleWrap(client_id),
};
session
.senders
senders
.send_to_screen(instruction)
.with_context(err_context)?;
},
Action::ToggleMouseMode => {}, // Handled client side
Action::PreviousSwapLayout => {
session
.senders
senders
.send_to_screen(ScreenInstruction::PreviousSwapLayout(client_id))
.with_context(err_context)?;
},
Action::NextSwapLayout => {
session
.senders
senders
.send_to_screen(ScreenInstruction::NextSwapLayout(client_id))
.with_context(err_context)?;
},
Action::QueryTabNames => {
session
.senders
senders
.send_to_screen(ScreenInstruction::QueryTabNames(client_id))
.with_context(err_context)?;
},
Action::NewTiledPluginPane(run_plugin, name) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::NewTiledPluginPane(
run_plugin, name, client_id,
))
.with_context(err_context)?;
},
Action::NewFloatingPluginPane(run_plugin, name) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::NewFloatingPluginPane(
run_plugin, name, client_id,
))
@ -694,8 +618,7 @@ pub(crate) fn route_action(
Action::StartOrReloadPlugin(url) => {
let run_plugin_location =
RunPluginLocation::parse(url.as_str()).with_context(err_context)?;
session
.senders
senders
.send_to_screen(ScreenInstruction::StartOrReloadPluginPane(
run_plugin_location,
None,
@ -703,8 +626,7 @@ pub(crate) fn route_action(
.with_context(err_context)?;
},
Action::LaunchOrFocusPlugin(run_plugin, should_float) => {
session
.senders
senders
.send_to_screen(ScreenInstruction::LaunchOrFocusPlugin(
run_plugin,
should_float,
@ -770,10 +692,12 @@ pub(crate) fn route_thread_main(
}
if route_action(
action,
rlocked_sessions,
&*os_input,
&to_server,
client_id,
rlocked_sessions.senders.clone(),
rlocked_sessions.capabilities.clone(),
rlocked_sessions.client_attributes.clone(),
rlocked_sessions.default_shell.clone(),
rlocked_sessions.layout.clone(),
)? {
should_break = true;
}

View file

@ -1364,6 +1364,12 @@ impl Screen {
tab.change_mode_info(mode_info.clone(), client_id);
tab.mark_active_pane_for_rerender(client_id);
}
if let Some(os_input) = &mut self.bus.os_input {
let _ =
os_input.send_to_client(client_id, ServerToClientMsg::SwitchToMode(mode_info.mode));
}
Ok(())
}
pub fn change_mode_for_all_clients(&mut self, mode_info: ModeInfo) -> Result<()> {
@ -1378,10 +1384,6 @@ impl Screen {
for client_id in connected_client_ids {
self.change_mode(mode_info.clone(), client_id)
.with_context(err_context)?;
if let Some(os_input) = &mut self.bus.os_input {
let _ = os_input
.send_to_client(client_id, ServerToClientMsg::SwitchToMode(mode_info.mode));
}
}
Ok(())
}

View file

@ -99,20 +99,24 @@ fn take_snapshots_and_cursor_coordinates_from_render_events<'a>(
fn send_cli_action_to_server(
session_metadata: &SessionMetaData,
cli_action: CliAction,
mock_screen: &mut MockScreen,
client_id: ClientId,
) {
let os_input = Box::new(mock_screen.os_input.clone());
let to_server = mock_screen.to_server.clone();
let get_current_dir = || PathBuf::from(".");
let actions = Action::actions_from_cli(cli_action, Box::new(get_current_dir), None).unwrap();
let senders = session_metadata.senders.clone();
let capabilities = PluginCapabilities::default();
let client_attributes = ClientAttributes::default();
let default_shell = None;
let default_layout = Box::new(Layout::default());
for action in actions {
route_action(
action,
&session_metadata,
&*os_input,
&to_server.clone(),
client_id,
senders.clone(),
capabilities,
client_attributes.clone(),
default_shell.clone(),
default_layout.clone(),
)
.unwrap();
}
@ -1023,7 +1027,7 @@ pub fn send_cli_write_chars_action_to_screen() {
let cli_action = CliAction::WriteChars {
chars: "input from the cli".into(),
};
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![pty_writer_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -1049,7 +1053,7 @@ pub fn send_cli_write_action_to_screen() {
let cli_action = CliAction::Write {
bytes: vec![102, 111, 111],
};
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![pty_writer_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -1076,12 +1080,7 @@ pub fn send_cli_resize_action_to_screen() {
resize: Resize::Increase,
direction: Some(Direction::Left),
};
send_cli_action_to_server(
&session_metadata,
resize_cli_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, resize_cli_action, client_id);
mock_screen.teardown(vec![pty_writer_thread, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
received_server_instructions.lock().unwrap().iter(),
@ -1112,12 +1111,7 @@ pub fn send_cli_focus_next_pane_action() {
server_receiver
);
let focus_next_pane_action = CliAction::FocusNextPane;
send_cli_action_to_server(
&session_metadata,
focus_next_pane_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, focus_next_pane_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1150,12 +1144,7 @@ pub fn send_cli_focus_previous_pane_action() {
server_receiver
);
let focus_next_pane_action = CliAction::FocusPreviousPane;
send_cli_action_to_server(
&session_metadata,
focus_next_pane_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, focus_next_pane_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1190,12 +1179,7 @@ pub fn send_cli_move_focus_pane_action() {
let move_focus_action = CliAction::MoveFocus {
direction: Direction::Right,
};
send_cli_action_to_server(
&session_metadata,
move_focus_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, move_focus_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1230,12 +1214,7 @@ pub fn send_cli_move_focus_or_tab_pane_action() {
let move_focus_action = CliAction::MoveFocusOrTab {
direction: Direction::Right,
};
send_cli_action_to_server(
&session_metadata,
move_focus_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, move_focus_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1270,7 +1249,7 @@ pub fn send_cli_move_pane_action() {
let cli_action = CliAction::MovePane {
direction: Some(Direction::Right),
};
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1309,7 +1288,7 @@ pub fn send_cli_dump_screen_action() {
0,
"fill pane up with something".as_bytes().to_vec(),
));
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
assert_snapshot!(format!(
@ -1340,7 +1319,7 @@ pub fn send_cli_edit_scrollback_action() {
0,
"fill pane up with something".as_bytes().to_vec(),
));
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![pty_thread, screen_thread]);
let dumped_file_name = mock_screen
@ -1395,18 +1374,8 @@ pub fn send_cli_scroll_up_action() {
std::thread::sleep(std::time::Duration::from_millis(100));
// we send two actions here because only the last line in the pane is empty, so one action
// won't show in a render
send_cli_action_to_server(
&session_metadata,
cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, cli_action.clone(), client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1449,44 +1418,14 @@ pub fn send_cli_scroll_down_action() {
));
std::thread::sleep(std::time::Duration::from_millis(100));
// scroll up some
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
// scroll down some
send_cli_action_to_server(
&session_metadata,
scroll_down_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_down_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, scroll_down_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_down_cli_action.clone(), client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1529,36 +1468,15 @@ pub fn send_cli_scroll_to_bottom_action() {
));
std::thread::sleep(std::time::Duration::from_millis(100));
// scroll up some
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
scroll_up_cli_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id);
// scroll to bottom
send_cli_action_to_server(
&session_metadata,
scroll_to_bottom_action.clone(),
&mut mock_screen,
client_id,
);
std::thread::sleep(std::time::Duration::from_millis(100));
@ -1602,12 +1520,7 @@ pub fn send_cli_scroll_to_top_action() {
));
std::thread::sleep(std::time::Duration::from_millis(100));
// scroll to top
send_cli_action_to_server(
&session_metadata,
scroll_to_top_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, scroll_to_top_action.clone(), client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1648,12 +1561,7 @@ pub fn send_cli_page_scroll_up_action() {
pane_contents.as_bytes().to_vec(),
));
std::thread::sleep(std::time::Duration::from_millis(100));
send_cli_action_to_server(
&session_metadata,
page_scroll_up_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, page_scroll_up_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1697,26 +1605,11 @@ pub fn send_cli_page_scroll_down_action() {
std::thread::sleep(std::time::Duration::from_millis(100));
// scroll up some
send_cli_action_to_server(
&session_metadata,
page_scroll_up_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
page_scroll_up_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, page_scroll_up_action.clone(), client_id);
send_cli_action_to_server(&session_metadata, page_scroll_up_action.clone(), client_id);
// scroll down
send_cli_action_to_server(
&session_metadata,
page_scroll_down_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, page_scroll_down_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1757,12 +1650,7 @@ pub fn send_cli_half_page_scroll_up_action() {
pane_contents.as_bytes().to_vec(),
));
std::thread::sleep(std::time::Duration::from_millis(100));
send_cli_action_to_server(
&session_metadata,
half_page_scroll_up_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, half_page_scroll_up_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1809,23 +1697,16 @@ pub fn send_cli_half_page_scroll_down_action() {
send_cli_action_to_server(
&session_metadata,
half_page_scroll_up_action.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
half_page_scroll_up_action.clone(),
&mut mock_screen,
client_id,
);
// scroll down
send_cli_action_to_server(
&session_metadata,
half_page_scroll_down_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, half_page_scroll_down_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1857,12 +1738,7 @@ pub fn send_cli_toggle_full_screen_action() {
server_receiver
);
let toggle_full_screen_action = CliAction::ToggleFullscreen;
send_cli_action_to_server(
&session_metadata,
toggle_full_screen_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, toggle_full_screen_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1894,12 +1770,7 @@ pub fn send_cli_toggle_pane_frames_action() {
server_receiver
);
let toggle_pane_frames_action = CliAction::TogglePaneFrames;
send_cli_action_to_server(
&session_metadata,
toggle_pane_frames_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, toggle_pane_frames_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -1940,15 +1811,9 @@ pub fn send_cli_toggle_active_tab_sync_action() {
send_cli_action_to_server(
&session_metadata,
cli_toggle_active_tab_sync_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(
&session_metadata,
cli_write_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, cli_write_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![pty_writer_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -1984,12 +1849,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() {
close_on_exit: false,
start_suspended: false,
};
send_cli_action_to_server(
&session_metadata,
cli_new_pane_action,
&mut mock_screen,
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
mock_screen.teardown(vec![pty_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -2025,12 +1885,7 @@ pub fn send_cli_new_pane_action_with_split_direction() {
close_on_exit: false,
start_suspended: false,
};
send_cli_action_to_server(
&session_metadata,
cli_new_pane_action,
&mut mock_screen,
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
mock_screen.teardown(vec![pty_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -2066,12 +1921,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() {
close_on_exit: false,
start_suspended: false,
};
send_cli_action_to_server(
&session_metadata,
cli_new_pane_action,
&mut mock_screen,
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
mock_screen.teardown(vec![pty_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -2104,12 +1954,7 @@ pub fn send_cli_edit_action_with_default_parameters() {
floating: false,
cwd: None,
};
send_cli_action_to_server(
&session_metadata,
cli_edit_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, cli_edit_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![pty_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -2142,12 +1987,7 @@ pub fn send_cli_edit_action_with_line_number() {
floating: false,
cwd: None,
};
send_cli_action_to_server(
&session_metadata,
cli_edit_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, cli_edit_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![pty_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -2180,12 +2020,7 @@ pub fn send_cli_edit_action_with_split_direction() {
floating: false,
cwd: None,
};
send_cli_action_to_server(
&session_metadata,
cli_edit_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, cli_edit_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![pty_thread, screen_thread]);
assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap()));
@ -2207,12 +2042,7 @@ pub fn send_cli_switch_mode_action() {
let cli_switch_mode = CliAction::SwitchMode {
input_mode: InputMode::Locked,
};
send_cli_action_to_server(
&session_metadata,
cli_switch_mode,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, cli_switch_mode, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![screen_thread]);
assert_snapshot!(format!(
@ -2247,7 +2077,6 @@ pub fn send_cli_toggle_pane_embed_or_float() {
send_cli_action_to_server(
&session_metadata,
toggle_pane_embed_or_floating.clone(),
&mut mock_screen,
client_id,
);
std::thread::sleep(std::time::Duration::from_millis(100));
@ -2255,7 +2084,6 @@ pub fn send_cli_toggle_pane_embed_or_float() {
send_cli_action_to_server(
&session_metadata,
toggle_pane_embed_or_floating.clone(),
&mut mock_screen,
client_id,
);
std::thread::sleep(std::time::Duration::from_millis(100));
@ -2291,28 +2119,13 @@ pub fn send_cli_toggle_floating_panes() {
let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating;
let toggle_floating_panes = CliAction::ToggleFloatingPanes;
// float the focused pane
send_cli_action_to_server(
&session_metadata,
toggle_pane_embed_or_floating,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, toggle_pane_embed_or_floating, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
// toggle floating panes (will hide the floated pane from the previous action)
send_cli_action_to_server(
&session_metadata,
toggle_floating_panes.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, toggle_floating_panes.clone(), client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
// toggle floating panes (will show the floated pane)
send_cli_action_to_server(
&session_metadata,
toggle_floating_panes.clone(),
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, toggle_floating_panes.clone(), client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -2344,12 +2157,7 @@ pub fn send_cli_close_pane_action() {
server_receiver
);
let close_pane_action = CliAction::ClosePane;
send_cli_action_to_server(
&session_metadata,
close_pane_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, close_pane_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -2386,12 +2194,7 @@ pub fn send_cli_new_tab_action_default_params() {
layout_dir: None,
cwd: None,
};
send_cli_action_to_server(
&session_metadata,
new_tab_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, new_tab_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![plugin_thread, screen_thread]);
let received_plugin_instructions = received_plugin_instructions.lock().unwrap();
@ -2431,12 +2234,7 @@ pub fn send_cli_new_tab_action_with_name_and_layout() {
layout_dir: None,
cwd: None,
};
send_cli_action_to_server(
&session_metadata,
new_tab_action,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, new_tab_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![plugin_thread, screen_thread]);
let new_tab_instruction = received_plugin_instructions
@ -2478,12 +2276,7 @@ pub fn send_cli_next_tab_action() {
server_receiver
);
let goto_next_tab = CliAction::GoToNextTab;
send_cli_action_to_server(
&session_metadata,
goto_next_tab,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, goto_next_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -2519,12 +2312,7 @@ pub fn send_cli_previous_tab_action() {
server_receiver
);
let goto_previous_tab = CliAction::GoToPreviousTab;
send_cli_action_to_server(
&session_metadata,
goto_previous_tab,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, goto_previous_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -2560,7 +2348,7 @@ pub fn send_cli_goto_tab_action() {
server_receiver
);
let goto_tab = CliAction::GoToTab { index: 1 };
send_cli_action_to_server(&session_metadata, goto_tab, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, goto_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -2596,7 +2384,7 @@ pub fn send_cli_close_tab_action() {
server_receiver
);
let close_tab = CliAction::CloseTab;
send_cli_action_to_server(&session_metadata, close_tab, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, close_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
@ -2634,7 +2422,7 @@ pub fn send_cli_rename_tab() {
let rename_tab = CliAction::RenameTab {
name: "new-tab-name".into(),
};
send_cli_action_to_server(&session_metadata, rename_tab, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, rename_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![plugin_thread, screen_thread]);
assert_snapshot!(format!(
@ -2669,15 +2457,10 @@ pub fn send_cli_undo_rename_tab() {
};
let undo_rename_tab = CliAction::UndoRenameTab;
// first rename the tab
send_cli_action_to_server(&session_metadata, rename_tab, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, rename_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
// then undo the tab rename to go back to the default name
send_cli_action_to_server(
&session_metadata,
undo_rename_tab,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, undo_rename_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![plugin_thread, screen_thread]);
assert_snapshot!(format!(
@ -2702,12 +2485,7 @@ pub fn send_cli_query_tab_names_action() {
server_receiver
);
let query_tab_names = CliAction::QueryTabNames;
send_cli_action_to_server(
&session_metadata,
query_tab_names,
&mut mock_screen,
client_id,
);
send_cli_action_to_server(&session_metadata, query_tab_names, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
let log_tab_names_instruction = received_server_instructions
@ -2743,7 +2521,7 @@ pub fn send_cli_launch_or_focus_plugin_action() {
floating: true,
url: url::Url::parse("file:/path/to/fake/plugin").unwrap(),
};
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![plugin_thread, screen_thread]);
@ -2798,7 +2576,7 @@ pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded() {
floating: true,
url: url::Url::parse("file:/path/to/fake/plugin").unwrap(),
};
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be
mock_screen.teardown(vec![plugin_thread, server_thread, screen_thread]);

View file

@ -64,6 +64,16 @@ pub fn open_terminal_floating(path: &Path) {
unsafe { host_open_terminal_floating() };
}
pub fn open_command_pane(path: &Path, args: Vec<String>) {
object_to_stdout(&(path, args));
unsafe { host_open_command_pane() };
}
pub fn open_command_pane_floating(path: &Path, args: Vec<String>) {
object_to_stdout(&(path, args));
unsafe { host_open_command_pane_floating() };
}
pub fn switch_tab_to(tab_idx: u32) {
unsafe { host_switch_tab_to(tab_idx) };
}
@ -80,6 +90,28 @@ pub fn hide_self() {
unsafe { host_hide_self() };
}
pub fn switch_to_input_mode(mode: &InputMode) {
object_to_stdout(&mode);
unsafe { host_switch_to_mode() };
}
pub fn new_tabs_with_layout(layout: &str) {
println!("{}", layout);
unsafe { host_new_tabs_with_layout() }
}
pub fn new_tab() {
unsafe { host_new_tab() }
}
pub fn go_to_next_tab() {
unsafe { host_go_to_next_tab() }
}
pub fn go_to_previous_tab() {
unsafe { host_go_to_previous_tab() }
}
pub fn report_panic(info: &std::panic::PanicInfo) {
println!("");
println!("A panic occured in a plugin");
@ -87,6 +119,156 @@ pub fn report_panic(info: &std::panic::PanicInfo) {
unsafe { host_report_panic() };
}
pub fn resize_focused_pane(resize: Resize) {
object_to_stdout(&resize);
unsafe { host_resize() };
}
pub fn resize_focused_pane_with_direction(resize: Resize, direction: Direction) {
object_to_stdout(&(resize, direction));
unsafe { host_resize_with_direction() };
}
pub fn focus_next_pane() {
unsafe { host_focus_next_pane() };
}
pub fn focus_previous_pane() {
unsafe { host_focus_previous_pane() };
}
pub fn move_focus(direction: Direction) {
object_to_stdout(&direction);
unsafe { host_move_focus() };
}
pub fn move_focus_or_tab(direction: Direction) {
object_to_stdout(&direction);
unsafe { host_move_focus_or_tab() };
}
pub fn detach() {
unsafe { host_detach() };
}
pub fn edit_scrollback() {
unsafe { host_edit_scrollback() };
}
pub fn write(bytes: Vec<u8>) {
object_to_stdout(&bytes);
unsafe { host_write() };
}
pub fn write_chars(chars: &str) {
println!("{}", chars);
unsafe { host_write_chars() };
}
pub fn toggle_tab() {
unsafe { host_toggle_tab() };
}
pub fn move_pane() {
unsafe { host_move_pane() };
}
pub fn move_pane_with_direction(direction: Direction) {
object_to_stdout(&direction);
unsafe { host_move_pane_with_direction() };
}
pub fn clear_screen() {
unsafe { host_clear_screen() };
}
pub fn scroll_up() {
unsafe { host_scroll_up() };
}
pub fn scroll_down() {
unsafe { host_scroll_down() };
}
pub fn scroll_to_top() {
unsafe { host_scroll_to_top() };
}
pub fn scroll_to_bottom() {
unsafe { host_scroll_to_bottom() };
}
pub fn page_scroll_up() {
unsafe { host_page_scroll_up() };
}
pub fn page_scroll_down() {
unsafe { host_page_scroll_down() };
}
pub fn toggle_focus_fullscreen() {
unsafe { host_toggle_focus_fullscreen() };
}
pub fn toggle_pane_frames() {
unsafe { host_toggle_pane_frames() };
}
pub fn toggle_pane_embed_or_eject() {
unsafe { host_toggle_pane_embed_or_eject() };
}
pub fn undo_rename_pane() {
unsafe { host_undo_rename_pane() };
}
pub fn close_focus() {
unsafe { host_close_focus() };
}
pub fn toggle_active_tab_sync() {
unsafe { host_toggle_active_tab_sync() };
}
pub fn close_focused_tab() {
unsafe { host_close_focused_tab() };
}
pub fn undo_rename_tab() {
unsafe { host_undo_rename_tab() };
}
pub fn quit_zellij() {
unsafe { host_quit_zellij() };
}
pub fn previous_swap_layout() {
unsafe { host_previous_swap_layout() };
}
pub fn next_swap_layout() {
unsafe { host_next_swap_layout() };
}
pub fn go_to_tab_name(tab_name: &str) {
println!("{}", tab_name);
unsafe { host_go_to_tab_name() };
}
pub fn focus_or_create_tab(tab_name: &str) {
print!("{}", tab_name);
unsafe { host_focus_or_create_tab() };
}
pub fn go_to_tab(tab_index: i32) {
unsafe { host_go_to_tab(tab_index) };
}
pub fn start_or_reload_plugin(url: &str) {
println!("{}", url);
unsafe { host_start_or_reload_plugin() };
}
// Internal Functions
#[doc(hidden)]
@ -134,6 +316,8 @@ extern "C" {
fn host_open_file_with_line_floating();
fn host_open_terminal();
fn host_open_terminal_floating();
fn host_open_command_pane();
fn host_open_command_pane_floating();
fn host_switch_tab_to(tab_idx: u32);
fn host_set_timeout(secs: f64);
fn host_exec_cmd();
@ -141,4 +325,44 @@ extern "C" {
fn host_post_message_to();
fn host_post_message_to_plugin();
fn host_hide_self();
fn host_switch_to_mode();
fn host_new_tabs_with_layout();
fn host_new_tab();
fn host_go_to_next_tab();
fn host_go_to_previous_tab();
fn host_resize();
fn host_resize_with_direction();
fn host_focus_next_pane();
fn host_focus_previous_pane();
fn host_move_focus();
fn host_move_focus_or_tab();
fn host_detach();
fn host_edit_scrollback();
fn host_write();
fn host_write_chars();
fn host_toggle_tab();
fn host_move_pane();
fn host_move_pane_with_direction();
fn host_clear_screen();
fn host_scroll_up();
fn host_scroll_down();
fn host_scroll_to_top();
fn host_scroll_to_bottom();
fn host_page_scroll_up();
fn host_page_scroll_down();
fn host_toggle_focus_fullscreen();
fn host_toggle_pane_frames();
fn host_toggle_pane_embed_or_eject();
fn host_undo_rename_pane();
fn host_close_focus();
fn host_toggle_active_tab_sync();
fn host_close_focused_tab();
fn host_undo_rename_tab();
fn host_quit_zellij();
fn host_previous_swap_layout();
fn host_next_swap_layout();
fn host_go_to_tab_name();
fn host_focus_or_create_tab();
fn host_go_to_tab(tab_index: i32);
fn host_start_or_reload_plugin();
}

View file

@ -10,6 +10,19 @@ pub enum TerminalAction {
RunCommand(RunCommand),
}
impl TerminalAction {
pub fn change_cwd(&mut self, new_cwd: PathBuf) {
match self {
TerminalAction::OpenFile(_, _, cwd) => {
*cwd = Some(new_cwd);
},
TerminalAction::RunCommand(run_command) => {
run_command.cwd = Some(new_cwd);
},
}
}
}
#[derive(Clone, Debug, Deserialize, Default, Serialize, PartialEq, Eq)]
pub struct RunCommand {
#[serde(alias = "cmd")]
@ -69,6 +82,19 @@ impl From<RunCommandAction> for RunCommand {
}
}
impl From<RunCommand> for RunCommandAction {
fn from(run_command: RunCommand) -> Self {
RunCommandAction {
command: run_command.command,
args: run_command.args,
cwd: run_command.cwd,
direction: None,
hold_on_close: run_command.hold_on_close,
hold_on_start: run_command.hold_on_start,
}
}
}
impl RunCommand {
pub fn new(command: PathBuf) -> Self {
RunCommand {