diff options
Diffstat (limited to 'default-plugins/strider/src/main.rs')
-rw-r--r-- | default-plugins/strider/src/main.rs | 224 |
1 files changed, 110 insertions, 114 deletions
diff --git a/default-plugins/strider/src/main.rs b/default-plugins/strider/src/main.rs index 1ad2e70ce..ce9a5273a 100644 --- a/default-plugins/strider/src/main.rs +++ b/default-plugins/strider/src/main.rs @@ -1,121 +1,122 @@ +mod file_list_view; +mod search_view; +mod shared; mod state; -use colored::*; -use state::{refresh_directory, FsEntry, State}; +use crate::file_list_view::FsEntry; +use shared::{render_current_path, render_instruction_line, render_search_term}; +use state::{refresh_directory, State}; use std::collections::BTreeMap; -use std::{cmp::min, time::Instant}; +use std::path::PathBuf; use zellij_tile::prelude::*; register_plugin!(State); impl ZellijPlugin for State { - fn load(&mut self, _configuration: BTreeMap<String, String>) { - refresh_directory(self); + fn load(&mut self, configuration: BTreeMap<String, String>) { + let plugin_ids = get_plugin_ids(); + self.initial_cwd = plugin_ids.initial_cwd; + let show_hidden_files = configuration + .get("show_hidden_files") + .map(|v| v == "true") + .unwrap_or(false); + self.hide_hidden_files = !show_hidden_files; + self.close_on_selection = configuration + .get("close_on_selection") + .map(|v| v == "true") + .unwrap_or(false); subscribe(&[ EventType::Key, EventType::Mouse, EventType::CustomMessage, EventType::Timer, + EventType::FileSystemUpdate, ]); + self.file_list_view.reset_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); + }, + None => { + refresh_directory(&std::path::Path::new("/")); + }, + } } fn update(&mut self, event: Event) -> bool { let mut should_render = false; - let prev_event = if self.ev_history.len() == 2 { - self.ev_history.pop_front() - } else { - None - }; - self.ev_history.push_back((event.clone(), Instant::now())); match event { + Event::FileSystemUpdate(paths) => { + self.update_files(paths); + should_render = true; + }, Event::Key(key) => match key { - Key::Esc => { - hide_self(); + Key::Char(character) if character != '\n' => { + self.update_search_term(character); should_render = true; }, - Key::Up | Key::Char('k') => { - let currently_selected = self.selected(); - *self.selected_mut() = self.selected().saturating_sub(1); - if currently_selected != self.selected() { - should_render = true; - } + Key::Backspace => { + self.handle_backspace(); + should_render = true; }, - 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; - } + Key::Esc | Key::Ctrl('c') => { + self.clear_search_term_or_descend(); + should_render = true; }, - Key::Right | Key::Char('\n') | Key::Char('l') if !self.files.is_empty() => { - self.traverse_dir_or_open_file(); - self.ev_history.clear(); + Key::Up => { + self.move_selection_up(); should_render = true; }, - Key::Left | Key::Char('h') => { - if self.path.components().count() > 2 { - // don't descend into /host - // the reason this is a hard-coded number (2) and not "== ROOT" - // or some such is that there are certain cases in which self.path - // is empty and this will work then too - should_render = true; - self.path.pop(); - refresh_directory(self); - } + Key::Down => { + self.move_selection_down(); + should_render = true; + }, + Key::Char('\n') if self.handling_filepick_request_from.is_some() => { + self.send_filepick_response(); + }, + Key::Char('\n') => { + self.open_selected_path(); + }, + Key::Right | Key::BackTab => { + self.traverse_dir(); + should_render = true; + }, + Key::Left => { + self.descend_to_previous_path(); + should_render = true; }, - Key::Char('.') => { + Key::Ctrl('e') => { should_render = true; self.toggle_hidden_files(); - refresh_directory(self); + refresh_directory(&self.file_list_view.path); }, - _ => (), }, Event::Mouse(mouse_event) => match mouse_event { 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; - } + self.move_selection_down(); + should_render = true; }, Mouse::ScrollUp(_) => { - let currently_selected = self.selected(); - *self.selected_mut() = self.selected().saturating_sub(1); - if currently_selected != self.selected() { - should_render = true; - } + self.move_selection_up(); + should_render = true; }, - Mouse::Release(line, _) => { - if line < 0 { - return should_render; - } - let mut should_select = true; - if let Some((Event::Mouse(Mouse::Release(prev_line, _)), t)) = prev_event { - if prev_line == line - && Instant::now().saturating_duration_since(t).as_millis() < 400 - { - self.traverse_dir_or_open_file(); - self.ev_history.clear(); - should_select = false; - should_render = true; - } - } - if should_select && self.scroll() + (line as usize) < self.files.len() { - let currently_selected = self.selected(); - *self.selected_mut() = self.scroll() + (line as usize); - if currently_selected != self.selected() { - should_render = true; - } - } + Mouse::LeftClick(line, _) => { + self.handle_left_click(line); + should_render = true; }, _ => {}, }, @@ -125,42 +126,37 @@ 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); + } + self.handling_filepick_request_from = Some((pipe_message.source, pipe_message.args)); + true + } else { + false + } + } 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(); - } - if self.selected() - self.scroll() + 2 > rows { - *self.scroll_mut() = self.selected() + 2 - rows; - } - - let is_last_row = i == rows.saturating_sub(1); - let i = self.scroll() + i; - if let Some(entry) = self.files.get(i) { - let mut path = entry.as_line(cols).normal(); - - if let FsEntry::Dir(..) = entry { - path = path.dimmed().bold(); - } - - if i == self.selected() { - if is_last_row { - print!("{}", path.clone().reversed()); - } else { - println!("{}", path.clone().reversed()); - } - } else { - if is_last_row { - print!("{}", path); - } else { - println!("{}", path); - } - } - } else if !is_last_row { - println!(); - } + 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(), + cols, + ); + if self.is_searching { + self.search_view.render(rows_for_list, cols); + } else { + self.file_list_view.render(rows_for_list, cols); } + render_instruction_line(rows, cols); } } |