From 7c0f5a2e0a4e7cc3d9cc03f6050af0932f3d1f00 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sun, 16 Aug 2026 20:36:22 +0000 Subject: [PATCH] navigation of views is now easier --- PROJECT.md | 2 ++ README.md | 2 +- src/app.rs | 4 ++-- src/ui.rs | 30 +++++++++++++++++++++++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/PROJECT.md b/PROJECT.md index a23f6a7..b38dc47 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -74,6 +74,8 @@ Research URLs: item editor, property editor, notes, category chooser, help, and status messages. - [x] Marking and bulk completion; Trash view, soft discard, and recovery. - [x] Responsive wide/compact rendering and mouse row/command/view interaction. +- [x] Vi-style `h`/`l` saved-view navigation with wraparound and legacy + `[`/`]` aliases. - [x] Application Preferences persisted as typed TOML at `~/.config/rogue-agenda/preferences.toml`: theme, command bar, rule/return/item markers, autosave, confirmations, date/time display, and number separators; diff --git a/README.md b/README.md index 36b24d9..f1a3193 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ or build failure stops the gate. | `F10` or `m` | Command menu | | `r` | Edit prerequisites for the selected item | | `/` | Search the current view | -| `[` / `]` | Previous / next saved view | +| `h` / `l` | Previous / next saved view (`[` / `]` are aliases) | | `Ctrl-S` | Save/checkpoint | | `?` or `F1` | Help | | `q` | Quit | diff --git a/src/app.rs b/src/app.rs index 014e688..8baa133 100644 --- a/src/app.rs +++ b/src/app.rs @@ -301,8 +301,8 @@ impl App { self.search.clone(), false, ), - KeyCode::Char(']') => self.switch_view(1)?, - KeyCode::Char('[') => self.switch_view(-1)?, + KeyCode::Char('l') | KeyCode::Char(']') => self.switch_view(1)?, + KeyCode::Char('h') | KeyCode::Char('[') => self.switch_view(-1)?, KeyCode::Delete => self.discard_or_restore()?, KeyCode::Esc if !self.search.is_empty() => { self.search.clear(); diff --git a/src/ui.rs b/src/ui.rs index 5e7ce06..46a479a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -633,7 +633,7 @@ fn draw_overlay(frame: &mut Frame<'_>, app: &mut App) { Line::from("↑↓/jk move Insert/n new Enter/F2 edit F3/c categories"), Line::from("F4/d done F5 note F6/p properties F7/Space mark"), Line::from("F8/v views F9 categories F10/m menu / search"), - Line::from("[ ] views r prerequisites Delete trash/recover"), + Line::from("h/l views ([/]) r prerequisites Delete trash/recover"), Line::from("Ctrl-S save q quit"), Line::from(""), Line::from("Mouse: click items, view tabs, or function-key tiles."), @@ -1259,6 +1259,34 @@ mod tests { assert!(screen.contains("When")); } + #[test] + fn main_screen_h_and_l_cycle_views_with_wraparound() { + let directory = tempdir().unwrap(); + let path = directory.path().join("view-navigation.agnd"); + let db = Database::open(&path).unwrap(); + let mut app = App::new_with_preferences( + db, + path, + AppPreferences::default(), + directory.path().join("preferences.toml"), + ) + .unwrap(); + assert!(app.views.len() > 1); + + app.handle_key(KeyEvent::new(KeyCode::Char('l'), KeyModifiers::NONE)) + .unwrap(); + assert_eq!(app.view_index, 1); + app.handle_key(KeyEvent::new(KeyCode::Char('h'), KeyModifiers::NONE)) + .unwrap(); + assert_eq!(app.view_index, 0); + app.handle_key(KeyEvent::new(KeyCode::Char('h'), KeyModifiers::NONE)) + .unwrap(); + assert_eq!(app.view_index, app.views.len() - 1); + app.handle_key(KeyEvent::new(KeyCode::Char(']'), KeyModifiers::NONE)) + .unwrap(); + assert_eq!(app.view_index, 0); + } + #[test] fn note_editor_renders_and_saves_entered_line_breaks() { let d = tempdir().unwrap();