From 6340b5e312cd4c52fa7a967b44aa331253c64779 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Wed, 28 Feb 2024 16:12:12 +0100 Subject: fix(plugins): respect cwd and start filepicker at filesystem root (#3161) * allow padding cwd to plugins * improve strider performance and fix alias cwd issue * style(fmt): rustfmt --- .../fixture-plugin-for-tests/src/main.rs | 5 + default-plugins/strider/src/main.rs | 7 + default-plugins/strider/src/state.rs | 48 +++--- zellij-server/src/plugins/mod.rs | 12 +- zellij-server/src/plugins/plugin_map.rs | 2 + zellij-server/src/plugins/unit/plugin_tests.rs | 163 +++++++++++++++++++++ ...__plugin_tests__run_plugin_in_specific_cwd.snap | 12 ++ ...gins__plugin_tests__start_or_reload_plugin.snap | 3 +- zellij-server/src/unit/screen_tests.rs | 4 + ...ts__send_cli_launch_or_focus_plugin_action.snap | 3 +- zellij-utils/assets/config/default.kdl | 4 +- zellij-utils/src/input/actions.rs | 5 + zellij-utils/src/input/layout.rs | 40 ++++- zellij-utils/src/input/plugins.rs | 5 + zellij-utils/src/input/unit/layout_test.rs | 9 ++ ...an_load_swap_layouts_from_a_different_file.snap | 8 +- zellij-utils/src/kdl/kdl_layout_parser.rs | 8 +- zellij-utils/src/kdl/mod.rs | 43 +++--- zellij-utils/src/plugin_api/action.rs | 2 + ...st__default_config_with_no_cli_arguments-2.snap | 16 ++ ...test__default_config_with_no_cli_arguments.snap | 10 ++ ...__layout_env_vars_override_config_env_vars.snap | 10 ++ ...__layout_keybinds_override_config_keybinds.snap | 11 +- ...test__layout_themes_override_config_themes.snap | 12 +- ...ayout_ui_config_overrides_config_ui_config.snap | 10 ++ 25 files changed, 397 insertions(+), 55 deletions(-) create mode 100644 zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_plugin_in_specific_cwd.snap diff --git a/default-plugins/fixture-plugin-for-tests/src/main.rs b/default-plugins/fixture-plugin-for-tests/src/main.rs index fe740f740..0da45a2f4 100644 --- a/default-plugins/fixture-plugin-for-tests/src/main.rs +++ b/default-plugins/fixture-plugin-for-tests/src/main.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +use std::io::prelude::*; use zellij_tile::prelude::*; // This is a fixture plugin used only for tests in Zellij @@ -300,6 +301,10 @@ impl ZellijPlugin for State { LayoutInfo::BuiltIn("compact".to_owned()), ); }, + Key::Ctrl('8') => { + let mut file = std::fs::File::create("/host/hi-from-plugin.txt").unwrap(); + file.write_all(b"Hi there!").unwrap(); + }, _ => {}, }, Event::CustomMessage(message, payload) => { diff --git a/default-plugins/strider/src/main.rs b/default-plugins/strider/src/main.rs index 2e06240af..1ad2e70ce 100644 --- a/default-plugins/strider/src/main.rs +++ b/default-plugins/strider/src/main.rs @@ -43,6 +43,9 @@ impl ZellijPlugin for State { Key::Down | Key::Char('j') => { let currently_selected = self.selected(); let next = self.selected().saturating_add(1); + if next >= self.files.len() { + refresh_directory(self); + } *self.selected_mut() = min(self.files.len().saturating_sub(1), next); if currently_selected != self.selected() { should_render = true; @@ -76,6 +79,9 @@ impl ZellijPlugin for State { Mouse::ScrollDown(_) => { let currently_selected = self.selected(); let next = self.selected().saturating_add(1); + if next >= self.files.len() { + refresh_directory(self); + } *self.selected_mut() = min(self.files.len().saturating_sub(1), next); if currently_selected != self.selected() { should_render = true; @@ -121,6 +127,7 @@ impl ZellijPlugin for State { } fn render(&mut self, rows: usize, cols: usize) { + self.current_rows = Some(rows); for i in 0..rows { if self.selected() < self.scroll() { *self.scroll_mut() = self.selected(); diff --git a/default-plugins/strider/src/state.rs b/default-plugins/strider/src/state.rs index be4ede4b6..230e92ea8 100644 --- a/default-plugins/strider/src/state.rs +++ b/default-plugins/strider/src/state.rs @@ -19,6 +19,7 @@ pub struct State { pub loading: bool, pub loading_animation_offset: u8, pub should_open_floating: bool, + pub current_rows: Option, } impl State { @@ -40,7 +41,7 @@ impl State { pub fn traverse_dir_or_open_file(&mut self) { if let Some(f) = self.files.get(self.selected()) { match f.clone() { - FsEntry::Dir(p, _) => { + FsEntry::Dir(p) => { self.path = p; refresh_directory(self); }, @@ -55,14 +56,14 @@ impl State { #[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] pub enum FsEntry { - Dir(PathBuf, usize), + Dir(PathBuf), File(PathBuf, u64), } impl FsEntry { pub fn name(&self) -> String { let path = match self { - FsEntry::Dir(p, _) => p, + FsEntry::Dir(p) => p, FsEntry::File(p, _) => p, }; path.file_name().unwrap().to_string_lossy().into_owned() @@ -70,7 +71,7 @@ impl FsEntry { pub fn as_line(&self, width: usize) -> String { let info = match self { - FsEntry::Dir(_, s) => s.to_string(), + FsEntry::Dir(_s) => "".to_owned(), FsEntry::File(_, s) => pb::convert(*s as f64), }; let space = width.saturating_sub(info.len()); @@ -89,22 +90,27 @@ impl FsEntry { } pub(crate) fn refresh_directory(state: &mut State) { - state.files = read_dir(Path::new(ROOT).join(&state.path)) - .unwrap() - .filter_map(|res| { - res.and_then(|d| { - if d.metadata()?.is_dir() { - let children = read_dir(d.path())?.count(); - Ok(FsEntry::Dir(d.path(), children)) - } else { - let size = d.metadata()?.len(); - Ok(FsEntry::File(d.path(), size)) - } - }) - .ok() - .filter(|d| !d.is_hidden_file() || !state.hide_hidden_files) - }) - .collect(); - + // TODO: might be good to do this asynchronously with a worker + let mut max_lines = (state.current_rows.unwrap_or(50) + state.scroll()) * 2; // 100 is arbitrary for performance reasons + let mut files = vec![]; + for entry in read_dir(Path::new(ROOT).join(&state.path)).unwrap() { + if let Ok(entry) = entry { + if max_lines == 0 { + break; + } + let entry_metadata = entry.metadata().unwrap(); + let entry = if entry_metadata.is_dir() { + FsEntry::Dir(entry.path()) + } else { + let size = entry_metadata.len(); + FsEntry::File(entry.path(), size) + }; + if !entry.is_hidden_file() || !state.hide_hidden_files { + max_lines = max_lines.saturating_sub(1); + files.push(entry); + } + } + } + state.files = files; state.files.sort_unstable(); } diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index 80a590453..e09364432 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -217,6 +217,7 @@ pub(crate) fn plugin_thread_main( skip_cache, ) => { run_plugin_or_alias.populate_run_plugin_if_needed(&plugin_aliases); + let cwd = run_plugin_or_alias.get_initial_cwd().or(cwd); let run_plugin = run_plugin_or_alias.get_run_plugin(); match wasm_bridge.load_plugin( &run_plugin, @@ -363,12 +364,15 @@ pub(crate) fn plugin_thread_main( for run_instruction in extracted_run_instructions { if let Some(Run::Plugin(run_plugin_or_alias)) = run_instruction { let run_plugin = run_plugin_or_alias.get_run_plugin(); + let cwd = run_plugin_or_alias + .get_initial_cwd() + .or_else(|| cwd.clone()); let skip_cache = false; let (plugin_id, _client_id) = wasm_bridge.load_plugin( &run_plugin, Some(tab_index), size, - None, + cwd, skip_cache, Some(client_id), None, @@ -537,7 +541,6 @@ pub(crate) fn plugin_thread_main( source_plugin_id, message, } => { - let cwd = message.new_plugin_args.as_ref().and_then(|n| n.cwd.clone()); let mut pipe_messages = vec![]; let skip_cache = message .new_plugin_args @@ -564,7 +567,7 @@ pub(crate) fn plugin_thread_main( PipeSource::Plugin(source_plugin_id), &plugin_url, &Some(message.plugin_config), - &cwd, + &None, skip_cache, should_float, &pane_id_to_replace.map(|p| p.into()), @@ -698,10 +701,11 @@ fn pipe_to_specific_plugins( cwd.clone(), ) { Ok(run_plugin_or_alias) => { + let initial_cwd = run_plugin_or_alias.get_initial_cwd(); let all_plugin_ids = wasm_bridge.get_or_load_plugins( run_plugin_or_alias, size, - cwd.clone(), + initial_cwd.or_else(|| cwd.clone()), skip_cache, should_float, pane_id_to_replace.is_some(), diff --git a/zellij-server/src/plugins/plugin_map.rs b/zellij-server/src/plugins/plugin_map.rs index e03cf1728..1d30596ec 100644 --- a/zellij-server/src/plugins/plugin_map.rs +++ b/zellij-server/src/plugins/plugin_map.rs @@ -246,10 +246,12 @@ impl PluginMap { .plugin .userspace_configuration .clone(); + let initial_cwd = running_plugin.plugin_env.plugin.initial_cwd.clone(); Some(RunPlugin { _allow_exec_host_cmd: false, location: run_plugin_location, configuration: run_plugin_configuration, + initial_cwd, }) } else { None diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index 07212c3b3..8fa262474 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -571,6 +571,7 @@ pub fn load_new_plugin_from_hd() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -650,6 +651,7 @@ pub fn load_new_plugin_with_plugin_alias() { name: "fixture_plugin_for_tests".to_owned(), configuration: Default::default(), run_plugin: None, + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -725,6 +727,7 @@ pub fn plugin_workers() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -804,6 +807,7 @@ pub fn plugin_workers_persist_state() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -893,6 +897,7 @@ pub fn can_subscribe_to_hd_events() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -970,6 +975,7 @@ pub fn switch_to_mode_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1041,6 +1047,7 @@ pub fn switch_to_mode_plugin_command_permission_denied() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1112,6 +1119,7 @@ pub fn new_tabs_with_layout_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1197,6 +1205,7 @@ pub fn new_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1268,6 +1277,7 @@ pub fn go_to_next_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1338,6 +1348,7 @@ pub fn go_to_previous_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1408,6 +1419,7 @@ pub fn resize_focused_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1478,6 +1490,7 @@ pub fn resize_focused_pane_with_direction_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1548,6 +1561,7 @@ pub fn focus_next_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1618,6 +1632,7 @@ pub fn focus_previous_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1688,6 +1703,7 @@ pub fn move_focus_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1758,6 +1774,7 @@ pub fn move_focus_or_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1828,6 +1845,7 @@ pub fn edit_scrollback_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1898,6 +1916,7 @@ pub fn write_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -1968,6 +1987,7 @@ pub fn write_chars_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2038,6 +2058,7 @@ pub fn toggle_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2108,6 +2129,7 @@ pub fn move_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2178,6 +2200,7 @@ pub fn move_pane_with_direction_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2248,6 +2271,7 @@ pub fn clear_screen_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2319,6 +2343,7 @@ pub fn scroll_up_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2390,6 +2415,7 @@ pub fn scroll_down_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2460,6 +2486,7 @@ pub fn scroll_to_top_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2530,6 +2557,7 @@ pub fn scroll_to_bottom_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2600,6 +2628,7 @@ pub fn page_scroll_up_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2670,6 +2699,7 @@ pub fn page_scroll_down_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2740,6 +2770,7 @@ pub fn toggle_focus_fullscreen_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2810,6 +2841,7 @@ pub fn toggle_pane_frames_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2880,6 +2912,7 @@ pub fn toggle_pane_embed_or_eject_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -2950,6 +2983,7 @@ pub fn undo_rename_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3020,6 +3054,7 @@ pub fn close_focus_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3090,6 +3125,7 @@ pub fn toggle_active_tab_sync_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3160,6 +3196,7 @@ pub fn close_focused_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3230,6 +3267,7 @@ pub fn undo_rename_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3300,6 +3338,7 @@ pub fn previous_swap_layout_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3370,6 +3409,7 @@ pub fn next_swap_layout_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3440,6 +3480,7 @@ pub fn go_to_tab_name_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3510,6 +3551,7 @@ pub fn focus_or_create_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3580,6 +3622,7 @@ pub fn go_to_tab() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3650,6 +3693,7 @@ pub fn start_or_reload_plugin() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3720,6 +3764,7 @@ pub fn quit_zellij_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3797,6 +3842,7 @@ pub fn detach_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3874,6 +3920,7 @@ pub fn open_file_floating_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -3955,6 +4002,7 @@ pub fn open_file_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4036,6 +4084,7 @@ pub fn open_file_with_line_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4118,6 +4167,7 @@ pub fn open_file_with_line_floating_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4199,6 +4249,7 @@ pub fn open_terminal_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4276,6 +4327,7 @@ pub fn open_terminal_floating_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4353,6 +4405,7 @@ pub fn open_command_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4430,6 +4483,7 @@ pub fn open_command_pane_floating_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4507,6 +4561,7 @@ pub fn switch_to_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4577,6 +4632,7 @@ pub fn hide_self_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4647,6 +4703,7 @@ pub fn show_self_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4716,6 +4773,7 @@ pub fn close_terminal_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4786,6 +4844,7 @@ pub fn close_plugin_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4856,6 +4915,7 @@ pub fn focus_terminal_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4926,6 +4986,7 @@ pub fn focus_plugin_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -4996,6 +5057,7 @@ pub fn rename_terminal_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5066,6 +5128,7 @@ pub fn rename_plugin_pane_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5136,6 +5199,7 @@ pub fn rename_tab_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5215,6 +5279,7 @@ pub fn send_configuration_to_plugins() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: PluginUserConfiguration::new(configuration), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5286,6 +5351,7 @@ pub fn request_plugin_permissions() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5352,6 +5418,7 @@ pub fn granted_permission_request_result() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5442,6 +5509,7 @@ pub fn denied_permission_request_result() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5526,6 +5594,7 @@ pub fn run_command_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5603,6 +5672,7 @@ pub fn run_command_with_env_vars_and_cwd_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5680,6 +5750,7 @@ pub fn web_request_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5757,6 +5828,7 @@ pub fn unblock_input_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5838,6 +5910,7 @@ pub fn block_input_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -5920,6 +5993,7 @@ pub fn pipe_output_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -6009,6 +6083,7 @@ pub fn pipe_message_to_plugin_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -6095,6 +6170,7 @@ pub fn switch_session_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -6175,6 +6251,7 @@ pub fn switch_session_with_layout_plugin_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -6255,6 +6332,7 @@ pub fn disconnect_other_clients_plugins_command() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), + ..Default::default() }); let tab_index = 1; let client_id = 1; @@ -6319,3 +6397,88 @@ pub fn disconnect_other_clients_plugins_command() { .clone(); assert_snapshot!(format!("{:#?}", switch_session_event)); } + +#[test] +#[ignore] +pub fn run_plugin_in_specific_cwd() { + // note that this test might sometimes fail when run alone without the rest of the suite due to + // timing issues + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let cache_path = plugin_host_folder.join("permissions_test.kdl"); + let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = + create_plugin_thread_with_server_receiver(Some(plugin_host_folder.clone())); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let plugin_initial_cwd = plugin_host_folder.join("custom_plugin_cwd"); + let _ = std::fs::create_dir_all(&plugin_initial_cwd); + let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + configuration: Default::default(), + initial_cwd: Some(plugin_initial_cwd.clone()), + }); + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( + received_screen_instructions, + ScreenInstruction::Exit, + screen_receiver, + 1, + &PermissionType::ChangeApplicationState, + cache_path, + plugin_thread_sender, + client_id + ); + let received_server_instruction = Arc::new(Mutex::new(vec![])); + let server_thread = log_actions_in_thread!( + received_server_instruction, + ServerInstruction::ClientExit, + server_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + false, + plugin_title, + run_plugin, + tab_index, + None, + client_id, + size, + None, + false, + )); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('8')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(500)); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('8')), // this sends this quit command so tha the test exits cleanly + )])); + teardown(); + server_thread.join().unwrap(); // this might take a while if the cache is cold + assert!( + std::fs::read_dir(plugin_initial_cwd) + .unwrap() + .map(|d| d.unwrap().path().to_string_lossy().to_string()) + .collect::>() + .join(",") + .contains("hi-from-plugin.txt"), + "File written into plugin initial cwd" + ); +} diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_plugin_in_specific_cwd.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_plugin_in_specific_cwd.snap new file mode 100644 index 000000000..c66b2f328 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_plugin_in_specific_cwd.snap @@ -0,0 +1,12 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 6481 +expression: "format!(\"{:#?}\", std :: fs :: read_dir(plugin_initial_cwd).unwrap().collect ::\n < Vec < _ >> ())" +--- +[ + Ok( + DirEntry( + "/tmp/.tmpvA1zie/custom_plugin_cwd/foo.txt", + ), + ), +] diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap index a55b17ecf..4c444a1fa 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/plugins/./unit/plugin_tests.rs -assertion_line: 3700 +assertion_line: 3749 expression: "format!(\"{:#?}\", new_tab_event)" --- Some( @@ -14,6 +14,7 @@ Some( configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), None, diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 64b1e188f..50df6a293 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -2999,6 +2999,7 @@ pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from("/path/to/fake/plugin")), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }; @@ -3079,6 +3080,7 @@ pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded_for_ _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from("/path/to/fake/plugin")), configuration: Default::default(), + ..Default::default() }), ..Default::default() }))), @@ -3348,6 +3350,7 @@ pub fn screen_can_break_plugin_pane_to_a_new_tab() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from("/path/to/fake/plugin")), configuration: Default::default(), + ..Default::default() }))); let mut pane_to_stay = TiledPaneLayout::default(); pane_to_stay.name = Some("pane_to_stay".to_owned()); @@ -3418,6 +3421,7 @@ pub fn screen_can_break_floating_plugin_pane_to_a_new_tab() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from("/path/to/fake/plugin")), configuration: Default::default(), + ..Default::default() }))); let mut floating_panes_layout = vec![floating_pane]; initial_layout.children_split_direction = SplitDirection::Vertical; diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap index 56b466ed0..cd58c620a 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2758 +assertion_line: 2983 expression: "format!(\"{:#?}\", pty_fill_plugin_cwd_instruction)" --- Some( @@ -19,6 +19,7 @@ Some( configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), 0, diff --git a/zellij-utils/assets/config/default.kdl b/zellij-utils/assets/config/default.kdl index c8e61bf43..f3decbc9e 100644 --- a/zellij-utils/assets/config/default.kdl +++ b/zellij-utils/assets/config/default.kdl @@ -194,7 +194,9 @@ plugins { welcome-screen location="zellij:session-manager" { welcome_screen true } - filepicker location="zellij:strider" + filepicker location="zellij:strider" { + cwd "/" + } } // Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 18ed0a8da..c71a8ca68 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -348,6 +348,9 @@ impl Action { height, } => { let current_dir = get_current_dir(); + // cwd should only be specified in a plugin alias if it was explicitly given to us, + // otherwise the current_dir might override a cwd defined in the alias itself + let alias_cwd = cwd.clone().map(|cwd| current_dir.join(cwd)); let cwd = cwd .map(|cwd| current_dir.join(cwd)) .or_else(|| Some(current_dir)); @@ -359,11 +362,13 @@ impl Action { _allow_exec_host_cmd: false, location, configuration: user_configuration, + initial_cwd: cwd.clone(), }) }, Err(_) => RunPluginOrAlias::Alias(PluginAlias::new( &plugin, &configuration.map(|c| c.inner().clone()), + alias_cwd, )), }; if floating { diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index ad2fca896..82da8cbf0 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -108,12 +108,18 @@ impl RunPluginOrAlias { .aliases .get(run_plugin_alias.name.as_str()) .map(|r| { - r.clone().merge_configuration( + let mut merged_run_plugin = r.clone().merge_configuration( &run_plugin_alias .configuration .as_ref() .map(|c| c.inner().clone()), - ) + ); + // if the alias has its own cwd, it should always override the alias + // value's cwd + if run_plugin_alias.initial_cwd.is_some() { + merged_run_plugin.initial_cwd = run_plugin_alias.initial_cwd.clone(); + } + merged_run_plugin }); run_plugin_alias.run_plugin = merged_run_plugin; } @@ -127,6 +133,9 @@ impl RunPluginOrAlias { pub fn get_configuration(&self) -> Option { self.get_run_plugin().map(|r| r.configuration.clone()) } + pub fn get_initial_cwd(&self) -> Option { + self.get_run_plugin().and_then(|r| r.initial_cwd.clone()) + } pub fn from_url( url: &str, configuration: &Option>, @@ -141,10 +150,11 @@ impl RunPluginOrAlias { .as_ref() .map(|c| PluginUserConfiguration::new(c.clone())) .unwrap_or_default(), + ..Default::default() })), Err(PluginsConfigError::InvalidUrlScheme(_)) | Err(PluginsConfigError::InvalidUrl(..)) => { - let mut plugin_alias = PluginAlias::new(&url, configuration); + let mut plugin_alias = PluginAlias::new(&url, configuration, None); if let Some(alias_dict) = alias_dict { plugin_alias.run_plugin = alias_dict .aliases @@ -190,6 +200,17 @@ impl RunPluginOrAlias { _ => false, } } + pub fn with_initial_cwd(mut self, initial_cwd: Option) -> Self { + match self { + RunPluginOrAlias::RunPlugin(ref mut run_plugin) => { + run_plugin.initial_cwd = initial_cwd; + }, + RunPluginOrAlias::Alias(ref mut alias) => { + alias.initial_cwd = initial_cwd; + }, + } + self + } } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] @@ -365,6 +386,7 @@ pub struct RunPlugin { pub _allow_exec_host_cmd: bool, pub location: RunPluginLocation, pub configuration: PluginUserConfiguration, + pub initial_cwd: Option, } impl RunPlugin { @@ -379,6 +401,10 @@ impl RunPlugin { self.configuration = PluginUserConfiguration::new(configuration); self } + pub fn with_initial_cwd(mut self, initial_cwd: Option) -> Self { + self.initial_cwd = initial_cwd; + self + } pub fn merge_configuration(mut self, configuration: &Option>) -> Self { if let Some(configuration) = configuration { self.configuration.merge(configuration); @@ -391,16 +417,22 @@ impl RunPlugin { pub struct PluginAlias { pub name: String, pub configuration: Option, + pub initial_cwd: Option, pub run_plugin: Option, } impl PluginAlias { - pub fn new(name: &str, configuration: &Option>) -> Self { + pub fn new( + name: &str, + configuration: &Option>, + initial_cwd: Option, + ) -> Self { PluginAlias { name: name.to_owned(), configuration: configuration .as_ref() .map(|c| PluginUserConfiguration::new(c.clone())), + initial_cwd, ..Default::default() } } diff --git a/zellij-utils/src/input/plugins.rs b/zellij-utils/src/input/plugins.rs index cb3d68916..eabdd3e84 100644 --- a/zellij-utils/src/input/plugins.rs +++ b/zellij-utils/src/input/plugins.rs @@ -40,6 +40,8 @@ pub struct PluginConfig { pub location: RunPluginLocation, /// Custom configuration for this plugin pub userspace_configuration: PluginUserConfiguration, + /// plugin initial working directory + pub initial_cwd: Option, } impl PluginConfig { @@ -51,6 +53,7 @@ impl PluginConfig { _allow_exec_host_cmd: run_plugin._allow_exec_host_cmd, location: run_plugin.location.clone(), userspace_configuration: run_plugin.configuration.clone(), + initial_cwd: run_plugin.initial_cwd.clone(), }), RunPluginLocation::Zellij(tag) => { let tag = tag.to_string(); @@ -67,6 +70,7 @@ impl PluginConfig { location: RunPluginLocation::parse(&format!("zellij:{}", tag), None) .ok()?, userspace_configuration: run_plugin.configuration.clone(), + initial_cwd: run_plugin.initial_cwd.clone(), }) } else { None @@ -78,6 +82,7 @@ impl PluginConfig { _allow_exec_host_cmd: run_plugin._allow_exec_host_cmd, location: run_plugin.location.clone(), userspace_configuration: run_plugin.configuration.clone(), + initial_cwd: run_plugin.initial_cwd.clone(), }), } } diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs index b2070ce1e..808d38465 100644 --- a/zellij-utils/src/input/unit/layout_test.rs +++ b/zellij-utils/src/input/unit/layout_test.rs @@ -555,6 +555,7 @@ fn layout_with_plugin_panes() { location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), _allow_exec_host_cmd: false, configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -565,6 +566,7 @@ fn layout_with_plugin_panes() { )), _allow_exec_host_cmd: false, configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -573,6 +575,7 @@ fn layout_with_plugin_panes() { location: RunPluginLocation::Zellij(PluginTag::new("status-bar")), _allow_exec_host_cmd: false, configuration: PluginUserConfiguration(expected_plugin_configuration), + ..Default::default() }))), ..Default::default() }, @@ -2094,6 +2097,7 @@ fn run_plugin_location_parsing() { _allow_exec_host_cmd: false, location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -2104,6 +2108,7 @@ fn run_plugin_location_parsing() { "/path/to/my/plugin.wasm", )), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -2112,6 +2117,7 @@ fn run_plugin_location_parsing() { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from("plugin.wasm")), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -2122,6 +2128,7 @@ fn run_plugin_location_parsing() { "relative/with space/plugin.wasm", )), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -2132,6 +2139,7 @@ fn run_plugin_location_parsing() { "/absolute/with space/plugin.wasm", )), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, @@ -2142,6 +2150,7 @@ fn run_plugin_location_parsing() { "c:/absolute/windows/plugin.wasm", )), configuration: Default::default(), + ..Default::default() }))), ..Default::default() }, diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap index abfd8801b..605b099f6 100644 --- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/input/./unit/layout_test.rs -assertion_line: 1935 +assertion_line: 1938 expression: "format!(\"{:#?}\", layout)" --- Layout { @@ -76,6 +76,7 @@ Layout { configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), ), @@ -180,6 +181,7 @@ Layout { configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), ), @@ -235,6 +237,7 @@ Layout { configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), ), @@ -404,6 +407,7 @@ Layout { configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), ), @@ -459,6 +463,7 @@ Layout { configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), ), @@ -709,6 +714,7 @@ Layout { configuration: PluginUserConfiguration( {}, ), + initial_cwd: None, }, ), ), diff --git a/zellij-utils/src/kdl/kdl_layout_parser.rs b/zellij-utils/src/kdl/kdl_layout_parser.rs index 2aa3ba572..1a53308e6 100644 --- a/zellij-utils/src/kdl/kdl_layout_parser.rs +++ b/zellij-utils/src/kdl/kdl_layout_parser.rs @@ -314,11 +314,14 @@ impl<'a> KdlLayoutParser<'a> { ), )?; let configuration = KdlLayoutParser::parse_plugin_user_configuration(&plugin_block)?; + let initial_cwd = + kdl_get_string_property_or_child_value!(&plugin_block, "cwd").map(|s| PathBuf::from(s)); + let cwd = self.cwd_prefix(initial_cwd.as_ref())?; let run_plugin_or_alias = RunPluginOrAlias::from_url( &string_url, &Some(configuration.inner().clone()), None, - self.cwd_prefix(None)?, + cwd.clone(), ) .map_err(|e| { ConfigError::new_kdl_error( @@ -326,7 +329,8 @@ impl<'a> KdlLayoutParser<'a> { url_node.span().offset(), url_node.span().len(), ) - })?; + })? + .with_initial_cwd(cwd); Ok(Some(Run::Plugin(run_plugin_or_alias))) } pub fn parse_plugin_user_configuration( diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index 23d7e69ea..69abe52a0 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -247,6 +247,22 @@ macro_rules! kdl_children { }; } +#[macro_export] +macro_rules! kdl_get_string_property_or_child_value { + ( $kdl_node:expr, $name:expr ) => { + $kdl_node + .get($name) + .and_then(|e| e.value().as_string()) + .or_else(|| { + $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)) + .and_then(|c| c.value().as_string()) + }) + }; +} + #[macro_export] macro_rules! kdl_string_arguments { ( $kdl_node:expr ) => {{ @@ -982,6 +998,8 @@ impl TryFrom<(&KdlNode, &Options)> for Action { .unwrap_or(false); let current_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); let configuration = KdlLayoutParser::parse_plugin_user_configuration(&kdl_action)?; + let initial_cwd = kdl_get_string_property_or_child_value!(kdl_action, "cwd") + .map(|s| PathBuf::from(s)); let run_plugin_or_alias = RunPluginOrAlias::from_url( &plugin_path, &Some(configuration.inner().clone()), @@ -994,7 +1012,8 @@ impl TryFrom<(&KdlNode, &Options)> for Action { kdl_action.span().offset(), kdl_action.span().len(), ) - })?; + })? + .with_initial_cwd(initial_cwd); Ok(Action::LaunchOrFocusPlugin( run_plugin_or_alias, should_float, @@ -1327,22 +1346,6 @@ macro_rules! kdl_get_bool_property_or_child_value_with_error { }; } -#[macro_export] -macro_rules! kdl_get_string_property_or_child_value { - ( $kdl_node:expr, $name:expr ) => { - $kdl_node - .get($name) - .and_then(|e| e.value().as_string()) - .or_else(|| { - $kdl_node - .children() - .and_then(|c| c.get($name)) - .and_then(|c| c.get(0)) - .and_then(|c| c.value().as_string()) - }) - }; -} - #[macro_export] macro_rules! kdl_property_or_child_value_node { ( $kdl_node:expr, $name:expr ) => { @@ -1851,8 +1854,12 @@ impl PluginAliases { { let configuration = KdlLayoutParser::parse_plugin_user_configuration(&alias_definition)?; + let mut initial_cwd = + kdl_get_string_property_or_child_value!(alias_definition, "cwd") + .map(|s| PathBuf::from(s)); let run_plugin = RunPlugin::from_url(string_url)? - .with_configuration(configuration.inner().clone()); + .with_configuration(configuration.inner().clone()) + .with_initial_cwd(initial_cwd); aliases.insert(alias_name.to_owned(), run_plugin); } } diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index 5673d1f9a..1c35c8548 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -556,6 +556,7 @@ impl TryFrom for Action { location: run_plugin_location, _allow_exec_host_cmd: false, configuration: PluginUserConfiguration::default(), + ..Default::default() }); let pane_name = payload.pane_name; let skip_plugin_cache = payload.skip_plugin_cache; @@ -579,6 +580,7 @@ impl TryFrom for Action { location: run_plugin_location, _allow_exec_host_cmd: false, configuration: PluginUserConfiguration::default(), + ..Default::default() }); let pane_name = payload.pane_name; let skip_plugin_cache = payload.skip_plugin_cache; diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap index ade6b1168..6b6471ee0 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap @@ -31,6 +31,7 @@ Layout { {}, ), ), + initial_cwd: None, run_plugin: None, }, ), @@ -81,6 +82,7 @@ Layout { {}, ), ), + initial_cwd: None, run_plugin: None,