diff options
| author | Aram Drevekenin <aram@poor.dev> | 2021-02-09 17:36:37 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-09 17:36:37 +0100 |
| commit | 14783c2b2c3bcd3b4b01e72c46d6af3ecbdd203c (patch) | |
| tree | 7e25be8c93e85ec9fc03335f1993f319f713c614 /src/common | |
| parent | Merge pull request #158 from mosaic-org/add-files (diff) | |
| download | sl0ppij-14783c2b2c3bcd3b4b01e72c46d6af3ecbdd203c.tar.gz sl0ppij-14783c2b2c3bcd3b4b01e72c46d6af3ecbdd203c.tar.xz sl0ppij-14783c2b2c3bcd3b4b01e72c46d6af3ecbdd203c.zip | |
feat(ui): new keybindings and status bar (#160)
* work
* feat(statusbar): new design and keybindings
* fix(ipc): add missing const
* style(fmt): rustfmt
* style(input): remove accidental comment
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/errors.rs | 2 | ||||
| -rw-r--r-- | src/common/input/actions.rs | 1 | ||||
| -rw-r--r-- | src/common/input/handler.rs | 124 | ||||
| -rw-r--r-- | src/common/input/keybinds.rs | 128 | ||||
| -rw-r--r-- | src/common/mod.rs | 20 | ||||
| -rw-r--r-- | src/common/screen.rs | 1 | ||||
| -rw-r--r-- | src/common/wasm_vm.rs | 16 |
7 files changed, 206 insertions, 86 deletions
diff --git a/src/common/errors.rs b/src/common/errors.rs index 90ca6f9e..27fe3103 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -167,6 +167,7 @@ pub enum ScreenContext { CloseFocusedPane, ToggleActiveTerminalFullscreen, SetSelectable, + SetInvisibleBorders, SetMaxHeight, ClosePane, ApplyLayout, @@ -203,6 +204,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenContext::ToggleActiveTerminalFullscreen } ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, + ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight, ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, ScreenInstruction::ApplyLayout(_) => ScreenContext::ApplyLayout, diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs index be7bcdb9..6f4a4521 100644 --- a/src/common/input/actions.rs +++ b/src/common/input/actions.rs @@ -18,6 +18,7 @@ pub enum Action { Write(Vec<u8>), /// Switch to the specified input mode SwitchToMode(handler::InputMode), + TogglePersistentMode, /// Resize focus pane in specified direction Resize(Direction), /// Switch focus to next pane in specified direction diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index b10e9df3..2a1c2c72 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -9,6 +9,7 @@ use crate::screen::ScreenInstruction; use crate::wasm_vm::PluginInstruction; use crate::CommandIsExecuting; +use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; use termion::input::TermReadEventsAndRaw; @@ -16,6 +17,7 @@ use super::keybinds::key_to_action; struct InputHandler { mode: InputMode, + mode_is_persistent: bool, os_input: Box<dyn OsApi>, command_is_executing: CommandIsExecuting, send_screen_instructions: SenderWithContext<ScreenInstruction>, @@ -35,6 +37,7 @@ impl InputHandler { ) -> Self { InputHandler { mode: InputMode::Normal, + mode_is_persistent: false, os_input, command_is_executing, send_screen_instructions, @@ -68,12 +71,13 @@ impl InputHandler { &key, raw_bytes, &self.mode, &keybinds, )); //@@@ This is a hack until we dispatch more than one action per key stroke - if entry_mode == InputMode::Command - && self.mode == InputMode::Command - { + if entry_mode == self.mode && !self.mode_is_persistent { self.mode = InputMode::Normal; update_state(&self.send_app_instructions, |_| AppState { - input_mode: self.mode, + input_state: InputState { + mode: self.mode, + persistent: self.mode_is_persistent, + }, }); } if should_break { @@ -113,13 +117,28 @@ impl InputHandler { } Action::SwitchToMode(mode) => { self.mode = mode; + if mode == InputMode::Normal { + self.mode_is_persistent = false; + } update_state(&self.send_app_instructions, |_| AppState { - input_mode: self.mode, + input_state: InputState { + mode: self.mode, + persistent: self.mode_is_persistent, + }, }); self.send_screen_instructions .send(ScreenInstruction::Render) .unwrap(); } + Action::TogglePersistentMode => { + self.mode_is_persistent = !self.mode_is_persistent; + update_state(&self.send_app_instructions, |_| AppState { + input_state: InputState { + mode: self.mode, + persistent: self.mode_is_persistent, + }, + }); + } Action::Resize(direction) => { let screen_instr = match direction { super::actions::Direction::Left => ScreenInstruction::ResizeLeft, @@ -224,6 +243,21 @@ impl InputHandler { } } +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] +pub struct InputState { + mode: InputMode, + persistent: bool, +} + +impl Default for InputState { + fn default() -> InputState { + InputState { + mode: InputMode::Normal, + persistent: false, + } + } +} + /// Dictates whether we're in command mode, persistent command mode, normal mode or exiting: /// - Normal mode either writes characters to the terminal, or switches to command mode /// using a particular key control @@ -231,41 +265,65 @@ impl InputHandler { /// back to normal mode /// - Persistent command mode is the same as command mode, but doesn't return automatically to /// normal mode -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter)] +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter, Serialize, Deserialize)] pub enum InputMode { Normal, Command, - CommandPersistent, + Resize, + Pane, + Tab, + Scroll, Exiting, } -// FIXME: This should be auto-generated from the soon-to-be-added `get_default_keybinds` -pub fn get_help(mode: &InputMode) -> Vec<String> { - let command_help = vec![ - "<n/b/z> Split".into(), - "<j/k/h/l> Resize".into(), - "<p> Focus Next".into(), - "<x> Close Pane".into(), - "<q> Quit".into(), - "<PgUp/PgDown> Scroll".into(), - "<1> New Tab".into(), - "<2/3> Move Tab".into(), - "<4> Close Tab".into(), - ]; - match mode { - InputMode::Normal => vec!["<Ctrl-g> Command Mode".into()], - InputMode::Command => [ - vec![ - "<Ctrl-g> Persistent Mode".into(), - "<ESC> Normal Mode".into(), - ], - command_help, - ] - .concat(), - InputMode::CommandPersistent => { - [vec!["<ESC/Ctrl-g> Normal Mode".into()], command_help].concat() +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct Help { + pub mode: InputMode, + pub mode_is_persistent: bool, + pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description> +} + +impl Default for InputMode { + fn default() -> InputMode { + InputMode::Normal + } +} + +pub fn get_help(input_state: &InputState) -> Help { + let mut keybinds: Vec<(String, String)> = vec![]; + match input_state.mode { + InputMode::Normal | InputMode::Command | InputMode::Exiting => { + keybinds.push((format!("p"), format!("Pane mode"))); + keybinds.push((format!("t"), format!("Tab mode"))); + keybinds.push((format!("r"), format!("Resize mode"))); } - InputMode::Exiting => vec!["Bye from Mosaic!".into()], + InputMode::Resize => { + keybinds.push((format!("←↓↑→"), format!("resize pane"))); + } + InputMode::Pane => { + keybinds.push((format!("←↓↑→"), format!("move focus"))); + keybinds.push((format!("p"), format!("next pane"))); + keybinds.push((format!("n"), format!("new pane"))); + keybinds.push((format!("d"), format!("down split"))); + keybinds.push((format!("r"), format!("right split"))); + keybinds.push((format!("x"), format!("exit pane"))); + keybinds.push((format!("f"), format!("fullscreen pane"))); + } + InputMode::Tab => { + keybinds.push((format!("←↓↑→"), format!("move tab focus"))); + keybinds.push((format!("n"), format!("new tab"))); + keybinds.push((format!("x"), format!("exit tab"))); + } + InputMode::Scroll => { + keybinds.push((format!("↓↑"), format!("scroll up/down"))); + } + } + keybinds.push((format!("ESC"), format!("Back"))); + keybinds.push((format!("q"), format!("Quit"))); + Help { + mode: input_state.mode, + mode_is_persistent: input_state.persistent, + keybinds, } } diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index c8a87d51..d6ace68d 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -28,57 +28,101 @@ fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> { match *mode { InputMode::Normal => { - // Ctrl+G -> Command Mode defaults.insert(Key::Ctrl('g'), Action::SwitchToMode(InputMode::Command)); } - command_mode @ InputMode::Command | command_mode @ InputMode::CommandPersistent => { - match command_mode { - InputMode::Command => { - // Ctrl+G -> Command Mode (Persistent) - defaults.insert( - Key::Ctrl('g'), - Action::SwitchToMode(InputMode::CommandPersistent), - ); - } - InputMode::CommandPersistent => { - // Ctrl+G -> Command Mode (Persistent) - defaults.insert(Key::Ctrl('g'), Action::SwitchToMode(InputMode::Normal)); - } - _ => unreachable!(), - } - // Esc -> Normal Mode + InputMode::Command => { + defaults.insert(Key::Char('r'), Action::SwitchToMode(InputMode::Resize)); + defaults.insert(Key::Char('p'), Action::SwitchToMode(InputMode::Pane)); + defaults.insert(Key::Char('t'), Action::SwitchToMode(InputMode::Tab)); + defaults.insert(Key::Char('s'), Action::SwitchToMode(InputMode::Scroll)); + defaults.insert(Key::Ctrl('g'), Action::TogglePersistentMode); defaults.insert(Key::Esc, Action::SwitchToMode(InputMode::Normal)); - // Resize commands + defaults.insert(Key::Char('q'), Action::Quit); + } + InputMode::Resize => { + defaults.insert(Key::Char('h'), Action::Resize(Direction::Left)); defaults.insert(Key::Char('j'), Action::Resize(Direction::Down)); defaults.insert(Key::Char('k'), Action::Resize(Direction::Up)); - defaults.insert(Key::Char('h'), Action::Resize(Direction::Left)); defaults.insert(Key::Char('l'), Action::Resize(Direction::Right)); - // Move pane commands - defaults.insert(Key::Char('u'), Action::MoveFocus(Direction::Down)); - defaults.insert(Key::Char('i'), Action::MoveFocus(Direction::Up)); - defaults.insert(Key::Char('y'), Action::MoveFocus(Direction::Left)); - defaults.insert(Key::Char('o'), Action::MoveFocus(Direction::Right)); - // Switch focus - // @@@ Currently just tab through panes - use right for this + + defaults.insert(Key::Left, Action::Resize(Direction::Left)); + defaults.insert(Key::Down, Action::Resize(Direction::Down)); + defaults.insert(Key::Up, Action::Resize(Direction::Up)); + defaults.insert(Key::Right, Action::Resize(Direction::Right)); + + defaults.insert(Key::Ctrl('b'), Action::Resize(Direction::Left)); + defaults.insert(Key::Ctrl('n'), Action::Resize(Direction::Down)); + defaults.insert(Key::Ctrl('p'), Action::Resize(Direction::Up)); + defaults.insert(Key::Ctrl('f'), Action::Resize(Direction::Right)); + + defaults.insert(Key::Char('q'), Action::Quit); + defaults.insert(Key::Ctrl('g'), Action::TogglePersistentMode); + defaults.insert(Key::Esc, Action::SwitchToMode(InputMode::Normal)); + } + InputMode::Pane => { + defaults.insert(Key::Char('h'), Action::MoveFocus(Direction::Left)); + defaults.insert(Key::Char('j'), Action::MoveFocus(Direction::Down)); + defaults.insert(Key::Char('k'), Action::MoveFocus(Direction::Up)); + defaults.insert(Key::Char('l'), Action::MoveFocus(Direction::Right)); + + defaults.insert(Key::Left, Action::MoveFocus(Direction::Left)); + defaults.insert(Key::Down, Action::MoveFocus(Direction::Down)); + defaults.insert(Key::Up, Action::MoveFocus(Direction::Up)); + defaults.insert(Key::Right, Action::MoveFocus(Direction::Right)); + + defaults.insert(Key::Ctrl('b'), Action::MoveFocus(Direction::Left)); + defaults.insert(Key::Ctrl('n'), Action::MoveFocus(Direction::Down)); + defaults.insert(Key::Ctrl('p'), Action::MoveFocus(Direction::Up)); + defaults.insert(Key::Ctrl('f'), Action::MoveFocus(Direction::Right)); + defaults.insert(Key::Char('p'), Action::SwitchFocus(Direction::Right)); - // Scroll - defaults.insert(Key::PageUp, Action::ScrollUp); - defaults.insert(Key::PageDown, Action::ScrollDown); - // Tab controls - defaults.insert(Key::Char('1'), Action::NewTab); - defaults.insert(Key::Char('2'), Action::GoToNextTab); - defaults.insert(Key::Char('3'), Action::GoToPreviousTab); - defaults.insert(Key::Char('4'), Action::CloseTab); - // New pane - defaults.insert(Key::Char('z'), Action::NewPane(None)); - defaults.insert(Key::Char('b'), Action::NewPane(Some(Direction::Down))); - defaults.insert(Key::Char('n'), Action::NewPane(Some(Direction::Right))); - // Toggle focus fullscreen - defaults.insert(Key::Char('e'), Action::ToggleFocusFullscreen); - // Close pane + defaults.insert(Key::Char('n'), Action::NewPane(None)); + defaults.insert(Key::Char('d'), Action::NewPane(Some(Direction::Down))); + defaults.insert(Key::Char('r'), Action::NewPane(Some(Direction::Right))); defaults.insert(Key::Char('x'), Action::CloseFocus); - // Close Mosaic + + defaults.insert(Key::Char('f'), Action::ToggleFocusFullscreen); + defaults.insert(Key::Char('q'), Action::Quit); + defaults.insert(Key::Ctrl('g'), Action::TogglePersistentMode); + defaults.insert(Key::Esc, Action::SwitchToMode(InputMode::Normal)); + } + InputMode::Tab => { + defaults.insert(Key::Char('h'), Action::GoToPreviousTab); + defaults.insert(Key::Char('j'), Action::GoToNextTab); + defaults.insert(Key::Char('k'), Action::GoToPreviousTab); + defaults.insert(Key::Char('l'), Action::GoToNextTab); + + defaults.insert(Key::Left, Action::GoToPreviousTab); + defaults.insert(Key::Down, Action::GoToNextTab); + defaults.insert(Key::Up, Action::GoToPreviousTab); + defaults.insert(Key::Right, Action::GoToNextTab); + + defaults.insert(Key::Ctrl('b'), Action::GoToPreviousTab); + defaults.insert(Key::Ctrl('n'), Action::GoToNextTab); + defaults.insert(Key::Ctrl('p'), Action::GoToPreviousTab); + defaults.insert(Key::Ctrl('f'), Action::GoToNextTab); + + defaults.insert(Key::Char('n'), Action::NewTab); + defaults.insert(Key::Char('x'), Action::CloseTab); + + defaults.insert(Key::Char('q'), Action::Quit); + defaults.insert(Key::Ctrl('g'), Action::TogglePersistentMode); + defaults.insert(Key::Esc, Action::SwitchToMode(InputMode::Normal)); + } + InputMode::Scroll => { + defaults.insert(Key::Char('j'), Action::ScrollDown); + defaults.insert(Key::Char('k'), Action::ScrollUp); + + defaults.insert(Key::Down, Action::ScrollDown); + defaults.insert(Key::Up, Action::ScrollUp); + + defaults.insert(Key::Ctrl('n'), Action::ScrollDown); + defaults.insert(Key::Ctrl('p'), Action::ScrollUp); + + defaults.insert(Key::Char('q'), Action::Quit); + defaults.insert(Key::Ctrl('g'), Action::TogglePersistentMode); + defaults.insert(Key::Esc, Action::SwitchToMode(InputMode::Normal)); } InputMode::Exiting => {} } diff --git a/src/common/mod.rs b/src/common/mod.rs index ab4b84e2..de0b9f76 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -17,7 +17,7 @@ use std::{collections::HashMap, fs}; use crate::panes::PaneId; use directories_next::ProjectDirs; -use input::handler::InputMode; +use input::handler::InputState; use serde::{Deserialize, Serialize}; use termion::input::TermRead; use wasm_vm::PluginEnv; @@ -43,18 +43,11 @@ pub enum ApiCommand { MoveFocus, } // FIXME: It would be good to add some more things to this over time -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct AppState { - pub input_mode: InputMode, + pub input_state: InputState, } -impl Default for AppState { - fn default() -> Self { - Self { - input_mode: InputMode::Normal, - } - } -} // FIXME: Make this a method on the big `Communication` struct, so that app_tx can be extracted // from self instead of being explicitly passed here pub fn update_state( @@ -362,6 +355,13 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .unwrap() .set_pane_max_height(id, max_height); } + ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => { + screen + .get_active_tab_mut() + .unwrap() + .set_pane_invisible_borders(id, invisible_borders); + screen.render(); + } ScreenInstruction::ClosePane(id) => { screen.get_active_tab_mut().unwrap().close_pane(id); screen.render(); diff --git a/src/common/screen.rs b/src/common/screen.rs index 69595c07..6ae89ddc 100644 --- a/src/common/screen.rs +++ b/src/common/screen.rs @@ -44,6 +44,7 @@ pub enum ScreenInstruction { ToggleActiveTerminalFullscreen, SetSelectable(PaneId, bool), SetMaxHeight(PaneId, usize), + SetInvisibleBorders(PaneId, bool), ClosePane(PaneId), ApplyLayout((Layout, Vec<RawFd>)), NewTab(RawFd), diff --git a/src/common/wasm_vm.rs b/src/common/wasm_vm.rs index 9f04488f..758d5e8a 100644 --- a/src/common/wasm_vm.rs +++ b/src/common/wasm_vm.rs @@ -5,6 +5,8 @@ use std::{ use wasmer::{imports, Function, ImportObject, Store, WasmerEnv}; use wasmer_wasi::WasiEnv; +use crate::utils::logging::debug_log_to_file; + use super::{ input::handler::get_help, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, PaneId, SenderWithContext, @@ -35,6 +37,7 @@ pub fn mosaic_imports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { imports! { "mosaic" => { "host_open_file" => Function::new_native_with_env(store, plugin_env.clone(), host_open_file), + "host_set_invisible_borders" => Function::new_native_with_env(store, plugin_env.clone(), host_set_invisible_borders), "host_set_max_height" => Function::new_native_with_env(store, plugin_env.clone(), host_set_max_height), "host_set_selectable" => Function::new_native_with_env(store, plugin_env.clone(), host_set_selectable), "host_get_help" => Function::new_native_with_env(store, plugin_env.clone(), host_get_help), @@ -74,6 +77,17 @@ fn host_set_max_height(plugin_env: &PluginEnv, max_height: i32) { .unwrap() } +fn host_set_invisible_borders(plugin_env: &PluginEnv, invisible_borders: i32) { + let invisible_borders = invisible_borders != 0; + plugin_env + .send_screen_instructions + .send(ScreenInstruction::SetInvisibleBorders( + PaneId::Plugin(plugin_env.plugin_id), + invisible_borders, + )) + .unwrap() +} + fn host_get_help(plugin_env: &PluginEnv) { let (state_tx, state_rx) = channel(); // FIXME: If I changed the application so that threads were sent the termination @@ -84,7 +98,7 @@ fn host_get_help(plugin_env: &PluginEnv) { .try_send(AppInstruction::GetState(state_tx)) .is_ok() { - let help = get_help(&state_rx.recv().unwrap().input_mode); + let help = get_help(&state_rx.recv().unwrap().input_state); wasi_write_string(&plugin_env.wasi_env, &serde_json::to_string(&help).unwrap()); } } |
