aboutsummaryrefslogtreecommitdiffstats
path: root/default-plugins
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2025-07-15 10:27:43 +0200
committerGitHub <noreply@github.com>2025-07-15 10:27:43 +0200
commitd4f5975527868d1bcc980e0d149be9aefd4efc34 (patch)
treeeb96b817d29f3cd4f346d1a579644c30b286678d /default-plugins
parentfix: populate layount metadata with the right cmd and cwd (#4287) (diff)
downloadsl0ppij-d4f5975527868d1bcc980e0d149be9aefd4efc34.tar.gz
sl0ppij-d4f5975527868d1bcc980e0d149be9aefd4efc34.tar.xz
sl0ppij-d4f5975527868d1bcc980e0d149be9aefd4efc34.zip
fix(plugins): forward CWD when opening new panes (#4290)
* use plugin cwd as last focused pane cwd when starting plugins * fix strider to use the new change_host_folder method * start terminals in same cwd as plugin pane if focused * style(fmt): rustfmt
Diffstat (limited to 'default-plugins')
-rw-r--r--default-plugins/strider/src/file_list_view.rs58
-rw-r--r--default-plugins/strider/src/main.rs37
-rw-r--r--default-plugins/strider/src/shared.rs21
-rw-r--r--default-plugins/strider/src/state.rs17
4 files changed, 76 insertions, 57 deletions
diff --git a/default-plugins/strider/src/file_list_view.rs b/default-plugins/strider/src/file_list_view.rs
index ccbbe292..a5a0bfa9 100644
--- a/default-plugins/strider/src/file_list_view.rs
+++ b/default-plugins/strider/src/file_list_view.rs
@@ -2,7 +2,7 @@ use crate::shared::{calculate_list_bounds, render_list_tip};
use crate::state::{refresh_directory, ROOT};
use pretty_bytes::converter::convert as pretty_bytes;
use std::collections::HashMap;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use unicode_width::UnicodeWidthStr;
use zellij_tile::prelude::*;
@@ -18,7 +18,7 @@ impl Default for FileListView {
fn default() -> Self {
FileListView {
path_is_dir: true,
- path: Default::default(),
+ path: PathBuf::new(),
files: Default::default(),
cursor_hist: Default::default(),
}
@@ -27,30 +27,48 @@ impl Default for FileListView {
impl FileListView {
pub fn descend_to_previous_path(&mut self) {
- self.path.pop();
+ if let Some(parent) = self.path.parent() {
+ self.path = parent.to_path_buf();
+ } else {
+ self.path = PathBuf::new();
+ }
self.path_is_dir = true;
self.files.clear();
self.clear_selected();
refresh_directory(&self.path);
}
- pub fn descend_to_root_path(&mut self) {
- self.path.clear();
+
+ pub fn descend_to_root_path(&mut self, initial_cwd: &PathBuf) {
+ self.path = initial_cwd.clone();
self.path_is_dir = true;
self.files.clear();
self.clear_selected();
- refresh_directory(&self.path);
}
+
pub fn enter_dir(&mut self, entry: &FsEntry) {
let is_dir = entry.is_folder();
- let path = entry.get_pathbuf_without_root_prefix();
+ let path = entry.get_full_pathbuf();
self.path = path;
self.path_is_dir = is_dir;
self.files.clear();
self.clear_selected();
}
+
pub fn clear_selected(&mut self) {
self.cursor_hist.remove(&self.path);
}
+
+ pub fn get_relative_path(&self) -> PathBuf {
+ if let Some(initial_cwd_part) = self.path.iter().next() {
+ self.path
+ .strip_prefix(initial_cwd_part)
+ .unwrap_or(&self.path)
+ .to_path_buf()
+ } else {
+ PathBuf::new()
+ }
+ }
+
pub fn update_files(
&mut self,
paths: Vec<(PathBuf, Option<FileMetadata>)>,
@@ -58,8 +76,11 @@ impl FileListView {
) {
let mut files = vec![];
for (entry, entry_metadata) in paths {
+ let entry = self
+ .path
+ .join(entry.strip_prefix("/host").unwrap_or(&entry));
if entry_metadata.map(|e| e.is_symlink).unwrap_or(false) {
- continue; // ignore symlinks
+ continue;
}
let entry = if entry_metadata.map(|e| e.is_dir).unwrap_or(false) {
FsEntry::Dir(entry)
@@ -74,20 +95,25 @@ impl FileListView {
self.files = files;
self.files.sort_unstable();
}
+
pub fn get_selected_entry(&self) -> Option<FsEntry> {
self.selected().and_then(|f| self.files.get(f).cloned())
}
+
pub fn selected_mut(&mut self) -> &mut usize {
self.cursor_hist.entry(self.path.clone()).or_default()
}
+
pub fn selected(&self) -> Option<usize> {
self.cursor_hist.get(&self.path).copied()
}
+
pub fn move_selection_up(&mut self) {
if let Some(selected) = self.selected() {
*self.selected_mut() = selected.saturating_sub(1);
}
}
+
pub fn move_selection_down(&mut self) {
if let Some(selected) = self.selected() {
let next = selected.saturating_add(1);
@@ -96,6 +122,7 @@ impl FileListView {
*self.selected_mut() = 0;
}
}
+
pub fn render(&mut self, rows: usize, cols: usize) {
let (start_index, selected_index_in_range, end_index) =
calculate_list_bounds(self.files.len(), rows.saturating_sub(1), self.selected());
@@ -121,7 +148,6 @@ impl FileListView {
);
format!("{}{}{}", file_or_folder_name, padding, size)
} else {
- // drop the size, no room for it
let padding = " ".repeat(cols.saturating_sub(file_or_folder_name_width));
format!("{}{}", file_or_folder_name, padding)
};
@@ -159,12 +185,14 @@ impl FsEntry {
};
path.file_name().unwrap().to_string_lossy().into_owned()
}
+
pub fn size(&self) -> Option<u64> {
match self {
FsEntry::Dir(_p) => None,
FsEntry::File(_, size) => Some(*size),
}
}
+
pub fn get_pathbuf_without_root_prefix(&self) -> PathBuf {
match self {
FsEntry::Dir(p) => p
@@ -178,14 +206,18 @@ impl FsEntry {
}
}
+ pub fn get_full_pathbuf(&self) -> PathBuf {
+ match self {
+ FsEntry::Dir(p) => p.clone(),
+ FsEntry::File(p, _) => p.clone(),
+ }
+ }
+
pub fn is_hidden_file(&self) -> bool {
self.name().starts_with('.')
}
pub fn is_folder(&self) -> bool {
- match self {
- FsEntry::Dir(_) => true,
- _ => false,
- }
+ matches!(self, FsEntry::Dir(_))
}
}
diff --git a/default-plugins/strider/src/main.rs b/default-plugins/strider/src/main.rs
index cd9dda4d..d770e495 100644
--- a/default-plugins/strider/src/main.rs
+++ b/default-plugins/strider/src/main.rs
@@ -31,29 +31,24 @@ impl ZellijPlugin for State {
EventType::CustomMessage,
EventType::Timer,
EventType::FileSystemUpdate,
+ EventType::HostFolderChanged,
+ EventType::PermissionRequestResult,
]);
self.file_list_view.clear_selected();
- // the caller_cwd might be different from the initial_cwd if this plugin was defined as an
- // alias, with access to a certain part of the file system (often broader) and was called
- // from an individual pane somewhere inside this broad scope - in this case, we want to
- // start in the same cwd as the caller, giving them the full access we were granted
- match configuration
- .get("caller_cwd")
- .map(|c| PathBuf::from(c))
- .and_then(|c| {
- c.strip_prefix(&self.initial_cwd)
- .ok()
- .map(|c| PathBuf::from(c))
- }) {
- Some(relative_caller_path) => {
- let relative_caller_path = FsEntry::Dir(relative_caller_path.to_path_buf());
- self.file_list_view.enter_dir(&relative_caller_path);
- refresh_directory(&self.file_list_view.path);
+
+ match configuration.get("caller_cwd").map(|c| PathBuf::from(c)) {
+ Some(caller_cwd) => {
+ self.file_list_view.path = caller_cwd;
},
None => {
- refresh_directory(&std::path::Path::new("/"));
+ self.file_list_view.path = self.initial_cwd.clone();
},
}
+ if self.initial_cwd != self.file_list_view.path {
+ change_host_folder(self.file_list_view.path.clone());
+ } else {
+ scan_host_folder(&"/host");
+ }
}
fn update(&mut self, event: Event) -> bool {
@@ -63,6 +58,10 @@ impl ZellijPlugin for State {
self.update_files(paths);
should_render = true;
},
+ Event::HostFolderChanged(new_host_folder) => {
+ scan_host_folder(&"/host");
+ should_render = true;
+ },
Event::Key(key) => match key.bare_key {
BareKey::Char(character) if key.has_no_modifiers() => {
self.update_search_term(character);
@@ -137,11 +136,10 @@ impl ZellijPlugin for State {
};
should_render
}
+
fn pipe(&mut self, pipe_message: PipeMessage) -> bool {
if pipe_message.is_private && pipe_message.name == "filepicker" {
if let PipeSource::Cli(pipe_id) = &pipe_message.source {
- // here we block the cli pipe input because we want it to wait until the user chose
- // a file
#[cfg(target_family = "wasm")]
block_cli_pipe_input(pipe_id);
}
@@ -157,7 +155,6 @@ impl ZellijPlugin for State {
let rows_for_list = rows.saturating_sub(6);
render_search_term(&self.search_term);
render_current_path(
- &self.initial_cwd,
&self.file_list_view.path,
self.file_list_view.path_is_dir,
self.handling_filepick_request_from.is_some(),
diff --git a/default-plugins/strider/src/shared.rs b/default-plugins/strider/src/shared.rs
index c51cb312..19728034 100644
--- a/default-plugins/strider/src/shared.rs
+++ b/default-plugins/strider/src/shared.rs
@@ -31,7 +31,6 @@ pub fn render_list_tip(y: usize, max_cols: usize) {
print_text_with_coordinates(tip, 0, y, Some(max_cols), None);
}
-// returns the list (start_index, selected_index_in_range, end_index)
pub fn calculate_list_bounds(
result_count: usize,
max_result_count: usize,
@@ -48,17 +47,17 @@ pub fn calculate_list_bounds(
break;
}
if !alternate && start_index > 0 {
- start_index -= 1;
- room_in_list -= 1;
+ start_index = start_index.saturating_sub(1);
+ room_in_list = room_in_list.saturating_sub(1);
} else if alternate && end_index < result_count {
end_index += 1;
- room_in_list -= 1;
+ room_in_list = room_in_list.saturating_sub(1);
} else if start_index > 0 {
- start_index -= 1;
- room_in_list -= 1;
+ start_index = start_index.saturating_sub(1);
+ room_in_list = room_in_list.saturating_sub(1);
} else if end_index < result_count {
end_index += 1;
- room_in_list -= 1;
+ room_in_list = room_in_list.saturating_sub(1);
} else {
break;
}
@@ -80,15 +79,13 @@ pub fn render_search_term(search_term: &str) {
}
pub fn render_current_path(
- initial_cwd: &PathBuf,
- path: &PathBuf,
+ full_path: &PathBuf,
path_is_dir: bool,
handling_filepick: bool,
max_cols: usize,
) {
let prompt = "PATH: ";
- let current_path = initial_cwd.join(path);
- let current_path = current_path.display().to_string();
+ let current_path = full_path.display().to_string();
let prompt_len = prompt.width();
let current_path_len = current_path.width();
@@ -118,7 +115,7 @@ pub fn render_current_path(
current_path
} else {
truncate_path(
- initial_cwd.join(path),
+ full_path.clone(),
current_path_len.saturating_sub(max_path_len),
)
};
diff --git a/default-plugins/strider/src/state.rs b/default-plugins/strider/src/state.rs
index 0bf5b268..93c6cf1b 100644
--- a/default-plugins/strider/src/state.rs
+++ b/default-plugins/strider/src/state.rs
@@ -16,7 +16,7 @@ pub struct State {
pub hide_hidden_files: bool,
pub current_rows: Option<usize>,
pub handling_filepick_request_from: Option<(PipeSource, BTreeMap<String, String>)>,
- pub initial_cwd: PathBuf, // TODO: get this from zellij
+ pub initial_cwd: PathBuf,
pub is_searching: bool,
pub search_term: String,
pub close_on_selection: bool,
@@ -137,7 +137,7 @@ impl State {
pub fn descend_to_root_path(&mut self) {
self.search_term.clear();
self.search_view.clear_and_reset_selection();
- self.file_list_view.descend_to_root_path();
+ self.file_list_view.descend_to_root_path(&self.initial_cwd);
refresh_directory(&self.file_list_view.path);
}
pub fn toggle_hidden_files(&mut self) {
@@ -214,13 +214,7 @@ impl State {
}
}
pub fn send_filepick_response(&mut self) {
- let selected_path = self.initial_cwd.join(
- self.file_list_view
- .path
- .strip_prefix(ROOT)
- .map(|p| p.to_path_buf())
- .unwrap_or_else(|_| self.file_list_view.path.clone()),
- );
+ let selected_path = &self.file_list_view.path;
match &self.handling_filepick_request_from {
Some((PipeSource::Plugin(plugin_id), args)) => {
pipe_message_to_plugin(
@@ -245,7 +239,6 @@ impl State {
}
}
-pub(crate) fn refresh_directory(path: &Path) {
- let path_on_host = Path::new(ROOT).join(path.strip_prefix("/").unwrap_or(path));
- scan_host_folder(&path_on_host);
+pub(crate) fn refresh_directory(full_path: &Path) {
+ change_host_folder(PathBuf::from(full_path));
}