aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/mapping.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/mapping.c')
-rw-r--r--src/nvim/mapping.c657
1 files changed, 359 insertions, 298 deletions
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 64a798a27b..831d1299a8 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -5,32 +5,43 @@
#include <assert.h>
#include <inttypes.h>
+#include <lauxlib.h>
+#include <limits.h>
#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "nvim/api/private/converter.h"
+#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
-#include "nvim/assert.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/cmdexpand.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/ex_docmd.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/keycodes.h"
#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
#include "nvim/mapping.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/option.h"
+#include "nvim/option_defs.h"
+#include "nvim/pos.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/ui.h"
+#include "nvim/search.h"
+#include "nvim/strings.h"
#include "nvim/vim.h"
/// List used for abbreviations.
@@ -151,7 +162,7 @@ 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((char_u *)mp->m_desc))) {
+ && (mp->m_desc == NULL || message_filtered(mp->m_desc))) {
return;
}
@@ -176,7 +187,7 @@ static void showmap(mapblock_T *mp, bool local)
// Display the LHS. Get length of what we write.
len = (size_t)msg_outtrans_special(mp->m_keys, true, 0);
do {
- msg_putchar(' '); // padd with blanks
+ msg_putchar(' '); // pad with blanks
len++;
} while (len < 12);
@@ -214,7 +225,6 @@ static void showmap(mapblock_T *mp, bool local)
last_set_msg(mp->m_script_ctx);
}
msg_clr_eos();
- ui_flush(); // show one line at a time
}
/// Replace termcodes in the given LHS and RHS and store the results into the
@@ -263,52 +273,59 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs
if (replaced == NULL) {
return false;
}
- mapargs->lhs_len = STRLEN(replaced);
- STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs));
+ 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);
if (replaced == NULL) {
return false;
}
- mapargs->alt_lhs_len = STRLEN(replaced);
- STRLCPY(mapargs->alt_lhs, replaced, sizeof(mapargs->alt_lhs));
+ mapargs->alt_lhs_len = strlen(replaced);
+ xstrlcpy(mapargs->alt_lhs, replaced, sizeof(mapargs->alt_lhs));
} else {
mapargs->alt_lhs_len = 0;
}
+ set_maparg_rhs(orig_rhs, orig_rhs_len, rhs_lua, 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)
+{
mapargs->rhs_lua = rhs_lua;
if (rhs_lua == LUA_NOREF) {
mapargs->orig_rhs_len = orig_rhs_len;
- mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char_u));
- STRLCPY(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
-
+ mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char));
+ xstrlcpy(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
- mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
+ mapargs->rhs = xcalloc(1, sizeof(char)); // single NUL-char
mapargs->rhs_len = 0;
mapargs->rhs_is_noop = true;
} else {
char *rhs_buf = NULL;
- replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL,
- cpo_flags);
- mapargs->rhs_len = STRLEN(replaced);
- // XXX: replace_termcodes may produce an empty string even if orig_rhs is non-empty
+ char *replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, 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)
mapargs->rhs_is_noop = orig_rhs_len != 0 && mapargs->rhs_len == 0;
- mapargs->rhs = (char_u *)replaced;
+ mapargs->rhs = replaced;
}
} else {
char tmp_buf[64];
// orig_rhs is not used for Lua mappings, but still needs to be a string.
- mapargs->orig_rhs = xcalloc(1, sizeof(char_u));
+ mapargs->orig_rhs = xcalloc(1, sizeof(char));
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);
- mapargs->rhs = vim_strsave((char_u *)tmp_buf);
+ mapargs->rhs = xstrdup(tmp_buf);
}
- return true;
}
/// Parse a string of |:map-arguments| into a @ref MapArguments struct.
@@ -330,53 +347,53 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs
/// @param[out] mapargs MapArguments struct holding all extracted argument
/// values.
/// @return 0 on success, 1 if invalid arguments are detected.
-static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *mapargs)
+static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapargs)
{
- const char_u *to_parse = strargs;
- to_parse = (char_u *)skipwhite((char *)to_parse);
+ const char *to_parse = strargs;
+ to_parse = skipwhite(to_parse);
CLEAR_POINTER(mapargs);
// Accept <buffer>, <nowait>, <silent>, <expr>, <script>, and <unique> in
// any order.
while (true) {
- if (STRNCMP(to_parse, "<buffer>", 8) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 8);
+ if (strncmp(to_parse, "<buffer>", 8) == 0) {
+ to_parse = skipwhite(to_parse + 8);
mapargs->buffer = true;
continue;
}
- if (STRNCMP(to_parse, "<nowait>", 8) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 8);
+ if (strncmp(to_parse, "<nowait>", 8) == 0) {
+ to_parse = skipwhite(to_parse + 8);
mapargs->nowait = true;
continue;
}
- if (STRNCMP(to_parse, "<silent>", 8) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 8);
+ if (strncmp(to_parse, "<silent>", 8) == 0) {
+ to_parse = skipwhite(to_parse + 8);
mapargs->silent = true;
continue;
}
// Ignore obsolete "<special>" modifier.
- if (STRNCMP(to_parse, "<special>", 9) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 9);
+ if (strncmp(to_parse, "<special>", 9) == 0) {
+ to_parse = skipwhite(to_parse + 9);
continue;
}
- if (STRNCMP(to_parse, "<script>", 8) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 8);
+ if (strncmp(to_parse, "<script>", 8) == 0) {
+ to_parse = skipwhite(to_parse + 8);
mapargs->script = true;
continue;
}
- if (STRNCMP(to_parse, "<expr>", 6) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 6);
+ if (strncmp(to_parse, "<expr>", 6) == 0) {
+ to_parse = skipwhite(to_parse + 6);
mapargs->expr = true;
continue;
}
- if (STRNCMP(to_parse, "<unique>", 8) == 0) {
- to_parse = (char_u *)skipwhite((char *)to_parse + 8);
+ if (strncmp(to_parse, "<unique>", 8) == 0) {
+ to_parse = skipwhite(to_parse + 8);
mapargs->unique = true;
continue;
}
@@ -393,7 +410,7 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
//
// With :unmap, literal white space is included in the {lhs}; there is no
// separate {rhs}.
- const char *lhs_end = (char *)to_parse;
+ const char *lhs_end = to_parse;
bool do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
while (*lhs_end && (is_unmap || !ascii_iswhite(*lhs_end))) {
if ((lhs_end[0] == Ctrl_V || (do_backslash && lhs_end[0] == '\\'))
@@ -405,20 +422,20 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
// {lhs_end} is a pointer to the "terminating whitespace" after {lhs}.
// Use that to initialize {rhs_start}.
- const char_u *rhs_start = (char_u *)skipwhite((char *)lhs_end);
+ const char *rhs_start = skipwhite((char *)lhs_end);
// Given {lhs} might be larger than MAXMAPLEN before replace_termcodes
// (e.g. "<Space>" is longer than ' '), so first copy into a buffer.
- size_t orig_lhs_len = (size_t)((char_u *)lhs_end - to_parse);
+ size_t orig_lhs_len = (size_t)(lhs_end - to_parse);
if (orig_lhs_len >= 256) {
return 1;
}
- char_u lhs_to_replace[256];
- STRLCPY(lhs_to_replace, to_parse, orig_lhs_len + 1);
+ char lhs_to_replace[256];
+ xstrlcpy(lhs_to_replace, to_parse, orig_lhs_len + 1);
- size_t orig_rhs_len = STRLEN(rhs_start);
- if (!set_maparg_lhs_rhs((char *)lhs_to_replace, orig_lhs_len,
- (char *)rhs_start, orig_rhs_len, LUA_NOREF,
+ size_t orig_rhs_len = strlen(rhs_start);
+ if (!set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len,
+ rhs_start, orig_rhs_len, LUA_NOREF,
CPO_TO_CPO_FLAGS, mapargs)) {
return 1;
}
@@ -433,7 +450,7 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
/// and "desc" fields are used.
/// "rhs", "rhs_lua", "orig_rhs" fields are cleared if "simplified" is false.
/// @param sid -1 to use current_sctx
-static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char_u *keys,
+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)
{
@@ -448,7 +465,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
}
}
- mp->m_keys = vim_strsave(keys);
+ mp->m_keys = xstrdup(keys);
mp->m_str = args->rhs;
mp->m_orig_str = args->orig_rhs;
mp->m_luaref = args->rhs_lua;
@@ -457,7 +474,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
args->orig_rhs = NULL;
args->rhs_lua = LUA_NOREF;
}
- mp->m_keylen = (int)STRLEN(mp->m_keys);
+ mp->m_keylen = (int)strlen(mp->m_keys);
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
mp->m_silent = args->silent;
@@ -483,7 +500,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
mp->m_next = *abbr_table;
*abbr_table = mp;
} else {
- const int n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ const int n = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]);
mp->m_next = map_table[n];
map_table[n] = mp;
}
@@ -502,7 +519,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T *buf)
{
mapblock_T *mp, **mpp;
- const char_u *p;
+ const char *p;
int n;
int retval = 0;
mapblock_T **abbr_table;
@@ -539,7 +556,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
goto theend;
}
- const char_u *lhs = (char_u *)&args->lhs;
+ const char *lhs = (char *)&args->lhs;
const bool did_simplify = args->alt_lhs_len != 0;
// The following is done twice if we have two versions of keys
@@ -553,11 +570,11 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
if (!did_simplify) {
break;
}
- lhs = (char_u *)&args->alt_lhs;
+ lhs = (char *)&args->alt_lhs;
len = (int)args->alt_lhs_len;
} else if (did_simplify && do_print) {
// when printing always use the not-simplified map
- lhs = (char_u *)&args->alt_lhs;
+ lhs = (char *)&args->alt_lhs;
len = (int)args->alt_lhs_len;
}
@@ -577,9 +594,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
const int first = vim_iswordp(lhs);
int last = first;
- p = lhs + utfc_ptr2len((char *)lhs);
+ p = (char *)lhs + utfc_ptr2len((char *)lhs);
n = 1;
- while (p < lhs + len) {
+ while (p < (char *)lhs + len) {
n++; // nr of (multi-byte) chars
last = vim_iswordp(p); // type of last char
if (same == -1 && last != first) {
@@ -626,7 +643,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
// check entries with the same mode
if ((mp->m_mode & mode) != 0
&& mp->m_keylen == len
- && STRNCMP(mp->m_keys, lhs, (size_t)len) == 0) {
+ && strncmp(mp->m_keys, lhs, (size_t)len) == 0) {
if (is_abbrev) {
semsg(_("E224: global abbreviation already exists for %s"),
mp->m_keys);
@@ -660,7 +677,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
did_local = true;
} else {
n = mp->m_keylen;
- if (STRNCMP(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) {
+ if (strncmp(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) {
showmap(mp, true);
did_local = true;
}
@@ -679,9 +696,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
for (int round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1
&& !did_it && !got_int; round++) {
int hash_start, hash_end;
- if (has_lhs || is_abbrev) {
+ if ((round == 0 && has_lhs) || is_abbrev) {
// just use one hash
- hash_start = is_abbrev ? 0 : MAP_HASH(mode, lhs[0]);
+ hash_start = is_abbrev ? 0 : MAP_HASH(mode, (uint8_t)lhs[0]);
hash_end = hash_start + 1;
} else {
// need to loop over all hash lists
@@ -703,13 +720,13 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
} else { // do we have a match?
if (round) { // second round: Try unmap "rhs" string
- n = (int)STRLEN(mp->m_str);
+ n = (int)strlen(mp->m_str);
p = mp->m_str;
} else {
n = mp->m_keylen;
p = mp->m_keys;
}
- if (STRNCMP(p, lhs, (size_t)(n < len ? n : len)) == 0) {
+ if (strncmp(p, lhs, (size_t)(n < len ? n : len)) == 0) {
if (maptype == MAPTYPE_UNMAP) {
// Delete entry.
// Only accept a full match. For abbreviations
@@ -791,7 +808,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// May need to put this entry into another hash list.
- int new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ int new_hash = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]);
if (!is_abbrev && new_hash != hash) {
*mpp = mp->m_next;
mp->m_next = map_table[new_hash];
@@ -840,7 +857,7 @@ 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, lhs, args, noremap, mode, is_abbrev,
+ map_add(buf, map_table, abbr_table, (char *)lhs, args, noremap, mode, is_abbrev,
-1, // sid
0, // lnum
keyround1_simplified);
@@ -884,7 +901,7 @@ theend:
///
/// @param maptype MAPTYPE_MAP for |:map|
/// MAPTYPE_UNMAP for |:unmap|
-/// MAPTYPE_NOREMAP for |noremap|.
+/// MAPTYPE_NOREMAP for |:noremap|.
/// @param arg C-string containing the arguments of the map/abbrev
/// command, i.e. everything except the initial `:[X][nore]map`.
/// - Cannot be a read-only string; it will be modified.
@@ -898,7 +915,7 @@ theend:
/// - 4 for out of mem (deprecated, WON'T HAPPEN)
/// - 5 for entry not unique
///
-int do_map(int maptype, char_u *arg, int mode, bool is_abbrev)
+int do_map(int maptype, char *arg, int mode, bool is_abbrev)
{
MapArguments parsed_args;
int result = str_to_mapargs(arg, maptype == MAPTYPE_UNMAP, &parsed_args);
@@ -965,12 +982,12 @@ static int get_map_mode(char **cmdp, bool forceit)
/// Clear all mappings (":mapclear") or abbreviations (":abclear").
/// "abbr" should be false for mappings, true for abbreviations.
/// This function used to be called map_clear().
-static void do_mapclear(char *cmdp, char_u *arg, int forceit, int abbr)
+static void do_mapclear(char *cmdp, char *arg, int forceit, int abbr)
{
int mode;
int local;
- local = (STRCMP(arg, "<buffer>") == 0);
+ local = (strcmp(arg, "<buffer>") == 0);
if (!local && *arg != NUL) {
emsg(_(e_invarg));
return;
@@ -1018,7 +1035,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, mp->m_keys[0]);
+ new_hash = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]);
if (!abbr && new_hash != hash) {
*mpp = mp->m_next;
if (local) {
@@ -1053,9 +1070,9 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo
int retval;
char *buf = NULL;
- const char_u *const rhs = (char_u *)replace_termcodes(str, strlen(str),
- &buf, REPTERM_DO_LT,
- NULL, CPO_TO_CPO_FLAGS);
+ const char *const rhs = replace_termcodes(str, strlen(str),
+ &buf, REPTERM_DO_LT,
+ NULL, CPO_TO_CPO_FLAGS);
#define MAPMODE(mode, modechars, chr, modeflags) \
do { \
@@ -1073,7 +1090,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((char *)rhs, mode, abbr);
+ retval = map_to_exists_mode(rhs, mode, abbr);
xfree(buf);
return retval;
@@ -1113,7 +1130,7 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
mp = maphash[hash];
}
for (; mp; mp = mp->m_next) {
- if ((mp->m_mode & mode) && strstr((char *)mp->m_str, rhs) != NULL) {
+ if ((mp->m_mode & mode) && strstr(mp->m_str, rhs) != NULL) {
return true;
}
}
@@ -1182,7 +1199,7 @@ static char_u *translate_mapping(char_u *str, int cpo_flags)
}
if (c) {
- ga_append(&ga, (char)c);
+ ga_append(&ga, (uint8_t)c);
}
}
ga_append(&ga, NUL);
@@ -1195,7 +1212,7 @@ 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_u *arg, bool forceit, bool isabbrev,
+char_u *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) {
@@ -1213,38 +1230,38 @@ char_u *set_context_in_map_cmd(expand_T *xp, char *cmd, char_u *arg, bool forcei
xp->xp_context = EXPAND_MAPPINGS;
expand_buffer = false;
for (;;) {
- if (STRNCMP(arg, "<buffer>", 8) == 0) {
+ if (strncmp(arg, "<buffer>", 8) == 0) {
expand_buffer = true;
- arg = (char_u *)skipwhite((char *)arg + 8);
+ arg = skipwhite(arg + 8);
continue;
}
- if (STRNCMP(arg, "<unique>", 8) == 0) {
- arg = (char_u *)skipwhite((char *)arg + 8);
+ if (strncmp(arg, "<unique>", 8) == 0) {
+ arg = skipwhite(arg + 8);
continue;
}
- if (STRNCMP(arg, "<nowait>", 8) == 0) {
- arg = (char_u *)skipwhite((char *)arg + 8);
+ if (strncmp(arg, "<nowait>", 8) == 0) {
+ arg = skipwhite(arg + 8);
continue;
}
- if (STRNCMP(arg, "<silent>", 8) == 0) {
- arg = (char_u *)skipwhite((char *)arg + 8);
+ if (strncmp(arg, "<silent>", 8) == 0) {
+ arg = skipwhite(arg + 8);
continue;
}
- if (STRNCMP(arg, "<special>", 9) == 0) {
- arg = (char_u *)skipwhite((char *)arg + 9);
+ if (strncmp(arg, "<special>", 9) == 0) {
+ arg = skipwhite(arg + 9);
continue;
}
- if (STRNCMP(arg, "<script>", 8) == 0) {
- arg = (char_u *)skipwhite((char *)arg + 8);
+ if (strncmp(arg, "<script>", 8) == 0) {
+ arg = skipwhite(arg + 8);
continue;
}
- if (STRNCMP(arg, "<expr>", 6) == 0) {
- arg = (char_u *)skipwhite((char *)arg + 6);
+ if (strncmp(arg, "<expr>", 6) == 0) {
+ arg = skipwhite(arg + 6);
continue;
}
break;
}
- xp->xp_pattern = (char *)arg;
+ xp->xp_pattern = arg;
}
return NULL;
@@ -1253,98 +1270,140 @@ char_u *set_context_in_map_cmd(expand_T *xp, char *cmd, char_u *arg, bool forcei
/// Find all mapping/abbreviation names that match regexp "regmatch".
/// For command line expansion of ":[un]map" and ":[un]abbrev" in all modes.
/// @return OK if matches found, FAIL otherwise.
-int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file)
+int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***matches)
{
- mapblock_T *mp;
- int hash;
- int count;
- int round;
- char_u *p;
- int i;
-
- *num_file = 0; // return values in case of FAIL
- *file = NULL;
-
- // round == 1: Count the matches.
- // round == 2: Build the array to keep the matches.
- for (round = 1; round <= 2; round++) {
- count = 0;
-
- for (i = 0; i < 7; i++) {
- if (i == 0) {
- p = (char_u *)"<silent>";
- } else if (i == 1) {
- p = (char_u *)"<unique>";
- } else if (i == 2) {
- p = (char_u *)"<script>";
- } else if (i == 3) {
- p = (char_u *)"<expr>";
- } else if (i == 4 && !expand_buffer) {
- p = (char_u *)"<buffer>";
- } else if (i == 5) {
- p = (char_u *)"<nowait>";
- } else if (i == 6) {
- p = (char_u *)"<special>";
- } else {
+ const bool fuzzy = cmdline_fuzzy_complete(pat);
+
+ *numMatches = 0; // return values in case of FAIL
+ *matches = NULL;
+
+ garray_T ga;
+ if (!fuzzy) {
+ ga_init(&ga, sizeof(char *), 3);
+ } else {
+ ga_init(&ga, sizeof(fuzmatch_str_T), 3);
+ }
+
+ // First search in map modifier arguments
+ for (int i = 0; i < 7; i++) {
+ char *p;
+ if (i == 0) {
+ p = "<silent>";
+ } else if (i == 1) {
+ p = "<unique>";
+ } else if (i == 2) {
+ p = "<script>";
+ } else if (i == 3) {
+ p = "<expr>";
+ } else if (i == 4 && !expand_buffer) {
+ p = "<buffer>";
+ } else if (i == 5) {
+ p = "<nowait>";
+ } else if (i == 6) {
+ p = "<special>";
+ } else {
+ continue;
+ }
+
+ bool match;
+ int score = 0;
+ if (!fuzzy) {
+ match = vim_regexec(regmatch, p, (colnr_T)0);
+ } else {
+ score = fuzzy_match_str(p, pat);
+ match = (score != 0);
+ }
+
+ if (!match) {
+ continue;
+ }
+
+ if (fuzzy) {
+ GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){
+ .idx = ga.ga_len,
+ .str = xstrdup(p),
+ .score = score,
+ }));
+ } else {
+ GA_APPEND(char *, &ga, xstrdup(p));
+ }
+ }
+
+ for (int hash = 0; hash < 256; hash++) {
+ mapblock_T *mp;
+ if (expand_isabbrev) {
+ if (hash > 0) { // only one abbrev list
+ break; // for (hash)
+ }
+ mp = first_abbr;
+ } else if (expand_buffer) {
+ mp = curbuf->b_maphash[hash];
+ } else {
+ mp = maphash[hash];
+ }
+ for (; mp; mp = mp->m_next) {
+ if (!(mp->m_mode & expand_mapmodes)) {
continue;
}
- if (vim_regexec(regmatch, (char *)p, (colnr_T)0)) {
- if (round == 1) {
- count++;
- } else {
- (*file)[count++] = (char *)vim_strsave(p);
- }
+ char *p = (char *)translate_mapping((char_u *)mp->m_keys, CPO_TO_CPO_FLAGS);
+ if (p == NULL) {
+ continue;
}
- }
- for (hash = 0; hash < 256; hash++) {
- if (expand_isabbrev) {
- if (hash > 0) { // only one abbrev list
- break; // for (hash)
- }
- mp = first_abbr;
- } else if (expand_buffer) {
- mp = curbuf->b_maphash[hash];
+ bool match;
+ int score = 0;
+ if (!fuzzy) {
+ match = vim_regexec(regmatch, p, (colnr_T)0);
} else {
- mp = maphash[hash];
+ score = fuzzy_match_str(p, pat);
+ match = (score != 0);
}
- for (; mp; mp = mp->m_next) {
- if (mp->m_mode & expand_mapmodes) {
- p = translate_mapping(mp->m_keys, CPO_TO_CPO_FLAGS);
- if (p != NULL && vim_regexec(regmatch, (char *)p, (colnr_T)0)) {
- if (round == 1) {
- count++;
- } else {
- (*file)[count++] = (char *)p;
- p = NULL;
- }
- }
- xfree(p);
- }
- } // for (mp)
- } // for (hash)
- if (count == 0) { // no match found
- break; // for (round)
- }
+ if (!match) {
+ xfree(p);
+ continue;
+ }
- if (round == 1) {
- *file = xmalloc((size_t)count * sizeof(char_u *));
- }
- } // for (round)
+ if (fuzzy) {
+ GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){
+ .idx = ga.ga_len,
+ .str = p,
+ .score = score,
+ }));
+ } else {
+ GA_APPEND(char *, &ga, p);
+ }
+ } // for (mp)
+ } // for (hash)
+ if (ga.ga_len == 0) {
+ return FAIL;
+ }
+
+ if (!fuzzy) {
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
+ } else {
+ fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, false);
+ *numMatches = ga.ga_len;
+ }
+
+ int count = *numMatches;
if (count > 1) {
// Sort the matches
- sort_strings(*file, count);
+ // Fuzzy matching already sorts the matches
+ if (!fuzzy) {
+ sort_strings(*matches, count);
+ }
// Remove multiple entries
- char **ptr1 = *file;
+ char **ptr1 = *matches;
char **ptr2 = ptr1 + 1;
char **ptr3 = ptr1 + count;
while (ptr2 < ptr3) {
- if (STRCMP(*ptr1, *ptr2)) {
+ if (strcmp(*ptr1, *ptr2) != 0) {
*++ptr1 = *ptr2++;
} else {
xfree(*ptr2++);
@@ -1353,7 +1412,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file)
}
}
- *num_file = count;
+ *numMatches = count;
return count == 0 ? FAIL : OK;
}
@@ -1373,12 +1432,12 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file)
// Then there must be white space before the abbr.
//
// Return true if there is an abbreviation, false if not.
-bool check_abbr(int c, char_u *ptr, int col, int mincol)
+bool check_abbr(int c, char *ptr, int col, int mincol)
{
int len;
int scol; // starting column of the abbr.
int j;
- char_u *s;
+ char *s;
char_u tb[MB_MAXBYTES + 4];
mapblock_T *mp;
mapblock_T *mp2;
@@ -1404,7 +1463,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
{
bool vim_abbr;
- char_u *p = mb_prevptr(ptr, ptr + col);
+ char *p = mb_prevptr(ptr, ptr + col);
if (!vim_iswordp(p)) {
vim_abbr = true; // Vim added abbr.
} else {
@@ -1417,7 +1476,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
while (p > ptr + mincol) {
p = mb_prevptr(ptr, p);
if (ascii_isspace(*p) || (!vim_abbr && is_id != vim_iswordp(p))) {
- p += utfc_ptr2len((char *)p);
+ p += utfc_ptr2len(p);
break;
}
clen++;
@@ -1441,19 +1500,19 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
(mp = mp->m_next)) {
int qlen = mp->m_keylen;
- char_u *q = mp->m_keys;
+ char *q = mp->m_keys;
int match;
if (strchr((const char *)mp->m_keys, K_SPECIAL) != NULL) {
// Might have K_SPECIAL escaped mp->m_keys.
- q = vim_strsave(mp->m_keys);
- vim_unescape_ks(q);
- qlen = (int)STRLEN(q);
+ q = xstrdup(mp->m_keys);
+ vim_unescape_ks((char_u *)q);
+ qlen = (int)strlen(q);
}
// find entries with right mode and keys
match = (mp->m_mode & State)
&& qlen == len
- && !STRNCMP(q, ptr, (size_t)len);
+ && !strncmp(q, ptr, (size_t)len);
if (q != mp->m_keys) {
xfree(q);
}
@@ -1491,9 +1550,9 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
int newlen = utf_char2bytes(c, (char *)tb + j);
tb[j + newlen] = NUL;
// Need to escape K_SPECIAL.
- char_u *escaped = (char_u *)vim_strsave_escape_ks((char *)tb + j);
+ char *escaped = vim_strsave_escape_ks((char *)tb + j);
if (escaped != NULL) {
- newlen = (int)STRLEN(escaped);
+ newlen = (int)strlen(escaped);
memmove(tb + j, escaped, (size_t)newlen);
j += newlen;
xfree(escaped);
@@ -1503,17 +1562,23 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
// insert the last typed char
(void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent);
}
- if (mp->m_expr) {
+
+ // copy values here, calling eval_map_expr() may make "mp" invalid!
+ const int noremap = mp->m_noremap;
+ const bool silent = mp->m_silent;
+ const bool expr = mp->m_expr;
+
+ if (expr) {
s = eval_map_expr(mp, c);
} else {
s = mp->m_str;
}
if (s != NULL) {
// insert the to string
- (void)ins_typebuf((char *)s, mp->m_noremap, 0, true, mp->m_silent);
+ (void)ins_typebuf(s, noremap, 0, true, silent);
// no abbrev. for these chars
- typebuf.tb_no_abbr_cnt += (int)STRLEN(s) + j + 1;
- if (mp->m_expr) {
+ typebuf.tb_no_abbr_cnt += (int)strlen(s) + j + 1;
+ if (expr) {
xfree(s);
}
}
@@ -1522,7 +1587,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
tb[1] = NUL;
len = clen; // Delete characters instead of bytes
while (len-- > 0) { // delete the from string
- (void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent);
+ (void)ins_typebuf((char *)tb, 1, 0, true, silent);
}
return true;
}
@@ -1532,20 +1597,23 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
/// Evaluate the RHS of a mapping or abbreviations and take care of escaping
/// special characters.
+/// Careful: after this "mp" will be invalid if the mapping was deleted.
///
/// @param c NUL or typed character for abbreviation
-char_u *eval_map_expr(mapblock_T *mp, int c)
+char *eval_map_expr(mapblock_T *mp, int c)
{
- char_u *p = NULL;
- char_u *expr = NULL;
+ char *p = NULL;
+ char *expr = NULL;
// Remove escaping of K_SPECIAL, because "str" is in a format to be used as
// typeahead.
if (mp->m_luaref == LUA_NOREF) {
- expr = vim_strsave(mp->m_str);
- vim_unescape_ks(expr);
+ expr = xstrdup(mp->m_str);
+ vim_unescape_ks((char_u *)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++;
@@ -1559,7 +1627,7 @@ char_u *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 = (char_u *)xstrndup(ret.data.string.data, ret.data.string.size);
+ p = xstrndup(ret.data.string.data, ret.data.string.size);
}
api_free_object(ret);
if (err.type != kErrorTypeNone) {
@@ -1567,7 +1635,7 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
api_clear_error(&err);
}
} else {
- p = (char_u *)eval_to_string((char *)expr, NULL, false);
+ p = eval_to_string(expr, NULL, false);
xfree(expr);
}
textlock--;
@@ -1580,13 +1648,13 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
return NULL;
}
- char_u *res = NULL;
+ char *res = NULL;
- if (mp->m_replace_keycodes) {
- replace_termcodes((char *)p, STRLEN(p), (char **)&res, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
+ if (replace_keycodes) {
+ replace_termcodes(p, strlen(p), &res, 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 = (char_u *)vim_strsave_escape_ks((char *)p);
+ res = vim_strsave_escape_ks(p);
}
xfree(p);
@@ -1600,8 +1668,8 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
int makemap(FILE *fd, buf_T *buf)
{
mapblock_T *mp;
- char_u c1, c2, c3;
- char_u *p;
+ char c1, c2, c3;
+ char *p;
char *cmd;
int abbr;
int hash;
@@ -1640,7 +1708,7 @@ int makemap(FILE *fd, buf_T *buf)
continue;
}
for (p = mp->m_str; *p != NUL; p++) {
- if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
+ if ((uint8_t)p[0] == K_SPECIAL && (uint8_t)p[1] == KS_EXTRA
&& p[2] == KE_SNR) {
break;
}
@@ -1811,9 +1879,9 @@ int makemap(FILE *fd, buf_T *buf)
// "what": 0 for :map lhs, 1 for :map rhs, 2 for :set
//
// return FAIL for failure, OK otherwise
-int put_escstr(FILE *fd, char_u *strstart, int what)
+int put_escstr(FILE *fd, char *strstart, int what)
{
- char_u *str = strstart;
+ char_u *str = (char_u *)strstart;
int c;
// :map xx <Nop>
@@ -1890,7 +1958,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
}
} else if (c < ' ' || c > '~' || c == '|'
|| (what == 0 && c == ' ')
- || (what == 1 && str == strstart && c == ' ')
+ || (what == 1 && str == (char_u *)strstart && c == ' ')
|| (what != 2 && c == '<')) {
if (putc(Ctrl_V, fd) < 0) {
return FAIL;
@@ -1912,14 +1980,14 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
/// @param abbr do abbreviations
/// @param mp_ptr return: pointer to mapblock or NULL
/// @param local_ptr return: buffer-local mapping or NULL
-char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr,
- int *local_ptr, int *rhs_lua)
+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);
+ len = (int)strlen(keys);
for (int local = 1; local >= 0; local--) {
// loop over all hash lists
for (int hash = 0; hash < 256; hash++) {
@@ -19