diff options
-rw-r--r-- | src/completion.rs | 12 | ||||
-rw-r--r-- | src/event_exec.rs | 59 | ||||
-rw-r--r-- | src/preview.rs | 195 | ||||
-rw-r--r-- | src/status.rs | 38 | ||||
-rw-r--r-- | src/tab.rs | 111 | ||||
-rw-r--r-- | src/term_manager.rs | 42 | ||||
-rw-r--r-- | src/trees.rs | 66 |
7 files changed, 176 insertions, 347 deletions
diff --git a/src/completion.rs b/src/completion.rs index fca4559..38ed615 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -4,7 +4,6 @@ use anyhow::Result; use strum::IntoEnumIterator; use crate::fileinfo::PathContent; -use crate::preview::ColoredTriplet; /// Different kind of completions #[derive(Clone, Default, Copy)] @@ -216,13 +215,18 @@ impl Completion { pub fn search_from_tree( &mut self, input_string: &str, - content: &[ColoredTriplet], + content: &[&std::ffi::OsStr], ) -> Result<()> { self.update( content .iter() - .filter(|(_, _, s)| s.text.contains(input_string)) - .map(|(_, _, s)| s.text.replace("▸ ", "").replace("▾ ", "")) + .filter(|&p| p.to_string_lossy().contains(input_string)) + .map(|p| { + p.to_string_lossy() + .into_owned() + .replace("▸ ", "") + .replace("▾ ", "") + }) .collect(), ); diff --git a/src/event_exec.rs b/src/event_exec.rs index 6117a63..611f896 100644 --- a/src/event_exec.rs +++ b/src/event_exec.rs @@ -73,18 +73,14 @@ impl EventAction { let tab = status.selected_non_mut(); match tab.mode { - Mode::Normal => { - let Some(file) = tab.path_content.selected() else { + Mode::Normal | Mode::Tree => { + let Ok(file) = tab.selected() else { return Ok(()); }; let path = file.path.clone(); status.toggle_flag_on_path(&path); status.selected().down_one_row(); } - Mode::Tree => { - let path = tab.directory.tree.current_node.filepath(); - status.toggle_flag_on_path(&path); - } _ => (), } Ok(()) @@ -378,7 +374,7 @@ impl EventAction { /// Basic folders (/, /dev... $HOME) and mount points (even impossible to /// visit ones) are proposed. pub fn shortcut(tab: &mut Tab) -> Result<()> { - std::env::set_current_dir(tab.current_directory_path())?; + std::env::set_current_dir(tab.current_directory_path().context("no parent")?)?; tab.shortcut.update_git_root(); tab.set_mode(Mode::Navigate(Navigate::Shortcut)); Ok(()) @@ -396,7 +392,7 @@ impl EventAction { }; let nvim_server = status.nvim_server.clone(); if status.flagged.is_empty() { - let Some(fileinfo) = status.selected_non_mut().selected() else { + let Ok(fileinfo) = status.selected_non_mut().selected() else { return Ok(()); }; let Some(path_str) = fileinfo.path.to_str() else { @@ -460,7 +456,7 @@ impl EventAction { log_line!("{DEFAULT_DRAGNDROP} must be installed."); return Ok(()); } - let Some(file) = status.selected_non_mut().selected() else { + let Ok(file) = status.selected_non_mut().selected() else { return Ok(()); }; let path_str = file @@ -539,7 +535,7 @@ impl EventAction { let tab = status.selected(); match tab.mode { Mode::Normal => tab.move_to_parent()?, - Mode::Tree => tab.tree_select_parent()?, + Mode::Tree => tab.tree_select_parent(), Mode::InputSimple(_) | Mode::InputCompleted(_) => { tab.input.cursor_left(); } @@ -556,7 +552,11 @@ impl EventAction { match tab.mode { Mode::Normal => LeaveMode::open_file(status), Mode::Tree => { - tab.select_first_child()?; + if tab.tree.selected_path().is_file() { + tab.tree_select_next()?; + } else { + LeaveMode::open_file(status)?; + }; status.update_second_pane_for_preview() } Mode::InputSimple(_) | Mode::InputCompleted(_) => { @@ -799,7 +799,7 @@ impl EventAction { return Ok(()); } if let Mode::Normal | Mode::Tree = tab.mode { - let Some(file_info) = tab.selected() else { + let Ok(file_info) = tab.selected() else { return Ok(()); }; info!("selected {:?}", file_info); @@ -1099,7 +1099,11 @@ impl Display for NodeCreation { impl NodeCreation { fn create(&self, tab: &mut Tab) -> Result<()> { let root_path = match tab.previous_mode { - Mode::Tree => tab.directory.tree.directory_of_selected()?.to_owned(), + Mode::Tree => tab + .tree + .directory_of_selected() + .context("no parent")? + .to_owned(), _ => tab.path_content.path.clone(), }; log::info!("root_path: {root_path:?}"); @@ -1137,6 +1141,9 @@ impl LeaveMode { /// Open the file with configured opener or enter the directory. pub fn open_file(status: &mut Status) -> Result<()> { let tab = status.selected(); + if matches!(tab.mode, Mode::Tree) { + return EventAction::open_file(status); + }; if tab.path_content.is_empty() { return Ok(()); } @@ -1292,15 +1299,15 @@ impl LeaveMode { /// We only try to rename in the same directory, so it shouldn't be a problem. /// Filename is sanitized before processing. pub fn rename(tab: &mut Tab) -> Result<()> { - let fileinfo = match tab.previous_mode { - Mode::Tree => &tab.directory.tree.current_node.fileinfo, - _ => tab - .path_content + let original_path = if let Mode::Tree = tab.mode { + tab.tree.selected_path() + } else { + tab.path_content .selected() - .context("rename: couldnt parse selected")?, + .context("rename: couldn't parse selected file")? + .path + .as_path() }; - - let original_path = &fileinfo.path; if let Some(parent) = original_path.parent() { let new_path = parent.join(sanitize_filename::sanitize(tab.input.string())); info!( @@ -1438,17 +1445,10 @@ impl LeaveMode { status.update_second_pane_for_preview() } + // TODO! enter the tree if it's a directory /// Execute the selected node if it's a file else enter the directory. pub fn tree(status: &mut Status) -> Result<()> { - let tab = status.selected(); - let node = tab.directory.tree.current_node.clone(); - if !node.is_dir { - EventAction::open_file(status) - } else { - tab.set_pathcontent(&node.filepath())?; - tab.make_tree(None)?; - Ok(()) - } + EventAction::open_file(status) } /// Store a password of some kind (sudo or device passphrase). @@ -1548,6 +1548,7 @@ impl LeaveMode { let (username, hostname, remote_path) = (strings[0], strings[1], strings[2]); let current_path: &str = tab .current_directory_path() + .context("no parent")? .to_str() .context("couldn't parse the path")?; let first_arg = &format!("{username}@{hostname}:{remote_path}"); diff --git a/src/preview.rs b/src/preview.rs index 89d656d..221bf2c 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -24,7 +24,9 @@ use crate::decompress::{list_files_tar, list_files_zip}; use crate::fileinfo::{FileInfo, FileKind}; use crate::filter::FilterKind; use crate::opener::execute_and_capture_output_without_check; -use crate::tree::{ColoredString, Tree}; +use crate::sort::SortKind; +use crate::tree::ColoredString; +use crate::trees::FileSystem; use crate::users::Users; use crate::utils::{clear_tmp_file, filename_from_path, is_program_in_path}; @@ -114,19 +116,11 @@ impl Preview { /// Creates a new `Directory` from the file_info /// It explores recursivelly the directory and creates a tree. /// The recursive exploration is limited to depth 2. - pub fn directory( - file_info: &FileInfo, - users: &Users, - filter: &FilterKind, - show_hidden: bool, - ) -> Result<Self> { + pub fn directory(file_info: &FileInfo, users: &Users) -> Result<Self> { Ok(Self::Directory(Directory::new( - &file_info.path, + file_info.path.to_owned(), users, - filter, - show_hidden, - Some(2), - )?)) + ))) } /// Creates a new preview instance based on the filekind and the extension of @@ -1049,181 +1043,34 @@ impl ColoredText { #[derive(Clone, Debug)] pub struct Directory { pub content: Vec<ColoredTriplet>, - pub tree: Tree, - len: usize, - pub selected_index: usize, } impl Directory { - /// Creates a new tree view of the directory. - /// We only hold the result here, since the tree itself has now usage atm. - pub fn new( - path: &Path, - users: &Users, - filter_kind: &FilterKind, - show_hidden: bool, - max_depth: Option<usize>, - ) -> Result<Self> { - let max_depth = match max_depth { - Some(max_depth) => max_depth, - None => Tree::MAX_DEPTH, - }; + pub fn new(path: PathBuf, users: &Users) -> Self { + let tree = FileSystem::new( + path, + 4, + SortKind::tree_default(), + users, + false, + &FilterKind::All, + ); - let mut tree = Tree::from_path(path, max_depth, users, filter_kind, show_hidden, vec![0])?; - tree.select_root(); - let (selected_index, content) = tree.into_navigable_content(); - Ok(Self { - tree, - len: content.len(), - content, - selected_index, - }) - } + let (_selected_index, content) = tree.into_navigable_content(users); - /// Creates an empty directory preview. - pub fn empty(path: &Path, users: &Users) -> Result<Self> { - Ok(Self { - tree: Tree::empty(path, users)?, - len: 0, - content: vec![], - selected_index: 0, - }) + Self { content } } - /// Reset the attributes to default one and free some unused memory. - pub fn clear(&mut self) { - self.len = 0; - self.content = vec![]; - self.selected_index = 0; - self.tree.clear(); + pub fn empty() -> Self { + Self { content: vec![] } } - /// Number of displayed lines. pub fn len(&self) -> usize { - self.len + self.content.len() } - /// True if there's no lines in preview. pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Select the root node and reset the view. - pub fn select_root(&mut self) -> Result<()> { - self.tree.select_root(); - (self.selected_index, self.content) = self.tree.into_navigable_content(); - self.update_tree_position_from_index()?; - Ok(()) - } - - /// Unselect every child node. - pub fn unselect_children(&mut self) { - self.tree.unselect_children() - } - - /// Select the "next" element of the tree if any. - /// This is the element immediatly below the current one. - pub fn select_next(&mut self) -> Result<()> { - if self.selected_index < self.content.len() { - self.tree.increase_required_height(); - self.unselect_children(); - self.selected_index += 1; - self.update_tree_position_from_index()?; - } - Ok(()) - } - - /// Select the previous sibling if any. - /// This is the element immediatly below the current one. - pub fn select_prev(&mut self) -> Result<()> { - if self.selected_index > 0 { - self.tree.decrease_required_height(); - self.unselect_children(); - self.selected_index -= 1; - self.update_tree_position_from_index()?; - } - Ok(()) - } - - /// Move up 10 times. - pub fn page_up(&mut self) -> Result<()> { - if self.selected_index > 10 { - self.selected_index -= 10; - } else { - self.selected_index = 1; - } - self.update_tree_position_from_index() - } - - /// Move down 10 times - pub fn page_down(&mut self) -> Result<()> { - self.selected_index += 10; - if self.selected_index > self.content.len() { - if !self.content.is_empty() { - self.selected_index = self.content.len(); - } else { - self.selected_index = 1; - } - } - self.update_tree_position_from_index() - } - - /// Update the position of the selected element from its index. - pub fn update_tree_position_from_index(&mut self) -> Result<()> { - self.tree.position = self.tree.position_from_index(self.selected_index); - let (_, _, node) = self.tree.select_from_position()?; - self.tree.current_node = node; - (_, self.content) = self.tree.into_navigable_content(); - Ok(()) - } - - /// Select the first child, if any. - pub fn select_first_child(&mut self) -> Result<()> { - self.tree.select_first_child()?; - (self.selected_index, self.content) = self.tree.into_navigable_content(); - self.update_tree_position_from_index()?; - Ok(()) - } - - /// Select the parent of current node. - pub fn select_parent(&mut self) -> Result<()> { - self.tree.select_parent()?; - (self.selected_index, self.content) = self.tree.into_navigable_content(); - self.update_tree_position_from_index()?; - Ok(()) - } - - /// Select the last leaf of the tree (ie the last line.) - pub fn go_to_bottom_leaf(&mut self) -> Result<()> { - self.tree.go_to_bottom_leaf()?; - (self.selected_index, self.content) = self.tree.into_navigable_content(); - self.update_tree_position_from_index()?; - Ok(()) - } - - /// Make a preview of the tree. - pub fn make_preview(&mut self) { - (self.selected_index, self.content) = self.tree.into_navigable_content(); - } - - /// Calculates the top, bottom and lenght of the view, depending on which element - /// is selected and the size of the window used to display. - pub fn calculate_tree_window(&self, terminal_height: usize) -> (usize, usize, usize) { - let length = self.content.len(); - - let top: usize; - let bottom: usize; - let window_height = terminal_height - ContentWindow::WINDOW_MARGIN_TOP; - if self.selected_index < terminal_height - 1 { - top = 0; - bottom = window_height; - } else { - let padding = std::cmp::max(10, terminal_height / 2); - top = self.selected_index - padding; - bottom = top + window_height; - } - - (top, bottom, length) + self.content.is_empty() } } diff --git a/src/status.rs b/src/status.rs index 9fe1871..341585c 100644 --- a/src/status.rs +++ b/src/status.rs @@ -32,7 +32,7 @@ use crate::password::{ drop_sudo_privileges, execute_sudo_command_with_password, reset_sudo_faillock, PasswordHolder, PasswordKind, PasswordUsage, }; -use crate::preview::{Directory, Preview}; +use crate::preview::Preview; use crate::removable_devices::RemovableDevices; use crate::selectable_content::SelectableContent; use crate::shell_menu::ShellMenu; @@ -408,9 +408,9 @@ impl Status { let dest = match self.selected_non_mut().previous_mode { Mode::Tree => self .selected_non_mut() - .directory .tree - .directory_of_selected()? + .directory_of_selected() + .context("no parent")? .display() .to_string(), _ => self @@ -582,9 +582,7 @@ impl Status { /// Drop the current tree, replace it with an empty one. pub fn remove_tree(&mut self) -> Result<()> { - let path = self.selected_non_mut().path_content.path.clone(); - let users = &self.selected_non_mut().users; - self.selected().directory = Directory::empty(&path, users)?; + self.selected().tree = FileSystem::empty(); Ok(()) } @@ -598,12 +596,12 @@ impl Status { if self.selected_non_mut().path_content.is_empty() { return Ok(()); } - let Some(file_info) = self.selected_non_mut().selected() else { + let Ok(file_info) = self.selected_non_mut().selected() else { return Ok(()); }; match file_info.file_kind { FileKind::NormalFile => { - let preview = Preview::file(file_info).unwrap_or_default(); + let preview = Preview::file(&file_info).unwrap_or_default(); self.selected().set_mode(Mode::Preview); self.selected().window.reset(preview.len()); self.selected().preview = preview; @@ -652,13 +650,8 @@ impl Status { .selected() .context("force preview: No file to select")?; let preview = match fileinfo.file_kind { - FileKind::Directory => Preview::directory( - fileinfo, - &self.tabs[0].users, - &self.tabs[0].filter, - self.tabs[0].show_hidden, - ), - _ => Preview::file(fileinfo), + FileKind::Directory => Preview::directory(&fileinfo, &self.tabs[0].users), + _ => Preview::file(&fileinfo), }; self.tabs[1].preview = preview.unwrap_or_default(); @@ -691,17 +684,16 @@ impl Status { /// Open a the selected file with its opener pub fn open_selected_file(&mut self) -> Result<()> { - let filepath = &self - .selected_non_mut() - .selected() - .context("Empty directory")? - .path - .clone(); - let opener = self.opener.open_info(filepath); + let filepath = if matches!(self.selected_non_mut().mode, Mode::Tree) { + self.selected_non_mut().tree.selected_path().to_owned() + } else { + self.selected_non_mut().selected()?.path.to_owned() + }; + let opener = self.opener.open_info(&filepath); if let Some(InternalVariant::NotSupported) = opener.internal_variant.as_ref() { self.mount_iso_drive()?; } else { - match self.opener.open(filepath) { + match self.opener.open(&filepath) { Ok(_) => (), Err(e) => info!( "Error opening {:?}: {:?}", @@ -13,13 +13,13 @@ use crate::history::History; use crate::input::Input; use crate::mode::{InputSimple, Mode}; use crate::opener::execute_in_child; -use crate::preview::{Directory, Preview}; +use crate::preview::Preview; use crate::selectable_content::SelectableContent; use crate::shortcut::Shortcut; use crate::sort::SortKind; -use crate::trees::FileSystem; +use crate::trees::{calculate_tree_window, FileSystem}; use crate::users::Users; -use crate::utils::{filename_from_path, row_to_window_index, set_clipboard}; +use crate::utils::{row_to_window_index, set_clipboard}; /// Holds every thing about the current tab of the application. /// Most of the mutation is done externally. @@ -50,8 +50,6 @@ pub struct Tab { pub shortcut: Shortcut, /// Last searched string pub searched: Option<String>, - /// Optional tree view - pub directory: Directory, /// The filter use before displaying files pub filter: FilterKind, /// Visited directories @@ -76,7 +74,6 @@ impl Tab { } else { path.parent().context("")? }; - let directory = Directory::empty(start_dir, &users)?; let filter = FilterKind::All; let show_hidden = args.all || settings.all; let mut path_content = PathContent::new(start_dir, &users, &filter, show_hidden)?; @@ -106,7 +103,6 @@ impl Tab { preview, shortcut, searched, - directory, filter, show_hidden, history, @@ -135,7 +131,7 @@ impl Tab { if matches!(self.previous_mode, Mode::Tree) => { self.completion - .search_from_tree(&self.input.string(), &self.directory.content) + .search_from_tree(&self.input.string(), &self.tree.paths()) } Mode::InputCompleted(InputCompleted::Command) => { self.completion.command(&self.input.string()) @@ -150,7 +146,7 @@ impl Tab { self.input.reset(); self.preview = Preview::empty(); self.completion.reset(); - self.directory.clear(); + self.tree = FileSystem::empty(); Ok(()) } @@ -303,12 +299,6 @@ impl Tab { } } - /// Select the root node of the tree. - pub fn tree_select_root(&mut self) -> Result<()> { - self.directory.unselect_children(); - self.directory.select_root() - } - /// Move to the parent of current path pub fn move_to_parent(&mut self) -> Result<()> { let path = self.path_content.path.clone(); @@ -342,13 +332,8 @@ impl Tab { /// Select the parent of current node. /// If we were at the root node, move to the parent and make a new tree. - pub fn tree_select_parent(&mut self) -> Result<()> { - self.directory.unselect_children(); - if self.directory.tree.position.len() <= 1 { - self.move_to_parent()?; - self.make_tree(None)? - } - self.directory.select_parent() + pub fn tree_select_parent(&mut self) { + self.tree.select_parent() } /// Move down 10 times in the tree @@ -378,12 +363,6 @@ impl Tab { Ok(()) } - /// Select the first child if any. - pub fn tree_select_first_child(&mut self) -> Result<()> { - self.directory.unselect_children(); - self.directory.select_first_child() - } - /// Go to the last leaf. pub fn tree_go_to_bottom_leaf(&mut self) -> Result<()> { self.tree.select_last(); @@ -395,19 +374,10 @@ impl Tab { /// if the selected node is a directory, that's it. /// else, it is the parent of the selected node. /// In other modes, it's the current path of pathcontent. - pub fn current_directory_path(&mut self) -> &path::Path { + pub fn current_directory_path(&mut self) -> Option<&path::Path> { match self.mode { - Mode::Tree => { - let path = &self.directory.tree.current_node.fileinfo.path; - if path.is_dir() { - return path; - } - let Some(parent) = path.parent() else { - return path::Path::new("/"); - }; - parent - } - _ => &self.path_content.path, + Mode::Tree => return self.tree.directory_of_selected(), + _ => Some(&self.path_content.path), } } @@ -417,16 +387,23 @@ impl Tab { /// In normal mode it's the current working directory. pub fn directory_of_selected(&self) -> Result<&path::Path> { match self.mode { - Mode::Tree => self.directory.tree.directory_of_selected(), + Mode::Tree => self.tree.directory_of_selected().context("No parent"), _ => Ok(&self.path_content.path), } } /// Optional Fileinfo of the selected element. - pub fn selected(&self) -> Option<&FileInfo> { + pub fn selected(&self) -> Result<FileInfo> { match self.mode { - Mode::Tree => Some(&self.directory.tree.current_node.fileinfo), - _ => self.path_content.selected(), + Mode::Tree => { + let node = self.tree.selected_node().context("no selected node")?; + node.fileinfo(&self.users) + } + _ => Ok(self + .path_content + .selected() + .context("no selected file")? + .to_owned()), } } @@ -536,11 +513,6 @@ impl Tab { Ok(()) } - /// Select the first child of the current node and reset the display. - pub fn select_first_child(&mut self) -> Result<()> { - self.tree_select_first_child() - } - /// Copy the selected filename to the clipboard. Only the filename. pub fn filename_to_clipboard(&self) -> Result<()> { set_clipboard( @@ -659,15 +631,12 @@ impl Tab { } fn tree_select_row(&mut self, row: u16, term_height: usize) -> Result<()> { - let screen_index = row_to_window_index(row) + 1; - // term.height = canvas.height + 2 rows for the canvas border - let (top, _, _) = self.directory.calculate_tree_window(term_height - 2); + let screen_index = row_to_window_index(row); + let (selected_index, content) = self.tree.into_navigable_content(&self.users); + let (top, _, _) = calculate_tree_window(selected_index, term_height, term_height); let index = screen_index + top; - self.directory.tree.unselect_children(); - self.directory.tree.position = self.directory.tree.position_from_index(index); - let (_, _, node) = self.directory.tree.select_from_position()?; - self.directory.make_preview(); - self.directory.tree.current_node = node; + let (_, _, colored_path) = content.get(index).context("no selected file")?; + self.tree.select_from_path(&colored_path.path); Ok(()) } @@ -723,21 +692,21 @@ impl Tab { } pub fn rename(&mut self) -> Result<()> { - if self.selected().is_some() { - let old_name = match self.mode { - Mode::Tree => self.directory.tree.current_node.filename(), - _ => filename_from_path( - &self - .path_content - .selected() - .context("Event rename: no file in current directory")? - .path, - )? - .to_owned(), + let old_name: String = if matches!(self.mode, Mode::Tree) { + self.tree + .selected_path() + .file_name() + .context("no filename")? + .to_string_lossy() + .into() + } else { + let Ok(fileinfo) = self.selected() else { + return Ok(()); }; - self.input.replace(&old_name); - self.set_mode(Mode::InputSimple(InputSimple::Rename)); - } + fileinfo.filename.to_owned() + }; + self.input.replace(&old_name); + self.set_mode(Mode::InputSimple(InputSimple::Rename)); Ok(()) } } diff --git a/src/term_manager.rs b/src/term_manager.rs index e7b5749..15bbf61 100644 --- a/src/term_manager.rs +++ b/src/term_manager.rs @@ -198,10 +198,10 @@ impl<'a> WinMain<'a> { match tab.mode { Mode::Normal | Mode::Tree => { if !status.display_full { - let Some(file) = tab.selected() else { + let Ok(file) = tab.selected() else { return Ok(0); }; - self.second_line_detailed(file, status, canvas) + self.second_line_detailed(&file, status, canvas) } else { self.second_line_simple(status, canvas) } @@ -296,7 +296,7 @@ impl<'a> WinMain<'a> { ] } - fn pick_previewed_fileinfo(&self) -> Option<&FileInfo> { + fn pick_previewed_fileinfo(&self) -> Result<FileInfo> { if self.status.dual_pane && self.status.preview_second { self.status.tabs[0].selected() } else { @@ -305,7 +305,7 @@ impl<'a> WinMain<'a> { } fn default_preview_first_line(&self, tab: &Tab) -> Vec<String> { - if let Some(fileinfo) = self.pick_previewed_fileinfo() { + if let Ok(fileinfo) = self.pick_previewed_fileinfo() { let mut strings = vec![" Preview ".to_owned()]; if !tab.preview.is_empty() { let index = match &tab.preview { @@ -394,36 +394,6 @@ impl<'a> WinMain<'a> { Ok(()) } - fn _tree(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> { - let left_margin = if status.display_full { 1 } else { 3 }; - let (_, height) = canvas.size()?; - let (top, bottom, len) = tab.directory.calculate_tree_window(height); - - for (i, (metadata, prefix, colored_string)) in tab.directory.window(top, bottom, len) { - let row = i + ContentWindow::WINDOW_MARGIN_TOP - top; - let mut attr = colored_string.color_effect.attr(); - if status.flagged.contains(&colored_string.path) { - attr.effect |= Effect::BOLD; - canvas.print_with_attr(row, 0, "█", ATTR_YELLOW_BOLD)?; - } - - let col_metadata = if status.display_full { - canvas.print_with_attr(row, left_margin, metadata, attr)? - } else { - 0 - }; - let col_tree_prefix = canvas.print(row, left_margin + col_metadata, prefix)?; - canvas.print_with_attr( - row, - left_margin + col_metadata + col_tree_prefix, - &colored_string.text, - attr, - )?; - } - self.second_line(status, tab, canvas)?; - Ok(()) - } - fn trees(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> { let left_margin = if status.display_full { 1 } else { 3 }; let (_, height) = canvas.size()?; @@ -975,9 +945,9 @@ impl<'a> WinSecondary<'a> { } let dest = match tab.previous_mode { Mode::Tree => tab - .directory .tree - .directory_of_selected()? + .directory_of_selected() + .context("No directory_of_selected")? .display() .to_string(), _ => tab.path_content.path_to_str(), diff --git a/src/trees.rs b/src/trees.rs index 0b77f62..a016ca7 100644 --- a/src/trees.rs +++ b/src/trees.rs @@ -143,8 +143,12 @@ impl FileSystem { } } - pub fn sort(&mut self, _sort_kind: SortKind) -> Result<()> { - todo!() + pub fn selected_path(&self) -> &Path { + self.selected.as_path() + } + + pub fn selected_node(&self) -> Option<&Node> { + self.nodes.get(&self.selected) } /// Select next sibling or the next sibling of the parent @@ -215,7 +219,6 @@ impl FileSystem { } None } - // TODO! find the bottom child of parent instead of jumping back 1 level /// Select previous sibling or the parent pub fn select_prev(&mut self) { @@ -283,6 +286,32 @@ impl FileSystem { self.selected = self.last_path.to_owned(); } + pub fn select_parent(&mut self) { + if let Some(parent_path) = self.selected.parent() { + let Some(parent_node) = self.nodes.get_mut(parent_path) else { + return; + }; + parent_node.select(); + let Some(selected_node) = self.nodes.get_mut(&self.selected) else { + un |