diff --git a/cmd.c b/cmd.c index 4dd780d..6382778 100644 --- a/cmd.c +++ b/cmd.c @@ -1024,7 +1024,7 @@ int cmd_apply_macro(cmd_context_t *ctx) { return MLE_OK; } -// Apply a macro +// Apply the last applied macro int cmd_apply_macro_last(cmd_context_t *ctx) { kmacro_t *macro; if (!ctx->editor->macro_last) return MLE_OK; @@ -1034,6 +1034,27 @@ int cmd_apply_macro_last(cmd_context_t *ctx) { return MLE_OK; } +// Apply the last applied macro +int cmd_print_macro(cmd_context_t *ctx) { + char *name; + kmacro_t *macro; + size_t i; + char key[MLE_MAX_KEYNAME_LEN + 1]; + editor_prompt(ctx->editor, "print_macro: Name?", NULL, &name); + if (!name) return MLE_OK; + HASH_FIND_STR(ctx->editor->macro_map, name, macro); + free(name); + if (!macro) MLE_RETURN_ERR(ctx->editor, "Macro not found%s", ""); + for (i = 0; i < macro->inputs_len; i++) { + editor_input_to_key(¯o->inputs[i], key); + MLE_FOREACH_CURSOR(ctx->cursor) { + mark_insert_before(cursor->mark, key, strlen(key)); + mark_insert_before(cursor->mark, " ", 1); + } + } + return MLE_OK; +} + // No-op int cmd_noop(cmd_context_t *ctx) { (void)ctx; diff --git a/editor.c b/editor.c index 3302b79..50670b1 100644 --- a/editor.c +++ b/editor.c @@ -1090,6 +1090,18 @@ int editor_force_redraw(editor_t *editor) { return MLE_OK; } +// Return a key name given a kinput. `keyname` must be allocated to at least +// `MLE_MAX_KEYNAME_LEN + 1`. Return `MLE_ERR` if `input` doesn't represent a +// valid input. +int editor_input_to_key(kinput_t *input, char *keyname) { + struct tb_event ev; + memset(&ev, 0, sizeof(ev)); + ev.mod = input->mod; + ev.ch = input->ch; + ev.key = input->key; + return _editor_event_to_key(&ev, keyname); +} + // If input == editor->macro_toggle_key, toggle macro mode and return 1. Else // return 0. static int _editor_maybe_toggle_macro(editor_t *editor, kinput_t *input) { @@ -1595,34 +1607,34 @@ static int _editor_key_to_input(char *key, kinput_t *ret_input) { // Return a key name given a key event static int _editor_event_to_key(struct tb_event *ev, char *ret_keyname) { char key[MLE_MAX_KEYNAME_LEN + 1]; + memset(key, 0, sizeof(key)); + #define MLE_KEY_DEF(pkname, pmodmin, pmodadd, pch, pkey) \ } else if ( \ (((pch) && ev->ch == (pch)) \ || (!(pch) && ev->key == (pkey))) \ && (((pmodmin) & ev->mod) == (pmodmin)) \ ) { \ - if ((pmodadd)) ev->mod &= ~(pmodadd); \ - sprintf(key, (pkname)); + snprintf(key, sizeof(key), (pkname)); if (0) { return MLE_ERR; #include "keys.h" - } else { - memset(key, 0, sizeof(key)); + } else if (ev->ch <= 0x10ffff && !(ev->ch >= 0xd800 && ev->ch <= 0xdfff)) { + if (ev->ch == 0) return MLE_ERR; // TODO: Support null-char input? tb_utf8_unicode_to_char(key, ev->ch); + } else { + return MLE_ERR; // No match for key and ch is not a valid codepoint } #undef MLE_KEY_DEF - if (ev->mod & TB_MOD_CTRL) { - *ret_keyname++ = 'C'; - } - if (ev->mod & TB_MOD_ALT) { - *ret_keyname++ = 'M'; - } - if (ev->mod & TB_MOD_SHIFT) { - *ret_keyname++ = 'S'; - } - if (ev->mod & TB_MOD_CTRL || ev->mod & TB_MOD_ALT || ev->mod & TB_MOD_SHIFT) { + + if (ev->mod & TB_MOD_CTRL) *ret_keyname++ = 'C'; + if (ev->mod & TB_MOD_ALT) *ret_keyname++ = 'M'; + if (ev->mod & TB_MOD_SHIFT) *ret_keyname++ = 'S'; + + if (ev->mod & (TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT)) { *ret_keyname++ = '-'; } + sprintf(ret_keyname, "%s", key); return MLE_OK; } @@ -1736,6 +1748,7 @@ static void _editor_register_cmds(editor_t *editor) { _editor_register_cmd_fn(editor, "cmd_perl", cmd_perl); _editor_register_cmd_fn(editor, "cmd_pop_kmap", cmd_pop_kmap); _editor_register_cmd_fn(editor, "cmd_prev", cmd_prev); + _editor_register_cmd_fn(editor, "cmd_print_macro", cmd_print_macro); _editor_register_cmd_fn(editor, "cmd_push_kmap", cmd_push_kmap); _editor_register_cmd_fn(editor, "cmd_quit", cmd_quit); _editor_register_cmd_fn(editor, "cmd_quit_without_saving", cmd_quit_without_saving); @@ -1743,8 +1756,8 @@ static void _editor_register_cmds(editor_t *editor) { _editor_register_cmd_fn(editor, "cmd_redraw", cmd_redraw); _editor_register_cmd_fn(editor, "cmd_remove_extra_cursors", cmd_remove_extra_cursors); _editor_register_cmd_fn(editor, "cmd_repeat", cmd_repeat); - _editor_register_cmd_fn(editor, "cmd_replace", cmd_replace); _editor_register_cmd_fn(editor, "cmd_replace_all", cmd_replace_all); + _editor_register_cmd_fn(editor, "cmd_replace", cmd_replace); _editor_register_cmd_fn(editor, "cmd_rfind_word", cmd_rfind_word); _editor_register_cmd_fn(editor, "cmd_rsearch", cmd_rsearch); _editor_register_cmd_fn(editor, "cmd_save_as", cmd_save_as); @@ -1896,6 +1909,7 @@ static void _editor_init_kmaps(editor_t *editor) { MLE_KBINDING_DEF("cmd_apply_macro", "M-Z"), MLE_KBINDING_DEF("cmd_apply_macro_by", "M-M **"), MLE_KBINDING_DEF("cmd_apply_macro_last", "f6"), + MLE_KBINDING_DEF("cmd_print_macro", "M-<"), MLE_KBINDING_DEF("cmd_next", "M-n"), MLE_KBINDING_DEF("cmd_prev", "M-p"), MLE_KBINDING_DEF("cmd_last", "M-0"), diff --git a/mle.h b/mle.h index b6e5172..0a2c2f5 100644 --- a/mle.h +++ b/mle.h @@ -439,6 +439,7 @@ int editor_display(editor_t *editor); int editor_debug_dump(editor_t *editor, FILE *fp); int editor_force_redraw(editor_t *editor); int editor_set_input_mode(editor_t *editor); +int editor_input_to_key(kinput_t *input, char *keyname); // bview functions bview_t *bview_get_split_root(bview_t *self); @@ -558,6 +559,7 @@ int cmd_outdent(cmd_context_t *ctx); int cmd_perl(cmd_context_t *ctx); int cmd_pop_kmap(cmd_context_t *ctx); int cmd_prev(cmd_context_t *ctx); +int cmd_print_macro(cmd_context_t *ctx); int cmd_push_kmap(cmd_context_t *ctx); int cmd_quit(cmd_context_t *ctx); int cmd_quit_without_saving(cmd_context_t *ctx); @@ -565,8 +567,8 @@ int cmd_redo(cmd_context_t *ctx); int cmd_redraw(cmd_context_t *ctx); int cmd_remove_extra_cursors(cmd_context_t *ctx); int cmd_repeat(cmd_context_t *ctx); -int cmd_replace(cmd_context_t *ctx); int cmd_replace_all(cmd_context_t *ctx); +int cmd_replace(cmd_context_t *ctx); int cmd_rfind_word(cmd_context_t *ctx); int cmd_rsearch(cmd_context_t *ctx); int cmd_save_as(cmd_context_t *ctx); diff --git a/tests/func/test_macro.sh b/tests/func/test_macro.sh new file mode 100755 index 0000000..20b64ea --- /dev/null +++ b/tests/func/test_macro.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +extra_opts=(-M 'printable a A S-a M-a M-A MS-a C-a CS-a CM-a CMS-a enter comma tab f1' ) +macro='M-< p r i n t a b l e enter' +declare -A expected +expected[printed_macro]='^a A S-a M-a M-A MS-a C-a CS-a CM-a CMS-a C-enter comma C-tab f1 $' +source 'test.sh'