feat: add SPC w {h,j,k,l} spatial window navigation

Pane focus follows actual screen layout: Artists (left), Albums (top-right),
Tracks (bottom-right). h/l jump between left/right columns, j/k move
between vertically stacked panes in the right column.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/claude-agent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Alexander
2026-05-10 13:37:52 +02:00
parent cde3fe1979
commit d1616c63bc
4 changed files with 26 additions and 17 deletions
+2 -1
View File
@@ -28,7 +28,8 @@ impl App {
} }
AppAction::FocusLeft => self.library.focus_left(), AppAction::FocusLeft => self.library.focus_left(),
AppAction::FocusRight => self.library.focus_right(), AppAction::FocusRight => self.library.focus_right(),
AppAction::CycleFocus => self.library.cycle_focus(), AppAction::FocusDown => self.library.focus_down(),
AppAction::FocusUp => self.library.focus_up(),
AppAction::GotoFirst => match self.library.focus { AppAction::GotoFirst => match self.library.focus {
LibraryFocus::Artists => self.library.artist_state.select(Some(0)), LibraryFocus::Artists => self.library.artist_state.select(Some(0)),
LibraryFocus::Albums => self.library.album_state.select(Some(0)), LibraryFocus::Albums => self.library.album_state.select(Some(0)),
+14 -14
View File
@@ -138,8 +138,9 @@ impl LibraryState {
pub fn focus_left(&mut self) { pub fn focus_left(&mut self) {
match self.focus { match self.focus {
LibraryFocus::Artists => {} LibraryFocus::Artists => {}
LibraryFocus::Albums => self.focus = LibraryFocus::Artists, LibraryFocus::Albums | LibraryFocus::Tracks => {
LibraryFocus::Tracks => self.focus = LibraryFocus::Albums, self.focus = LibraryFocus::Artists;
}
} }
} }
@@ -150,21 +151,20 @@ impl LibraryState {
self.focus = LibraryFocus::Albums; self.focus = LibraryFocus::Albums;
} }
} }
LibraryFocus::Albums => { LibraryFocus::Albums | LibraryFocus::Tracks => {}
if self.selected_album().is_some() {
self.focus = LibraryFocus::Tracks;
}
}
LibraryFocus::Tracks => {}
} }
} }
pub fn cycle_focus(&mut self) { pub fn focus_down(&mut self) {
self.focus = match self.focus { if self.focus == LibraryFocus::Albums {
LibraryFocus::Artists => LibraryFocus::Albums, self.focus = LibraryFocus::Tracks;
LibraryFocus::Albums => LibraryFocus::Tracks, }
LibraryFocus::Tracks => LibraryFocus::Artists, }
};
pub fn focus_up(&mut self) {
if self.focus == LibraryFocus::Tracks {
self.focus = LibraryFocus::Albums;
}
} }
fn reset_album_selection(&mut self) { fn reset_album_selection(&mut self) {
+2 -1
View File
@@ -5,7 +5,8 @@ pub enum AppAction {
MoveDown, MoveDown,
FocusLeft, FocusLeft,
FocusRight, FocusRight,
CycleFocus, FocusDown,
FocusUp,
GotoFirst, GotoFirst,
GotoLast, GotoLast,
HalfPageDown, HalfPageDown,
+8 -1
View File
@@ -11,7 +11,7 @@ pub fn build_normal_keymap() -> KeyTrie<AppAction> {
.unwrap(); .unwrap();
t.bind_desc("l", AppAction::FocusRight, "focus right") t.bind_desc("l", AppAction::FocusRight, "focus right")
.unwrap(); .unwrap();
t.bind_desc("Tab", AppAction::CycleFocus, "cycle focus") t.bind_desc("Tab", AppAction::FocusRight, "next pane")
.unwrap(); .unwrap();
t.bind_desc("G", AppAction::GotoLast, "last item").unwrap(); t.bind_desc("G", AppAction::GotoLast, "last item").unwrap();
t.bind_desc("C-d", AppAction::HalfPageDown, "half page down") t.bind_desc("C-d", AppAction::HalfPageDown, "half page down")
@@ -41,6 +41,13 @@ pub fn build_normal_keymap() -> KeyTrie<AppAction> {
b.bind_desc("p", AppAction::PrevTab, "prev")?; b.bind_desc("p", AppAction::PrevTab, "prev")?;
Ok(()) Ok(())
})?; })?;
g.group("w", "+window", |w| {
w.bind_desc("h", AppAction::FocusLeft, "pane left")?;
w.bind_desc("l", AppAction::FocusRight, "pane right")?;
w.bind_desc("j", AppAction::FocusDown, "pane down")?;
w.bind_desc("k", AppAction::FocusUp, "pane up")?;
Ok(())
})?;
g.bind_desc("h", AppAction::ShowHelp, "help")?; g.bind_desc("h", AppAction::ShowHelp, "help")?;
g.bind_desc("q", AppAction::Quit, "quit")?; g.bind_desc("q", AppAction::Quit, "quit")?;
g.bind_desc("n", AppAction::ToggleNotifications, "notifications")?; g.bind_desc("n", AppAction::ToggleNotifications, "notifications")?;