@@ -1,135 +1,23 @@
1+pub mod default;
2+pub mod macros;
3+
14pub use crate::commands::MappableCommand;
25use crate::config::Config;
3−use helix_core::hashmap;
6+use arc_swap::{
7+ access::{DynAccess, DynGuard},
8+ ArcSwap,
9+};
410use helix_view::{document::Mode, info::Info, input::KeyEvent};
511use serde::Deserialize;
612use std::{
713 borrow::Cow,
814 collections::{BTreeSet, HashMap},
915 ops::{Deref, DerefMut},
16+ sync::Arc,
1017};
1118
12−#[macro_export]
13−macro_rules! key {
14− ($key:ident) => {
15− ::helix_view::input::KeyEvent {
16− code: ::helix_view::keyboard::KeyCode::$key,
17− modifiers: ::helix_view::keyboard::KeyModifiers::NONE,
18− }
19− };
20− ($($ch:tt)*) => {
21− ::helix_view::input::KeyEvent {
22− code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
23− modifiers: ::helix_view::keyboard::KeyModifiers::NONE,
24− }
25− };
26−}
27−
28−#[macro_export]
29−macro_rules! shift {
30− ($key:ident) => {
31− ::helix_view::input::KeyEvent {
32− code: ::helix_view::keyboard::KeyCode::$key,
33− modifiers: ::helix_view::keyboard::KeyModifiers::SHIFT,
34− }
35− };
36− ($($ch:tt)*) => {
37− ::helix_view::input::KeyEvent {
38− code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
39− modifiers: ::helix_view::keyboard::KeyModifiers::SHIFT,
40− }
41− };
42−}
43−
44−#[macro_export]
45−macro_rules! ctrl {
46− ($key:ident) => {
47− ::helix_view::input::KeyEvent {
48− code: ::helix_view::keyboard::KeyCode::$key,
49− modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
50− }
51− };
52− ($($ch:tt)*) => {
53− ::helix_view::input::KeyEvent {
54− code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
55− modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
56− }
57− };
58−}
59−
60−#[macro_export]
61−macro_rules! alt {
62− ($key:ident) => {
63− ::helix_view::input::KeyEvent {
64− code: ::helix_view::keyboard::KeyCode::$key,
65− modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
66− }
67− };
68− ($($ch:tt)*) => {
69− ::helix_view::input::KeyEvent {
70− code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
71− modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
72− }
73− };
74−}
75−
76−/// Macro for defining the root of a `Keymap` object. Example:
77−///
78−/// ```
79−/// # use helix_core::hashmap;
80−/// # use helix_term::keymap;
81−/// # use helix_term::keymap::Keymap;
82−/// let normal_mode = keymap!({ "Normal mode"
83−/// "i" => insert_mode,
84−/// "g" => { "Goto"
85−/// "g" => goto_file_start,
86−/// "e" => goto_file_end,
87−/// },
88−/// "j" | "down" => move_line_down,
89−/// });
90−/// let keymap = Keymap::new(normal_mode);
91−/// ```
92−#[macro_export]
93−macro_rules! keymap {
94− (@trie $cmd:ident) => {
95− $crate::keymap::KeyTrie::Leaf($crate::commands::MappableCommand::$cmd)
96− };
97−
98− (@trie
99− { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
100− ) => {
101− keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
102− };
103−
104− (@trie [$($cmd:ident),* $(,)?]) => {
105− $crate::keymap::KeyTrie::Sequence(vec![$($crate::commands::Command::$cmd),*])
106− };
107−
108− (
109− { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
110− ) => {
111− // modified from the hashmap! macro
112− {
113− let _cap = hashmap!(@count $($($key),+),*);
114− let mut _map = ::std::collections::HashMap::with_capacity(_cap);
115− let mut _order = ::std::vec::Vec::with_capacity(_cap);
116− $(
117− $(
118− let _key = $key.parse::<::helix_view::input::KeyEvent>().unwrap();
119− let _duplicate = _map.insert(
120− _key,
121− keymap!(@trie $value)
122− );
123− assert!(_duplicate.is_none(), "Duplicate key found: {:?}", _duplicate.unwrap());
124− _order.push(_key);
125− )+
126− )*
127− let mut _node = $crate::keymap::KeyTrieNode::new($label, _map, _order);
128− $( _node.is_sticky = $sticky; )?
129− $crate::keymap::KeyTrie::Node(_node)
130− }
131− };
132−}
19+use default::default;
20+use macros::key;
13321
13422#[derive(Debug, Clone)]
13523pub struct KeyTrieNode {
@@ -381,23 +269,17 @@ impl Default for Keymap {
381269 }
382270}
383271
384−#[derive(Debug, Clone, PartialEq, Deserialize)]
385272pub struct Keymaps {
386− #[serde(flatten)]
387− pub map: HashMap<Mode, Keymap>,
388−
273+ pub map: Box<dyn DynAccess<HashMap<Mode, Keymap>>>,
389274 /// Stores pending keys waiting for the next key. This is relative to a
390275 /// sticky node if one is in use.
391− #[serde(skip)]
392276 state: Vec<KeyEvent>,
393−
394277 /// Stores the sticky node if one is activated.
395− #[serde(skip)]
396278 pub sticky: Option<KeyTrieNode>,
397279}
398280
399281impl Keymaps {
400− pub fn new(map: HashMap<Mode, Keymap>) -> Self {
282+ pub fn new(map: Box<dyn DynAccess<HashMap<Mode, Keymap>>>) -> Self {
401283 Self {
402284 map,
403285 state: Vec::new(),
@@ -405,6 +287,10 @@ impl Keymaps {
405287 }
406288 }
407289
290+ pub fn map(&self) -> DynGuard<HashMap<Mode, Keymap>> {
291+ self.map.load()
292+ }
293+
408294 /// Returns list of keys waiting to be disambiguated in current mode.
409295 pub fn pending(&self) -> &[KeyEvent] {
410296 &self.state
@@ -419,7 +305,8 @@ impl Keymaps {
419305 /// sticky node is in use, it will be cleared.
420306 pub fn get(&mut self, mode: Mode, key: KeyEvent) -> KeymapResult {
421307 // TODO: remove the sticky part and look up manually
422− let keymap = &self.map[&mode];
308+ let keymaps = &*self.map();
309+ let keymap = &keymaps[&mode];
423310
424311 if key!(Esc) == key {
425312 if !self.state.is_empty() {
@@ -470,372 +357,25 @@ impl Keymaps {
470357
471358impl Default for Keymaps {
472359 fn default() -> Self {
473− let normal = keymap!({ "Normal mode"
474− "h" | "left" => move_char_left,
475− "j" | "down" => move_line_down,
476− "k" | "up" => move_line_up,
477− "l" | "right" => move_char_right,
478−
479− "t" => find_till_char,
480− "f" => find_next_char,
481− "T" => till_prev_char,
482− "F" => find_prev_char,
483− "r" => replace,
484− "R" => replace_with_yanked,
485− "A-." => repeat_last_motion,
486−
487− "~" => switch_case,
488− "`" => switch_to_lowercase,
489− "A-`" => switch_to_uppercase,
490−
491− "home" => goto_line_start,
492− "end" => goto_line_end,
493−
494− "w" => move_next_word_start,
495− "b" => move_prev_word_start,
496− "e" => move_next_word_end,
497−
498− "W" => move_next_long_word_start,
499− "B" => move_prev_long_word_start,
500− "E" => move_next_long_word_end,
501−
502− "v" => select_mode,
503− "G" => goto_line,
504− "g" => { "Goto"
505− "g" => goto_file_start,
506− "e" => goto_last_line,
507− "f" => goto_file,
508− "h" => goto_line_start,
509− "l" => goto_line_end,
510− "s" => goto_first_nonwhitespace,
511− "d" => goto_definition,
512− "y" => goto_type_definition,
513− "r" => goto_reference,
514− "i" => goto_implementation,
515− "t" => goto_window_top,
516− "c" => goto_window_center,
517− "b" => goto_window_bottom,
518− "a" => goto_last_accessed_file,
519− "m" => goto_last_modified_file,
520− "n" => goto_next_buffer,
521− "p" => goto_previous_buffer,
522− "." => goto_last_modification,
523− },
524− ":" => command_mode,
525−
526− "i" => insert_mode,
527− "I" => prepend_to_line,
528− "a" => append_mode,
529− "A" => append_to_line,
530− "o" => open_below,
531− "O" => open_above,
532−
533− "d" => delete_selection,
534− "A-d" => delete_selection_noyank,
535− "c" => change_selection,
536− "A-c" => change_selection_noyank,
537−
538− "C" => copy_selection_on_next_line,
539− "A-C" => copy_selection_on_prev_line,
540−
541−
542− "s" => select_regex,
543− "A-s" => split_selection_on_newline,
544− "S" => split_selection,
545− ";" => collapse_selection,
546− "A-;" => flip_selections,
547− "A-k" | "A-up" => expand_selection,
548− "A-j" | "A-down" => shrink_selection,
549− "A-h" | "A-left" => select_prev_sibling,
550− "A-l" | "A-right" => select_next_sibling,
551−
552− "%" => select_all,
553− "x" => extend_line,
554− "X" => extend_to_line_bounds,
555− // crop_to_whole_line
556−
557− "m" => { "Match"
558− "m" => match_brackets,
559− "s" => surround_add,
560− "r" => surround_replace,
561− "d" => surround_delete,
562− "a" => select_textobject_around,
563− "i" => select_textobject_inner,
564− },
565− "[" => { "Left bracket"
566− "d" => goto_prev_diag,
567− "D" => goto_first_diag,
568− "f" => goto_prev_function,
569− "c" => goto_prev_class,
570− "a" => goto_prev_parameter,
571− "o" => goto_prev_comment,
572− "space" => add_newline_above,
573− },
574− "]" => { "Right bracket"
575− "d" => goto_next_diag,
576− "D" => goto_last_diag,
577− "f" => goto_next_function,
578− "c" => goto_next_class,
579− "a" => goto_next_parameter,
580− "o" => goto_next_comment,
581− "space" => add_newline_below,
582− },
583−
584− "/" => search,
585− "?" => rsearch,
586− "n" => search_next,
587− "N" => search_prev,
588− "*" => search_selection,
589−
590− "u" => undo,
591− "U" => redo,
592− "A-u" => earlier,
593− "A-U" => later,
594−
595− "y" => yank,
596− // yank_all
597− "p" => paste_after,
598− // paste_all
599− "P" => paste_before,
600−
601− "Q" => record_macro,
602− "q" => replay_macro,
603−
604− ">" => indent,
605− "<" => unindent,
606− "=" => format_selections,
607− "J" => join_selections,
608− "K" => keep_selections,
609− "A-K" => remove_selections,
610−
611− "," => keep_primary_selection,
612− "A-," => remove_primary_selection,
613−
614− // "q" => record_macro,
615− // "Q" => replay_macro,
616−
617− "&" => align_selections,
618− "_" => trim_selections,
619−
620− "(" => rotate_selections_backward,
621− ")" => rotate_selections_forward,
622− "A-(" => rotate_selection_contents_backward,
623− "A-)" => rotate_selection_contents_forward,
624−
625− "A-:" => ensure_selections_forward,
626−
627− "esc" => normal_mode,
628− "C-b" | "pageup" => page_up,
629− "C-f" | "pagedown" => page_down,
630− "C-u" => half_page_up,
631− "C-d" => half_page_down,
632−
633− "C-w" => { "Window"
634− "C-w" | "w" => rotate_view,
635− "C-s" | "s" => hsplit,
636− "C-v" | "v" => vsplit,
637− "f" => goto_file_hsplit,
638− "F" => goto_file_vsplit,
639− "C-q" | "q" => wclose,
640− "C-o" | "o" => wonly,
641− "C-h" | "h" | "left" => jump_view_left,
642− "C-j" | "j" | "down" => jump_view_down,
643− "C-k" | "k" | "up" => jump_view_up,
644− "C-l" | "l" | "right" => jump_view_right,
645− "n" => { "New split scratch buffer"
646− "C-s" | "s" => hsplit_new,
647− "C-v" | "v" => vsplit_new,
648− },
649− },
650−
651− // move under <space>c
652− "C-c" => toggle_comments,
653−
654− // z family for save/restore/combine from/to sels from register
655−
656− "tab" => jump_forward, // tab == <C-i>
657− "C-o" => jump_backward,
658− "C-s" => save_selection,
659−
660− "space" => { "Space"
661− "f" => file_picker,
662− "b" => buffer_picker,
663− "s" => symbol_picker,
664− "S" => workspace_symbol_picker,
665− "a" => code_action,
666− "'" => last_picker,
667− "d" => { "Debug (experimental)" sticky=true
668− "l" => dap_launch,
669− "b" => dap_toggle_breakpoint,
670− "c" => dap_continue,
671− "h" => dap_pause,
672− "i" => dap_step_in,
673− "o" => dap_step_out,
674− "n" => dap_next,
675− "v" => dap_variables,
676− "t" => dap_terminate,
677− "C-c" => dap_edit_condition,
678− "C-l" => dap_edit_log,
679− "s" => { "Switch"
680− "t" => dap_switch_thread,
681− "f" => dap_switch_stack_frame,
682− // sl, sb
683− },
684− "e" => dap_enable_exceptions,
685− "E" => dap_disable_exceptions,
686− },
687− "w" => { "Window"
688− "C-w" | "w" => rotate_view,
689− "C-s" | "s" => hsplit,
690− "C-v" | "v" => vsplit,
691− "f" => goto_file_hsplit,
692− "F" => goto_file_vsplit,
693− "C-q" | "q" => wclose,
694− "C-o" | "o" => wonly,
695− "C-h" | "h" | "left" => jump_view_left,
696− "C-j" | "j" | "down" => jump_view_down,
697− "C-k" | "k" | "up" => jump_view_up,
698− "C-l" | "l" | "right" => jump_view_right,
699− "n" => { "New split scratch buffer"
700− "C-s" | "s" => hsplit_new,
701− "C-v" | "v" => vsplit_new,
702− },
703− },
704− "y" => yank_joined_to_clipboard,
705− "Y" => yank_main_selection_to_clipboard,
706− "p" => paste_clipboard_after,
707− "P" => paste_clipboard_before,
708− "R" => replace_selections_with_clipboard,
709− "/" => global_search,
710− "k" => hover,
711− "r" => rename_symbol,
712− "?" => command_palette,
713− },
714− "z" => { "View"
715− "z" | "c" => align_view_center,
716− "t" => align_view_top,
717− "b" => align_view_bottom,
718− "m" => align_view_middle,
719− "k" | "up" => scroll_up,
720− "j" | "down" => scroll_down,
721− "C-b" | "pageup" => page_up,
722− "C-f" | "pagedown" => page_down,
723− "C-u" => half_page_up,
724− "C-d" => half_page_down,
725− },
726− "Z" => { "View" sticky=true
727− "z" | "c" => align_view_center,
728− "t" => align_view_top,
729− "b" => align_view_bottom,
730− "m" => align_view_middle,
731− "k" | "up" => scroll_up,
732− "j" | "down" => scroll_down,
733− "C-b" | "pageup" => page_up,
734− "C-f" | "pagedown" => page_down,
735− "C-u" => half_page_up,
736− "C-d" => half_page_down,
737− },
738−
739− "\"" => select_register,
740− "|" => shell_pipe,
741− "A-|" => shell_pipe_to,
742− "!" => shell_insert_output,
743− "A-!" => shell_append_output,
744− "$" => shell_keep_pipe,
745− "C-z" => suspend,
746−
747− "C-a" => increment,
748− "C-x" => decrement,
749− });
750− let mut select = normal.clone();
751− select.merge_nodes(keymap!({ "Select mode"
752− "h" | "left" => extend_char_left,
753− "j" | "down" => extend_line_down,
754− "k" | "up" => extend_line_up,
755− "l" | "right" => extend_char_right,
756−
757− "w" => extend_next_word_start,
758− "b" => extend_prev_word_start,
759− "e" => extend_next_word_end,
760− "W" => extend_next_long_word_start,
761− "B" => extend_prev_long_word_start,
762− "E" => extend_next_long_word_end,
763−
764− "n" => extend_search_next,
765− "N" => extend_search_prev,
766−
767− "t" => extend_till_char,
768− "f" => extend_next_char,
769− "T" => extend_till_prev_char,
770− "F" => extend_prev_char,
771−
772− "home" => extend_to_line_start,
773− "end" => extend_to_line_end,
774− "esc" => exit_select_mode,
775−
776− "v" => normal_mode,
777− }));
778− let insert = keymap!({ "Insert mode"
779− "esc" => normal_mode,
780−
781− "backspace" => delete_char_backward,
782− "C-h" => delete_char_backward,
783− "del" => delete_char_forward,
784− "C-d" => delete_char_forward,
785− "ret" => insert_newline,
786− "C-j" => insert_newline,
787− "tab" => insert_tab,
788− "C-w" => delete_word_backward,
789− "A-backspace" => delete_word_backward,
790− "A-d" => delete_word_forward,
791−
792− "left" => move_char_left,
793− "C-b" => move_char_left,
794− "down" => move_line_down,
795− "C-n" => move_line_down,
796− "up" => move_line_up,
797− "C-p" => move_line_up,
798− "right" => move_char_right,
799− "C-f" => move_char_right,
800− "A-b" => move_prev_word_end,
801− "A-left" => move_prev_word_end,
802− "A-f" => move_next_word_start,
803− "A-right" => move_next_word_start,
804− "A-<" => goto_file_start,
805− "A->" => goto_file_end,
806− "pageup" => page_up,
807− "pagedown" => page_down,
808− "home" => goto_line_start,
809− "C-a" => goto_line_start,
810− "end" => goto_line_end_newline,
811− "C-e" => goto_line_end_newline,
812−
813− "C-k" => kill_to_line_end,
814− "C-u" => kill_to_line_start,
815−
816− "C-x" => completion,
817− "C-r" => insert_register,
818− });
819− Self::new(hashmap!(
820− Mode::Normal => Keymap::new(normal),
821− Mode::Select => Keymap::new(select),
822− Mode::Insert => Keymap::new(insert),
823− ))
360+ Self::new(Box::new(ArcSwap::new(Arc::new(default()))))
824361 }
825362}
826363
827364/// Merge default config keys with user overwritten keys for custom user config.
828365pub fn merge_keys(mut config: Config) -> Config {
829− let mut delta = std::mem::take(&mut config.keys);
830− for (mode, keys) in &mut config.keys.map {
831− keys.merge(delta.map.remove(mode).unwrap_or_default())
366+ let mut delta = std::mem::replace(&mut config.keys, default());
367+ for (mode, keys) in &mut config.keys {
368+ keys.merge(delta.remove(mode).unwrap_or_default())
832369 }
833370 config
834371}
835372
836373#[cfg(test)]
837374mod tests {
375+ use super::macros::keymap;
838376 use super::*;
377+ use arc_swap::access::Constant;
378+ use helix_core::hashmap;
839379
840380 #[test]
841381 #[should_panic]
@@ -855,7 +395,7 @@ mod tests {
855395 #[test]
856396 fn merge_partial_keys() {
857397 let config = Config {
858− keys: Keymaps::new(hashmap! {
398+ keys: hashmap! {
859399 Mode::Normal => Keymap::new(
860400 keymap!({ "Normal mode"
861401 "i" => normal_mode,
@@ -867,13 +407,13 @@ mod tests {
867407 },
868408 })
869409 )
870− }),
410+ },
871411 ..Default::default()
872412 };
873413 let mut merged_config = merge_keys(config.clone());
874414 assert_ne!(config, merged_config);
875415
876− let keymap = &mut merged_config.keys;
416+ let mut keymap = Keymaps::new(Box::new(Constant(merged_config.keys.clone())));
877417 assert_eq!(
878418 keymap.get(Mode::Normal, key!('i')),
879419 KeymapResult::Matched(MappableCommand::normal_mode),
@@ -891,7 +431,7 @@ mod tests {
891431 "Leaf should replace node"
892432 );
893433
894− let keymap = merged_config.keys.map.get_mut(&Mode::Normal).unwrap();
434+ let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
895435 // Assumes that `g` is a node in default keymap
896436 assert_eq!(
897437 keymap.root().search(&[key!('g'), key!('$')]).unwrap(),
@@ -911,14 +451,14 @@ mod tests {
911451 "Old leaves in subnode should be present in merged node"
912452 );
913453
914− assert!(merged_config.keys.map.get(&Mode::Normal).unwrap().len() > 1);
915− assert!(merged_config.keys.map.get(&Mode::Insert).unwrap().len() > 0);
454+ assert!(merged_config.keys.get(&Mode::Normal).unwrap().len() > 1);
455+ assert!(merged_config.keys.get(&Mode::Insert).unwrap().len() > 0);
916456 }
917457
918458 #[test]
919459 fn order_should_be_set() {
920460 let config = Config {
921− keys: Keymaps::new(hashmap! {
461+ keys: hashmap! {
922462 Mode::Normal => Keymap::new(
923463 keymap!({ "Normal mode"
924464 "space" => { ""
@@ -929,12 +469,12 @@ mod tests {
929469 },
930470 })
931471 )
932− }),
472+ },
933473 ..Default::default()
934474 };
935475 let mut merged_config = merge_keys(config.clone());
936476 assert_ne!(config, merged_config);
937− let keymap = merged_config.keys.map.get_mut(&Mode::Normal).unwrap();
477+ let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
938478 // Make sure mapping works
939479 assert_eq!(
940480 keymap
@@ -951,8 +491,8 @@ mod tests {
951491
952492 #[test]
953493 fn aliased_modes_are_same_in_default_keymap() {
954− let keymaps = Keymaps::default();
955− let root = keymaps.map.get(&Mode::Normal).unwrap().root();
494+ let keymaps = Keymaps::default().map();
495+ let root = keymaps.get(&Mode::Normal).unwrap().root();
956496 assert_eq!(
957497 root.search(&[key!(' '), key!('w')]).unwrap(),
958498 root.search(&["C-w".parse::<KeyEvent>().unwrap()]).unwrap(),