diff options
author | qkzk <qu3nt1n@gmail.com> | 2022-11-21 20:28:37 +0100 |
---|---|---|
committer | qkzk <qu3nt1n@gmail.com> | 2022-11-21 20:28:37 +0100 |
commit | cf86e7d29109f8eb60a341011e034f4347d9e3f3 (patch) | |
tree | f655f1abefcf219e30c84538c973a1daf6396b1a | |
parent | 95db27f292e7ee8ea0a63583987431df1ea79dd1 (diff) |
improve tab navigation interfacetab-bar
-rw-r--r-- | readme.md | 6 | ||||
-rw-r--r-- | src/actioner.rs | 24 | ||||
-rw-r--r-- | src/status.rs | 16 | ||||
-rw-r--r-- | src/term_manager.rs | 47 |
4 files changed, 82 insertions, 11 deletions
@@ -130,6 +130,12 @@ - [x] preview - [ ] auto mount usb keys ??? [rusb](https://github.com/a1ien/rusb) - [ ] mtp... but fast [libmtp.rs](https://docs.rs/libmtp-rs/0.7.7/libmtp_rs/) +- [x] improve tabs interface + - [x] tab bar + - [x] digit move to respective tab + - [x] <TAB> creates a new tab if only one + - [x] <BACKTAB> moves to previous tab + - [x] hardcoded limit to 10 tabs ## BUGS diff --git a/src/actioner.rs b/src/actioner.rs index 7e49a33..0c0a33c 100644 --- a/src/actioner.rs +++ b/src/actioner.rs @@ -78,6 +78,7 @@ impl Actioner { Event::Key(Key::PageUp) => self.page_up(status), Event::Key(Key::Enter) => self.enter(status), Event::Key(Key::Tab) => self.tab(status), + Event::Key(Key::BackTab) => self.backtab(status), Event::Key(Key::WheelUp(_, _, _)) => self.up(status), Event::Key(Key::WheelDown(_, _, _)) => self.down(status), Event::Key(Key::SingleClick(MouseButton::Left, row, _)) => { @@ -299,17 +300,31 @@ impl Actioner { } /// Select next completion and insert it + /// Select next tab fn tab(&self, status: &mut Status) -> FmResult<()> { match status.selected().mode { Mode::Goto | Mode::Exec | Mode::Search => { status.selected().event_replace_input_with_completion() } - Mode::Normal => status.next(), + Mode::Normal => { + if status.len_index_of_tabs().0 == 1 { + status.new_tab() + } + status.next() + } _ => (), }; Ok(()) } + /// Select previous tab + fn backtab(&self, status: &mut Status) -> FmResult<()> { + if let Mode::Normal = status.selected().mode { + status.prev() + } + Ok(()) + } + fn ctrl_f(&self, status: &mut Status) -> FmResult<()> { let output = Skimer::new(self.term.clone()).no_source( status @@ -362,7 +377,12 @@ impl Actioner { } Mode::Normal => match self.binds.get(&c) { Some(event_char) => event_char.match_char(status), - None => Ok(()), + None => { + if c.is_ascii_digit() { + status.go_tab(c) + } + Ok(()) + } }, Mode::Help | Mode::Preview | Mode::Shortcut => status.selected().event_normal(), Mode::Jump => Ok(()), diff --git a/src/status.rs b/src/status.rs index 0c32cfa..9bd14ee 100644 --- a/src/status.rs +++ b/src/status.rs @@ -44,6 +44,7 @@ pub struct Status { } impl Status { + const MAX_TAB: u32 = 10; const MAX_PERMISSIONS: u32 = 0o777; pub fn new(args: Args, config: Config, height: usize, term: Arc<Term>) -> FmResult<Self> { @@ -58,8 +59,21 @@ impl Status { }) } + pub fn len_index_of_tabs(&self) -> (usize, usize) { + (self.tabs.len(), self.index) + } + pub fn new_tab(&mut self) { - self.tabs.push(self.tabs[self.index].clone()) + if self.tabs.len() < Self::MAX_TAB as usize { + self.tabs.push(self.tabs[self.index].clone()) + } + } + + pub fn go_tab(&mut self, digit: char) { + let index = digit.to_digit(10).unwrap_or(Self::MAX_TAB) as usize; + if self.tabs.len() > index { + self.index = index + } } pub fn drop_tab(&mut self) { diff --git a/src/term_manager.rs b/src/term_manager.rs index f6bdd7f..8e98797 100644 --- a/src/term_manager.rs +++ b/src/term_manager.rs @@ -104,17 +104,23 @@ impl Display { /// When a confirmation is needed we ask the user to input `'y'` or /// something else. fn first_line(&mut self, status: &Status, disk_space: String) -> FmResult<()> { - let first_row = self.create_first_row(status, disk_space)?; - self.draw_colored_strings(first_row)?; + let (offset, first_row) = self.create_first_row(status, disk_space)?; + self.draw_colored_strings(offset, first_row)?; Ok(()) } - fn create_first_row(&mut self, status: &Status, disk_space: String) -> FmResult<Vec<String>> { + fn create_first_row( + &mut self, + status: &Status, + disk_space: String, + ) -> FmResult<(usize, Vec<String>)> { let tab = status.selected_non_mut(); - Ok(match tab.mode { + let mut offset = 0; + let first_row = match tab.mode { Mode::Normal => { + offset = self.tab_bar(status)?; vec![ - format!("Tab: {}/{} ", status.index + 1, status.len()), + // format!("Tab: {}/{} ", status.index + 1, status.len()), format!("{} ", tab.path_content.path_to_str()?), format!("{} files ", tab.path_content.files.len()), format!("{} ", tab.path_content.used_space()), @@ -149,13 +155,38 @@ impl Display { format!("{}", tab.input.string.clone()), ] } - }) + }; + Ok((offset, first_row)) + } + + fn tab_bar(&self, status: &Status) -> FmResult<usize> { + let mut attr = Attr::default(); + self.term.print_with_attr(0, 0, "[", attr)?; + let (number_of_tabs, selected_index) = status.len_index_of_tabs(); + + for tab in 0..(number_of_tabs) { + if tab == selected_index { + attr = Attr { + bg: Color::default(), + fg: Color::CYAN, + effect: Effect::REVERSE, + }; + } + self.term + .print_with_attr(0, 2 * tab + 1, &format!("{}", tab), attr)?; + attr = Attr::default(); + self.term + .print_with_attr(0, 2 * number_of_tabs, " ", Attr::default())?; + } + self.term + .print_with_attr(0, 2 * number_of_tabs, "]", Attr::default())?; + Ok(2 * number_of_tabs + 2) } - fn draw_colored_strings(&self, first_row: Vec<String>) -> FmResult<()> { + fn draw_colored_strings(&self, offset: usize, first_row: Vec<String>) -> FmResult<()> { let mut col = 0; for (text, color) in std::iter::zip(first_row.iter(), Self::LINE_COLORS.iter().cycle()) { - self.term.print_with_attr(0, col, text, *color)?; + self.term.print_with_attr(0, offset + col, text, *color)?; col += text.len() } Ok(()) |