aboutsummaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2021-02-09 17:36:37 +0100
committerGitHub <noreply@github.com>2021-02-09 17:36:37 +0100
commit14783c2b2c3bcd3b4b01e72c46d6af3ecbdd203c (patch)
tree7e25be8c93e85ec9fc03335f1993f319f713c614 /src/common
parentMerge pull request #158 from mosaic-org/add-files (diff)
downloadsl0ppij-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.rs2
-rw-r--r--src/common/input/actions.rs1
-rw-r--r--src/common/input/handler.rs124
-rw-r--r--src/common/input/keybinds.rs128
-rw-r--r--src/common/mod.rs20
-rw-r--r--src/common/screen.rs1
-rw-r--r--src/common/wasm_vm.rs16
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());
}
}