From d5a53d37fc808355ffdf98c3a1d2fb858bc0eb22 Mon Sep 17 00:00:00 2001 From: Alok Singh Date: Mon, 4 Mar 2019 20:06:35 -0800 Subject: [PATCH] Implement select next and previous siblings This also changes the mapping to select parent to Alt shift p instead of alt-p, but that's not much of a change since 'select parent' was only implemented yesterday and is not in any official release. --- README.md | 3 ++- src/config.rs | 8 +++++++- src/screen.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 80f3c24..3beb124 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,8 @@ de-select node | Esc | save | C-x exit | Esc with nothing selected | exit | C-c jump to weighted next task | C-v | cut / paste node | C-y move selected up in child list | C-g | move selected down in child list | C-d -search for node at or below current view | C-u | Select parent | A-p +search for node at or below current view | C-u | Select parent | A-S-p (alt shift) +Select next sibling | A-n | select previous sibling | A-p can be customized by setting the `KEYFILE` env var to the path of a [key configuration file](default.keys) diff --git a/src/config.rs b/src/config.rs index 754590f..9260089 100644 --- a/src/config.rs +++ b/src/config.rs @@ -46,6 +46,8 @@ pub enum Action { UndoDelete, Help, SelectParent, + SelectNextSibling, + SelectPrevSibling, } fn to_action(input: String) -> Option { @@ -83,6 +85,8 @@ fn to_action(input: String) -> Option { "undo_delete" => Some(Action::UndoDelete), "help" => Some(Action::Help), "select_parent" => Some(Action::SelectParent), + "select_next_sibling" => Some(Action::SelectNextSibling), + "select_prev_sibling" => Some(Action::SelectPrevSibling), _ => None, } } @@ -160,7 +164,9 @@ impl Default for Config { (Ctrl('u'), Action::Search), (Ctrl('z'), Action::UndoDelete), (Ctrl('?'), Action::Help), - (Alt('p'), Action::SelectParent), + (Alt('P'), Action::SelectParent), + (Alt('n'), Action::SelectNextSibling), + (Alt('p'), Action::SelectPrevSibling), ] .into_iter() .collect(), diff --git a/src/screen.rs b/src/screen.rs index bd52858..c35b158 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -221,6 +221,8 @@ impl Screen { Action::Search => self.search_forward(), Action::UndoDelete => self.undo_delete(), Action::SelectParent => self.select_parent(), + Action::SelectNextSibling => self.select_next_sibling(), + Action::SelectPrevSibling => self.select_prev_sibling(), }, None => warn!("received unknown input"), } @@ -1255,6 +1257,37 @@ impl Screen { } } + fn select_next_sibling(&mut self) { self.select_neighbor(SearchDirection::Forward); } + + fn select_prev_sibling(&mut self) { self.select_neighbor(SearchDirection::Backward); } + + fn select_neighbor(&mut self, dir: SearchDirection) -> Option { + use SearchDirection::*; + let selected_id = self.selected?; + let parent = self.nodes.get(&self.parent(selected_id)?)?; + + let selected_idx = parent.children.iter().position(|&id| id == selected_id)? as u64; + let offset: isize = if dir == Forward { 1 } else { -1 }; + if let Some(&neighbor_id) = parent + .children + .get((selected_idx as isize + offset) as usize) + { + self.select_node(neighbor_id); + } else { + let pos = if dir == Forward { + 0 + } else { + parent.children.len() - 1 + }; + // Wrap around if there is no neighbor sibling. We know that + // `parent.children` is nonempty because `selected_id` is one of them, + // so the indexing is safe. + self.select_node(parent.children[pos]); + } + + None + } + fn drill_down(&mut self) { trace!("drill_down()"); // bust grapheme cache on new view @@ -2295,6 +2328,7 @@ impl Screen { } } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] enum SearchDirection { Forward, Backward,