diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/mapping.c | |
parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.gz rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.bz2 rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.zip |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/mapping.c')
-rw-r--r-- | src/nvim/mapping.c | 669 |
1 files changed, 403 insertions, 266 deletions
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 831d1299a8..17593a9121 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -1,48 +1,54 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // mapping.c: Code for mappings and abbreviations. #include <assert.h> -#include <inttypes.h> #include <lauxlib.h> #include <limits.h> #include <stdbool.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" +#include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" +#include "nvim/cmdexpand_defs.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_session.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/highlight_defs.h" +#include "nvim/highlight.h" #include "nvim/keycodes.h" #include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mapping.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option_defs.h" -#include "nvim/pos.h" +#include "nvim/option_vars.h" +#include "nvim/pos_defs.h" #include "nvim/regexp.h" +#include "nvim/regexp_defs.h" #include "nvim/runtime.h" #include "nvim/search.h" +#include "nvim/state_defs.h" #include "nvim/strings.h" -#include "nvim/vim.h" +#include "nvim/types_defs.h" +#include "nvim/ui.h" +#include "nvim/vim_defs.h" /// List used for abbreviations. static mapblock_T *first_abbr = NULL; // first entry in abbrlist @@ -61,10 +67,65 @@ static mapblock_T *(maphash[MAX_MAPHASH]) = { 0 }; (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | \ MODE_OP_PENDING | MODE_TERMINAL)) ? (c1) : ((c1) ^ 0x80)) +/// All possible |:map-arguments| usable in a |:map| command. +/// +/// The <special> argument has no effect on mappings and is excluded from this +/// struct declaration. |:noremap| is included, since it behaves like a map +/// argument when used in a mapping. +/// +/// @see mapblock_T +struct map_arguments { + bool buffer; + bool expr; + bool noremap; + bool nowait; + bool script; + bool silent; + bool unique; + bool replace_keycodes; + + /// The {lhs} of the mapping. + /// + /// vim limits this to MAXMAPLEN characters, allowing us to use a static + /// buffer. Setting lhs_len to a value larger than MAXMAPLEN can signal + /// that {lhs} was too long and truncated. + char lhs[MAXMAPLEN + 1]; + size_t lhs_len; + + /// Unsimplifed {lhs} of the mapping. If no simplification has been done then alt_lhs_len is 0. + char alt_lhs[MAXMAPLEN + 1]; + size_t alt_lhs_len; + + char *rhs; /// The {rhs} of the mapping. + size_t rhs_len; + LuaRef rhs_lua; /// lua function as {rhs} + bool rhs_is_noop; /// True when the {rhs} should be <Nop>. + + char *orig_rhs; /// The original text of the {rhs}. + size_t orig_rhs_len; + char *desc; /// map description +}; +typedef struct map_arguments MapArguments; +#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, false, \ + { 0 }, 0, { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL } + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mapping.c.generated.h" #endif +static const char e_global_abbreviation_already_exists_for_str[] + = N_("E224: Global abbreviation already exists for %s"); +static const char e_global_mapping_already_exists_for_str[] + = N_("E225: Global mapping already exists for %s"); +static const char e_abbreviation_already_exists_for_str[] + = N_("E226: Abbreviation already exists for %s"); +static const char e_mapping_already_exists_for_str[] + = N_("E227: Mapping already exists for %s"); +static const char e_entries_missing_in_mapset_dict_argument[] + = N_("E460: Entries missing in mapset() dict argument"); +static const char e_illegal_map_mode_string_str[] + = N_("E1276: Illegal map mode string: '%s'"); + /// Get the start of the hashed map list for "state" and first character "c". mapblock_T *get_maphash_list(int state, int c) { @@ -95,9 +156,7 @@ mapblock_T *get_maphash(int index, buf_T *buf) /// "mpp" is a pointer to the m_next field of the PREVIOUS entry! static void mapblock_free(mapblock_T **mpp) { - mapblock_T *mp; - - mp = *mpp; + mapblock_T *mp = *mpp; xfree(mp->m_keys); if (!mp->m_simplified) { NLUA_CLEAR_REF(mp->m_luaref); @@ -159,26 +218,23 @@ static char *map_mode_to_chars(int mode) /// @param local true for buffer-local map static void showmap(mapblock_T *mp, bool local) { - size_t len = 1; - if (message_filtered(mp->m_keys) && message_filtered(mp->m_str) && (mp->m_desc == NULL || message_filtered(mp->m_desc))) { return; } - if (msg_didout || msg_silent != 0) { + // When ext_messages is active, msg_didout is never set. + if (msg_didout || msg_silent != 0 || ui_has(kUIMessages)) { msg_putchar('\n'); if (got_int) { // 'q' typed at MORE prompt return; } } - { - char *const mapchars = map_mode_to_chars(mp->m_mode); - msg_puts(mapchars); - len = strlen(mapchars); - xfree(mapchars); - } + char *const mapchars = map_mode_to_chars(mp->m_mode); + msg_puts(mapchars); + size_t len = strlen(mapchars); + xfree(mapchars); while (++len <= 3) { msg_putchar(' '); @@ -268,16 +324,16 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs bool did_simplify = false; const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; char *bufarg = lhs_buf; - char *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, flags, &did_simplify, - cpo_flags); + char *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, 0, + flags, &did_simplify, cpo_flags); if (replaced == NULL) { return false; } mapargs->lhs_len = strlen(replaced); xstrlcpy(mapargs->lhs, replaced, sizeof(mapargs->lhs)); if (did_simplify) { - replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, flags | REPTERM_NO_SIMPLIFY, - NULL, cpo_flags); + replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, 0, + flags | REPTERM_NO_SIMPLIFY, NULL, cpo_flags); if (replaced == NULL) { return false; } @@ -287,14 +343,15 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs mapargs->alt_lhs_len = 0; } - set_maparg_rhs(orig_rhs, orig_rhs_len, rhs_lua, cpo_flags, mapargs); + set_maparg_rhs(orig_rhs, orig_rhs_len, rhs_lua, 0, cpo_flags, mapargs); return true; } /// @see set_maparg_lhs_rhs static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len, - const LuaRef rhs_lua, const int cpo_flags, MapArguments *const mapargs) + const LuaRef rhs_lua, const scid_T sid, const int cpo_flags, + MapArguments *const mapargs) { mapargs->rhs_lua = rhs_lua; @@ -308,8 +365,8 @@ static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len mapargs->rhs_is_noop = true; } else { char *rhs_buf = NULL; - char *replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL, - cpo_flags); + char *replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, sid, + REPTERM_DO_LT, NULL, cpo_flags); mapargs->rhs_len = strlen(replaced); // NB: replace_termcodes may produce an empty string even if orig_rhs is non-empty // (e.g. a single ^V, see :h map-empty-rhs) @@ -323,7 +380,7 @@ static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len mapargs->orig_rhs_len = 0; // stores <lua>ref_no<cr> in map_str mapargs->rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "%c%c%c%d\r", K_SPECIAL, - (char_u)KS_EXTRA, KE_LUA, rhs_lua); + KS_EXTRA, KE_LUA, rhs_lua); mapargs->rhs = xstrdup(tmp_buf); } } @@ -422,7 +479,7 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa // {lhs_end} is a pointer to the "terminating whitespace" after {lhs}. // Use that to initialize {rhs_start}. - const char *rhs_start = skipwhite((char *)lhs_end); + const char *rhs_start = skipwhite(lhs_end); // Given {lhs} might be larger than MAXMAPLEN before replace_termcodes // (e.g. "<Space>" is longer than ' '), so first copy into a buffer. @@ -449,7 +506,7 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa /// @param args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait", "replace_keycodes" and /// and "desc" fields are used. /// "rhs", "rhs_lua", "orig_rhs" fields are cleared if "simplified" is false. -/// @param sid -1 to use current_sctx +/// @param sid 0 to use current_sctx static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char *keys, MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid, linenr_T lnum, bool simplified) @@ -482,7 +539,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, mp->m_simplified = simplified; mp->m_expr = args->expr; mp->m_replace_keycodes = args->replace_keycodes; - if (sid >= 0) { + if (sid != 0) { mp->m_script_ctx.sc_sid = sid; mp->m_script_ctx.sc_lnum = lnum; } else { @@ -518,33 +575,16 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, /// @param buf Target Buffer static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T *buf) { - mapblock_T *mp, **mpp; - const char *p; - int n; int retval = 0; - mapblock_T **abbr_table; - mapblock_T **map_table; - int noremap; - map_table = maphash; - abbr_table = &first_abbr; + // If <buffer> was given, we'll be searching through the buffer's + // mappings/abbreviations, not the globals. + mapblock_T **map_table = args->buffer ? buf->b_maphash : maphash; + mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr; // For ":noremap" don't remap, otherwise do remap. - if (maptype == MAPTYPE_NOREMAP) { - noremap = REMAP_NONE; - } else { - noremap = REMAP_YES; - } - - if (args->buffer) { - // If <buffer> was given, we'll be searching through the buffer's - // mappings/abbreviations, not the globals. - map_table = buf->b_maphash; - abbr_table = &buf->b_first_abbr; - } - if (args->script) { - noremap = REMAP_SCRIPT; - } + int noremap = args->script ? REMAP_SCRIPT + : maptype == MAPTYPE_NOREMAP ? REMAP_NONE : REMAP_YES; const bool has_lhs = (args->lhs[0] != NUL); const bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop; @@ -594,15 +634,15 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, const int first = vim_iswordp(lhs); int last = first; - p = (char *)lhs + utfc_ptr2len((char *)lhs); - n = 1; - while (p < (char *)lhs + len) { + const char *p = lhs + utfc_ptr2len(lhs); + int n = 1; + while (p < lhs + len) { n++; // nr of (multi-byte) chars last = vim_iswordp(p); // type of last char if (same == -1 && last != first) { same = n - 1; // count of same char type } - p += utfc_ptr2len((char *)p); + p += utfc_ptr2len(p); } if (last && n > 2 && same >= 0 && same < n - 1) { retval = 1; @@ -631,6 +671,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, && maptype != MAPTYPE_UNMAP) { // need to loop over all global hash lists for (int hash = 0; hash < 256 && !got_int; hash++) { + mapblock_T *mp; if (is_abbrev) { if (hash != 0) { // there is only one abbreviation list break; @@ -645,10 +686,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, && mp->m_keylen == len && strncmp(mp->m_keys, lhs, (size_t)len) == 0) { if (is_abbrev) { - semsg(_("E224: global abbreviation already exists for %s"), - mp->m_keys); + semsg(_(e_global_abbreviation_already_exists_for_str), mp->m_keys); } else { - semsg(_("E225: global mapping already exists for %s"), mp->m_keys); + semsg(_(e_global_mapping_already_exists_for_str), mp->m_keys); } retval = 5; goto theend; @@ -661,6 +701,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, if (map_table != buf->b_maphash && !has_rhs && maptype != MAPTYPE_UNMAP) { // need to loop over all global hash lists for (int hash = 0; hash < 256 && !got_int; hash++) { + mapblock_T *mp; if (is_abbrev) { if (hash != 0) { // there is only one abbreviation list break; @@ -676,7 +717,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, showmap(mp, true); did_local = true; } else { - n = mp->m_keylen; + int n = mp->m_keylen; if (strncmp(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) { showmap(mp, true); did_local = true; @@ -706,8 +747,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, hash_end = 256; } for (int hash = hash_start; hash < hash_end && !got_int; hash++) { - mpp = is_abbrev ? abbr_table : &(map_table[hash]); - for (mp = *mpp; mp != NULL && !got_int; mp = *mpp) { + mapblock_T **mpp = is_abbrev ? abbr_table : &(map_table[hash]); + for (mapblock_T *mp = *mpp; mp != NULL && !got_int; mp = *mpp) { if ((mp->m_mode & mode) == 0) { // skip entries with wrong mode mpp = &(mp->m_next); @@ -719,6 +760,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, did_it = true; } } else { // do we have a match? + int n; + const char *p; if (round) { // second round: Try unmap "rhs" string n = (int)strlen(mp->m_str); p = mp->m_str; @@ -733,8 +776,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // we ignore trailing space when matching with // the "lhs", since an abbreviation can't have // trailing space. - if (n != len && (!is_abbrev || round || n > len - || *skipwhite((char *)lhs + n) != NUL)) { + if (n != len && (!is_abbrev || round || n > len || *skipwhite(lhs + n) != NUL)) { mpp = &(mp->m_next); continue; } @@ -762,9 +804,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, break; } else if (args->unique) { if (is_abbrev) { - semsg(_("E226: abbreviation already exists for %s"), p); + semsg(_(e_abbreviation_already_exists_for_str), p); } else { - semsg(_("E227: mapping already exists for %s"), p); + semsg(_(e_mapping_already_exists_for_str), p); } retval = 5; goto theend; @@ -844,9 +886,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // print entries if (!did_it && !did_local) { if (is_abbrev) { - msg(_("No abbreviation found")); + msg(_("No abbreviation found"), 0); } else { - msg(_("No mapping found")); + msg(_("No mapping found"), 0); } } goto theend; // listing finished @@ -857,9 +899,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, } // Get here when adding a new entry to the maphash[] list or abbrlist. - map_add(buf, map_table, abbr_table, (char *)lhs, args, noremap, mode, is_abbrev, - -1, // sid - 0, // lnum + map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev, + 0, // sid + 0, // lnum keyround1_simplified); } @@ -942,12 +984,10 @@ free_and_return: /// Get the mapping mode from the command name. static int get_map_mode(char **cmdp, bool forceit) { - char *p; - int modec; int mode; - p = *cmdp; - modec = (uint8_t)(*p++); + char *p = *cmdp; + int modec = (uint8_t)(*p++); if (modec == 'i') { mode = MODE_INSERT; // :imap } else if (modec == 'l') { @@ -984,16 +1024,13 @@ static int get_map_mode(char **cmdp, bool forceit) /// This function used to be called map_clear(). static void do_mapclear(char *cmdp, char *arg, int forceit, int abbr) { - int mode; - int local; - - local = (strcmp(arg, "<buffer>") == 0); + bool local = strcmp(arg, "<buffer>") == 0; if (!local && *arg != NUL) { emsg(_(e_invarg)); return; } - mode = get_map_mode(&cmdp, forceit); + int mode = get_map_mode(&cmdp, forceit); map_clear_mode(curbuf, mode, local, abbr); } @@ -1005,11 +1042,8 @@ static void do_mapclear(char *cmdp, char *arg, int forceit, int abbr) /// @param abbr true for abbreviations void map_clear_mode(buf_T *buf, int mode, bool local, bool abbr) { - mapblock_T *mp, **mpp; - int hash; - int new_hash; - - for (hash = 0; hash < 256; hash++) { + for (int hash = 0; hash < 256; hash++) { + mapblock_T **mpp; if (abbr) { if (hash > 0) { // there is only one abbrlist break; @@ -1027,7 +1061,7 @@ void map_clear_mode(buf_T *buf, int mode, bool local, bool abbr) } } while (*mpp != NULL) { - mp = *mpp; + mapblock_T *mp = *mpp; if (mp->m_mode & mode) { mp->m_mode &= ~mode; if (mp->m_mode == 0) { // entry can be deleted @@ -1035,7 +1069,7 @@ void map_clear_mode(buf_T *buf, int mode, bool local, bool abbr) continue; } // May need to put this entry into another hash list. - new_hash = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]); + int new_hash = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]); if (!abbr && new_hash != hash) { *mpp = mp->m_next; if (local) { @@ -1067,12 +1101,10 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { int mode = 0; - int retval; char *buf = NULL; - const char *const rhs = replace_termcodes(str, strlen(str), - &buf, REPTERM_DO_LT, - NULL, CPO_TO_CPO_FLAGS); + const char *const rhs = replace_termcodes(str, strlen(str), &buf, 0, + REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); #define MAPMODE(mode, modechars, chr, modeflags) \ do { \ @@ -1090,7 +1122,7 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo MAPMODE(mode, modechars, 'c', MODE_CMDLINE); #undef MAPMODE - retval = map_to_exists_mode(rhs, mode, abbr); + int retval = map_to_exists_mode(rhs, mode, abbr); xfree(buf); return retval; @@ -1108,13 +1140,12 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo /// @return true if there is at least one mapping with given parameters. int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr) { - mapblock_T *mp; - int hash; bool exp_buffer = false; // Do it twice: once for global maps and once for local maps. - for (;;) { - for (hash = 0; hash < 256; hash++) { + while (true) { + for (int hash = 0; hash < 256; hash++) { + mapblock_T *mp; if (abbr) { if (hash > 0) { // There is only one abbr list. break; @@ -1162,12 +1193,13 @@ static bool expand_buffer = false; /// @param cpo_flags Value of various flags present in &cpo /// /// @return NULL when there is a problem. -static char_u *translate_mapping(char_u *str, int cpo_flags) +static char *translate_mapping(char *str_in, int cpo_flags) { + uint8_t *str = (uint8_t *)str_in; garray_T ga; ga_init(&ga, 1, 40); - bool cpo_bslash = !(cpo_flags&FLAG_CPO_BSLASH); + bool cpo_bslash = cpo_flags & FLAG_CPO_BSLASH; for (; *str; str++) { int c = *str; @@ -1188,13 +1220,13 @@ static char_u *translate_mapping(char_u *str, int cpo_flags) str += 2; } if (IS_SPECIAL(c) || modifiers) { // special key - ga_concat(&ga, (char *)get_special_key_name(c, modifiers)); + ga_concat(&ga, get_special_key_name(c, modifiers)); continue; // for (str) } } if (c == ' ' || c == '\t' || c == Ctrl_J || c == Ctrl_V - || (c == '\\' && !cpo_bslash)) { + || c == '<' || (c == '\\' && !cpo_bslash)) { ga_append(&ga, cpo_bslash ? Ctrl_V : '\\'); } @@ -1203,7 +1235,7 @@ static char_u *translate_mapping(char_u *str, int cpo_flags) } } ga_append(&ga, NUL); - return (char_u *)(ga.ga_data); + return (char *)ga.ga_data; } /// Work out what to complete when doing command line completion of mapping @@ -1212,8 +1244,8 @@ static char_u *translate_mapping(char_u *str, int cpo_flags) /// @param forceit true if '!' given /// @param isabbrev true if abbreviation /// @param isunmap true if unmap/unabbrev command -char_u *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, bool isabbrev, - bool isunmap, cmdidx_T cmdidx) +char *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, bool isabbrev, + bool isunmap, cmdidx_T cmdidx) { if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap) { xp->xp_context = EXPAND_NOTHING; @@ -1229,7 +1261,7 @@ char_u *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, expand_isabbrev = isabbrev; xp->xp_context = EXPAND_MAPPINGS; expand_buffer = false; - for (;;) { + while (true) { if (strncmp(arg, "<buffer>", 8) == 0) { expand_buffer = true; arg = skipwhite(arg + 8); @@ -1308,7 +1340,7 @@ int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***mat bool match; int score = 0; if (!fuzzy) { - match = vim_regexec(regmatch, p, (colnr_T)0); + match = vim_regexec(regmatch, p, 0); } else { score = fuzzy_match_str(p, pat); match = (score != 0); @@ -1342,11 +1374,11 @@ int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***mat mp = maphash[hash]; } for (; mp; mp = mp->m_next) { - if (!(mp->m_mode & expand_mapmodes)) { + if (mp->m_simplified || !(mp->m_mode & expand_mapmodes)) { continue; } - char *p = (char *)translate_mapping((char_u *)mp->m_keys, CPO_TO_CPO_FLAGS); + char *p = translate_mapping(mp->m_keys, CPO_TO_CPO_FLAGS); if (p == NULL) { continue; } @@ -1354,7 +1386,7 @@ int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***mat bool match; int score = 0; if (!fuzzy) { - match = vim_regexec(regmatch, p, (colnr_T)0); + match = vim_regexec(regmatch, p, 0); } else { score = fuzzy_match_str(p, pat); match = (score != 0); @@ -1434,15 +1466,8 @@ int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***mat // Return true if there is an abbreviation, false if not. bool check_abbr(int c, char *ptr, int col, int mincol) { - int len; - int scol; // starting column of the abbr. - int j; - char *s; - char_u tb[MB_MAXBYTES + 4]; - mapblock_T *mp; - mapblock_T *mp2; + uint8_t tb[MB_MAXBYTES + 4]; int clen = 0; // length in characters - bool is_id = true; if (typebuf.tb_no_abbr_cnt) { // abbrev. are not recursive return false; @@ -1461,7 +1486,10 @@ bool check_abbr(int c, char *ptr, int col, int mincol) return false; } + int scol; // starting column of the abbr. + { + bool is_id = true; bool vim_abbr; char *p = mb_prevptr(ptr, ptr + col); if (!vim_iswordp(p)) { @@ -1489,24 +1517,24 @@ bool check_abbr(int c, char *ptr, int col, int mincol) } if (scol < col) { // there is a word in front of the cursor ptr += scol; - len = col - scol; - mp = curbuf->b_first_abbr; - mp2 = first_abbr; + int len = col - scol; + mapblock_T *mp = curbuf->b_first_abbr; + mapblock_T *mp2 = first_abbr; if (mp == NULL) { mp = mp2; mp2 = NULL; } for (; mp; - mp->m_next == NULL ? (mp = mp2, mp2 = NULL) : - (mp = mp->m_next)) { + mp->m_next == NULL ? (mp = mp2, mp2 = NULL) + : (mp = mp->m_next)) { int qlen = mp->m_keylen; char *q = mp->m_keys; int match; - if (strchr((const char *)mp->m_keys, K_SPECIAL) != NULL) { + if (strchr(mp->m_keys, K_SPECIAL) != NULL) { // Might have K_SPECIAL escaped mp->m_keys. q = xstrdup(mp->m_keys); - vim_unescape_ks((char_u *)q); + vim_unescape_ks(q); qlen = (int)strlen(q); } // find entries with right mode and keys @@ -1532,13 +1560,13 @@ bool check_abbr(int c, char *ptr, int col, int mincol) // // Character CTRL-] is treated specially - it completes the // abbreviation, but is not inserted into the input stream. - j = 0; + int j = 0; if (c != Ctrl_RSB) { // special key code, split up if (IS_SPECIAL(c) || c == K_SPECIAL) { tb[j++] = K_SPECIAL; - tb[j++] = (char_u)K_SECOND(c); - tb[j++] = (char_u)K_THIRD(c); + tb[j++] = (uint8_t)K_SECOND(c); + tb[j++] = (uint8_t)K_THIRD(c); } else { if (c < ABBR_OFF && (c < ' ' || c > '~')) { tb[j++] = Ctrl_V; // special char needs CTRL-V @@ -1568,6 +1596,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) const bool silent = mp->m_silent; const bool expr = mp->m_expr; + char *s; if (expr) { s = eval_map_expr(mp, c); } else { @@ -1609,15 +1638,14 @@ char *eval_map_expr(mapblock_T *mp, int c) // typeahead. if (mp->m_luaref == LUA_NOREF) { expr = xstrdup(mp->m_str); - vim_unescape_ks((char_u *)expr); + vim_unescape_ks(expr); } const bool replace_keycodes = mp->m_replace_keycodes; // Forbid changing text or using ":normal" to avoid most of the bad side // effects. Also restore the cursor position. - textlock++; - ex_normal_lock++; + expr_map_lock++; set_vim_var_char(c); // set v:char to the typed character const pos_T save_cursor = curwin->w_cursor; const int save_msg_col = msg_col; @@ -1627,7 +1655,7 @@ char *eval_map_expr(mapblock_T *mp, int c) Array args = ARRAY_DICT_INIT; Object ret = nlua_call_ref(mp->m_luaref, NULL, args, true, &err); if (ret.type == kObjectTypeString) { - p = xstrndup(ret.data.string.data, ret.data.string.size); + p = string_to_cstr(ret.data.string); } api_free_object(ret); if (err.type != kErrorTypeNone) { @@ -1635,11 +1663,10 @@ char *eval_map_expr(mapblock_T *mp, int c) api_clear_error(&err); } } else { - p = eval_to_string(expr, NULL, false); + p = eval_to_string(expr, false); xfree(expr); } - textlock--; - ex_normal_lock--; + expr_map_lock--; curwin->w_cursor = save_cursor; msg_col = save_msg_col; msg_row = save_msg_row; @@ -1651,7 +1678,7 @@ char *eval_map_expr(mapblock_T *mp, int c) char *res = NULL; if (replace_keycodes) { - replace_termcodes(p, strlen(p), &res, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); + replace_termcodes(p, strlen(p), &res, 0, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); } else { // Escape K_SPECIAL in the result to be able to use the string as typeahead. res = vim_strsave_escape_ks(p); @@ -1667,18 +1694,13 @@ char *eval_map_expr(mapblock_T *mp, int c) /// @param buf buffer for local mappings or NULL int makemap(FILE *fd, buf_T *buf) { - mapblock_T *mp; - char c1, c2, c3; - char *p; - char *cmd; - int abbr; - int hash; bool did_cpo = false; // Do the loop twice: Once for mappings, once for abbreviations. // Then loop over all map hash lists. - for (abbr = 0; abbr < 2; abbr++) { - for (hash = 0; hash < 256; hash++) { + for (int abbr = 0; abbr < 2; abbr++) { + for (int hash = 0; hash < 256; hash++) { + mapblock_T *mp; if (abbr) { if (hash > 0) { // there is only one abbr list break; @@ -1707,6 +1729,7 @@ int makemap(FILE *fd, buf_T *buf) if (mp->m_luaref != LUA_NOREF) { continue; } + char *p; for (p = mp->m_str; *p != NUL; p++) { if ((uint8_t)p[0] == K_SPECIAL && (uint8_t)p[1] == KS_EXTRA && p[2] == KE_SNR) { @@ -1720,14 +1743,10 @@ int makemap(FILE *fd, buf_T *buf) // It's possible to create a mapping and then ":unmap" certain // modes. We recreate this here by mapping the individual // modes, which requires up to three of them. - c1 = NUL; - c2 = NUL; - c3 = NUL; - if (abbr) { - cmd = "abbr"; - } else { - cmd = "map"; - } + char c1 = NUL; + char c2 = NUL; + char c3 = NUL; + char *cmd = abbr ? "abbr" : "map"; switch (mp->m_mode) { case MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING: break; @@ -1814,8 +1833,7 @@ int makemap(FILE *fd, buf_T *buf) did_cpo = true; } else { const char specials[] = { (char)(uint8_t)K_SPECIAL, NL, NUL }; - if (strpbrk((const char *)mp->m_str, specials) != NULL - || strpbrk((const char *)mp->m_keys, specials) != NULL) { + if (strpbrk(mp->m_str, specials) != NULL || strpbrk(mp->m_keys, specials) != NULL) { did_cpo = true; } } @@ -1881,8 +1899,7 @@ int makemap(FILE *fd, buf_T *buf) // return FAIL for failure, OK otherwise int put_escstr(FILE *fd, char *strstart, int what) { - char_u *str = (char_u *)strstart; - int c; + uint8_t *str = (uint8_t *)strstart; // :map xx <Nop> if (*str == NUL && what == 1) { @@ -1906,7 +1923,7 @@ int put_escstr(FILE *fd, char *strstart, int what) continue; } - c = *str; + int c = *str; // Special key codes have to be translated to be able to make sense // when they are read back. if (c == K_SPECIAL && what != 2) { @@ -1921,7 +1938,7 @@ int put_escstr(FILE *fd, char *strstart, int what) str += 2; } if (IS_SPECIAL(c) || modifiers) { // special key - if (fputs((char *)get_special_key_name(c, modifiers), fd) < 0) { + if (fputs(get_special_key_name(c, modifiers), fd) < 0) { return FAIL; } continue; @@ -1958,7 +1975,7 @@ int put_escstr(FILE *fd, char *strstart, int what) } } else if (c < ' ' || c > '~' || c == '|' || (what == 0 && c == ' ') - || (what == 1 && str == (char_u *)strstart && c == ' ') + || (what == 1 && str == (uint8_t *)strstart && c == ' ') || (what != 2 && c == '<')) { if (putc(Ctrl_V, fd) < 0) { return FAIL; @@ -1983,14 +2000,13 @@ int put_escstr(FILE *fd, char *strstart, int what) char *check_map(char *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, int *local_ptr, int *rhs_lua) { - int len, minlen; - mapblock_T *mp; *rhs_lua = LUA_NOREF; - len = (int)strlen(keys); + int len = (int)strlen(keys); for (int local = 1; local >= 0; local--) { // loop over all hash lists for (int hash = 0; hash < 256; hash++) { + mapblock_T *mp; if (abbr) { if (hash > 0) { // there is only one list. break; @@ -2015,7 +2031,7 @@ char *check_map(char *keys, int mode, int exact, int ign_mod, int abbr, mapblock s += 3; keylen -= 3; } - minlen = keylen < len ? keylen : len; + int minlen = keylen < len ? keylen : len; if (strncmp(s, keys, (size_t)minlen) == 0) { if (mp_ptr != NULL) { *mp_ptr = mp; @@ -2050,28 +2066,25 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } - if (map_to_exists(name, mode, abbr)) { - rettv->vval.v_number = true; - } else { - rettv->vval.v_number = false; - } + rettv->vval.v_number = map_to_exists(name, mode, abbr); } /// Fill a Dictionary with all applicable maparg() like dictionaries /// /// @param mp The maphash that contains the mapping information /// @param buffer_value The "buffer" value +/// @param abbr True if abbreviation /// @param compatible True for compatible with old maparg() dict /// /// @return A Dictionary. static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt, - const long buffer_value, const bool compatible) + const int buffer_value, const bool abbr, const bool compatible) FUNC_ATTR_NONNULL_ARG(1) { Dictionary dict = ARRAY_DICT_INIT; char *const lhs = str2special_save(mp->m_keys, compatible, !compatible); char *const mapmode = map_mode_to_chars(mp->m_mode); - varnumber_T noremap_value; + int noremap_value; if (compatible) { // Keep old compatible behavior @@ -2091,26 +2104,29 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs : cstr_as_string(str2special_save(mp->m_str, false, true)))); } if (mp->m_desc != NULL) { - PUT(dict, "desc", STRING_OBJ(cstr_to_string(mp->m_desc))); + PUT(dict, "desc", CSTR_TO_OBJ(mp->m_desc)); } - PUT(dict, "lhs", STRING_OBJ(cstr_as_string(lhs))); - PUT(dict, "lhsraw", STRING_OBJ(cstr_to_string((const char *)mp->m_keys))); + PUT(dict, "lhs", CSTR_AS_OBJ(lhs)); + PUT(dict, "lhsraw", CSTR_TO_OBJ(mp->m_keys)); if (lhsrawalt != NULL) { // Also add the value for the simplified entry. - PUT(dict, "lhsrawalt", STRING_OBJ(cstr_to_string(lhsrawalt))); + PUT(dict, "lhsrawalt", CSTR_TO_OBJ(lhsrawalt)); } PUT(dict, "noremap", INTEGER_OBJ(noremap_value)); PUT(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0)); PUT(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0)); PUT(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0)); - PUT(dict, "sid", INTEGER_OBJ((varnumber_T)mp->m_script_ctx.sc_sid)); - PUT(dict, "lnum", INTEGER_OBJ((varnumber_T)mp->m_script_ctx.sc_lnum)); - PUT(dict, "buffer", INTEGER_OBJ((varnumber_T)buffer_value)); + PUT(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid)); + PUT(dict, "scriptversion", INTEGER_OBJ(1)); + PUT(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum)); + PUT(dict, "buffer", INTEGER_OBJ(buffer_value)); PUT(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0)); if (mp->m_replace_keycodes) { PUT(dict, "replace_keycodes", INTEGER_OBJ(1)); } - PUT(dict, "mode", STRING_OBJ(cstr_as_string(mapmode))); + PUT(dict, "mode", CSTR_AS_OBJ(mapmode)); + PUT(dict, "abbr", INTEGER_OBJ(abbr ? 1 : 0)); + PUT(dict, "mode_bits", INTEGER_OBJ(mp->m_mode)); return dict; } @@ -2152,8 +2168,8 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; const int mode = get_map_mode((char **)&which, 0); - char *keys_simplified = replace_termcodes(keys, strlen(keys), &keys_buf, flags, &did_simplify, - CPO_TO_CPO_FLAGS); + char *keys_simplified = replace_termcodes(keys, strlen(keys), &keys_buf, 0, + flags, &did_simplify, CPO_TO_CPO_FLAGS); mapblock_T *mp = NULL; int buffer_local; LuaRef rhs_lua; @@ -2162,10 +2178,8 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) if (did_simplify) { // When the lhs is being simplified the not-simplified keys are // preferred for printing, like in do_map(). - (void)replace_termcodes(keys, - strlen(keys), - &alt_keys_buf, flags | REPTERM_NO_SIMPLIFY, NULL, - CPO_TO_CPO_FLAGS); + (void)replace_termcodes(keys, strlen(keys), &alt_keys_buf, 0, + flags | REPTERM_NO_SIMPLIFY, NULL, CPO_TO_CPO_FLAGS); rhs = check_map(alt_keys_buf, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua); } @@ -2185,7 +2199,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) { Dictionary dict = mapblock_fill_dict(mp, did_simplify ? keys_simplified : NULL, - buffer_local, true); + buffer_local, abbr, true); (void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL); api_free_dictionary(dict); } else { @@ -2198,22 +2212,99 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) xfree(alt_keys_buf); } +/// Get the mapping mode from the mode string. +/// It may contain multiple characters, eg "nox", or "!", or ' ' +/// Return 0 if there is an error. +static int get_map_mode_string(const char *const mode_string, const bool abbr) +{ + const char *p = mode_string; + const int MASK_V = MODE_VISUAL | MODE_SELECT; + const int MASK_MAP = MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING; + const int MASK_BANG = MODE_INSERT | MODE_CMDLINE; + + if (*p == NUL) { + p = " "; // compatibility + } + int mode = 0; + int modec; + while ((modec = (uint8_t)(*p++))) { + int tmode; + switch (modec) { + case 'i': + tmode = MODE_INSERT; break; + case 'l': + tmode = MODE_LANGMAP; break; + case 'c': + tmode = MODE_CMDLINE; break; + case 'n': + tmode = MODE_NORMAL; break; + case 'x': + tmode = MODE_VISUAL; break; + case 's': + tmode = MODE_SELECT; break; + case 'o': + tmode = MODE_OP_PENDING; break; + case 't': + tmode = MODE_TERMINAL; break; + case 'v': + tmode = MASK_V; break; + case '!': + tmode = MASK_BANG; break; + case ' ': + tmode = MASK_MAP; break; + default: + return 0; // error, unknown mode character + } + mode |= tmode; + } + if ((abbr && (mode & ~MASK_BANG) != 0) + || (!abbr && (mode & (mode - 1)) != 0 // more than one bit set + && ( + // false if multiple bits set in mode and mode is fully + // contained in one mask + !(((mode & MASK_BANG) != 0 && (mode & ~MASK_BANG) == 0) + || ((mode & MASK_MAP) != 0 && (mode & ~MASK_MAP) == 0))))) { + return 0; + } + + return mode; +} + /// "mapset()" function void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { + const char *which; char buf[NUMBUFLEN]; - const char *which = tv_get_string_buf_chk(&argvars[0], buf); - if (which == NULL) { - return; + int is_abbr; + dict_T *d; + + // If first arg is a dict, then that's the only arg permitted. + const bool dict_only = argvars[0].v_type == VAR_DICT; + + if (dict_only) { + d = argvars[0].vval.v_dict; + which = tv_dict_get_string(d, "mode", false); + is_abbr = (int)tv_dict_get_bool(d, "abbr", -1); + if (which == NULL || is_abbr < 0) { + emsg(_(e_entries_missing_in_mapset_dict_argument)); + return; + } + } else { + which = tv_get_string_buf_chk(&argvars[0], buf); + if (which == NULL) { + return; + } + is_abbr = (int)tv_get_bool(&argvars[1]); + if (tv_check_for_dict_arg(argvars, 2) == FAIL) { + return; + } + d = argvars[2].vval.v_dict; } - const int mode = get_map_mode((char **)&which, 0); - const bool is_abbr = tv_get_number(&argvars[1]) != 0; - - if (argvars[2].v_type != VAR_DICT) { - emsg(_(e_dictreq)); + const int mode = get_map_mode_string(which, is_abbr); + if (mode == 0) { + semsg(_(e_illegal_map_mode_string_str), which); return; } - dict_T *d = argvars[2].vval.v_dict; // Get the values in the same order as above in get_maparg(). char *lhs = tv_dict_get_string(d, "lhs", false); @@ -2232,7 +2323,7 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) api_free_object(callback_obj); } if (lhs == NULL || lhsraw == NULL || orig_rhs == NULL) { - emsg(_("E460: entries missing in mapset() dict argument")); + emsg(_(e_entries_missing_in_mapset_dict_argument)); api_free_luaref(rhs_lua); return; } @@ -2248,12 +2339,13 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) .replace_keycodes = tv_dict_get_number(d, "replace_keycodes") != 0, .desc = tv_dict_get_string(d, "desc", false), }; - set_maparg_rhs(orig_rhs, strlen(orig_rhs), rhs_lua, CPO_TO_CPO_FLAGS, &args); scid_T sid = (scid_T)tv_dict_get_number(d, "sid"); linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum"); bool buffer = tv_dict_get_number(d, "buffer") != 0; // mode from the dict is not used + set_maparg_rhs(orig_rhs, strlen(orig_rhs), rhs_lua, sid, CPO_TO_CPO_FLAGS, &args); + mapblock_T **map_table = buffer ? curbuf->b_maphash : maphash; mapblock_T **abbr_table = buffer ? &curbuf->b_first_abbr : &first_abbr; @@ -2273,6 +2365,59 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) sid, lnum, false); } +/// "maplist()" function +void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; + const bool abbr = argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]); + + tv_list_alloc_ret(rettv, kListLenUnknown); + + // Do it twice: once for global maps and once for local maps. + for (int buffer_local = 0; buffer_local <= 1; buffer_local++) { + for (int hash = 0; hash < 256; hash++) { + mapblock_T *mp; + if (abbr) { + if (hash > 0) { // there is only one abbr list + break; + } + if (buffer_local) { + mp = curbuf->b_first_abbr; + } else { + mp = first_abbr; + } + } else if (buffer_local) { + mp = curbuf->b_maphash[hash]; + } else { + mp = maphash[hash]; + } + for (; mp; mp = mp->m_next) { + if (mp->m_simplified) { + continue; + } + + char *keys_buf = NULL; + bool did_simplify = false; + + char *lhs = str2special_save(mp->m_keys, true, false); + (void)replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify, + CPO_TO_CPO_FLAGS); + xfree(lhs); + + Dictionary dict = mapblock_fill_dict(mp, + did_simplify ? keys_buf : NULL, + buffer_local, abbr, true); + typval_T d = TV_INITIAL_VALUE; + (void)object_to_vim(DICTIONARY_OBJ(dict), &d, NULL); + assert(d.v_type == VAR_DICT); + tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict); + api_free_dictionary(dict); + xfree(keys_buf); + } + } + } +} + /// "maparg()" function void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -2328,13 +2473,13 @@ static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE; static void langmap_set_entry(int from, int to) { langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); - unsigned int a = 0; + unsigned a = 0; assert(langmap_mapga.ga_len >= 0); - unsigned int b = (unsigned int)langmap_mapga.ga_len; + unsigned b = (unsigned)langmap_mapga.ga_len; // Do a binary search for an existing entry. while (a != b) { - unsigned int i = (a + b) / 2; + unsigned i = (a + b) / 2; int d = entries[i].from - from; if (d == 0) { @@ -2353,7 +2498,7 @@ static void langmap_set_entry(int from, int to) // insert new entry at position "a" entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a; memmove(entries + 1, entries, - ((unsigned int)langmap_mapga.ga_len - a) * sizeof(langmap_entry_T)); + ((unsigned)langmap_mapga.ga_len - a) * sizeof(langmap_entry_T)); langmap_mapga.ga_len++; entries[0].from = from; entries[0].to = to; @@ -2385,23 +2530,20 @@ int langmap_adjust_mb(int c) void langmap_init(void) { for (int i = 0; i < 256; i++) { - langmap_mapchar[i] = (char_u)i; // we init with a one-to-one map + langmap_mapchar[i] = (uint8_t)i; // we init with a one-to-one map } ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8); } /// Called when langmap option is set; the language map can be /// changed at any time! -void langmap_set(void) +const char *did_set_langmap(optset_T *args) { - char *p; - char *p2; - int from, to; - - ga_clear(&langmap_mapga); // clear the previous map first - langmap_init(); // back to one-to-one map + ga_clear(&langmap_mapga); // clear the previous map first + langmap_init(); // back to one-to-one map - for (p = p_langmap; p[0] != NUL;) { + for (char *p = p_langmap; p[0] != NUL;) { + char *p2; for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';'; MB_PTR_ADV(p2)) { if (p2[0] == '\\' && p2[1] != NUL) { @@ -2421,8 +2563,8 @@ void langmap_set(void) if (p[0] == '\\' && p[1] != NUL) { p++; } - from = utf_ptr2char(p); - to = NUL; + int from = utf_ptr2char(p); + int to = NUL; if (p2 == NULL) { MB_PTR_ADV(p); if (p[0] != ',') { @@ -2440,16 +2582,17 @@ void langmap_set(void) } } if (to == NUL) { - semsg(_("E357: 'langmap': Matching character missing for %s"), - transchar(from)); - return; + snprintf(args->os_errbuf, args->os_errbuflen, + _("E357: 'langmap': Matching character missing for %s"), + transchar(from)); + return args->os_errbuf; } if (from >= 256) { langmap_set_entry(from, to); } else { assert(to <= UCHAR_MAX); - langmap_mapchar[from & 255] = (char_u)to; + langmap_mapchar[from & 255] = (uint8_t)to; } // Advance to next pair @@ -2460,8 +2603,10 @@ void langmap_set(void) p = p2; if (p[0] != NUL) { if (p[0] != ',') { - semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p); - return; + snprintf(args->os_errbuf, args->os_errbuflen, + _("E358: 'langmap': Extra characters after semicolon: %s"), + p); + return args->os_errbuf; } p++; } @@ -2470,16 +2615,17 @@ void langmap_set(void) } } } + + return NULL; } static void do_exmap(exarg_T *eap, int isabbrev) { - int mode; char *cmdp = eap->cmd; - mode = get_map_mode(&cmdp, eap->forceit || isabbrev); + int mode = get_map_mode(&cmdp, eap->forceit || isabbrev); switch (do_map((*cmdp == 'n') ? MAPTYPE_NOREMAP - : (*cmdp == 'u') ? MAPTYPE_UNMAP : MAPTYPE_MAP, + : (*cmdp == 'u') ? MAPTYPE_UNMAP : MAPTYPE_MAP, eap->arg, mode, isabbrev)) { case 1: emsg(_(e_invarg)); @@ -2502,7 +2648,7 @@ void ex_map(exarg_T *eap) // If we are in a secure mode we print the mappings for security reasons. if (secure) { secure = 2; - msg_outtrans(eap->cmd); + msg_outtrans(eap->cmd, 0); msg_putchar('\n'); } do_exmap(eap, false); @@ -2549,26 +2695,22 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod const sctx_T save_current_sctx = api_set_sctx(channel_id); - if (opts != NULL && opts->callback.type == kObjectTypeLuaRef) { - lua_funcref = opts->callback.data.luaref; - opts->callback.data.luaref = LUA_NOREF; - } MapArguments parsed_args = MAP_ARGUMENTS_INIT; if (opts) { -#define KEY_TO_BOOL(name) \ - parsed_args.name = api_object_to_bool(opts->name, #name, false, err); \ - if (ERROR_SET(err)) { \ - goto fail_and_free; \ - } - - KEY_TO_BOOL(nowait); - KEY_TO_BOOL(noremap); - KEY_TO_BOOL(silent); - KEY_TO_BOOL(script); - KEY_TO_BOOL(expr); - KEY_TO_BOOL(unique); - KEY_TO_BOOL(replace_keycodes); -#undef KEY_TO_BOOL + parsed_args.nowait = opts->nowait; + parsed_args.noremap = opts->noremap; + parsed_args.silent = opts->silent; + parsed_args.script = opts->script; + parsed_args.expr = opts->expr; + parsed_args.unique = opts->unique; + parsed_args.replace_keycodes = opts->replace_keycodes; + if (HAS_KEY(opts, keymap, callback)) { + lua_funcref = opts->callback; + opts->callback = LUA_NOREF; + } + if (HAS_KEY(opts, keymap, desc)) { + parsed_args.desc = string_to_cstr(opts->desc); + } } parsed_args.buffer = !global; @@ -2584,32 +2726,26 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod goto fail_and_free; } - if (opts != NULL && opts->desc.type == kObjectTypeString) { - parsed_args.desc = string_to_cstr(opts->desc.data.string); - } else { - parsed_args.desc = NULL; - } if (parsed_args.lhs_len > MAXMAPLEN || parsed_args.alt_lhs_len > MAXMAPLEN) { api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data); goto fail_and_free; } - if (mode.size > 1) { - api_set_error(err, kErrorTypeValidation, "Shortname is too long: %s", mode.data); - goto fail_and_free; + char *p = mode.size > 0 ? mode.data : "m"; + bool forceit = *p == '!'; + // integer value of the mapping mode, to be passed to do_map() + int mode_val = get_map_mode(&p, forceit); + if (forceit) { + assert(p == mode.data); + p++; } - int mode_val; // integer value of the mapping mode, to be passed to do_map() - char *p = (mode.size) ? mode.data : "m"; - if (strncmp(p, "!", 2) == 0) { - mode_val = get_map_mode(&p, true); // mapmode-ic - } else { - mode_val = get_map_mode(&p, false); - if (mode_val == (MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING) && mode.size > 0) { - // get_map_mode() treats unrecognized mode shortnames as ":map". - // This is an error unless the given shortname was empty string "". - api_set_error(err, kErrorTypeValidation, "Invalid mode shortname: \"%s\"", p); - goto fail_and_free; - } + bool is_abbrev = (mode_val & (MODE_INSERT | MODE_CMDLINE)) != 0 && *p == 'a'; + if (is_abbrev) { + p++; + } + if (mode.size > 0 && (size_t)(p - mode.data) != mode.size) { + api_set_error(err, kErrorTypeValidation, "Invalid mode shortname: \"%s\"", mode.data); + goto fail_and_free; } if (parsed_args.lhs_len == 0) { @@ -2645,14 +2781,14 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod maptype_val = MAPTYPE_NOREMAP; } - switch (buf_do_map(maptype_val, &parsed_args, mode_val, 0, target_buf)) { + switch (buf_do_map(maptype_val, &parsed_args, mode_val, is_abbrev, target_buf)) { case 0: break; case 1: - api_set_error(err, kErrorTypeException, (char *)e_invarg, 0); + api_set_error(err, kErrorTypeException, e_invarg, 0); goto fail_and_free; case 2: - api_set_error(err, kErrorTypeException, (char *)e_nomap, 0); + api_set_error(err, kErrorTypeException, e_nomap, 0); goto fail_and_free; case 5: api_set_error(err, kErrorTypeException, @@ -2687,7 +2823,7 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf) int int_mode = get_map_mode(&p, 0); // Determine the desired buffer value - long buffer_value = (buf == NULL) ? 0 : buf->handle; + int buffer_value = (buf == NULL) ? 0 : buf->handle; for (int i = 0; i < MAX_MAPHASH; i++) { for (const mapblock_T *current_maphash = get_maphash(i, buf); @@ -2699,7 +2835,8 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf) // Check for correct mode if (int_mode & current_maphash->m_mode) { ADD(mappings, - DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value, false))); + DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, + buffer_value, false, false))); } } } |