@@ -40,6 +40,7 @@ use crate::{
4040
4141use crate::job::{self, Job, Jobs};
4242use futures_util::{FutureExt, TryFutureExt};
43+use std::collections::HashMap;
4344use std::{fmt, future::Future};
4445
4546use std::{
@@ -76,6 +77,16 @@ impl<'a> Context<'a> {
7677 self.on_next_key_callback = Some(Box::new(on_next_key_callback));
7778 }
7879
80+ #[inline]
81+ pub fn on_next_key_mode(&mut self, map: HashMap<KeyEvent, fn(&mut Context)>) {
82+ self.on_next_key(move |cx, event| {
83+ cx.editor.autoinfo = None;
84+ if let Some(func) = map.get(&event) {
85+ func(cx);
86+ }
87+ });
88+ }
89+
7990 #[inline]
8091 pub fn callback<T, F>(
8192 &mut self,
@@ -3406,84 +3417,95 @@ macro_rules! mode_info {
34063417 // TODO: how to use one expr for both pat and expr?
34073418 // TODO: how to use replaced function name as str at compile time?
34083419 // TODO: extend to support multiple keys, but first solve the other two
3409− {$name:literal, $cx:expr, $($key:expr => $func:expr; $desc:literal),+,} => {
3410− mode_info! {
3411− $name, $cx,
3412− $($key; $key => $func; $desc,)+
3420+ (@join $first:expr $(,$rest:expr)*) => {
3421+ concat!($first, $(", ", $rest),*)
3422+ };
3423+ {$mode:ident, $name:literal, $(#[doc = $desc:literal] $($key:expr),+ => $func:expr),+,} => {
3424+ #[doc = $name]
3425+ #[doc = ""]
3426+ #[doc = "<table><tr><th>key</th><th>desc</th></tr><tbody>"]
3427+ $(
3428+ #[doc = "<tr><td>"]
3429+ #[doc = mode_info!(@join $($key),+)]
3430+ #[doc = "</td><td>"]
3431+ #[doc = $desc]
3432+ #[doc = "</td></tr>"]
3433+ )+
3434+ #[doc = "</tbody></table>"]
3435+ pub fn $mode(cx: &mut Context) {
3436+ cx.editor.autoinfo = Some(Info::key(
3437+ $name,
3438+ vec![$((vec![$($key.parse().unwrap()),+], $desc)),+],
3439+ ));
3440+ use helix_core::hashmap;
3441+ let mut map = hashmap! {
3442+ $($($key.parse::<KeyEvent>().unwrap() => $func as for<'r, 's> fn(&'r mut Context<'s>)),+),*
3443+ };
3444+ cx.on_next_key_mode(map);
34133445 }
34143446 };
3415− {$name:literal, $cx:expr, $($key:expr; $keyp:pat => $func:expr; $desc:literal),+,} => {
3416− $cx.editor.autoinfo = Some(Info::key(
3417− $name,
3418− vec![
3419− $(
3420− (vec![$key], $desc),
3421− )+
3422− ],
3423− ));
3424− $cx.on_next_key(move |cx, event| {
3425− cx.editor.autoinfo = None;
3426− match event {
3427− $(
3428− $keyp => $func(cx),
3429− )+
3430− _ => {}
3431− }
3432− })
3433− }
34343447}
34353448
3436−fn space_mode(cx: &mut Context) {
3437− mode_info! {
3438− "space mode", cx,
3439− key!('f'); key!('f') => file_picker; "file picker",
3440− key!('b'); key!('b') => buffer_picker; "buffer picker",
3441− key!('s'); key!('s') => symbol_picker; "symbol picker",
3442− key!('w'); key!('w') => window_mode; "window mode",
3443− key!('y'); key!('y') => yank_joined_to_clipboard; "yank joined to clipboard",
3444− key!('Y'); key!('Y') => yank_main_selection_to_clipboard; "yank main selection to clipboard",
3445− key!('p'); key!('p') => paste_clipboard_after; "paste system clipboard after selections",
3446− key!('P'); key!('P') => paste_clipboard_before; "paste system clipboard before selections",
3447− key!('R'); key!('R') => replace_selections_with_clipboard; "replace selections with clipboard",
3448− key!(' '); key!(' ') => keep_primary_selection; "keep primary selection",
3449− }
3449+mode_info! {
3450+ space_mode, "space mode",
3451+ /// file picker
3452+ "f" => file_picker,
3453+ /// buffer picker
3454+ "b" => buffer_picker,
3455+ /// symbol picker
3456+ "s" => symbol_picker,
3457+ /// window mode
3458+ "w" => window_mode,
3459+ /// yank joined to clipboard
3460+ "y" => yank_joined_to_clipboard,
3461+ /// yank main selection to clipboard
3462+ "Y" => yank_main_selection_to_clipboard,
3463+ /// paste system clipboard after selections
3464+ "p" => paste_clipboard_after,
3465+ /// paste system clipboard before selections
3466+ "P" => paste_clipboard_before,
3467+ /// replace selections with clipboard
3468+ "R" => replace_selections_with_clipboard,
3469+ /// keep primary selection
3470+ "space" => keep_primary_selection,
34503471}
34513472
34523473// TODO: generated, delete it later
3453−// fn space_mode(cx: &mut Context) {
3474+// /// space mode
3475+// ///
3476+// /// | key | desc |
3477+// /// |-----|------|
3478+// /// | f | file picker |
3479+// /// | b | buffer picker |
3480+// /// ...
3481+// pub fn space_mode(cx: &mut Context) {
34543482// cx.editor.autoinfo = Some(Info::key(
3455−// "space",
3483+// "space mode",
34563484// vec![
3457−// (vec![key!('f')], "file picker"),
3458−// (vec![key!('b')], "buffer picker"),
3459−// (vec![key!('s')], "symbol picker"),
3460−// (vec![key!('w')], "window mode"),
3461−// (vec![key!('y')], "yank joined to clipboard"),
3462−// (vec![key!('Y')], "yank main selection to clipboard"),
3463−// (vec![key!('p')], "paste clipboard after"),
3464−// (vec![key!('P')], "paste clipboard before"),
3465−// (vec![key!('R')], "replace selections with clipboard"),
3466−// (vec![key!(' ')], "keep primary selection"),
3485+// (vec!["f".parse().unwrap()], "file picker"),
3486+// (vec!["b".parse().unwrap()], "buffer picker"),
3487+// (vec!["s".parse().unwrap()], "symbol picker"),
3488+// (vec!["w".parse().unwrap()], "window mode"),
3489+// (vec!["y".parse().unwrap()], "yank joined to clipboard"),
3490+// (vec!["Y".parse().unwrap()], "yank main selection to clipboard"),
3491+// (vec!["p".parse().unwrap()], "paste system clipboard after selections"),
3492+// (vec!["P".parse().unwrap()], "paste system clipboard before selections"),
3493+// (vec!["R".parse().unwrap()], "replace selections with clipboard"),
3494+// (vec![" ".parse().unwrap()], "keep primary selection"),
34673495// ],
34683496// ));
3469−// cx.on_next_key(move |cx, event| {
3470−// cx.editor.autoinfo = None;
3471−// match event {
3472−// key!('f') => file_picker(cx),
3473−// key!('b') => buffer_picker(cx),
3474−// key!('s') => symbol_picker(cx),
3475−// key!('w') => window_mode(cx),
3476−// key!('y') => yank_joined_to_clipboard(cx),
3477−// key!('Y') => yank_main_selection_to_clipboard(cx),
3478−// key!('p') => paste_clipboard_after(cx),
3479−// key!('P') => paste_clipboard_before(cx),
3480−// key!('R') => replace_selections_with_clipboard(cx),
3481−// // key!(' ') => toggle_alternate_buffer(cx),
3482−// // TODO: temporary since space mode took its old key
3483−// key!(' ') => keep_primary_selection(cx),
3484−// _ => {}
3485−// }
3486−// })
3497+// let mut map: HashMap<KeyEvent, fn(&mut Context)> = HashMap::with_capacity(10);
3498+// map.insert("f".parse().unwrap(), file_picker);
3499+// map.insert("b".parse().unwrap(), buffer_picker);
3500+// map.insert("s".parse().unwrap(), symbol_picker);
3501+// map.insert("w".parse().unwrap(), window_mode);
3502+// map.insert("y".parse().unwrap(), yank_joined_to_clipboard);
3503+// map.insert("Y".parse().unwrap(), yank_main_selection_to_clipboard);
3504+// map.insert("p".parse().unwrap(), paste_clipboard_after);
3505+// map.insert("P".parse().unwrap(), paste_clipboard_before);
3506+// map.insert("R".parse().unwrap(), replace_selections_with_clipboard);
3507+// map.insert(" ".parse().unwrap(), keep_primary_selection);
3508+// cx.on_next_key_mode(map);
34873509// }
34883510
34893511fn view_mode(cx: &mut Context) {