Skip to content

Commit

Permalink
refactor(term): resolve key events using an arrary of keymaps
Browse files Browse the repository at this point in the history
  • Loading branch information
ymgyt committed Mar 21, 2024
1 parent 257beaa commit 311e384
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 35 deletions.
44 changes: 15 additions & 29 deletions crates/synd_term/src/application/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
config,
interact::Interactor,
job::Jobs,
keymap::{KeyTrie, Keymaps},
keymap::{KeymapId, Keymaps},
terminal::Terminal,
ui::{
self,
Expand Down Expand Up @@ -91,6 +91,10 @@ impl Application {
}

pub fn with(terminal: Terminal, client: Client, config: Config) -> Self {
let mut keymaps = Keymaps::default();
keymaps.enable(KeymapId::Global);
keymaps.enable(KeymapId::Login);

Self {
terminal,
client,
Expand All @@ -103,7 +107,7 @@ impl Application {
idle_timer: Box::pin(tokio::time::sleep(config.idle_timer_interval)),
screen: Screen::Login,
config,
keymaps: Keymaps::default(),
keymaps,
should_quit: false,
should_render: false,
}
Expand All @@ -129,6 +133,9 @@ impl Application {
pub fn set_credential(&mut self, cred: Credential) {
self.client.set_credential(cred);
self.components.auth.authenticated();
self.keymaps.disable(KeymapId::Login);
self.keymaps.enable(KeymapId::Tabs);
self.keymaps.enable(KeymapId::Entries);
self.initial_fetch();
self.screen = Screen::Browse;
self.should_render = true;
Expand Down Expand Up @@ -281,6 +288,9 @@ impl Application {
self.complete_device_authroize_flow(provider, device_access_token);
}
Command::MoveTabSelection(direction) => {
self.keymaps.toggle(KeymapId::Entries);
self.keymaps.toggle(KeymapId::Subscription);

match self.components.tabs.move_selection(&direction) {
Tab::Feeds if !self.components.subscription.has_subscription() => {
next = Some(Command::FetchSubscription {
Expand Down Expand Up @@ -424,7 +434,6 @@ impl Application {
.expect("Failed to render");
}

#[allow(clippy::single_match, clippy::too_many_lines)]
fn handle_terminal_event(&mut self, event: std::io::Result<CrosstermEvent>) -> Option<Command> {
match event.unwrap() {
CrosstermEvent::Resize(columns, rows) => {
Expand All @@ -435,33 +444,10 @@ impl Application {
..
}) => None,
CrosstermEvent::Key(key) => {
self.reset_idle_timer();

tracing::debug!("Handle key event: {key:?}");
match self.screen {
Screen::Login => match self.keymaps.login.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => {}
},
Screen::Browse => match self.keymaps.tabs.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => match self.components.tabs.current() {
Tab::Entries => match self.keymaps.entries.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => {}
},
Tab::Feeds => match self.keymaps.subscription.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => {}
},
},
},
}

match self.keymaps.global.search(&[key]) {
Some(crate::keymap::KeyTrie::Command(cmd)) => Some(cmd),
_ => None,
}

self.reset_idle_timer();
self.keymaps.search(key)
}
_ => None,
}
Expand Down
6 changes: 3 additions & 3 deletions crates/synd_term/src/keymap/default.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::keymap::{macros::keymap, Keymaps};
use crate::keymap::{macros::keymap, KeymapsConfig};

pub fn default() -> Keymaps {
pub fn default() -> KeymapsConfig {
let login = keymap!({
"enter" => authenticate,
"k" => move_up_authentication_provider,
Expand Down Expand Up @@ -36,7 +36,7 @@ pub fn default() -> Keymaps {
"q" | "C-c" => quit ,
});

Keymaps {
KeymapsConfig {
login,
tabs,
entries,
Expand Down
89 changes: 86 additions & 3 deletions crates/synd_term/src/keymap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,112 @@ pub mod macros;

use crate::command::Command;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeymapId {
Global = 0,
Login = 1,
Tabs = 2,
Entries = 3,
Subscription = 4,
}

#[derive(Debug)]
pub struct Keymaps {
struct Keymap {
#[allow(unused)]
id: KeymapId,
enable: bool,
trie: KeyTrie,
}

impl Keymap {
fn new(id: KeymapId, trie: KeyTrie) -> Self {
Self {
id,
enable: false,
trie,
}
}

fn search(&mut self, event: &KeyEvent) -> Option<Command> {
match self.trie.search(&[event]) {
Some(KeyTrie::Command(cmd)) => Some(cmd),
Some(KeyTrie::Node(_)) | None => None,
}
}
}

pub struct KeymapsConfig {
pub login: KeyTrie,
pub tabs: KeyTrie,
pub entries: KeyTrie,
pub subscription: KeyTrie,
pub global: KeyTrie,
}

impl Default for Keymaps {
impl Default for KeymapsConfig {
fn default() -> Self {
default::default()
}
}

#[derive(Debug)]
pub struct Keymaps {
keymaps: Box<[Keymap; 5]>,
}

impl Keymaps {
pub fn new(config: KeymapsConfig) -> Self {
// order is matter
let keymaps = [
Keymap::new(KeymapId::Global, config.global),
Keymap::new(KeymapId::Login, config.login),
Keymap::new(KeymapId::Tabs, config.tabs),
Keymap::new(KeymapId::Entries, config.entries),
Keymap::new(KeymapId::Subscription, config.subscription),
];

Self {
keymaps: Box::new(keymaps),
}
}

pub fn enable(&mut self, id: KeymapId) {
self.keymaps[id as usize].enable = true;
}

pub fn disable(&mut self, id: KeymapId) {
self.keymaps[id as usize].enable = false;
}

pub fn toggle(&mut self, id: KeymapId) {
let enable = self.keymaps[id as usize].enable;
self.keymaps[id as usize].enable = !enable;
}

pub fn search(&mut self, event: KeyEvent) -> Option<Command> {
for keymap in self.keymaps.iter_mut().rev().filter(|k| k.enable) {
if let Some(cmd) = keymap.search(&event) {
return Some(cmd);
}
}
None
}
}

impl Default for Keymaps {
fn default() -> Self {
Self::new(KeymapsConfig::default())
}
}

#[derive(Clone, Debug)]
pub enum KeyTrie {
Command(Command),
Node(KeyTrieNode),
}

impl KeyTrie {
pub fn search(&self, keys: &[KeyEvent]) -> Option<KeyTrie> {
pub fn search(&self, keys: &[&KeyEvent]) -> Option<KeyTrie> {
let mut trie = self;
for key in keys {
trie = match trie {
Expand Down

0 comments on commit 311e384

Please sign in to comment.