Poking around

This commit is contained in:
a-kenji 2021-03-11 13:58:58 +01:00
parent c97c553870
commit 2b2b7325e7
11 changed files with 193 additions and 154 deletions

View File

@ -22,7 +22,6 @@ _zellij() {
'--max-panes=[Maximum panes on screen, caution: opening more panes will close old ones]' \
'-l+[Path to a layout yaml file]' \
'--layout=[Path to a layout yaml file]' \
'-c+[Path to the configuration yaml file]' \
'--config=[Path to the configuration yaml file]' \
'-m[Send "move focused pane" to active zellij session]' \
'--move-focus[Send "move focused pane" to active zellij session]' \

View File

@ -20,7 +20,7 @@ _zellij() {
case "${cmd}" in
zellij)
opts=" -m -d -h -V -s -o -l -c --move-focus --debug --help --version --split --open-file --max-panes --layout --config "
opts=" -m -d -h -V -s -o -l --move-focus --debug --help --version --split --open-file --max-panes --layout --config "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -59,10 +59,6 @@ _zellij() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-c)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;

View File

@ -2,7 +2,7 @@ complete -c zellij -n "__fish_use_subcommand" -s s -l split -d 'Send "split (dir
complete -c zellij -n "__fish_use_subcommand" -s o -l open-file -d 'Send "open file in new pane" to active zellij session'
complete -c zellij -n "__fish_use_subcommand" -l max-panes -d 'Maximum panes on screen, caution: opening more panes will close old ones'
complete -c zellij -n "__fish_use_subcommand" -s l -l layout -d 'Path to a layout yaml file'
complete -c zellij -n "__fish_use_subcommand" -s c -l config -d 'Path to the configuration yaml file'
complete -c zellij -n "__fish_use_subcommand" -l config -d 'Path to the configuration yaml file'
complete -c zellij -n "__fish_use_subcommand" -s m -l move-focus -d 'Send "move focused pane" to active zellij session'
complete -c zellij -n "__fish_use_subcommand" -s d -l debug
complete -c zellij -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'

View File

@ -1,12 +1,17 @@
---
keybinds:
Normal:
- {F: 1}: [GoToTab: 1,]
- {F: 2}: [GoToTab: 2,]
- {F: 3}: [GoToTab: 3,]
- {F: 4}: [GoToTab: 4,]
- {F: 5}: [NewTab: ,]
- ? - F: 6
- F: 7
: - {GoToTab: 5}
- Backspace: [NewPane: Right, NewPane: Right,]
- action: [GoToTab: 1,]
key: [F: 1,]
- action: [GoToTab: 2,]
key: [F: 2,]
- action: [GoToTab: 3,]
key: [F: 3,]
- action: [GoToTab: 4,]
key: [F: 3,]
- action: [NewTab,]
key: [F: 5,]
- action: [NewPane: Right, NewPane: Right,]
key: [F: 6,]
- action: [NewPane: Right, NewPane: Right,]
key: [F: 6,]

View File

@ -25,7 +25,7 @@ pub struct CliArgs {
pub layout: Option<PathBuf>,
/// Path to the configuration yaml file
#[structopt(short, long)]
#[structopt(long)]
pub config: Option<PathBuf>,
#[structopt(short, long)]

View File

@ -1,12 +1,11 @@
//! Deserializes configuration options.
use std;
use std::error;
use std::fmt::{self, Display};
use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use super::input::keybinds::{Keybinds, MultipleKeybinds};
use super::input::keybinds::{Keybinds, KeybindsFromYaml};
use crate::utils::logging::*;
use directories_next::ProjectDirs;
@ -15,7 +14,7 @@ use serde::Deserialize;
/// Intermediate deserialisation config struct
#[derive(Debug, Deserialize)]
pub struct ConfigFromYaml {
pub keybinds: Option<MultipleKeybinds>,
pub keybinds: Option<KeybindsFromYaml>,
}
/// Main configuration.
@ -53,7 +52,7 @@ impl Config {
/// The allow is here, because rust assumes there is no
/// error handling when logging the error to the log file.
#[allow(unused_must_use)]
pub fn new(path: &PathBuf) -> Result<Config, ConfigError> {
pub fn new(path: &Path) -> Result<Config, ConfigError> {
match File::open(path) {
Ok(mut file) => {
let mut yaml_config = String::new();
@ -81,7 +80,7 @@ impl Config {
Ok(Config::new(&config_path)?)
} else {
let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap();
let mut config_path: PathBuf = project_dirs.config_dir().to_owned().into();
let mut config_path: PathBuf = project_dirs.config_dir().to_owned();
config_path.push("config.yaml");
Ok(Config::new(&config_path)?)
}

View File

@ -60,49 +60,43 @@ impl InputHandler {
self.send_pty_instructions.update(err_ctx);
self.send_app_instructions.update(err_ctx);
self.send_screen_instructions.update(err_ctx);
if let Ok(_keybinds) = Keybinds::get_default_keybinds() {
let keybinds = self.config.keybinds.clone();
'input_loop: loop {
//@@@ I think this should actually just iterate over stdin directly
let stdin_buffer = self.os_input.read_from_stdin();
drop(
self.send_plugin_instructions
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
);
for key_result in stdin_buffer.events_and_raw() {
match key_result {
Ok((event, raw_bytes)) => match event {
termion::event::Event::Key(key) => {
// FIXME this explicit break is needed because the current test
// framework relies on it to not create dead threads that loop
// and eat up CPUs. Do not remove until the test framework has
// been revised. Sorry about this (@categorille)
if {
let mut should_break = false;
// Hacked on way to have a means of testing Macros, needs to
// get properly integrated
for action in Keybinds::key_to_actions(
&key, raw_bytes, &self.mode, &keybinds,
) {
should_break |= self.dispatch_action(action);
}
should_break
} {
break 'input_loop;
let keybinds = self.config.keybinds.clone();
'input_loop: loop {
//@@@ I think this should actually just iterate over stdin directly
let stdin_buffer = self.os_input.read_from_stdin();
drop(
self.send_plugin_instructions
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
);
for key_result in stdin_buffer.events_and_raw() {
match key_result {
Ok((event, raw_bytes)) => match event {
termion::event::Event::Key(key) => {
// FIXME this explicit break is needed because the current test
// framework relies on it to not create dead threads that loop
// and eat up CPUs. Do not remove until the test framework has
// been revised. Sorry about this (@categorille)
if {
let mut should_break = false;
// Hacked on way to have a means of testing Macros, needs to
// get properly integrated
for action in
Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds)
{
should_break |= self.dispatch_action(action);
}
should_break
} {
break 'input_loop;
}
termion::event::Event::Mouse(_)
| termion::event::Event::Unsupported(_) => {
unimplemented!("Mouse and unsupported events aren't supported!");
}
},
Err(err) => panic!("Encountered read error: {:?}", err),
}
}
termion::event::Event::Mouse(_) | termion::event::Event::Unsupported(_) => {
unimplemented!("Mouse and unsupported events aren't supported!");
}
},
Err(err) => panic!("Encountered read error: {:?}", err),
}
}
} else {
//@@@ Error handling?
self.exit();
}
}

View File

@ -8,50 +8,41 @@ use serde::Deserialize;
use strum::IntoEnumIterator;
use termion::event::Key;
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[derive(Clone, Debug, PartialEq)]
pub struct Keybinds(HashMap<InputMode, ModeKeybinds>);
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ModeKeybinds(HashMap<Key, Vec<Action>>);
/// Intermediate struct for configuration.
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct MultipleKeybinds(HashMap<InputMode, Vec<ModeKeybind>>);
/// Intermediate struct for configuration.
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
struct MultipleModeKeybinds(HashMap<Vec<Key>, Vec<Action>>);
/// Intermediate struct used for deserialisation
#[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct KeybindsFromYaml(HashMap<InputMode, Vec<KeyActionFromYaml>>);
/// Intermediate enum for configuration.
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(untagged)]
enum ModeKeybind {
ModeKeybinds(ModeKeybinds),
MultipleModeKeybinds(MultipleModeKeybinds),
/// Intermediate struct used for deserialisation
#[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct KeyActionFromYaml {
action: Vec<Action>,
key: Vec<Key>,
}
impl Default for Keybinds {
fn default() -> Keybinds {
Keybinds::get_default_keybinds().expect("Something is wrong with the default Keybinds")
}
}
impl Keybinds {
pub fn new() -> Keybinds {
Keybinds::from(HashMap::<InputMode, ModeKeybinds>::new())
}
pub fn get_default_keybinds() -> Result<Keybinds, String> {
let mut defaults = Keybinds::new();
for mode in InputMode::iter() {
defaults
.0
.insert(mode, Keybinds::get_defaults_for_mode(&mode)?);
.insert(mode, Keybinds::get_defaults_for_mode(&mode));
}
defaults
}
}
Ok(defaults)
impl Keybinds {
pub fn new() -> Keybinds {
Keybinds(HashMap::<InputMode, ModeKeybinds>::new())
}
pub fn get_default_keybinds_with_config(keybinds: Option<MultipleKeybinds>) -> Keybinds {
pub fn get_default_keybinds_with_config(keybinds: Option<KeybindsFromYaml>) -> Keybinds {
let default_keybinds = Keybinds::default();
if let Some(keybinds) = keybinds {
default_keybinds.merge_keybinds(Keybinds::from(keybinds))
@ -80,7 +71,7 @@ impl Keybinds {
}
/// Returns the default keybinds for a given [`InputMode`].
fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
fn get_defaults_for_mode(mode: &InputMode) -> ModeKeybinds {
let mut defaults = HashMap::new();
match *mode {
@ -212,8 +203,7 @@ impl Keybinds {
defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Command)]);
}
}
Ok(ModeKeybinds::from(defaults))
ModeKeybinds(defaults)
}
/// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current
@ -242,39 +232,27 @@ impl Keybinds {
}
impl ModeKeybinds {
pub fn new() -> ModeKeybinds {
ModeKeybinds::from(HashMap::<Key, Vec<Action>>::new())
fn new() -> ModeKeybinds {
ModeKeybinds(HashMap::<Key, Vec<Action>>::new())
}
/// Merges `self` with `other`, if keys are the same, `other` overwrites.
pub fn merge(self, other: ModeKeybinds) -> ModeKeybinds {
fn merge(self, other: ModeKeybinds) -> ModeKeybinds {
let mut merged = self;
merged.0.extend(other.0.clone());
merged.0.extend(other.0);
merged
}
}
/// Converts from the `MultipleKeybinds` struct to a `Keybinds` struct.
/// TODO @a-kenji Error on conflicting keybinds?
/// Atm the Lower Keybind will take precedence and will overwrite the
/// one further up.
impl From<MultipleKeybinds> for Keybinds {
fn from(multiple: MultipleKeybinds) -> Keybinds {
impl From<KeybindsFromYaml> for Keybinds {
fn from(keybinds_from_yaml: KeybindsFromYaml) -> Keybinds {
let mut keybinds = Keybinds::new();
for mode in InputMode::iter() {
let mut mode_keybinds = ModeKeybinds::new();
for mode_keybind in multiple.0.get(&mode).iter() {
for keybind in mode_keybind.iter() {
match keybind {
ModeKeybind::ModeKeybinds(k) => {
mode_keybinds = mode_keybinds.clone().merge(k.clone());
}
ModeKeybind::MultipleModeKeybinds(k) => {
mode_keybinds =
mode_keybinds.clone().merge(ModeKeybinds::from(k.clone()));
}
}
for key_action in keybinds_from_yaml.0.get(&mode).iter() {
for keybind in key_action.iter() {
mode_keybinds = mode_keybinds.merge(ModeKeybinds::from(keybind.clone()));
}
}
keybinds.0.insert(mode, mode_keybinds);
@ -283,25 +261,18 @@ impl From<MultipleKeybinds> for Keybinds {
}
}
impl From<HashMap<InputMode, ModeKeybinds>> for Keybinds {
fn from(map: HashMap<InputMode, ModeKeybinds>) -> Keybinds {
Keybinds(map)
}
}
impl From<HashMap<Key, Vec<Action>>> for ModeKeybinds {
fn from(map: HashMap<Key, Vec<Action>>) -> ModeKeybinds {
ModeKeybinds(map)
}
}
/// For each `Key` assigned to `Action`s,
/// map the `Action`s to the key
impl From<KeyActionFromYaml> for ModeKeybinds {
fn from(key_action: KeyActionFromYaml) -> ModeKeybinds {
let keys = key_action.key;
let actions = key_action.action;
impl From<MultipleModeKeybinds> for ModeKeybinds {
fn from(multiple: MultipleModeKeybinds) -> ModeKeybinds {
let single: HashMap<Key, Vec<Action>> = multiple
.0
.into_iter()
.flat_map(|(k, v)| (k.into_iter().map(move |k| (k, v.clone()))))
.collect();
ModeKeybinds::from(single)
ModeKeybinds(
keys.into_iter()
.map(|k| (k, actions.clone()))
.collect::<HashMap<Key, Vec<Action>>>(),
)
}
}

View File

@ -1,13 +1,12 @@
//! For Configuration Options
use super::super::config::*;
use crate::common::input::keybinds::*;
use crate::common::input::actions::*;
use crate::common::input::keybinds::*;
use std::path::PathBuf;
use termion::event::Key;
#[test]
fn no_config_file_equals_default_config() {
let no_file = PathBuf::from(r"../fixtures/config/config.yamlll");
@ -23,29 +22,29 @@ fn no_config_option_file_equals_default_config() {
assert_eq!(config, default);
}
#[test]
fn multiple_keys_mapped_to_one_action() {
let options = r"
---
keybindings:
Normal:
- ? - F: 6
- F: 7
- F: 8
: - {GoToTab: 5}
";
//#[test]
//fn multiple_keys_mapped_to_one_action() {
//let options = r"
//---
//keybindings:
//Normal:
//- ? - F: 6
//- F: 7
//- F: 8
//: - {GoToTab: 5}
//";
let config_options = Config::from_yaml(&options).unwrap();
//let config_options = Config::from_yaml(&options).unwrap();
assert_eq!(config_options, config_options)
}
//assert_eq!(config_options, config_options)
//}
//#[test]
//fn merge_keybinds_merges(){
//let mut self_keybinds = Keybinds::new();
//let mut self_mode_keybinds = ModeKeybinds::new();
//self_mode_keybinds.0.insert(Key::F(1), vec![Action::GoToTab(5)]);
//let mut other_keybinds = Keybinds::new();
//let mut self_mode_keybinds = ModeKeybinds::new();
//let mut expected = Keybinds::new();
//let mut self_keybinds = Keybinds::new();
//let mut self_mode_keybinds = ModeKeybinds::new();
//self_mode_keybinds.0.insert(Key::F(1), vec![Action::GoToTab(5)]);
//let mut other_keybinds = Keybinds::new();
//let mut self_mode_keybinds = ModeKeybinds::new();
//let mut expected = Keybinds::new();
//}

View File

@ -0,0 +1,76 @@
use super::super::actions::*;
use super::super::keybinds::*;
use termion::event::Key;
#[test]
fn merge_keybinds_merges_different_keys() {
let mut mode_keybinds_self = ModeKeybinds::new();
mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
let mut mode_keybinds_other = ModeKeybinds::new();
mode_keybinds_other
.0
.insert(Key::Backspace, vec![Action::NoOp]);
let mut mode_keybinds_expected = ModeKeybinds::new();
mode_keybinds_expected
.0
.insert(Key::F(1), vec![Action::NoOp]);
mode_keybinds_expected
.0
.insert(Key::Backspace, vec![Action::NoOp]);
let mode_keybinds_merged = mode_keybinds_self.merge(mode_keybinds_other);
assert_eq!(mode_keybinds_expected, mode_keybinds_merged);
}
#[test]
fn merge_mode_keybinds_overwrites_same_keys() {
let mut mode_keybinds_self = ModeKeybinds::new();
mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
let mut mode_keybinds_other = ModeKeybinds::new();
mode_keybinds_other
.0
.insert(Key::F(1), vec![Action::GoToTab(1)]);
let mut mode_keybinds_expected = ModeKeybinds::new();
mode_keybinds_expected
.0
.insert(Key::F(1), vec![Action::GoToTab(1)]);
let mode_keybinds_merged = mode_keybinds_self.merge(mode_keybinds_other);
assert_eq!(mode_keybinds_expected, mode_keybinds_merged);
}
#[test]
fn merge_keybinds_merges() {
let mut mode_keybinds_self = ModeKeybinds::new();
mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
let mut mode_keybinds_other = ModeKeybinds::new();
mode_keybinds_other
.0
.insert(Key::Backspace, vec![Action::NoOp]);
let mut keybinds_self = Keybinds::new();
keybinds_self
.0
.insert(InputMode::Normal, mode_keybinds_self.clone());
let mut keybinds_other = Keybinds::new();
keybinds_other
.0
.insert(InputMode::Resize, mode_keybinds_other.clone());
let mut keybinds_expected = Keybinds::new();
keybinds_expected.0.insert(
InputMode::Normal,
mode_keybinds_self
);
keybinds_expected.0.insert(
InputMode::Resize,
mode_keybinds_other
);
assert_eq!(
keybinds_expected,
keybinds_self.merge_keybinds(keybinds_other)
)
}

View File

@ -656,7 +656,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
let send_pty_instructions = send_pty_instructions.clone();
let send_plugin_instructions = send_plugin_instructions.clone();
let os_input = os_input.clone();
let config = config.clone();
let config = config;
move || {
input_loop(
os_input,