Skip to content

Commit

Permalink
feat: introducing keymapping and nested mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
wllfaria committed May 10, 2024
1 parent dcae09d commit cdef434
Show file tree
Hide file tree
Showing 14 changed files with 570 additions and 279 deletions.
8 changes: 5 additions & 3 deletions Cargo.lock

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

5 changes: 3 additions & 2 deletions config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
anyhow.workspace = true
tracing.workspace = true
serde.workspace = true

directories = "5.0.1"

dirs = "5.0.1"
toml = "0.8.12"
90 changes: 90 additions & 0 deletions config/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use crate::{
default_config::DEFAULT_CONFIG, EditorMode, APP_NAME, CONFIG_FILE, XDG_DEFAULTS, XDG_ENV_VARS,
};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf};

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum Action {
Undo,
FindNext,
FindPrevious,

NextWord,
PreviousWord,
MoveLeft,
MoveDown,
MoveUp,
MoveRight,
MoveToBottom,
MoveToTop,
MoveToLineEnd,
MoveToLineStart,
PageDown,
PageUp,
DeleteWord,
DeleteLine,
DeleteBack,
DeleteUntilEOL,
DeleteCurrentChar,
InsertLineBelow,
InsertLineAbove,
PasteBelow,
InsertAhead,
EnterMode(EditorMode),
InsertAtEOL,
MoveAfterWhitespaceReverse,
MoveAfterWhitespace,
DeletePreviousNonWrapping,

InsertChar(char),
InsertTab,
InsertLine,
DeletePreviousChar,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub editor_keys: Keys,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Keys {
pub normal: HashMap<String, KeyAction>,
pub insert: HashMap<String, KeyAction>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum KeyAction {
Simple(Action),
Multiple(Vec<Action>),
Complex(HashMap<String, KeyAction>),
}

pub fn get_config_dir() -> PathBuf {
let path = std::env::var(XDG_ENV_VARS[0])
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from(XDG_DEFAULTS[0]));

dirs::home_dir().unwrap_or_default().join(path)
}

#[tracing::instrument]
pub fn load_config() -> Config {
let config_file = get_config_dir().join(APP_NAME).join(CONFIG_FILE);

std::fs::read_to_string(config_file)
.map(|toml| toml::from_str::<Config>(&toml))
.unwrap_or_else(|_| toml::from_str::<Config>(DEFAULT_CONFIG))
.expect("failed to load default config")
}

impl std::fmt::Display for EditorMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Normal => f.write_str("NORMAL"),
Self::Insert => f.write_str("INSERT"),
}
}
}
35 changes: 35 additions & 0 deletions config/src/data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::path::PathBuf;

use crate::{APP_NAME, SCHEMAS_DIR, XDG_DEFAULTS, XDG_ENV_VARS};

pub fn setup_data_dir() -> anyhow::Result<PathBuf> {
let data_dir = get_data_dir();
if !data_dir.exists() && !data_dir.is_dir() {
std::fs::create_dir(&data_dir)?;
}

Ok(data_dir)
}

fn get_data_dir() -> PathBuf {
let path = std::env::var(XDG_ENV_VARS[1])
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from(XDG_DEFAULTS[1]));

dirs::home_dir()
.unwrap_or_default()
.join(path)
.join(APP_NAME)
}

#[tracing::instrument(err)]
pub fn get_schemas_dir() -> anyhow::Result<PathBuf> {
let data_dir = get_data_dir();
let schemas_dir = data_dir.join(SCHEMAS_DIR);

if !schemas_dir.exists() && !schemas_dir.is_dir() {
std::fs::create_dir(&schemas_dir)?;
}

Ok(schemas_dir)
}
47 changes: 47 additions & 0 deletions config/src/default_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
pub static DEFAULT_CONFIG: &str = r##"
[editor_keys.normal]
"u" = "Undo"
"n" = "FindNext"
"S-N" = "FindPrevious"
"w" = "NextWord"
"b" = "PreviousWord"
"h" = "MoveLeft"
"Left" = "MoveLeft"
"j" = "MoveDown"
"Down" = "MoveDown"
"k" = "MoveUp"
"Up" = "MoveUp"
"l" = "MoveRight"
"Right" = "MoveRight"
"S-G" = "MoveToBottom"
"g" = { "g" = "MoveToTop" }
"$" = "MoveToLineEnd"
"End" = "MoveToLineEnd"
"Home" = "MoveToLineStart"
"0" = "MoveToLineStart"
"C-d" = "PageDown"
"C-u" = "PageUp"
"d" = { "w" = "DeleteWord", "d" = "DeleteLine", "b" = "DeleteBack" }
"S-D" = "DeleteUntilEOL"
"x" = "DeleteCurrentChar"
"o" = "InsertLineBelow"
"S-O" = "InsertLineAbove"
"p" = "PasteBelow"
"a" = "InsertAhead"
#"/" = { EnterMode = "Search" }
"i" = { EnterMode = "Insert" }
"S-I" = ["MoveToLineStart", { EnterMode = "Insert" }]
"S-A" = "InsertAtEOL"
"S-B" = "MoveAfterWhitespaceReverse"
"S-W" = "MoveAfterWhitespace"
"S-X" = "DeletePreviousNonWrapping"
[editor_keys.insert]
"Tab" = "InsertTab"
"Enter" = "InsertLine"
"Backspace" = "DeletePreviousChar"
"Esc" = { EnterMode = "Normal" }
"C-c" = { EnterMode = "Normal" }
"C-W" = "DeleteBack"
"##;
59 changes: 25 additions & 34 deletions config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,31 @@
use directories::ProjectDirs;
use std::path::PathBuf;

fn get_data_dir() -> anyhow::Result<PathBuf> {
let directory = if let Ok(s) = std::env::var("REQTUI_DATA") {
PathBuf::from(s)
} else if let Some(proj_dirs) = ProjectDirs::from("com", "reqtui", "reqtui") {
proj_dirs.data_local_dir().to_path_buf()
} else {
anyhow::bail!("data directory not found");
};

Ok(directory)
mod config;
mod data;
mod default_config;

pub use config::{load_config, Action, Config, KeyAction};
pub use data::{get_schemas_dir, setup_data_dir};
use serde::{Deserialize, Serialize};

#[derive(PartialEq, Deserialize, Serialize, Debug, Clone)]
pub enum EditorMode {
Insert,
Normal,
}

pub fn setup_data_dir() -> anyhow::Result<PathBuf> {
let data_dir = get_data_dir()?;
pub static LOG_FILE: &str = "reqtui.log";
pub static APP_NAME: &str = "reqtui";
pub static SCHEMAS_DIR: &str = "schemas";
pub static CONFIG_FILE: &str = "reqtui.toml";
pub static THEMES_DIR: &str = "themes";

if !data_dir.exists() && !data_dir.is_dir() {
std::fs::create_dir(&data_dir)?;
}
#[cfg(unix)]
static XDG_ENV_VARS: [&str; 2] = ["XDG_CONFIG_HOME", "XDG_DATA_HOME"];

Ok(data_dir)
}
#[cfg(windows)]
static XDG_ENV_VARS: [&str; 2] = ["LOCALAPPDATA", "LOCALAPPDATA"];

pub fn get_logfile() -> &'static str {
"reqtui.log"
}
#[cfg(unix)]
static XDG_DEFAULTS: [&str; 2] = [".config", ".local/share"];

#[tracing::instrument(err)]
pub fn get_schemas_dir() -> anyhow::Result<PathBuf> {
let data_dir = get_data_dir()?;
let schemas_dir = data_dir.join("schemas");

if !schemas_dir.exists() && !schemas_dir.is_dir() {
std::fs::create_dir(&schemas_dir)?;
}

Ok(schemas_dir)
}
#[cfg(windows)]
static XDG_DEFAULTS: [&str; 2] = ["AppData\\Local", "AppData\\Local"];
1 change: 0 additions & 1 deletion reqtui/src/schema/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ where
T: AsRef<Path>,
{
let items = std::fs::read_dir(&schemas_dir)?;
tracing::debug!("{:?}", schemas_dir.as_ref());

let mut collections = vec![];

Expand Down
6 changes: 4 additions & 2 deletions tui/benches/api_explorer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ fn handling_key_events() {
let colors = colors::Colors::default();
let schema = create_sample_schema();
let size = Rect::new(0, 0, 80, 24);
let mut api_explorer = ApiExplorer::new(size, schema, &colors);
let config = config::load_config();
let mut api_explorer = ApiExplorer::new(size, schema, &colors, &config);
let mut terminal = Terminal::new(TestBackend::new(size.width, size.height)).unwrap();
let mut frame = terminal.get_frame();

Expand All @@ -89,7 +90,8 @@ fn creating_with_highlight() {
let colors = colors::Colors::default();
let schema = create_sample_schema();
let size = Rect::new(0, 0, 80, 24);
let mut api_explorer = ApiExplorer::new(size, schema, &colors);
let config = config::load_config();
let mut api_explorer = ApiExplorer::new(size, schema, &colors, &config);
let mut terminal = Terminal::new(TestBackend::new(size.width, size.height)).unwrap();
let _frame = terminal.get_frame();

Expand Down
17 changes: 10 additions & 7 deletions tui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,27 @@ use crate::{
event_pool::{Event, EventPool},
screen_manager::ScreenManager,
};
use reqtui::{command::Command, schema::Schema};

use ratatui::{backend::CrosstermBackend, Terminal};
use reqtui::{command::Command, schema::Schema};
use std::io::Stdout;
use tokio::sync::mpsc;

pub struct App<'a> {
pub struct App<'app> {
event_pool: EventPool,
terminal: Terminal<CrosstermBackend<Stdout>>,
should_quit: bool,
screen_manager: ScreenManager<'a>,
screen_manager: ScreenManager<'app>,
}

impl<'a> App<'a> {
pub fn new(colors: &'a colors::Colors, schemas: Vec<Schema>) -> anyhow::Result<Self> {
impl<'app> App<'app> {
pub fn new(
colors: &'app colors::Colors,
schemas: Vec<Schema>,
config: &'app config::Config,
) -> anyhow::Result<Self> {
let terminal = Terminal::new(CrosstermBackend::new(std::io::stdout()))?;
Ok(Self {
screen_manager: ScreenManager::new(terminal.size()?, colors, schemas)?,
screen_manager: ScreenManager::new(terminal.size()?, colors, schemas, config)?,
event_pool: EventPool::new(60f64),
should_quit: false,
terminal,
Expand Down
3 changes: 1 addition & 2 deletions tui/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ pub mod input;
pub mod terminal_too_small;

use crate::event_pool::Event;
use reqtui::command::Command;

use crossterm::event::KeyEvent;
use ratatui::{layout::Rect, Frame};
use reqtui::command::Command;
use tokio::sync::mpsc::UnboundedSender;

pub trait Eventful {
Expand Down
Loading

0 comments on commit cdef434

Please sign in to comment.