aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-06-23 21:17:11 +0800
committerGitHub <noreply@github.com>2022-06-23 21:17:11 +0800
commit7718b758461265d8966468c104ce5454538471e2 (patch)
treec58cec1a66defb6c84c113cb76c03e759db47feb
parent05ca14a8810555495c309b8add3002773c77123d (diff)
downloadrneovim-7718b758461265d8966468c104ce5454538471e2.tar.gz
rneovim-7718b758461265d8966468c104ce5454538471e2.tar.bz2
rneovim-7718b758461265d8966468c104ce5454538471e2.zip
refactor: move some mapping-related code to a separate file (#19061)
This marks the following Vim patches as ported: vim-patch:8.1.1785: map functionality mixed with character input Problem: Map functionality mixed with character input. Solution: Move the map functionality to a separate file. (Yegappan Lakshmanan, closes vim/vim#4740) Graduate the +localmap feature. https://github.com/vim/vim/commit/b66bab381c8ba71fd6e92327d1d34c6f8a65f2a7 vim-patch:8.2.3643: header for source file is outdated Problem: Header for source file is outdated. Solution: Make the header more accurate. (closes vim/vim#9186) https://github.com/vim/vim/commit/a3f83feb63eae5464a620ae793c002eb45f7a838 Also cherry-pick a change for <unique> mappings from patch 8.2.0807. Rename map_clear_mode() to do_mapclear().
-rwxr-xr-xscripts/vim-patch.sh4
-rw-r--r--src/nvim/api/buffer.c1
-rw-r--r--src/nvim/api/private/helpers.c189
-rw-r--r--src/nvim/api/vim.c1
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/digraph.c1
-rw-r--r--src/nvim/edit.c29
-rw-r--r--src/nvim/eval.c51
-rw-r--r--src/nvim/eval/funcs.c96
-rw-r--r--src/nvim/ex_docmd.c57
-rw-r--r--src/nvim/ex_getln.c1
-rw-r--r--src/nvim/ex_session.c2
-rw-r--r--src/nvim/getchar.c2034
-rw-r--r--src/nvim/getchar.h44
-rw-r--r--src/nvim/keycodes.c72
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mapping.c2553
-rw-r--r--src/nvim/mapping.h54
-rw-r--r--src/nvim/normal.c1
-rw-r--r--src/nvim/option.c170
-rw-r--r--src/nvim/window.c1
21 files changed, 2705 insertions, 2659 deletions
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 472b79cbf4..d5424f51ab 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -233,6 +233,10 @@ preprocess_patch() {
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/userfunc\.c/\1\/eval\/userfunc\.c/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
+ # Rename map.c to mapping.c
+ LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/map\(\.[ch]\)/\1\/mapping\2/g' \
+ "$file" > "$file".tmp && mv "$file".tmp "$file"
+
# Rename session.c to ex_session.c
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/session\(\.[ch]\)/\1\/ex_session\2/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 9dc95de243..0810d155f6 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -22,6 +22,7 @@
#include "nvim/ex_docmd.h"
#include "nvim/extmark.h"
#include "nvim/lua/executor.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 9cadef0385..436bcd5212 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -21,7 +21,6 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/extmark.h"
#include "nvim/fileio.h"
-#include "nvim/getchar.h"
#include "nvim/highlight_group.h"
#include "nvim/lib/kvec.h"
#include "nvim/lua/executor.h"
@@ -441,142 +440,6 @@ Array string_to_array(const String input, bool crlf)
return ret;
}
-/// Set, tweak, or remove a mapping in a mode. Acts as the implementation for
-/// functions like @ref nvim_buf_set_keymap.
-///
-/// Arguments are handled like @ref nvim_set_keymap unless noted.
-/// @param buffer Buffer handle for a specific buffer, or 0 for the current
-/// buffer, or -1 to signify global behavior ("all buffers")
-/// @param is_unmap When true, removes the mapping that matches {lhs}.
-void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mode, String lhs,
- String rhs, Dict(keymap) *opts, Error *err)
-{
- LuaRef lua_funcref = LUA_NOREF;
- bool global = (buffer == -1);
- if (global) {
- buffer = 0;
- }
- buf_T *target_buf = find_buffer_by_handle(buffer, err);
-
- if (!target_buf) {
- return;
- }
-
- 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);
-#undef KEY_TO_BOOL
- }
- parsed_args.buffer = !global;
-
- set_maparg_lhs_rhs(lhs.data, lhs.size,
- rhs.data, rhs.size, lua_funcref,
- CPO_TO_CPO_FLAGS, &parsed_args);
- 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;
- }
- 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;
- }
- }
-
- if (parsed_args.lhs_len == 0) {
- api_set_error(err, kErrorTypeValidation, "Invalid (empty) LHS");
- goto fail_and_free;
- }
-
- bool is_noremap = parsed_args.noremap;
- assert(!(is_unmap && is_noremap));
-
- if (!is_unmap && lua_funcref == LUA_NOREF
- && (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) {
- if (rhs.size == 0) { // assume that the user wants RHS to be a <Nop>
- parsed_args.rhs_is_noop = true;
- } else {
- abort(); // should never happen
- }
- } else if (is_unmap && (parsed_args.rhs_len || parsed_args.rhs_lua != LUA_NOREF)) {
- if (parsed_args.rhs_len) {
- api_set_error(err, kErrorTypeValidation,
- "Gave nonempty RHS in unmap command: %s", parsed_args.rhs);
- } else {
- api_set_error(err, kErrorTypeValidation, "Gave nonempty RHS for unmap");
- }
- goto fail_and_free;
- }
-
- // buf_do_map() reads noremap/unmap as its own argument.
- int maptype_val = 0;
- if (is_unmap) {
- maptype_val = 1;
- } else if (is_noremap) {
- maptype_val = 2;
- }
-
- switch (buf_do_map(maptype_val, &parsed_args, mode_val, 0, target_buf)) {
- case 0:
- break;
- case 1:
- api_set_error(err, kErrorTypeException, (char *)e_invarg, 0);
- goto fail_and_free;
- case 2:
- api_set_error(err, kErrorTypeException, (char *)e_nomap, 0);
- goto fail_and_free;
- case 5:
- api_set_error(err, kErrorTypeException,
- "E227: mapping already exists for %s", parsed_args.lhs);
- goto fail_and_free;
- default:
- assert(false && "Unrecognized return code!");
- goto fail_and_free;
- } // switch
-
- parsed_args.rhs_lua = LUA_NOREF; // don't clear ref on success
-fail_and_free:
- current_sctx = save_current_sctx;
- NLUA_CLEAR_REF(parsed_args.rhs_lua);
- xfree(parsed_args.rhs);
- xfree(parsed_args.orig_rhs);
- XFREE_CLEAR(parsed_args.desc);
-}
-
/// Collects `n` buffer lines into array `l`, optionally replacing newlines
/// with NUL.
///
@@ -930,58 +793,6 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...)
err->type = errType;
}
-/// Get an array containing dictionaries describing mappings
-/// based on mode and buffer id
-///
-/// @param mode The abbreviation for the mode
-/// @param buf The buffer to get the mapping array. NULL for global
-/// @param from_lua Whether it is called from internal lua api.
-/// @returns Array of maparg()-like dictionaries describing mappings
-ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
-{
- Array mappings = ARRAY_DICT_INIT;
- dict_T *const dict = tv_dict_alloc();
-
- // Convert the string mode to the integer mode
- // that is stored within each mapblock
- char *p = mode.data;
- int int_mode = get_map_mode(&p, 0);
-
- // Determine the desired buffer value
- long 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);
- current_maphash;
- current_maphash = current_maphash->m_next) {
- if (current_maphash->m_simplified) {
- continue;
- }
- // Check for correct mode
- if (int_mode & current_maphash->m_mode) {
- mapblock_fill_dict(dict, current_maphash, buffer_value, false);
- Object api_dict = vim_to_object((typval_T[]) { { .v_type = VAR_DICT,
- .vval.v_dict = dict } });
- if (from_lua) {
- Dictionary d = api_dict.data.dictionary;
- for (size_t j = 0; j < d.size; j++) {
- if (strequal("callback", d.items[j].key.data)) {
- d.items[j].value.type = kObjectTypeLuaRef;
- d.items[j].value.data.luaref = api_new_luaref((LuaRef)d.items[j].value.data.integer);
- break;
- }
- }
- }
- ADD(mappings, api_dict);
- tv_dict_clear(dict);
- }
- }
- }
- tv_dict_free(dict);
-
- return mappings;
-}
-
/// Force obj to bool.
/// If it fails, returns false and sets err
/// @param obj The object to coerce to a boolean
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b7df1398f5..c5881dbc5f 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -38,6 +38,7 @@
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index f13f6e35ea..85e34e910d 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -53,6 +53,7 @@
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index b461082be0..99e99a8a9e 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -18,6 +18,7 @@
#include "nvim/ex_getln.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/mapping.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 8f7ba03b14..e0717ef8bc 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -31,6 +31,7 @@
#include "nvim/indent_c.h"
#include "nvim/keycodes.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -6768,34 +6769,6 @@ void free_last_insert(void)
#endif
-/// Add character "c" to buffer "s"
-///
-/// Escapes the special meaning of K_SPECIAL, handles multi-byte
-/// characters.
-///
-/// @param[in] c Character to add.
-/// @param[out] s Buffer to add to. Must have at least MB_MAXBYTES + 1 bytes.
-///
-/// @return Pointer to after the added bytes.
-char_u *add_char2buf(int c, char_u *s)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
-{
- char_u temp[MB_MAXBYTES + 1];
- const int len = utf_char2bytes(c, (char *)temp);
- for (int i = 0; i < len; i++) {
- c = (uint8_t)temp[i];
- // Need to escape K_SPECIAL like in the typeahead buffer.
- if (c == K_SPECIAL) {
- *s++ = K_SPECIAL;
- *s++ = KS_SPECIAL;
- *s++ = KE_FILLER;
- } else {
- *s++ = (char_u)c;
- }
- }
- return s;
-}
-
/*
* move cursor to start of line
* if flags & BL_WHITE move to first non-white
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 43d6ed558f..be2df9488e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6791,57 +6791,6 @@ char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
return argv;
}
-/// Fill a dictionary with all applicable maparg() like dictionaries
-///
-/// @param dict The dictionary to be filled
-/// @param mp The maphash that contains the mapping information
-/// @param buffer_value The "buffer" value
-/// @param compatible True for compatible with old maparg() dict
-void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, long buffer_value,
- bool compatible)
- FUNC_ATTR_NONNULL_ALL
-{
- char *const lhs = str2special_save((const char *)mp->m_keys,
- compatible, !compatible);
- char *const mapmode = map_mode_to_chars(mp->m_mode);
- varnumber_T noremap_value;
-
- if (compatible) {
- // Keep old compatible behavior
- // This is unable to determine whether a mapping is a <script> mapping
- noremap_value = !!mp->m_noremap;
- } else {
- // Distinguish between <script> mapping
- // If it's not a <script> mapping, check if it's a noremap
- noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap;
- }
-
- if (mp->m_luaref != LUA_NOREF) {
- tv_dict_add_nr(dict, S_LEN("callback"), mp->m_luaref);
- } else {
- if (compatible) {
- tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
- } else {
- tv_dict_add_allocated_str(dict, S_LEN("rhs"),
- str2special_save((const char *)mp->m_str, false,
- true));
- }
- }
- if (mp->m_desc != NULL) {
- tv_dict_add_allocated_str(dict, S_LEN("desc"), xstrdup(mp->m_desc));
- }
- tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
- tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
- tv_dict_add_nr(dict, S_LEN("script"), mp->m_noremap == REMAP_SCRIPT ? 1 : 0);
- tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
- tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0);
- tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ctx.sc_sid);
- tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)mp->m_script_ctx.sc_lnum);
- tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value);
- tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0);
- tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
-}
-
void return_register(int regname, typval_T *rettv)
{
char buf[2] = { (char)regname, 0 };
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8e49d1b9a8..f7d6b016fd 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -38,6 +38,7 @@
#include "nvim/input.h"
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/match.h"
#include "nvim/math.h"
@@ -5647,89 +5648,6 @@ static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = (varnumber_T)time(NULL);
}
-static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
-{
- char *keys_buf = NULL;
- char_u *alt_keys_buf = NULL;
- bool did_simplify = false;
- char_u *rhs;
- LuaRef rhs_lua;
- int mode;
- int abbr = FALSE;
- int get_dict = FALSE;
- mapblock_T *mp;
- int buffer_local;
- int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
-
- // Return empty string for failure.
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- char *keys = (char *)tv_get_string(&argvars[0]);
- if (*keys == NUL) {
- return;
- }
-
- char buf[NUMBUFLEN];
- const char *which;
- if (argvars[1].v_type != VAR_UNKNOWN) {
- which = tv_get_string_buf_chk(&argvars[1], buf);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- abbr = tv_get_number(&argvars[2]);
- if (argvars[3].v_type != VAR_UNKNOWN) {
- get_dict = tv_get_number(&argvars[3]);
- }
- }
- } else {
- which = "";
- }
- if (which == NULL) {
- return;
- }
-
- mode = get_map_mode((char **)&which, 0);
-
- char_u *keys_simplified
- = (char_u *)replace_termcodes(keys,
- STRLEN(keys), &keys_buf, flags, &did_simplify,
- CPO_TO_CPO_FLAGS);
- rhs = check_map(keys_simplified, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
- 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),
- (char **)&alt_keys_buf, flags | REPTERM_NO_SIMPLIFY, NULL,
- CPO_TO_CPO_FLAGS);
- rhs = check_map(alt_keys_buf, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
- }
-
- if (!get_dict) {
- // Return a string.
- if (rhs != NULL) {
- if (*rhs == NUL) {
- rettv->vval.v_string = xstrdup("<Nop>");
- } else {
- rettv->vval.v_string = str2special_save((char *)rhs, false, false);
- }
- } else if (rhs_lua != LUA_NOREF) {
- size_t msglen = 100;
- char *msg = (char *)xmalloc(msglen);
- snprintf(msg, msglen, "<Lua function %d>", mp->m_luaref);
- rettv->vval.v_string = msg;
- }
- } else {
- tv_dict_alloc_ret(rettv);
- if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
- // Return a dictionary.
- mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
- }
- }
-
- xfree(keys_buf);
- xfree(alt_keys_buf);
-}
-
/// luaeval() function implementation
static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
@@ -5748,18 +5666,6 @@ static void f_map(typval_T *argvars, typval_T *rettv, FunPtr fptr)
filter_map(argvars, rettv, TRUE);
}
-/// "maparg()" function
-static void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- get_maparg(argvars, rettv, TRUE);
-}
-
-/// "mapcheck()" function
-static void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- get_maparg(argvars, rettv, FALSE);
-}
-
static void find_some_match(typval_T *const argvars, typval_T *const rettv,
const SomeMatchType type)
{
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 49db5c3716..53a05ccc04 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -44,6 +44,7 @@
#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/match.h"
#include "nvim/mbyte.h"
@@ -5256,45 +5257,6 @@ theend:
return tab_number;
}
-/// ":abbreviate" and friends.
-static void ex_abbreviate(exarg_T *eap)
-{
- do_exmap(eap, TRUE); // almost the same as mapping
-}
-
-/// ":map" and friends.
-static void ex_map(exarg_T *eap)
-{
- /*
- * If we are sourcing .exrc or .vimrc in current directory we
- * print the mappings for security reasons.
- */
- if (secure) {
- secure = 2;
- msg_outtrans((char_u *)eap->cmd);
- msg_putchar('\n');
- }
- do_exmap(eap, FALSE);
-}
-
-/// ":unmap" and friends.
-static void ex_unmap(exarg_T *eap)
-{
- do_exmap(eap, FALSE);
-}
-
-/// ":mapclear" and friends.
-static void ex_mapclear(exarg_T *eap)
-{
- map_clear_mode((char_u *)eap->cmd, (char_u *)eap->arg, eap->forceit, false);
-}
-
-/// ":abclear" and friends.
-static void ex_abclear(exarg_T *eap)
-{
- map_clear_mode((char_u *)eap->cmd, (char_u *)eap->arg, true, true);
-}
-
static void ex_autocmd(exarg_T *eap)
{
// Disallow autocommands from .exrc and .vimrc in current
@@ -8381,23 +8343,6 @@ void do_sleep(long msec)
}
}
-static void do_exmap(exarg_T *eap, int isabbrev)
-{
- int mode;
- char *cmdp = eap->cmd;
- mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
-
- switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
- (char_u *)eap->arg, mode, isabbrev)) {
- case 1:
- emsg(_(e_invarg));
- break;
- case 2:
- emsg(isabbrev ? _(e_noabbr) : _(e_nomap));
- break;
- }
-}
-
/// ":winsize" command (obsolete).
static void ex_winsize(exarg_T *eap)
{
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 211eeff45e..e442c907b3 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -46,6 +46,7 @@
#include "nvim/log.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 3b6f7b90bf..e60be80923 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -25,9 +25,9 @@
#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
-#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/keycodes.h"
+#include "nvim/mapping.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 57d25e5c45..4426f52353 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1,14 +1,8 @@
// 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
-/*
- * getchar.c
- *
- * functions related with getting a character from the user/mapping/redo/...
- *
- * manipulations with redo buffer and stuff buffer
- * mappings and abbreviations
- */
+// getchar.c: Code related to getting a character from the user or a script
+// file, manipulations with redo buffer and stuff buffer.
#include <assert.h>
#include <inttypes.h>
@@ -22,18 +16,15 @@
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
-#include "nvim/eval.h"
#include "nvim/event/loop.h"
-#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/ex_session.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/input.h"
#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -46,7 +37,6 @@
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/plines.h"
-#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@@ -91,26 +81,6 @@ static int typeahead_char = 0; // typeahead char that's not flushed
*/
static int block_redo = FALSE;
-// Make a hash value for a mapping.
-// "mode" is the lower 4 bits of the State for the mapping.
-// "c1" is the first character of the "lhs".
-// Returns a value between 0 and 255, index in maphash.
-// Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
-#define MAP_HASH(mode, \
- c1) (((mode) & \
- (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | \
- MODE_OP_PENDING | MODE_TERMINAL)) ? (c1) : ((c1) ^ 0x80))
-
-// Each mapping is put in one of the MAX_MAPHASH hash lists,
-// to speed up finding it.
-static mapblock_T *(maphash[MAX_MAPHASH]);
-static bool maphash_valid = false;
-
-/*
- * List used for abbreviations.
- */
-static mapblock_T *first_abbr = NULL; // first entry in abbrlist
-
static int KeyNoremap = 0; // remapping flags
/*
@@ -837,18 +807,10 @@ static void init_typebuf(void)
}
}
-void init_default_mappings(void)
+/// @return true when keys cannot be remapped.
+bool noremap_keys(void)
{
- add_map((char_u *)"Y y$", MODE_NORMAL, true);
-
- // Use normal! <C-L> to prevent inserting raw <C-L> when using i_<C-O>
- // See https://github.com/neovim/neovim/issues/17473
- add_map((char_u *)"<C-L> <Cmd>nohlsearch<Bar>diffupdate<Bar>normal! <C-L><CR>",
- MODE_NORMAL, true);
- add_map((char_u *)"<C-U> <C-G>u<C-U>", MODE_INSERT, true);
- add_map((char_u *)"<C-W> <C-G>u<C-W>", MODE_INSERT, true);
- add_map((char_u *)"* y/\\\\V<C-R>\"<CR>", MODE_VISUAL, true);
- add_map((char_u *)"# y?\\\\V<C-R>\"<CR>", MODE_VISUAL, true);
+ return KeyNoremap & (RM_NONE|RM_SCRIPT);
}
// Insert a string in position 'offset' in the typeahead buffer (for "@r"
@@ -1860,7 +1822,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
// - waiting for a char with --more--
// - in Ctrl-X mode, and we get a valid char for that mode
tb_c1 = typebuf.tb_buf[typebuf.tb_off];
- if (no_mapping == 0 && maphash_valid
+ if (no_mapping == 0 && is_maphash_valid()
&& (no_zero_mapping == 0 || tb_c1 != '0')
&& (typebuf.tb_maplen == 0 || is_plug_map
|| (!(typebuf.tb_noremap[typebuf.tb_off] & (RM_NONE|RM_ABBR))))
@@ -1877,8 +1839,8 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
nolmaplen = 0;
}
// First try buffer-local mappings.
- mp = curbuf->b_maphash[MAP_HASH(local_State, tb_c1)];
- mp2 = maphash[MAP_HASH(local_State, tb_c1)];
+ mp = get_buf_maphash_list(local_State, tb_c1);
+ mp2 = get_maphash_list(local_State, tb_c1);
if (mp == NULL) {
// There are no buffer-local mappings.
mp = mp2;
@@ -2816,1970 +2778,6 @@ int fix_input_buffer(char_u *buf, int len)
return len;
}
-/// Replace termcodes in the given LHS and RHS and store the results into the
-/// `lhs` and `rhs` of the given @ref MapArguments struct.
-///
-/// `rhs` and `orig_rhs` will both point to new allocated buffers. `orig_rhs`
-/// will hold a copy of the given `orig_rhs`.
-///
-/// The `*_len` variables will be set appropriately. If the length of
-/// the final `lhs` exceeds `MAXMAPLEN`, `lhs_len` will be set equal to the
-/// original larger length and `lhs` will be truncated.
-///
-/// If RHS should be <Nop>, `rhs` will be an empty string, `rhs_len` will be
-/// zero, and `rhs_is_noop` will be set to true.
-///
-/// Any memory allocated by @ref replace_termcodes is freed before this function
-/// returns.
-///
-/// @param[in] orig_lhs Original mapping LHS, with characters to replace.
-/// @param[in] orig_lhs_len `strlen` of orig_lhs.
-/// @param[in] orig_rhs Original mapping RHS, with characters to replace.
-/// @param[in] rhs_lua Lua reference for Lua maps.
-/// @param[in] orig_rhs_len `strlen` of orig_rhs.
-/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
-/// @param[out] mapargs MapArguments struct holding the replaced strings.
-void set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs_len,
- const char *const orig_rhs, const size_t orig_rhs_len, const LuaRef rhs_lua,
- const int cpo_flags, MapArguments *const mapargs)
-{
- char *lhs_buf = NULL;
- char *alt_lhs_buf = NULL;
- char *rhs_buf = NULL;
-
- // If mapping has been given as ^V<C_UP> say, then replace the term codes
- // with the appropriate two bytes. If it is a shifted special key, unshift
- // it too, giving another two bytes.
- //
- // replace_termcodes() may move the result to allocated memory, which
- // needs to be freed later (*lhs_buf and *rhs_buf).
- // replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
- // If something like <C-H> is simplified to 0x08 then mark it as simplified.
- bool did_simplify = false;
- const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
- char *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &lhs_buf, flags, &did_simplify,
- cpo_flags);
- mapargs->lhs_len = STRLEN(replaced);
- STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs));
- if (did_simplify) {
- replaced = replace_termcodes(orig_lhs, orig_lhs_len, &alt_lhs_buf, flags | REPTERM_NO_SIMPLIFY,
- NULL, cpo_flags);
- mapargs->alt_lhs_len = STRLEN(replaced);
- STRLCPY(mapargs->alt_lhs, replaced, sizeof(mapargs->alt_lhs));
- } else {
- mapargs->alt_lhs_len = 0;
- }
-
- 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);
-
- if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
- mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
- mapargs->rhs_len = 0;
- mapargs->rhs_is_noop = true;
- } else {
- 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
- // (e.g. a single ^V, see :h map-empty-rhs)
- mapargs->rhs_is_noop = orig_rhs_len != 0 && mapargs->rhs_len == 0;
- mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u));
- STRLCPY(mapargs->rhs, replaced, mapargs->rhs_len + 1);
- }
- } 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_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);
- }
-
- xfree(lhs_buf);
- xfree(alt_lhs_buf);
- xfree(rhs_buf);
-}
-
-/// Parse a string of |:map-arguments| into a @ref MapArguments struct.
-///
-/// Termcodes, backslashes, CTRL-V's, etc. inside the extracted {lhs} and
-/// {rhs} are replaced by @ref set_maparg_lhs_rhs.
-///
-/// rhs and orig_rhs in the returned mapargs will be set to null or a pointer
-/// to allocated memory and should be freed even on error.