Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support key binds mapping #21

Merged
merged 16 commits into from
Aug 9, 2024
Merged
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ semver = "1.0.23"
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.122"
sha1 = "0.10.6"
strum = "0.26.3"
toml = "0.8.19"
tui-input = "0.9.0"
tui-tree-widget = "0.21.0"
Expand Down
31 changes: 31 additions & 0 deletions assets/default-keybind.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
ForceQuit = ["ctrl-c"]
Quit = ["q"]
NavigateUp = ["k", "up"]
NavigateDown = ["j", "down"]
NavigateRight = ["l", "right"]
NavigateLeft = ["h", "left"]

# close widget or cancel progress but not quit app
CloseOrCancel = ["esc"]
HelpToggle = ["?"]
GoToTop = ["g"]
GoToBottom = ["shift-G"]
GoToNext = ["n"]
GoToPrevious = ["shift-N"]
yanganto marked this conversation as resolved.
Show resolved Hide resolved
ScrollDown = ["ctrl-e"]
ScrollUp = ["ctrl-y"]
PageUp = ["ctrl-b"]
PageDown = ["ctrl-f"]
HalfPageUp = ["ctrl-u"]
HalfPageDown = ["ctrl-d"]
SelectTop = ["shift-H"]
SelectMiddle = ["shift-M"]
SelectBottom = ["shift-L"]
Confirm = ["enter"]
Search = ["/"]

# copy part of information, ex: copy the short commit hash not all
ShortCopy = ["c"]
FullCopy = ["shift-C"]

RefListToggle = ["tab"]
82 changes: 82 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
yanganto marked this conversation as resolved.
Show resolved Hide resolved
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};

flake-utils.url = "github:numtide/flake-utils";
};

outputs = { self, rust-overlay, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
in
with pkgs;
{
devShells = rec {
default = mkShell {
buildInputs = [
rust-bin.stable.latest.default
];
};
};
}
);
}
61 changes: 36 additions & 25 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use ratatui::{
use crate::{
color::ColorSet,
config::Config,
event::{AppEvent, Receiver, Sender},
event::{AppEvent, Receiver, Sender, UserEvent},
external::copy_to_clipboard,
git::Repository,
graph::{Graph, GraphImage},
key_code_char,
keybind::KeyBind,
protocol::ImageProtocol,
view::View,
widget::commit_list::{CommitInfo, CommitListState},
Expand Down Expand Up @@ -46,16 +46,19 @@ pub struct App<'a> {
view: View<'a>,
status_line: StatusLine,

keybind: &'a KeyBind,
config: &'a Config,
image_protocol: ImageProtocol,
tx: Sender,
}

impl<'a> App<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new(
repository: &'a Repository,
graph: &'a Graph,
graph_image: &'a GraphImage,
keybind: &'a KeyBind,
config: &'a Config,
color_set: &'a ColorSet,
image_protocol: ImageProtocol,
Expand Down Expand Up @@ -94,6 +97,7 @@ impl<'a> App<'a> {
repository,
status_line: StatusLine::None,
view,
keybind,
config,
image_protocol,
tx,
Expand All @@ -109,31 +113,33 @@ impl App<'_> {
) -> std::io::Result<()> {
loop {
terminal.draw(|f| self.render(f))?;
match self.status_line {
yanganto marked this conversation as resolved.
Show resolved Hide resolved
StatusLine::None | StatusLine::Input(_, _) => {
// do nothing
}
StatusLine::NotificationInfo(_)
| StatusLine::NotificationSuccess(_)
| StatusLine::NotificationWarn(_) => {
// Clear message and pass key input as is
self.clear_status_line();
}
StatusLine::NotificationError(_) => {
// Clear message and cancel key input
self.clear_status_line();
continue;
}
}

match rx.recv() {
AppEvent::Key(key) => match key {
key_code_char!('c', Ctrl) => {
return Ok(());
AppEvent::Key(key) => match self.keybind.get(&key) {
Some(UserEvent::ForceQuit) => {
self.tx.send(AppEvent::Quit);
}
_ => {
match self.status_line {
StatusLine::None | StatusLine::Input(_, _) => {
// do nothing
}
StatusLine::NotificationInfo(_)
| StatusLine::NotificationSuccess(_)
| StatusLine::NotificationWarn(_) => {
// Clear message and pass key input as is
self.clear_status_line();
}
StatusLine::NotificationError(_) => {
// Clear message and cancel key input
self.clear_status_line();
continue;
}
}

self.view.handle_key(key);
Some(ue) => {
self.view.handle_event(ue, key);
}
None => {
self.view.handle_event(&UserEvent::Unknown, key);
}
},
AppEvent::Resize(w, h) => {
Expand Down Expand Up @@ -286,7 +292,12 @@ impl App<'_> {

fn open_help(&mut self) {
let before_view = std::mem::take(&mut self.view);
self.view = View::of_help(before_view, self.image_protocol, self.tx.clone());
self.view = View::of_help(
before_view,
self.image_protocol,
self.tx.clone(),
self.keybind,
);
}

fn close_help(&mut self) {
Expand Down
6 changes: 6 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use serde::Deserialize;

use crate::keybind::KeyBind;

const APP_DIR_NAME: &str = "serie";
const CONFIG_FILE_NAME: &str = "config.toml";

Expand All @@ -15,6 +17,7 @@ const DEFAULT_DETAIL_DATE_LOCAL: bool = true;
pub struct Config {
#[serde(default)]
pub ui: UiConfig,
pub custom_keybind_patch: Option<KeyBind>,
yanganto marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize)]
Expand Down Expand Up @@ -131,6 +134,7 @@ mod tests {
date_local: true,
},
},
custom_keybind_patch: None,
};
assert_eq!(actual, expected);
}
Expand Down Expand Up @@ -163,6 +167,7 @@ mod tests {
date_local: false,
},
},
custom_keybind_patch: None,
};
assert_eq!(actual, expected);
}
Expand All @@ -188,6 +193,7 @@ mod tests {
date_local: true,
},
},
custom_keybind_patch: None,
};
assert_eq!(actual, expected);
}
Expand Down
61 changes: 61 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::{
};

use ratatui::crossterm::event::KeyEvent;
use serde::Deserialize;
use strum::{EnumIter, EnumMessage};

pub enum AppEvent {
Key(KeyEvent),
Expand Down Expand Up @@ -79,3 +81,62 @@ pub fn init() -> (Sender, Receiver) {

(tx, rx)
}

/// The event triggered by user's key input
#[derive(Clone, Debug, strum::Display, Deserialize, EnumIter, Eq, EnumMessage, Hash, PartialEq)]
pub enum UserEvent {
// NOTE User Event should have document, else the enum item will be hidden in the help page
/// Navigate up
NavigateUp,
/// Navigate down
NavigateDown,
/// Navigate right
NavigateRight,
/// Navigate left
NavigateLeft,
/// Force Quit serie without passing input into widges or views
ForceQuit,
/// Quit serie
Quit,
/// Close widget or cancel current progress
CloseOrCancel,
/// Toggle Help page
HelpToggle,
/// Go to top
GoToTop,
/// Go to bottom
GoToBottom,
/// Go to next item
GoToNext,
/// Go to previous item
GoToPrevious,
/// Scroll one line up
ScrollUp,
/// Scroll one line down
ScrollDown,
/// Scroll one page up
PageUp,
/// Scroll one page down
PageDown,
/// Scroll half page up
HalfPageUp,
/// Scroll half page down
HalfPageDown,
/// Select top part
SelectTop,
/// Select middle part
SelectMiddle,
/// Select bottom part
SelectBottom,
/// Confirm
Confirm,
/// Search
Search,
/// Copy part of content
ShortCopy,
/// Copy
FullCopy,
/// Toggle for Reference List
RefListToggle,
Unknown,
}
Loading