Skip to content

Commit

Permalink
refactor(term): add helix like keymaps
Browse files Browse the repository at this point in the history
  • Loading branch information
ymgyt committed Mar 20, 2024
1 parent 9b082d8 commit 257beaa
Show file tree
Hide file tree
Showing 14 changed files with 301 additions and 186 deletions.
2 changes: 1 addition & 1 deletion crates/synd_auth/src/device_flow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ impl<'s> DeviceAccessTokenRequest<'s> {

/// Successful Response
/// <https://datatracker.ietf.org/doc/html/rfc6749#section-5.1>
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DeviceAccessTokenResponse {
/// the access token issued by the authorization server
pub access_token: String,
Expand Down
2 changes: 1 addition & 1 deletion crates/synd_term/src/application/direction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Direction {
Up,
Down,
Expand Down
168 changes: 36 additions & 132 deletions crates/synd_term/src/application/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{pin::Pin, time::Duration};

use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use crossterm::event::{Event as CrosstermEvent, KeyEvent, KeyEventKind};
use futures_util::{FutureExt, Stream, StreamExt};
use ratatui::{style::palette::tailwind, widgets::Widget};
use synd_auth::device_flow::{
Expand All @@ -16,6 +16,7 @@ use crate::{
config,
interact::Interactor,
job::Jobs,
keymap::{KeyTrie, Keymaps},
terminal::Terminal,
ui::{
self,
Expand Down Expand Up @@ -77,8 +78,8 @@ pub struct Application {
theme: Theme,
idle_timer: Pin<Box<Sleep>>,
config: Config,
keymaps: Keymaps,

prev_key_seq: Vec<KeyEvent>,
screen: Screen,
should_render: bool,
should_quit: bool,
Expand All @@ -100,9 +101,9 @@ impl Application {
in_flight: InFlight::new().with_throbber_timer_interval(config.throbber_timer_interval),
theme: Theme::with_palette(&tailwind::BLUE),
idle_timer: Box::pin(tokio::time::sleep(config.idle_timer_interval)),
prev_key_seq: Vec::with_capacity(2),
screen: Screen::Login,
config,
keymaps: Keymaps::default(),
should_quit: false,
should_render: false,
}
Expand Down Expand Up @@ -230,14 +231,26 @@ impl Application {
Command::Idle => {
self.handle_idle();
}
Command::Authenticate(provider) => match provider {
AuthenticationProvider::Github => {
self.authenticate(provider, self.authenticator.device_flows.github.clone());
Command::Authenticate => {
if self.components.auth.state() != &AuthenticateState::NotAuthenticated {
continue;
}
AuthenticationProvider::Google => {
self.authenticate(provider, self.authenticator.device_flows.google.clone());
let provider = self.components.auth.selected_provider();
match provider {
AuthenticationProvider::Github => {
self.authenticate(
provider,
self.authenticator.device_flows.github.clone(),
);
}
AuthenticationProvider::Google => {
self.authenticate(
provider,
self.authenticator.device_flows.google.clone(),
);
}
}
},
}
Command::MoveAuthenticationProvider(direction) => {
self.components.auth.move_selection(&direction);
self.should_render = true;
Expand Down Expand Up @@ -424,138 +437,29 @@ impl Application {
CrosstermEvent::Key(key) => {
self.reset_idle_timer();

// TODO: impl helix like KeyTrie
tracing::debug!("Handle key event: {key:?}");
match self.screen {
Screen::Login => match key.code {
KeyCode::Enter => {
if self.components.auth.state() == &AuthenticateState::NotAuthenticated
{
return Some(Command::Authenticate(
self.components.auth.selected_provider(),
));
};
}
KeyCode::Char('j') => {
return Some(Command::MoveAuthenticationProvider(Direction::Down))
}
KeyCode::Char('k') => {
return Some(Command::MoveAuthenticationProvider(Direction::Up))
}
Screen::Login => match self.keymaps.login.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => {}
},
Screen::Browse => match key.code {
KeyCode::Tab => return Some(Command::MoveTabSelection(Direction::Right)),
KeyCode::BackTab => {
return Some(Command::MoveTabSelection(Direction::Left))
}
Screen::Browse => match self.keymaps.tabs.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => match self.components.tabs.current() {
Tab::Entries => match key.code {
KeyCode::Char('j') => {
self.prev_key_seq.clear();
return Some(Command::MoveEntry(Direction::Down));
}
KeyCode::Char('k') => {
self.prev_key_seq.clear();
return Some(Command::MoveEntry(Direction::Up));
}
KeyCode::Char('r') => {
self.prev_key_seq.clear();
return Some(Command::ReloadEntries);
}
KeyCode::Enter => {
self.prev_key_seq.clear();
return Some(Command::OpenEntry);
}
KeyCode::Char('g') => match self.prev_key_seq.as_slice() {
&[KeyEvent {
code: KeyCode::Char('g'),
..
}] => {
self.prev_key_seq.clear();
return Some(Command::MoveEntryFirst);
}
_ => {
self.prev_key_seq.push(key);
}
},
KeyCode::Char('e') => match self.prev_key_seq.as_slice() {
&[KeyEvent {
code: KeyCode::Char('g'),
..
}] => {
self.prev_key_seq.clear();
return Some(Command::MoveEntryLast);
}
_ => {
self.prev_key_seq.clear();
}
},
_ => {
self.prev_key_seq.clear();
}
Tab::Entries => match self.keymaps.entries.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => {}
},
Tab::Feeds => match key.code {
KeyCode::Char('a') => {
self.prev_key_seq.clear();
return Some(Command::PromptFeedSubscription);
}
KeyCode::Char('d') => {
self.prev_key_seq.clear();
return Some(Command::PromptFeedUnsubscription);
}
KeyCode::Char('j') => {
self.prev_key_seq.clear();
return Some(Command::MoveSubscribedFeed(Direction::Down));
}
KeyCode::Char('k') => {
self.prev_key_seq.clear();
return Some(Command::MoveSubscribedFeed(Direction::Up));
}
KeyCode::Char('r') => {
self.prev_key_seq.clear();
return Some(Command::ReloadSubscription);
}
KeyCode::Enter => {
self.prev_key_seq.clear();
return Some(Command::OpenFeed);
}
KeyCode::Char('g') => match self.prev_key_seq.as_slice() {
&[KeyEvent {
code: KeyCode::Char('g'),
..
}] => {
self.prev_key_seq.clear();
return Some(Command::MoveSubscribedFeedFirst);
}
_ => {
self.prev_key_seq.push(key);
}
},
KeyCode::Char('e') => match self.prev_key_seq.as_slice() {
&[KeyEvent {
code: KeyCode::Char('g'),
..
}] => {
self.prev_key_seq.clear();
return Some(Command::MoveSubscribedFeedLast);
}
_ => {
self.prev_key_seq.clear();
}
},
_ => {
self.prev_key_seq.clear();
}
Tab::Feeds => match self.keymaps.subscription.search(&[key]) {
Some(KeyTrie::Command(cmd)) => return Some(cmd),
_ => {}
},
},
},
};
match key.code {
KeyCode::Char('q') => Some(Command::Quit),
KeyCode::Char('c') if key.modifiers == KeyModifiers::CONTROL => {
Some(Command::Quit)
}
}

match self.keymaps.global.search(&[key]) {
Some(crate::keymap::KeyTrie::Command(cmd)) => Some(cmd),
_ => None,
}
}
Expand Down
42 changes: 21 additions & 21 deletions crates/synd_term/src/client/mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub mod subscribe_feed {
#[allow(dead_code)]
type ID = String;
type Rfc3339Time = crate::client::scalar::Rfc3339Time;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum FeedType {
ATOM,
RSS1,
Expand Down Expand Up @@ -50,7 +50,7 @@ pub mod subscribe_feed {
}
}
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum ResponseCode {
OK,
UNAUTHORIZED,
Expand Down Expand Up @@ -90,7 +90,7 @@ pub mod subscribe_feed {
pub input: SubscribeFeedInput,
}
impl Variables {}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct Feed {
pub id: ID,
#[serde(rename = "type")]
Expand All @@ -106,62 +106,62 @@ pub mod subscribe_feed {
pub links: FeedLinks,
pub authors: FeedAuthors,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct FeedEntries {
pub nodes: Vec<FeedEntriesNodes>,
}
pub type FeedEntriesNodes = EntryMeta;
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct FeedLinks {
pub nodes: Vec<FeedLinksNodes>,
}
pub type FeedLinksNodes = Link;
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct FeedAuthors {
pub nodes: Vec<String>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct EntryMeta {
pub title: Option<String>,
pub published: Option<Rfc3339Time>,
pub updated: Option<Rfc3339Time>,
pub summary: Option<String>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct Link {
pub href: String,
pub rel: Option<String>,
#[serde(rename = "mediaType")]
pub media_type: Option<String>,
pub title: Option<String>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct ResponseData {
#[serde(rename = "subscribeFeed")]
pub subscribe_feed: SubscribeFeedSubscribeFeed,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "__typename")]
pub enum SubscribeFeedSubscribeFeed {
SubscribeFeedSuccess(SubscribeFeedSubscribeFeedOnSubscribeFeedSuccess),
SubscribeFeedError(SubscribeFeedSubscribeFeedOnSubscribeFeedError),
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct SubscribeFeedSubscribeFeedOnSubscribeFeedSuccess {
pub feed: SubscribeFeedSubscribeFeedOnSubscribeFeedSuccessFeed,
pub status: SubscribeFeedSubscribeFeedOnSubscribeFeedSuccessStatus,
}
pub type SubscribeFeedSubscribeFeedOnSubscribeFeedSuccessFeed = Feed;
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct SubscribeFeedSubscribeFeedOnSubscribeFeedSuccessStatus {
pub code: ResponseCode,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct SubscribeFeedSubscribeFeedOnSubscribeFeedError {
pub status: SubscribeFeedSubscribeFeedOnSubscribeFeedErrorStatus,
pub message: String,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct SubscribeFeedSubscribeFeedOnSubscribeFeedErrorStatus {
pub code: ResponseCode,
}
Expand Down Expand Up @@ -193,7 +193,7 @@ pub mod unsubscribe_feed {
type Int = i64;
#[allow(dead_code)]
type ID = String;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum ResponseCode {
OK,
UNAUTHORIZED,
Expand Down Expand Up @@ -233,30 +233,30 @@ pub mod unsubscribe_feed {
pub input: UnsubscribeFeedInput,
}
impl Variables {}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct ResponseData {
#[serde(rename = "unsubscribeFeed")]
pub unsubscribe_feed: UnsubscribeFeedUnsubscribeFeed,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "__typename")]
pub enum UnsubscribeFeedUnsubscribeFeed {
UnsubscribeFeedSuccess(UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedSuccess),
UnsubscribeFeedError(UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedError),
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedSuccess {
pub status: UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedSuccessStatus,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedSuccessStatus {
pub code: ResponseCode,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedError {
pub status: UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedErrorStatus,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct UnsubscribeFeedUnsubscribeFeedOnUnsubscribeFeedErrorStatus {
pub code: ResponseCode,
}
Expand Down
2 changes: 1 addition & 1 deletion crates/synd_term/src/client/payload.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{client::query, types};

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct FetchEntriesPayload {
pub entries: Vec<types::Entry>,
pub page_info: types::PageInfo,
Expand Down

0 comments on commit 257beaa

Please sign in to comment.