mirror of https://github.com/helix-editor/helix
parent
b42e1d20d2
commit
e9de036c16
|
@ -551,8 +551,28 @@ impl MappableCommand {
|
|||
surround_add, "Surround add",
|
||||
surround_replace, "Surround replace",
|
||||
surround_delete, "Surround delete",
|
||||
select_textobject_around, "Select around object",
|
||||
select_textobject_inner, "Select inside object",
|
||||
select_textobject_inside_type, "Select inside type definition (tree-sitter)",
|
||||
select_textobject_around_type, "Select around type definition (tree-sitter)",
|
||||
select_textobject_inside_function, "Select inside function (tree-sitter)",
|
||||
select_textobject_around_function, "Select around function (tree-sitter)",
|
||||
select_textobject_inside_parameter, "Select inside argument/parameter (tree-sitter)",
|
||||
select_textobject_around_parameter, "Select around argument/parameter (tree-sitter)",
|
||||
select_textobject_inside_comment, "Select inside comment (tree-sitter)",
|
||||
select_textobject_around_comment, "Select around comment (tree-sitter)",
|
||||
select_textobject_inside_test, "Select inside test (tree-sitter)",
|
||||
select_textobject_around_test, "Select around test (tree-sitter)",
|
||||
select_textobject_inside_entry, "Select inside data structure entry (tree-sitter)",
|
||||
select_textobject_around_entry, "Select around data structure entry (tree-sitter)",
|
||||
select_textobject_inside_paragraph, "Select inside paragraph",
|
||||
select_textobject_around_paragraph, "Select around paragraph",
|
||||
select_textobject_inside_closest_surrounding_pair, "Select inside closest surrounding pair (tree-sitter)",
|
||||
select_textobject_around_closest_surrounding_pair, "Select around closest surrounding pair (tree-sitter)",
|
||||
select_textobject_inside_word, "Select inside word",
|
||||
select_textobject_around_word, "Select around word",
|
||||
select_textobject_inside_WORD, "Select inside WORD",
|
||||
select_textobject_around_WORD, "Select around WORD",
|
||||
select_textobject_inside_change, "Select inside VCS change",
|
||||
select_textobject_around_change, "Select around VCS change",
|
||||
goto_next_function, "Goto next function",
|
||||
goto_prev_function, "Goto previous function",
|
||||
goto_next_class, "Goto next type definition",
|
||||
|
@ -703,6 +723,47 @@ impl PartialEq for MappableCommand {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: this is mostly a copy of MappableCommand. Fold this into MappableCommand?
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FallbackCommand {
|
||||
name: &'static str,
|
||||
fun: fn(cx: &mut Context, ch: char),
|
||||
doc: &'static str,
|
||||
}
|
||||
|
||||
macro_rules! static_fallback_commands {
|
||||
( $($name:ident, $doc:literal,)* ) => {
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: Self = Self {
|
||||
name: stringify!($name),
|
||||
fun: $name,
|
||||
doc: $doc
|
||||
};
|
||||
)*
|
||||
|
||||
pub const FALLBACK_COMMAND_LIST: &'static [Self] = &[
|
||||
$( Self::$name, )*
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
impl FallbackCommand {
|
||||
pub fn execute(&self, cx: &mut Context, ch: char) {
|
||||
(self.fun)(cx, ch)
|
||||
}
|
||||
|
||||
pub fn doc(&self) -> &str {
|
||||
self.doc
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
static_fallback_commands!(
|
||||
select_textobject_inside_surrounding_pair, "Select inside any character acting as a pair (tree-sitter)",
|
||||
select_textobject_around_surrounding_pair, "Select around any character acting as a pair (tree-sitter)",
|
||||
);
|
||||
}
|
||||
|
||||
fn no_op(_cx: &mut Context) {}
|
||||
|
||||
type MoveFn =
|
||||
|
@ -5847,48 +5908,179 @@ fn goto_prev_entry(cx: &mut Context) {
|
|||
goto_ts_object_impl(cx, "entry", Direction::Backward)
|
||||
}
|
||||
|
||||
fn select_textobject_around(cx: &mut Context) {
|
||||
select_textobject(cx, textobject::TextObject::Around);
|
||||
fn select_textobject_inside_type(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Inside, "class");
|
||||
}
|
||||
|
||||
fn select_textobject_inner(cx: &mut Context) {
|
||||
select_textobject(cx, textobject::TextObject::Inside);
|
||||
fn select_textobject_around_type(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Around, "class");
|
||||
}
|
||||
|
||||
fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
|
||||
fn select_textobject_inside_function(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Inside, "function");
|
||||
}
|
||||
|
||||
fn select_textobject_around_function(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Around, "function");
|
||||
}
|
||||
|
||||
fn select_textobject_inside_parameter(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Inside, "parameter");
|
||||
}
|
||||
|
||||
fn select_textobject_around_parameter(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Around, "parameter");
|
||||
}
|
||||
|
||||
fn select_textobject_inside_comment(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Inside, "comment");
|
||||
}
|
||||
|
||||
fn select_textobject_around_comment(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Around, "comment");
|
||||
}
|
||||
|
||||
fn select_textobject_inside_test(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Inside, "test");
|
||||
}
|
||||
|
||||
fn select_textobject_around_test(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Around, "test");
|
||||
}
|
||||
|
||||
fn select_textobject_inside_entry(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Inside, "entry");
|
||||
}
|
||||
|
||||
fn select_textobject_around_entry(cx: &mut Context) {
|
||||
textobject_treesitter(cx, textobject::TextObject::Around, "entry");
|
||||
}
|
||||
|
||||
fn textobject_treesitter(
|
||||
cx: &mut Context,
|
||||
obj_type: textobject::TextObject,
|
||||
object_name: &'static str,
|
||||
) {
|
||||
let count = cx.count();
|
||||
|
||||
cx.on_next_key(move |cx, event| {
|
||||
cx.editor.autoinfo = None;
|
||||
if let Some(ch) = event.char() {
|
||||
let textobject = move |editor: &mut Editor| {
|
||||
let motion = move |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
let text = doc.text().slice(..);
|
||||
|
||||
let textobject_treesitter = |obj_name: &str, range: Range| -> Range {
|
||||
let (lang_config, syntax) = match doc.language_config().zip(doc.syntax()) {
|
||||
Some(t) => t,
|
||||
None => return range,
|
||||
None => {
|
||||
editor.set_status("Syntax information is not available in current buffer");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let text = doc.text().slice(..);
|
||||
let selection = doc.selection(view.id).clone().transform(|range| {
|
||||
textobject::textobject_treesitter(
|
||||
text,
|
||||
range,
|
||||
objtype,
|
||||
obj_name,
|
||||
obj_type,
|
||||
object_name,
|
||||
syntax.tree().root_node(),
|
||||
lang_config,
|
||||
count,
|
||||
)
|
||||
});
|
||||
doc.set_selection(view.id, selection);
|
||||
};
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
if ch == 'g' && doc.diff_handle().is_none() {
|
||||
fn select_textobject_inside_paragraph(cx: &mut Context) {
|
||||
textobject_paragraph(cx, textobject::TextObject::Inside);
|
||||
}
|
||||
|
||||
fn select_textobject_around_paragraph(cx: &mut Context) {
|
||||
textobject_paragraph(cx, textobject::TextObject::Around);
|
||||
}
|
||||
|
||||
fn textobject_paragraph(cx: &mut Context, textobject: textobject::TextObject) {
|
||||
let count = cx.count();
|
||||
let motion = move |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
let text = doc.text().slice(..);
|
||||
let selection = doc
|
||||
.selection(view.id)
|
||||
.clone()
|
||||
.transform(|range| textobject::textobject_paragraph(text, range, textobject, count));
|
||||
doc.set_selection(view.id, selection);
|
||||
};
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
fn select_textobject_inside_closest_surrounding_pair(cx: &mut Context) {
|
||||
textobject_closest_surrounding_pair(cx, textobject::TextObject::Inside);
|
||||
}
|
||||
|
||||
fn select_textobject_around_closest_surrounding_pair(cx: &mut Context) {
|
||||
textobject_closest_surrounding_pair(cx, textobject::TextObject::Around);
|
||||
}
|
||||
|
||||
fn textobject_closest_surrounding_pair(cx: &mut Context, textobject: textobject::TextObject) {
|
||||
let count = cx.count();
|
||||
let motion = move |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
let text = doc.text().slice(..);
|
||||
let syntax = doc.syntax();
|
||||
let selection = doc.selection(view.id).clone().transform(|range| {
|
||||
textobject::textobject_pair_surround_closest(syntax, text, range, textobject, count)
|
||||
});
|
||||
doc.set_selection(view.id, selection);
|
||||
};
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
fn select_textobject_inside_word(cx: &mut Context) {
|
||||
textobject_word(cx, textobject::TextObject::Inside, false);
|
||||
}
|
||||
|
||||
fn select_textobject_around_word(cx: &mut Context) {
|
||||
textobject_word(cx, textobject::TextObject::Around, false);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn select_textobject_inside_WORD(cx: &mut Context) {
|
||||
textobject_word(cx, textobject::TextObject::Inside, true);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn select_textobject_around_WORD(cx: &mut Context) {
|
||||
textobject_word(cx, textobject::TextObject::Around, true);
|
||||
}
|
||||
|
||||
fn textobject_word(cx: &mut Context, textobject: textobject::TextObject, longword: bool) {
|
||||
let count = cx.count();
|
||||
let motion = move |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
let text = doc.text().slice(..);
|
||||
let selection = doc.selection(view.id).clone().transform(|range| {
|
||||
textobject::textobject_word(text, range, textobject, count, longword)
|
||||
});
|
||||
doc.set_selection(view.id, selection);
|
||||
};
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
fn select_textobject_inside_change(cx: &mut Context) {
|
||||
textobject_change(cx);
|
||||
}
|
||||
|
||||
fn select_textobject_around_change(cx: &mut Context) {
|
||||
textobject_change(cx);
|
||||
}
|
||||
|
||||
fn textobject_change(cx: &mut Context) {
|
||||
let motion = move |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
let Some(diff_handle) = doc.diff_handle() else {
|
||||
editor.set_status("Diff is not available in current buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
let textobject_change = |range: Range| -> Range {
|
||||
let diff_handle = doc.diff_handle().unwrap();
|
||||
};
|
||||
let diff = diff_handle.load();
|
||||
let text = doc.text().slice(..);
|
||||
let selection = doc.selection(view.id).clone().transform(|range| {
|
||||
let line = range.cursor_line(text);
|
||||
let hunk_idx = if let Some(hunk_idx) = diff.hunk_at(line as u32, false) {
|
||||
hunk_idx
|
||||
|
@ -5900,66 +6092,41 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
|
|||
let start = text.line_to_char(hunk.start as usize);
|
||||
let end = text.line_to_char(hunk.end as usize);
|
||||
Range::new(start, end).with_direction(range.direction())
|
||||
});
|
||||
drop(diff);
|
||||
doc.set_selection(view.id, selection);
|
||||
};
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
let selection = doc.selection(view.id).clone().transform(|range| {
|
||||
match ch {
|
||||
'w' => textobject::textobject_word(text, range, objtype, count, false),
|
||||
'W' => textobject::textobject_word(text, range, objtype, count, true),
|
||||
't' => textobject_treesitter("class", range),
|
||||
'f' => textobject_treesitter("function", range),
|
||||
'a' => textobject_treesitter("parameter", range),
|
||||
'c' => textobject_treesitter("comment", range),
|
||||
'T' => textobject_treesitter("test", range),
|
||||
'e' => textobject_treesitter("entry", range),
|
||||
'p' => textobject::textobject_paragraph(text, range, objtype, count),
|
||||
'm' => textobject::textobject_pair_surround_closest(
|
||||
doc.syntax(),
|
||||
text,
|
||||
range,
|
||||
objtype,
|
||||
count,
|
||||
),
|
||||
'g' => textobject_change(range),
|
||||
// TODO: cancel new ranges if inconsistent surround matches across lines
|
||||
ch if !ch.is_ascii_alphanumeric() => textobject::textobject_pair_surround(
|
||||
doc.syntax(),
|
||||
text,
|
||||
range,
|
||||
objtype,
|
||||
ch,
|
||||
count,
|
||||
),
|
||||
_ => range,
|
||||
fn select_textobject_inside_surrounding_pair(cx: &mut Context, ch: char) {
|
||||
textobject_surrounding_pair(cx, textobject::TextObject::Inside, ch);
|
||||
}
|
||||
|
||||
fn select_textobject_around_surrounding_pair(cx: &mut Context, ch: char) {
|
||||
textobject_surrounding_pair(cx, textobject::TextObject::Around, ch);
|
||||
}
|
||||
|
||||
fn textobject_surrounding_pair(
|
||||
cx: &mut Context,
|
||||
textobject: textobject::TextObject,
|
||||
pair_char: char,
|
||||
) {
|
||||
if pair_char.is_ascii_alphanumeric() {
|
||||
return;
|
||||
}
|
||||
|
||||
let count = cx.count();
|
||||
let motion = move |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
let text = doc.text().slice(..);
|
||||
let syntax = doc.syntax();
|
||||
let selection = doc.selection(view.id).clone().transform(|range| {
|
||||
textobject::textobject_pair_surround(syntax, text, range, textobject, pair_char, count)
|
||||
});
|
||||
doc.set_selection(view.id, selection);
|
||||
};
|
||||
cx.editor.apply_motion(textobject);
|
||||
}
|
||||
});
|
||||
|
||||
let title = match objtype {
|
||||
textobject::TextObject::Inside => "Match inside",
|
||||
textobject::TextObject::Around => "Match around",
|
||||
_ => return,
|
||||
};
|
||||
let help_text = [
|
||||
("w", "Word"),
|
||||
("W", "WORD"),
|
||||
("p", "Paragraph"),
|
||||
("t", "Type definition (tree-sitter)"),
|
||||
("f", "Function (tree-sitter)"),
|
||||
("a", "Argument/parameter (tree-sitter)"),
|
||||
("c", "Comment (tree-sitter)"),
|
||||
("T", "Test (tree-sitter)"),
|
||||
("e", "Data structure entry (tree-sitter)"),
|
||||
("m", "Closest surrounding pair (tree-sitter)"),
|
||||
("g", "Change"),
|
||||
(" ", "... or any character acting as a pair"),
|
||||
];
|
||||
|
||||
cx.editor.autoinfo = Some(Info::new(title, &help_text));
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
static SURROUND_HELP_TEXT: [(&str, &str); 6] = [
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pub mod default;
|
||||
pub mod macros;
|
||||
|
||||
use crate::commands::FallbackCommand;
|
||||
pub use crate::commands::MappableCommand;
|
||||
use arc_swap::{
|
||||
access::{DynAccess, DynGuard},
|
||||
|
@ -24,7 +25,8 @@ pub struct KeyTrieNode {
|
|||
name: String,
|
||||
map: HashMap<KeyEvent, KeyTrie>,
|
||||
order: Vec<KeyEvent>,
|
||||
pub is_sticky: bool,
|
||||
is_sticky: bool,
|
||||
fallback: Option<FallbackCommand>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for KeyTrieNode {
|
||||
|
@ -49,6 +51,7 @@ impl KeyTrieNode {
|
|||
map,
|
||||
order,
|
||||
is_sticky: false,
|
||||
fallback: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,13 +102,16 @@ impl KeyTrieNode {
|
|||
.unwrap()
|
||||
});
|
||||
|
||||
let body: Vec<_> = body
|
||||
let mut body: Vec<_> = body
|
||||
.into_iter()
|
||||
.map(|(events, desc)| {
|
||||
let events = events.iter().map(ToString::to_string).collect::<Vec<_>>();
|
||||
(events.join(", "), desc)
|
||||
})
|
||||
.collect();
|
||||
if let Some(fallback) = self.fallback.as_ref() {
|
||||
body.push(("...".to_string(), fallback.doc()));
|
||||
}
|
||||
Info::new(self.name.clone(), &body)
|
||||
}
|
||||
}
|
||||
|
@ -267,6 +273,28 @@ impl KeyTrie {
|
|||
}
|
||||
Some(trie)
|
||||
}
|
||||
|
||||
pub fn search_fallback(&self, keys: &[KeyEvent]) -> Option<&FallbackCommand> {
|
||||
// TODO: this is copied from above, hacky
|
||||
let mut trie = self;
|
||||
let mut keys = keys.iter().peekable();
|
||||
while let Some(key) = keys.next() {
|
||||
trie = match trie {
|
||||
KeyTrie::Node(map) => match map.get(key) {
|
||||
Some(i) => Some(i),
|
||||
None => {
|
||||
if keys.peek().is_none() {
|
||||
return map.fallback.as_ref();
|
||||
}
|
||||
None
|
||||
}
|
||||
},
|
||||
// leaf encountered while keys left to process
|
||||
KeyTrie::MappableCommand(_) | KeyTrie::Sequence(_) => None,
|
||||
}?
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -281,6 +309,7 @@ pub enum KeymapResult {
|
|||
/// Key is invalid in combination with previous keys. Contains keys leading upto
|
||||
/// and including current (invalid) key.
|
||||
Cancelled(Vec<KeyEvent>),
|
||||
Fallback(FallbackCommand, char),
|
||||
}
|
||||
|
||||
/// A map of command names to keybinds that will execute the command.
|
||||
|
@ -376,7 +405,16 @@ impl Keymaps {
|
|||
self.state.clear();
|
||||
KeymapResult::MatchedSequence(cmds.clone())
|
||||
}
|
||||
None => KeymapResult::Cancelled(self.state.drain(..).collect()),
|
||||
None => {
|
||||
if let Some(ch) = key.char() {
|
||||
if let Some(fallback) = trie.search_fallback(&self.state[1..]) {
|
||||
self.state.clear();
|
||||
return KeymapResult::Fallback(fallback.clone(), ch);
|
||||
}
|
||||
}
|
||||
|
||||
KeymapResult::Cancelled(self.state.drain(..).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,8 +104,32 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
|
|||
"s" => surround_add,
|
||||
"r" => surround_replace,
|
||||
"d" => surround_delete,
|
||||
"a" => select_textobject_around,
|
||||
"i" => select_textobject_inner,
|
||||
"i" => { "Match inside" fallback=select_textobject_inside_surrounding_pair
|
||||
"w" => select_textobject_inside_word,
|
||||
"W" => select_textobject_inside_WORD,
|
||||
"p" => select_textobject_inside_paragraph,
|
||||
"t" => select_textobject_inside_type,
|
||||
"f" => select_textobject_inside_function,
|
||||
"a" => select_textobject_inside_parameter,
|
||||
"c" => select_textobject_inside_comment,
|
||||
"T" => select_textobject_inside_test,
|
||||
"e" => select_textobject_inside_entry,
|
||||
"m" => select_textobject_inside_closest_surrounding_pair,
|
||||
"g" => select_textobject_inside_change,
|
||||
},
|
||||
"a" => { "Match around" fallback=select_textobject_around_surrounding_pair
|
||||
"w" => select_textobject_around_word,
|
||||
"W" => select_textobject_around_WORD,
|
||||
"p" => select_textobject_around_paragraph,
|
||||
"t" => select_textobject_around_type,
|
||||
"f" => select_textobject_around_function,
|
||||
"a" => select_textobject_around_parameter,
|
||||
"c" => select_textobject_around_comment,
|
||||
"T" => select_textobject_around_test,
|
||||
"e" => select_textobject_around_entry,
|
||||
"m" => select_textobject_around_closest_surrounding_pair,
|
||||
"g" => select_textobject_around_change,
|
||||
},
|
||||
},
|
||||
"[" => { "Left bracket"
|
||||
"d" => goto_prev_diag,
|
||||
|
|
|
@ -84,9 +84,9 @@ macro_rules! keymap {
|
|||
};
|
||||
|
||||
(@trie
|
||||
{ $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
|
||||
{ $label:literal $(sticky=$sticky:literal)? $(fallback=$fallback:ident)? $($($key:literal)|+ => $value:tt,)+ }
|
||||
) => {
|
||||
keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
|
||||
keymap!({ $label $(sticky=$sticky)? $(fallback=$fallback)? $($($key)|+ => $value,)+ })
|
||||
};
|
||||
|
||||
(@trie [$($cmd:ident),* $(,)?]) => {
|
||||
|
@ -94,7 +94,7 @@ macro_rules! keymap {
|
|||
};
|
||||
|
||||
(
|
||||
{ $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
|
||||
{ $label:literal $(sticky=$sticky:literal)? $(fallback=$fallback:ident)? $($($key:literal)|+ => $value:tt,)+ }
|
||||
) => {
|
||||
// modified from the hashmap! macro
|
||||
{
|
||||
|
@ -113,6 +113,7 @@ macro_rules! keymap {
|
|||
)+
|
||||
)*
|
||||
let mut _node = $crate::keymap::KeyTrieNode::new($label, _map, _order);
|
||||
$( _node.fallback = Some($crate::commands::FallbackCommand::$fallback); )?
|
||||
$( _node.is_sticky = $sticky; )?
|
||||
$crate::keymap::KeyTrie::Node(_node)
|
||||
}
|
||||
|
|
|
@ -926,6 +926,9 @@ impl EditorView {
|
|||
}
|
||||
}
|
||||
KeymapResult::NotFound | KeymapResult::Cancelled(_) => return Some(key_result),
|
||||
KeymapResult::Fallback(fallback, ch) => {
|
||||
fallback.execute(cxt, *ch);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue