From dde4f09f51ffaf8df5cc2a81eed935e31e1f94ba Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 31 Mar 2022 15:47:53 +0800 Subject: vim-patch:8.1.2145: cannot map when modifyOtherKeys is enabled Problem: Cannot map when modifyOtherKeys is enabled. Solution: Add the mapping twice, both with modifier and as 0x08. Use only the first one when modifyOtherKeys has been detected. https://github.com/vim/vim/commit/459fd785e4a8d044147a3f83a5fca8748528aa84 Add REPTERM_NO_SPECIAL instead of REPTERM_SPECIAL because the meaning of "special" is different between Vim and Nvim. Omit seenModifyOtherKeys as Nvim supports attaching multiple UIs. Omit tests as they send terminal codes. Keep the behavior of API functions. --- src/nvim/api/private/helpers.c | 5 +- src/nvim/api/vim.c | 14 +- src/nvim/buffer_defs.h | 2 + src/nvim/eval.c | 2 +- src/nvim/eval/funcs.c | 2 +- src/nvim/ex_docmd.c | 3 +- src/nvim/getchar.c | 549 ++++++++++++++++++++----------------- src/nvim/getchar.h | 6 +- src/nvim/keymap.c | 111 ++++---- src/nvim/menu.c | 4 +- src/nvim/option.c | 4 +- src/nvim/os/input.c | 3 +- src/nvim/vim.h | 6 + src/nvim/viml/parser/expressions.c | 5 +- 14 files changed, 390 insertions(+), 326 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 5ba4700f62..8383f29400 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -632,7 +632,7 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod } else { parsed_args.desc = NULL; } - if (parsed_args.lhs_len > MAXMAPLEN) { + 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; } @@ -1128,6 +1128,9 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua) 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); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 0f9a4a0e0d..2174cd1620 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -403,9 +403,19 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, Bool return (String) { .data = NULL, .size = 0 }; } + int flags = 0; + if (from_part) { + flags |= REPTERM_FROM_PART; + } + if (do_lt) { + flags |= REPTERM_DO_LT; + } + if (!special) { + flags |= REPTERM_NO_SPECIAL; + } + char *ptr = NULL; - replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr, - from_part, do_lt, special, CPO_TO_CPO_FLAGS); + replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr, flags, NULL, CPO_TO_CPO_FLAGS); return cstr_as_string(ptr); } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 8d2f7c4545..c71d022018 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -356,6 +356,8 @@ struct mapblock { LuaRef m_luaref; // lua function reference as rhs int m_keylen; // strlen(m_keys) int m_mode; // valid mode + int m_simplified; // m_keys was simplified, do no use this map + // if keys are typed int m_noremap; // if non-zero no re-mapping for m_str char m_silent; // used, don't echo commands char m_nowait; // used diff --git a/src/nvim/eval.c b/src/nvim/eval.c index e192a6de6b..af6e7e470d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4965,7 +4965,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) // Special key, e.g.: "\" case '<': - extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true); + extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true, true, NULL); if (extra != 0) { name += extra; if (name >= rettv->vval.v_string + len) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f97ceedeb7..71a090afed 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5684,7 +5684,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) mode = get_map_mode((char_u **)&which, 0); - keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true, + keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, REPTERM_FROM_PART | REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua); xfree(keys_buf); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 4562f6c751..f3b11cc103 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5180,8 +5180,7 @@ int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, lo char_u *rep_buf = NULL; garray_T *gap; - replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, true, - CPO_TO_CPO_FLAGS); + replace_termcodes(rep, STRLEN(rep), &rep_buf, 0, NULL, CPO_TO_CPO_FLAGS); if (rep_buf == NULL) { // Can't replace termcodes - try using the string as is rep_buf = vim_strsave(rep); diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index f2df7b49fd..89a9a1ea95 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2711,11 +2711,12 @@ int fix_input_buffer(char_u *buf, int len) /// @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_u *orig_lhs, const size_t orig_lhs_len, const char_u *orig_rhs, - const size_t orig_rhs_len, LuaRef rhs_lua, int cpo_flags, - MapArguments *mapargs) +void set_maparg_lhs_rhs(const char_u *const orig_lhs, const size_t orig_lhs_len, + const char_u *const orig_rhs, const size_t orig_rhs_len, + const LuaRef rhs_lua, const int cpo_flags, MapArguments *const mapargs) { char_u *lhs_buf = NULL; + char_u *alt_lhs_buf = NULL; char_u *rhs_buf = NULL; // If mapping has been given as ^V say, then replace the term codes @@ -2725,10 +2726,22 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const // 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. - char_u *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &lhs_buf, - true, true, true, cpo_flags); + // If something like is simplified to 0x08 then mark it as simplified. + bool did_simplify = false; + const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; + char_u *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) { @@ -2741,8 +2754,8 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const mapargs->rhs_len = 0; mapargs->rhs_is_noop = true; } else { - replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, - false, true, true, cpo_flags); + replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL, + cpo_flags); mapargs->rhs_len = STRLEN(replaced); mapargs->rhs_is_noop = false; mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u)); @@ -2760,6 +2773,7 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const } xfree(lhs_buf); + xfree(alt_lhs_buf); xfree(rhs_buf); } @@ -2894,15 +2908,9 @@ int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *mapargs) int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T *buf) { mapblock_T *mp, **mpp; - char_u *p; + const char_u *p; int n; - int len = 0; // init for GCC - int did_it = false; - int did_local = false; - int round; int retval = 0; - int hash; - int new_hash; mapblock_T **abbr_table; mapblock_T **map_table; int noremap; @@ -2929,8 +2937,9 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T validate_maphash(); - bool has_lhs = (args->lhs[0] != NUL); - bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop; + 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; + const bool do_print = !has_lhs || (maptype != 1 && !has_rhs); // check for :unmap without argument if (maptype == 1 && !has_lhs) { @@ -2938,298 +2947,323 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T goto theend; } - char_u *lhs = (char_u *)&args->lhs; - char_u *rhs = args->rhs; - char_u *orig_rhs = args->orig_rhs; + const char_u *lhs = (char_u *)&args->lhs; + const char_u *const rhs = args->rhs; + const char_u *const orig_rhs = args->orig_rhs; + const bool did_simplify = args->alt_lhs_len != 0; - // check arguments and translate function keys - if (has_lhs) { - len = (int)args->lhs_len; - if (len > MAXMAPLEN) { - retval = 1; - goto theend; - } + // The following is done twice if we have two versions of keys + for (int keyround = 1; keyround <= 2; keyround++) { + bool did_it = false; + bool did_local = false; + int len = (int)args->lhs_len; - if (is_abbrev && maptype != 1) { - // - // If an abbreviation ends in a keyword character, the - // rest must be all keyword-char or all non-keyword-char. - // Otherwise we won't be able to find the start of it in a - // vi-compatible way. - // - int same = -1; - - const int first = vim_iswordp(lhs); - int last = first; - p = lhs + utfc_ptr2len(lhs); - 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(p); + if (keyround == 2) { + if (!did_simplify) { + break; } - if (last && n > 2 && same >= 0 && same < n - 1) { + lhs = (char_u *)&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; + len = (int)args->alt_lhs_len; + } + + // check arguments and translate function keys + if (has_lhs) { + if (len > MAXMAPLEN) { retval = 1; goto theend; } - // An abbreviation cannot contain white space. - for (n = 0; n < len; n++) { - if (ascii_iswhite(lhs[n])) { + + if (is_abbrev && maptype != 1) { + // + // If an abbreviation ends in a keyword character, the + // rest must be all keyword-char or all non-keyword-char. + // Otherwise we won't be able to find the start of it in a + // vi-compatible way. + // + int same = -1; + + const int first = vim_iswordp(lhs); + int last = first; + p = lhs + utfc_ptr2len(lhs); + 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(p); + } + if (last && n > 2 && same >= 0 && same < n - 1) { retval = 1; goto theend; } - } // for + // An abbreviation cannot contain white space. + for (n = 0; n < len; n++) { + if (ascii_iswhite(lhs[n])) { + retval = 1; + goto theend; + } + } // for + } } - } - if (has_lhs && has_rhs && is_abbrev) { // if we will add an abbreviation, - no_abbr = false; // reset flag that indicates there are no abbreviations - } + if (has_lhs && has_rhs && is_abbrev) { // if we will add an abbreviation, + no_abbr = false; // reset flag that indicates there are no abbreviations + } - if (!has_lhs || (maptype != 1 && !has_rhs)) { - msg_start(); - } + if (do_print) { + msg_start(); + } - // Check if a new local mapping wasn't already defined globally. - if (map_table == buf->b_maphash && has_lhs && has_rhs && maptype != 1) { - // need to loop over all global hash lists - for (hash = 0; hash < 256 && !got_int; hash++) { - if (is_abbrev) { - if (hash != 0) { // there is only one abbreviation list - break; + // Check if a new local mapping wasn't already defined globally. + if (map_table == buf->b_maphash && has_lhs && has_rhs && maptype != 1) { + // need to loop over all global hash lists + for (int hash = 0; hash < 256 && !got_int; hash++) { + if (is_abbrev) { + if (hash != 0) { // there is only one abbreviation list + break; + } + mp = first_abbr; + } else { + mp = maphash[hash]; } - mp = first_abbr; - } else { - mp = maphash[hash]; - } - for (; mp != NULL && !got_int; mp = mp->m_next) { - // check entries with the same mode - if ((mp->m_mode & mode) != 0 - && mp->m_keylen == len - && args->unique - && STRNCMP(mp->m_keys, lhs, (size_t)len) == 0) { - if (is_abbrev) { - semsg(_("E224: global abbreviation already exists for %s"), - mp->m_keys); - } else { - semsg(_("E225: global mapping already exists for %s"), mp->m_keys); + for (; mp != NULL && !got_int; mp = mp->m_next) { + // check entries with the same mode + if ((mp->m_mode & mode) != 0 + && mp->m_keylen == len + && args->unique + && STRNCMP(mp->m_keys, lhs, (size_t)len) == 0) { + if (is_abbrev) { + semsg(_("E224: global abbreviation already exists for %s"), + mp->m_keys); + } else { + semsg(_("E225: global mapping already exists for %s"), mp->m_keys); + } + retval = 5; + goto theend; } - retval = 5; - goto theend; } } } - } - // When listing global mappings, also list buffer-local ones here. - if (map_table != buf->b_maphash && !has_rhs && maptype != 1) { - // need to loop over all global hash lists - for (hash = 0; hash < 256 && !got_int; hash++) { - if (is_abbrev) { - if (hash != 0) { // there is only one abbreviation list - break; + // When listing global mappings, also list buffer-local ones here. + if (map_table != buf->b_maphash && !has_rhs && maptype != 1) { + // need to loop over all global hash lists + for (int hash = 0; hash < 256 && !got_int; hash++) { + if (is_abbrev) { + if (hash != 0) { // there is only one abbreviation list + break; + } + mp = buf->b_first_abbr; + } else { + mp = buf->b_maphash[hash]; } - mp = buf->b_first_abbr; - } else { - mp = buf->b_maphash[hash]; - } - for (; mp != NULL && !got_int; mp = mp->m_next) { - // check entries with the same mode - if ((mp->m_mode & mode) != 0) { - if (!has_lhs) { // show all entries - showmap(mp, true); - did_local = true; - } else { - n = mp->m_keylen; - if (STRNCMP(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) { + for (; mp != NULL && !got_int; mp = mp->m_next) { + // check entries with the same mode + if ((mp->m_mode & mode) != 0) { + if (!has_lhs) { // show all entries showmap(mp, true); did_local = true; + } else { + n = mp->m_keylen; + if (STRNCMP(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) { + showmap(mp, true); + did_local = true; + } } } } } } - } - // Find an entry in the maphash[] list that matches. - // For :unmap we may loop two times: once to try to unmap an entry with a - // matching 'from' part, a second time, if the first fails, to unmap an - // entry with a matching 'to' part. This was done to allow ":ab foo bar" - // to be unmapped by typing ":unab foo", where "foo" will be replaced by - // "bar" because of the abbreviation. - for (round = 0; (round == 0 || maptype == 1) && round <= 1 - && !did_it && !got_int; round++) { - // need to loop over all hash lists - for (hash = 0; hash < 256 && !got_int; hash++) { - if (is_abbrev) { - if (hash > 0) { // there is only one abbreviation list - break; - } - mpp = abbr_table; - } else { - mpp = &(map_table[hash]); - } - for (mp = *mpp; mp != NULL && !got_int; mp = *mpp) { - if (!(mp->m_mode & mode)) { // skip entries with wrong mode - mpp = &(mp->m_next); - continue; + // Find an entry in the maphash[] list that matches. + // For :unmap we may loop two times: once to try to unmap an entry with a + // matching 'from' part, a second time, if the first fails, to unmap an + // entry with a matching 'to' part. This was done to allow ":ab foo bar" + // to be unmapped by typing ":unab foo", where "foo" will be replaced by + // "bar" because of the abbreviation. + for (int round = 0; (round == 0 || maptype == 1) && round <= 1 + && !did_it && !got_int; round++) { + // need to loop over all hash lists + for (int hash = 0; hash < 256 && !got_int; hash++) { + if (is_abbrev) { + if (hash > 0) { // there is only one abbreviation list + break; + } + mpp = abbr_table; + } else { + mpp = &(map_table[hash]); } - if (!has_lhs) { // show all entries - showmap(mp, map_table != maphash); - did_it = true; - } else { // do we have a match? - if (round) { // second round: Try unmap "rhs" string - n = (int)STRLEN(mp->m_str); - p = mp->m_str; - } else { - n = mp->m_keylen; - p = mp->m_keys; + for (mp = *mpp; mp != NULL && !got_int; mp = *mpp) { + if (!(mp->m_mode & mode)) { // skip entries with wrong mode + mpp = &(mp->m_next); + continue; } - if (STRNCMP(p, lhs, (size_t)(n < len ? n : len)) == 0) { - if (maptype == 1) { // delete entry - // Only accept a full match. For abbreviations 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(lhs + n) != NUL)) { + if (!has_lhs) { // show all entries + showmap(mp, map_table != maphash); + did_it = true; + } else { // do we have a match? + if (round) { // second round: Try unmap "rhs" string + 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 (maptype == 1) { + // Delete entry. + // Only accept a full match. For abbreviations + // 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(lhs + n) != NUL)) { + mpp = &(mp->m_next); + continue; + } + // We reset the indicated mode bits. If nothing + // is left the entry is deleted below. + mp->m_mode &= ~mode; + did_it = true; // remember we did something + } else if (!has_rhs) { // show matching entry + showmap(mp, map_table != maphash); + did_it = true; + } else if (n != len) { // new entry is ambiguous mpp = &(mp->m_next); continue; - } - // We reset the indicated mode bits. If nothing is - // left the entry is deleted below. - mp->m_mode &= ~mode; - did_it = true; // remember we did something - } else if (!has_rhs) { // show matching entry - showmap(mp, map_table != maphash); - did_it = true; - } else if (n != len) { // new entry is ambiguous - mpp = &(mp->m_next); - continue; - } else if (args->unique) { - if (is_abbrev) { - semsg(_("E226: abbreviation already exists for %s"), p); + } else if (args->unique) { + if (is_abbrev) { + semsg(_("E226: abbreviation already exists for %s"), p); + } else { + semsg(_("E227: mapping already exists for %s"), p); + } + retval = 5; + goto theend; } else { - semsg(_("E227: mapping already exists for %s"), p); - } - retval = 5; - goto theend; - } else { // new rhs for existing entry - mp->m_mode &= ~mode; // remove mode bits - if (mp->m_mode == 0 && !did_it) { // reuse entry - XFREE_CLEAR(mp->m_str); - XFREE_CLEAR(mp->m_orig_str); - XFREE_CLEAR(mp->m_desc); - NLUA_CLEAR_REF(mp->m_luaref); - - mp->m_str = vim_strsave(rhs); - mp->m_orig_str = vim_strsave(orig_rhs); - mp->m_luaref = args->rhs_lua; - mp->m_noremap = noremap; - mp->m_nowait = args->nowait; - mp->m_silent = args->silent; - mp->m_mode = mode; - mp->m_expr = args->expr; - mp->m_script_ctx = current_sctx; - mp->m_script_ctx.sc_lnum += sourcing_lnum; - nlua_set_sctx(&mp->m_script_ctx); - if (args->desc != NULL) { - mp->m_desc = xstrdup(args->desc); + // new rhs for existing entry + mp->m_mode &= ~mode; // remove mode bits + if (mp->m_mode == 0 && !did_it) { // reuse entry + XFREE_CLEAR(mp->m_str); + XFREE_CLEAR(mp->m_orig_str); + XFREE_CLEAR(mp->m_desc); + NLUA_CLEAR_REF(mp->m_luaref); + + mp->m_str = vim_strsave(rhs); + mp->m_orig_str = vim_strsave(orig_rhs); + mp->m_luaref = args->rhs_lua; + mp->m_noremap = noremap; + mp->m_nowait = args->nowait; + mp->m_silent = args->silent; + mp->m_mode = mode; + mp->m_simplified = did_simplify && keyround == 1; + mp->m_expr = args->expr; + mp->m_script_ctx = current_sctx; + mp->m_script_ctx.sc_lnum += sourcing_lnum; + nlua_set_sctx(&mp->m_script_ctx); + if (args->desc != NULL) { + mp->m_desc = xstrdup(args->desc); + } + did_it = true; } - did_it = true; } - } - if (mp->m_mode == 0) { // entry can be deleted - mapblock_free(mpp); - continue; // continue with *mpp - } + if (mp->m_mode == 0) { // entry can be deleted + mapblock_free(mpp); + continue; // continue with *mpp + } - // May need to put this entry into another hash list. - new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]); - if (!is_abbrev && new_hash != hash) { - *mpp = mp->m_next; - mp->m_next = map_table[new_hash]; - map_table[new_hash] = mp; + // May need to put this entry into another hash list. + int new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]); + if (!is_abbrev && new_hash != hash) { + *mpp = mp->m_next; + mp->m_next = map_table[new_hash]; + map_table[new_hash] = mp; - continue; // continue with *mpp + continue; // continue with *mpp + } } } + mpp = &(mp->m_next); } - mpp = &(mp->m_next); } } - } - if (maptype == 1) { // delete entry - if (!did_it) { - retval = 2; // no match - } else if (*lhs == Ctrl_C) { - // If CTRL-C has been unmapped, reuse it for Interrupting. - if (map_table == buf->b_maphash) { - buf->b_mapped_ctrl_c &= ~mode; - } else { - mapped_ctrl_c &= ~mode; + if (maptype == 1) { + // delete entry + if (!did_it) { + retval = 2; // no match + } else if (*lhs == Ctrl_C) { + // If CTRL-C has been unmapped, reuse it for Interrupting. + if (map_table == buf->b_maphash) { + buf->b_mapped_ctrl_c &= ~mode; + } else { + mapped_ctrl_c &= ~mode; + } } + continue; } - goto theend; - } - if (!has_lhs || !has_rhs) { // print entries - if (!did_it && !did_local) { - if (is_abbrev) { - msg(_("No abbreviation found")); - } else { - msg(_("No mapping found")); + if (!has_lhs || !has_rhs) { + // print entries + if (!did_it && !did_local) { + if (is_abbrev) { + msg(_("No abbreviation found")); + } else { + msg(_("No mapping found")); + } } + goto theend; // listing finished } - goto theend; // listing finished - } - if (did_it) { // have added the new entry already - goto theend; - } + if (did_it) { + continue; // have added the new entry already + } - // Get here when adding a new entry to the maphash[] list or abbrlist. - mp = xmalloc(sizeof(mapblock_T)); + // Get here when adding a new entry to the maphash[] list or abbrlist. + mp = xmalloc(sizeof(mapblock_T)); - // If CTRL-C has been mapped, don't always use it for Interrupting. - if (*lhs == Ctrl_C) { - if (map_table == buf->b_maphash) { - buf->b_mapped_ctrl_c |= mode; - } else { - mapped_ctrl_c |= mode; + // If CTRL-C has been mapped, don't always use it for Interrupting. + if (*lhs == Ctrl_C) { + if (map_table == buf->b_maphash) { + buf->b_mapped_ctrl_c |= mode; + } else { + mapped_ctrl_c |= mode; + } } - } - mp->m_keys = vim_strsave(lhs); - mp->m_str = vim_strsave(rhs); - mp->m_orig_str = vim_strsave(orig_rhs); - mp->m_luaref = args->rhs_lua; - mp->m_keylen = (int)STRLEN(mp->m_keys); - mp->m_noremap = noremap; - mp->m_nowait = args->nowait; - mp->m_silent = args->silent; - mp->m_mode = mode; - mp->m_expr = args->expr; - mp->m_script_ctx = current_sctx; - mp->m_script_ctx.sc_lnum += sourcing_lnum; - nlua_set_sctx(&mp->m_script_ctx); - mp->m_desc = NULL; - if (args->desc != NULL) { - mp->m_desc = xstrdup(args->desc); - } - - // add the new entry in front of the abbrlist or maphash[] list - if (is_abbrev) { - mp->m_next = *abbr_table; - *abbr_table = mp; - } else { - n = MAP_HASH(mp->m_mode, mp->m_keys[0]); - mp->m_next = map_table[n]; - map_table[n] = mp; + mp->m_keys = vim_strsave(lhs); + mp->m_str = vim_strsave(rhs); + mp->m_orig_str = vim_strsave(orig_rhs); + mp->m_luaref = args->rhs_lua; + mp->m_keylen = (int)STRLEN(mp->m_keys); + mp->m_noremap = noremap; + mp->m_nowait = args->nowait; + mp->m_silent = args->silent; + mp->m_mode = mode; + mp->m_simplified = did_simplify && keyround == 1; + mp->m_expr = args->expr; + mp->m_script_ctx = current_sctx; + mp->m_script_ctx.sc_lnum += sourcing_lnum; + nlua_set_sctx(&mp->m_script_ctx); + mp->m_desc = NULL; + if (args->desc != NULL) { + mp->m_desc = xstrdup(args->desc); + } + + // add the new entry in front of the abbrlist or maphash[] list + if (is_abbrev) { + mp->m_next = *abbr_table; + *abbr_table = mp; + } else { + n = MAP_HASH(mp->m_mode, mp->m_keys[0]); + mp->m_next = map_table[n]; + map_table[n] = mp; + } } theend: @@ -3600,9 +3634,8 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo int retval; char_u *buf; - char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf, - false, true, true, - CPO_TO_CPO_FLAGS); + const char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf, REPTERM_DO_LT, + NULL, CPO_TO_CPO_FLAGS); #define MAPMODE(mode, modechars, chr, modeflags) \ do { \ diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h index 9b8605f1df..237f0632bd 100644 --- a/src/nvim/getchar.h +++ b/src/nvim/getchar.h @@ -48,6 +48,10 @@ struct map_arguments { char_u 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_u alt_lhs[MAXMAPLEN + 1]; + size_t alt_lhs_len; + char_u *rhs; /// The {rhs} of the mapping. size_t rhs_len; LuaRef rhs_lua; /// lua function as rhs @@ -59,7 +63,7 @@ struct map_arguments { }; typedef struct map_arguments MapArguments; #define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \ - { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL } + { 0 }, 0, { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL } #define KEYLEN_PART_KEY (-1) // keylen value for incomplete key-code #define KEYLEN_PART_MAP (-2) // keylen value for incomplete mapping diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 3fdc140ebd..07975545be 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -570,16 +570,18 @@ char_u *get_special_key_name(int c, int modifiers) // be at least 19 bytes per "" form. /// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL. /// @param[in] in_string Inside a double quoted string +/// @param[in] simplify simplify , etc. +/// @param[out] did_simplify found , etc. /// /// @return Number of characters added to dst, zero for no match. -unsigned int trans_special(const char_u **srcp, const size_t src_len, char_u *const dst, - const bool keycode, const bool in_string) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +unsigned int trans_special(const char_u **const srcp, const size_t src_len, char_u *const dst, + const bool keycode, const bool in_string, const bool simplify, + bool *const did_simplify) + FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT { int modifiers = 0; - int key; - - key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string); + int key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string, simplify, + did_simplify); if (key == 0) { return 0; } @@ -626,11 +628,14 @@ unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst) /// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL. /// @param[in] keep_x_key Don鈥檛 translate xHome to Home key. /// @param[in] in_string In string, double quote is escaped +/// @param[in] simplify simplify , etc. +/// @param[out] did_simplify found , etc. /// /// @return Key and modifiers or 0 if there is no match. -int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, const bool keycode, - const bool keep_x_key, const bool in_string) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL +int find_special_key(const char_u **const srcp, const size_t src_len, int *const modp, + const bool keycode, const bool keep_x_key, const bool in_string, + const bool simplify, bool *const did_simplify) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { const char_u *last_dash; const char_u *end_of_name; @@ -748,7 +753,7 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, // Normal Key with modifier: // Try to make a single byte code (except for Alt/Meta modifiers). if (!IS_SPECIAL(key)) { - key = extract_modifiers(key, &modifiers); + key = extract_modifiers(key, &modifiers, simplify, did_simplify); } *modp = modifiers; @@ -762,7 +767,10 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, /// Try to include modifiers (except alt/meta) in the key. /// Changes "Shift-a" to 'A', "Ctrl-@" to , etc. -static int extract_modifiers(int key, int *modp) +/// @param[in] simplify if false, don't do Ctrl +/// @param[out] did_simplify set when it is not NULL and "simplify" is true and +/// Ctrl is removed from modifiers +static int extract_modifiers(int key, int *modp, const bool simplify, bool *const did_simplify) { int modifiers = *modp; @@ -773,15 +781,19 @@ static int extract_modifiers(int key, int *modp) modifiers &= ~MOD_MASK_SHIFT; } } - if ((modifiers & MOD_MASK_CTRL) && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) { + // and mean the same thing, always use "H" + if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key)) { key = TOUPPER_ASC(key); - int new_key = CTRL_CHR(key); - if (new_key != TAB && new_key != CAR && new_key != ESC) { - key = new_key; - modifiers &= ~MOD_MASK_CTRL; - if (key == 0) { // is - key = K_ZERO; - } + } + if (simplify && (modifiers & MOD_MASK_CTRL) + && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) { + key = CTRL_CHR(key); + modifiers &= ~MOD_MASK_CTRL; + if (key == 0) { // is + key = K_ZERO; + } + if (did_simplify != NULL) { + *did_simplify = true; } } @@ -853,34 +865,31 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag) return 0; // Shouldn't get here } -/// Replace any terminal code strings with the equivalent internal -/// representation +/// Replace any terminal code strings with the equivalent internal representation. +/// +/// Used for the "from" and "to" part of a mapping, and the "to" part of a menu command. +/// Any strings like "" are also replaced, unless `special` is false. +/// K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER. /// -/// Used for the "from" and "to" part of a mapping, and the "to" part of -/// a menu command. Any strings like "" are also replaced, unless -/// `special` is false. K_SPECIAL by itself is replaced by K_SPECIAL -/// KS_SPECIAL KE_FILLER. +/// When "flags" has REPTERM_FROM_PART, trailing is included, otherwise it is removed (to make +/// ":map xx ^V" map xx to nothing). When cpo_flags contains FLAG_CPO_BSLASH, a backslash can be +/// used in place of . All other characters are removed. /// /// @param[in] from What characters to replace. /// @param[in] from_len Length of the "from" argument. -/// @param[out] bufp Location where results were saved in case of success -/// (allocated). Will be set to NULL in case of failure. -/// @param[in] do_lt If true, also translate . -/// @param[in] from_part If true, trailing is included, otherwise it is -/// removed (to make ":map xx ^V" map xx to nothing). -/// When cpo_flags contains #FLAG_CPO_BSLASH, a backslash -/// can be used in place of . All other -/// characters are removed. -/// @param[in] special Replace keycodes, e.g. becomes a "\n" char. -/// @param[in] cpo_flags Relevant flags derived from p_cpo, see -/// #CPO_TO_CPO_FLAGS. +/// @param[out] bufp Location where results were saved in case of success (allocated). +/// Will be set to NULL in case of failure. +/// @param[in] flags REPTERM_FROM_PART see above +/// REPTERM_DO_LT also translate +/// REPTERM_NO_SPECIAL do not accept notation +/// REPTERM_NO_SIMPLIFY do not simplify into 0x08, etc. +/// @param[out] did_simplify set when some code was simplied, unless it is NULL. +/// @param[in] cpo_flags Relevant flags derived from p_cpo, see CPO_TO_CPO_FLAGS. /// -/// @return Pointer to an allocated memory in case of success, "from" in case of -/// failure. In case of success returned pointer is also saved to -/// "bufp". -char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bufp, - const bool from_part, const bool do_lt, const bool special, int cpo_flags) - FUNC_ATTR_NONNULL_ALL +/// @return Pointer to an allocated memory, which is also saved to "bufp". +char_u *replace_termcodes(const char_u *const from, const size_t from_len, char_u **const bufp, + const int flags, bool *const did_simplify, const int cpo_flags) + FUNC_ATTR_NONNULL_ARG(1, 3) { ssize_t i; size_t slen; @@ -888,10 +897,10 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu size_t dlen = 0; const char_u *src; const char_u *const end = from + from_len - 1; - int do_backslash; // backslash is a special character char_u *result; // buffer for resulting string - do_backslash = !(cpo_flags&FLAG_CPO_BSLASH); + const bool do_backslash = !(cpo_flags & FLAG_CPO_BSLASH); // backslash is a special character + const bool do_special = !(flags & REPTERM_NO_SPECIAL); // Allocate space for the translation. Worst case a single character is // replaced by 6 bytes (shifted special key), plus a NUL at the end. @@ -901,7 +910,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu src = from; // Check for #n at start only: function key n - if (from_part && from_len > 1 && src[0] == '#' + if ((flags & REPTERM_FROM_PART) && from_len > 1 && src[0] == '#' && ascii_isdigit(src[1])) { // function key result[dlen++] = K_SPECIAL; result[dlen++] = 'k'; @@ -916,8 +925,8 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu // Copy each byte from *from to result[dlen] while (src <= end) { // Check for special <> keycodes, like "" - if (special && (do_lt || ((end - src) >= 3 - && STRNCMP(src, "", 4) != 0))) { + if (do_special && ((flags & REPTERM_DO_LT) || ((end - src) >= 3 + && STRNCMP(src, "", 4) != 0))) { // Replace by K_SNR _. // (room: 5 * 6 = 30 bytes; needed: 3 + + 1 <= 14) if (end - src >= 4 && STRNICMP(src, "", 5) == 0) { @@ -936,15 +945,15 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu } } - slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, true, - false); + slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, true, false, + (flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify); if (slen) { dlen += slen; continue; } } - if (special) { + if (do_special) { char_u *p, *s, len; // Replace by the value of "mapleader". @@ -984,7 +993,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu if (key == Ctrl_V || (do_backslash && key == '\\')) { src++; // skip CTRL-V or backslash if (src > end) { - if (from_part) { + if (flags & REPTERM_FROM_PART) { result[dlen++] = key; } break; diff --git a/src/nvim/menu.c b/src/nvim/menu.c index f648a06284..d2293a6923 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -236,8 +236,8 @@ void ex_menu(exarg_T *eap) } else if (modes & MENU_TIP_MODE) { map_buf = NULL; // Menu tips are plain text. } else { - map_to = (char *)replace_termcodes((char_u *)map_to, STRLEN(map_to), - (char_u **)&map_buf, false, true, true, CPO_TO_CPO_FLAGS); + map_to = (char *)replace_termcodes((char_u *)map_to, STRLEN(map_to), (char_u **)&map_buf, + REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); } menuarg.modes = modes; menuarg.noremap[0] = noremap; diff --git a/src/nvim/option.c b/src/nvim/option.c index 49c76d2452..79231385ad 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3015,7 +3015,7 @@ ambw_end: } else if (varp == &p_pt) { // 'pastetoggle': translate key codes like in a mapping if (*p_pt) { - (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, true, + (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); if (p != NULL) { if (new_value_alloced) { @@ -5222,7 +5222,7 @@ int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) } else if (has_lt) { arg--; // put arg at the '<' modifiers = 0; - key = find_special_key(&arg, len + 1, &modifiers, true, true, false); + key = find_special_key(&arg, len + 1, &modifiers, true, true, false, true, NULL); if (modifiers) { // can't handle modifiers here key = 0; } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 745b888b5e..4c617c9031 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -239,8 +239,7 @@ size_t input_enqueue(String keys) // K_SPECIAL(0x80). uint8_t buf[19] = { 0 }; unsigned int new_size - = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, - false); + = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, false, true, NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 3c8a865fb1..2672d0b2bc 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -318,4 +318,10 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() #define REPLACE_CR_NCHAR (-1) #define REPLACE_NL_NCHAR (-2) +// Flags for replace_termcodes() +#define REPTERM_FROM_PART 1 +#define REPTERM_DO_LT 2 +#define REPTERM_NO_SPECIAL 4 +#define REPTERM_NO_SIMPLIFY 8 + #endif // NVIM_VIM_H diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index b8b0a38f44..ec747d56d4 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1817,9 +1817,8 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no } // Special key, e.g.: "\" case '<': { - const size_t special_len = ( - trans_special((const char_u **)&p, (size_t)(e - p), - (char_u *)v_p, true, true)); + const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p), + (char_u *)v_p, true, true, true, NULL); if (special_len != 0) { v_p += special_len; } else { -- cgit From 68ddbdd03b0d5884261ab3a7b624195a4a77bd8d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Apr 2022 16:50:50 +0800 Subject: test(old): revert changes from ed88ca75034a48916d165e88459c791c450df550 Copy test_regex_char_classes.vim from upstream to avoid future encoding problems. --- src/nvim/testdir/test_eval_stuff.vim | 2 +- src/nvim/testdir/test_regex_char_classes.vim | 106 ++++++++++++++------------- src/nvim/testdir/test_substitute.vim | 56 +++++++------- 3 files changed, 83 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim index 12febfeb93..95eccde35c 100644 --- a/src/nvim/testdir/test_eval_stuff.vim +++ b/src/nvim/testdir/test_eval_stuff.vim @@ -185,7 +185,7 @@ func Test_let_register() call Assert_reg('"', 'v', "abc", "['abc']", "abc", "['abc']") let @" = "abc\n" call Assert_reg('"', 'V', "abc\n", "['abc']", "abc\n", "['abc']") - let @" = "abc\r" + let @" = "abc\" call Assert_reg('"', 'V', "abc\r\n", "['abc\r']", "abc\r\n", "['abc\r']") let @= = '"abc"' call Assert_reg('=', 'v', "abc", "['abc']", '"abc"', "['\"abc\"']") diff --git a/src/nvim/testdir/test_regex_char_classes.vim b/src/nvim/testdir/test_regex_char_classes.vim index b0d76a15e2..db16f057c8 100644 --- a/src/nvim/testdir/test_regex_char_classes.vim +++ b/src/nvim/testdir/test_regex_char_classes.vim @@ -66,22 +66,22 @@ func Test_regex_char_classes() let save_enc = &encoding set encoding=utf-8 - let input = "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱" + let input = "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱" " Format is [cmd_to_run, expected_output] let tests = [ \ [':s/\%#=0\d//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\d//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\d//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[0-9]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[0-9]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[0-9]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\D//g', \ "0123456789"], \ [':s/\%#=1\D//g', @@ -95,17 +95,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^0-9]//g', \ "0123456789"], \ [':s/\%#=0\o//g', - \ "\t\\r !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\o//g', - \ "\t\\r !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\o//g', - \ "\t\\r !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[0-7]//g', - \ "\t\\r !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[0-7]//g', - \ "\t\\r !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[0-7]//g', - \ "\t\\r !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\O//g', \ "01234567"], \ [':s/\%#=1\O//g', @@ -119,17 +119,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^0-7]//g', \ "01234567"], \ [':s/\%#=0\x//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\x//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\x//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[0-9A-Fa-f]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[0-9A-Fa-f]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[0-9A-Fa-f]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\X//g', \ "0123456789ABCDEFabcdef"], \ [':s/\%#=1\X//g', @@ -143,17 +143,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^0-9A-Fa-f]//g', \ "0123456789ABCDEFabcdef"], \ [':s/\%#=0\w//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\w//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\w//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[0-9A-Za-z_]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[0-9A-Za-z_]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[0-9A-Za-z_]//g', - \ "\t\\r !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\W//g', \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"], \ [':s/\%#=1\W//g', @@ -167,17 +167,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^0-9A-Za-z_]//g', \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"], \ [':s/\%#=0\h//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\h//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\h//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[A-Za-z_]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[A-Za-z_]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[A-Za-z_]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\H//g', \ "ABCDEFGHIXYZ_abcdefghiwxyz"], \ [':s/\%#=1\H//g', @@ -191,17 +191,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^A-Za-z_]//g', \ "ABCDEFGHIXYZ_abcdefghiwxyz"], \ [':s/\%#=0\a//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\a//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\a//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[A-Za-z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[A-Za-z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[A-Za-z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\A//g', \ "ABCDEFGHIXYZabcdefghiwxyz"], \ [':s/\%#=1\A//g', @@ -215,17 +215,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^A-Za-z]//g', \ "ABCDEFGHIXYZabcdefghiwxyz"], \ [':s/\%#=0\l//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\l//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\l//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[a-z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[a-z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[a-z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\L//g', \ "abcdefghiwxyz"], \ [':s/\%#=1\L//g', @@ -239,17 +239,17 @@ func Test_regex_char_classes() \ [':s/\%#=2[^a-z]//g', \ "abcdefghiwxyz"], \ [':s/\%#=0\u//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1\u//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2\u//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[A-Z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[A-Z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[A-Z]//g', - \ "\t\\r !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0\U//g', \ "ABCDEFGHIXYZ"], \ [':s/\%#=1\U//g', @@ -269,11 +269,11 @@ func Test_regex_char_classes() \ [':s/\%#=2\%' . line('.') . 'l^\t...//g', \ "!\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[0-z]//g', - \ "\t\\r !\"#$%&'()#+'-./{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=1[0-z]//g', - \ "\t\\r !\"#$%&'()#+'-./{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=2[0-z]//g', - \ "\t\\r !\"#$%&'()#+'-./{|}~\\u0080\u0082\u0090\u009bΡ记娱"], + \ "\t\\ !\"#$%&'()#+'-./{|}~\\u0080\u0082\u0090\u009bΡ记娱"], \ [':s/\%#=0[^0-z]//g', \ "0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz"], \ [':s/\%#=1[^0-z]//g', @@ -293,3 +293,5 @@ func Test_regex_char_classes() enew! close endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index 86fd0147a5..7a15e9a6f1 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -177,9 +177,9 @@ func Test_sub_cmd_1() \ ['I', 's/I/\lII/', ['iI']], \ ['J', 's/J/\LJ\EJ/', ['jJ']], \ ['K', 's/K/\Uk\ek/', ['Kk']], - \ ['lLl', "s/L/\\r/", ["l\", 'l']], + \ ['lLl', "s/L/\\/", ["l\", 'l']], \ ['mMm', 's/M/\r/', ['m', 'm']], - \ ['nNn', "s/N/\\\\r/", ["n\", 'n']], + \ ['nNn', "s/N/\\\\/", ["n\", 'n']], \ ['oOo', 's/O/\n/', ["o\no"]], \ ['pPp', 's/P/\b/', ["p\p"]], \ ['qQq', 's/Q/\t/', ["q\tq"]], @@ -208,9 +208,9 @@ func Test_sub_cmd_2() \ ['I', 's/I/\lII/', ['iI']], \ ['J', 's/J/\LJ\EJ/', ['jJ']], \ ['K', 's/K/\Uk\ek/', ['Kk']], - \ ['lLl', "s/L/\\r/", ["l\", 'l']], + \ ['lLl', "s/L/\\/", ["l\", 'l']], \ ['mMm', 's/M/\r/', ['m', 'm']], - \ ['nNn', "s/N/\\\\r/", ["n\", 'n']], + \ ['nNn', "s/N/\\\\/", ["n\", 'n']], \ ['oOo', 's/O/\n/', ["o\no"]], \ ['pPp', 's/P/\b/', ["p\p"]], \ ['qQq', 's/Q/\t/', ["q\tq"]], @@ -230,9 +230,9 @@ func Test_sub_cmd_3() " List entry format: [input, cmd, output] let tests = [['aAa', "s/A/\\='\\'/", ['a\a']], \ ['bBb', "s/B/\\='\\\\'/", ['b\\b']], - \ ['cCc', "s/C/\\='\\r'/", ["c\", 'c']], - \ ['dDd', "s/D/\\='\\\\r'/", ["d\\\", 'd']], - \ ['eEe', "s/E/\\='\\\\\\r'/", ["e\\\\\", 'e']], + \ ['cCc', "s/C/\\='\\'/", ["c\", 'c']], + \ ['dDd', "s/D/\\='\\\\'/", ["d\\\", 'd']], + \ ['eEe', "s/E/\\='\\\\\\'/", ["e\\\\\", 'e']], \ ['fFf', "s/F/\\='\r'/", ['f', 'f']], \ ['gGg', "s/G/\\='\\'/", ["g\", 'g']], \ ['hHh', "s/H/\\='\\\\'/", ["h\\\", 'h']], @@ -254,11 +254,11 @@ func Test_sub_cmd_4() \ ['a\a']], \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/", \ ['b\b']], - \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\\r', '')/", + \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\\', '')/", \ ["c\", 'c']], - \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\\r', '')/", + \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\\', '')/", \ ["d\", 'd']], - \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\\r', '')/", + \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\\', '')/", \ ["e\\\", 'e']], \ ['fFf', "s/F/\\=substitute(submatch(0), '.', '\\r', '')/", \ ['f', 'f']], @@ -316,7 +316,7 @@ func Test_sub_cmd_7() set cpo& " List entry format: [input, cmd, output] - let tests = [ ["A\\rA", 's/A./\=submatch(0)/', ['A', 'A']], + let tests = [ ["A\\A", 's/A./\=submatch(0)/', ['A', 'A']], \ ["B\\B", 's/B./\=submatch(0)/', ['B', 'B']], \ ["C\\C", 's/C./\=strtrans(string(submatch(0, 1)))/', [strtrans("['C\']C")]], \ ["D\\\nD", 's/D.\nD/\=strtrans(string(submatch(0, 1)))/', [strtrans("['D\', 'D']")]], @@ -467,11 +467,11 @@ func Test_sub_replace_1() call assert_equal('iI', substitute('I', 'I', '\lII', '')) call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', '')) call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', '')) - call assert_equal("l\\rl", - \ substitute('lLl', 'L', "\\r", '')) - call assert_equal("m\rm", substitute('mMm', 'M', '\r', '')) - call assert_equal("n\\rn", - \ substitute('nNn', 'N', "\\\\r", '')) + call assert_equal("l\\l", + \ substitute('lLl', 'L', "\\", '')) + call assert_equal("m\m", substitute('mMm', 'M', '\r', '')) + call assert_equal("n\\n", + \ substitute('nNn', 'N', "\\\\", '')) call assert_equal("o\no", substitute('oOo', 'O', '\n', '')) call assert_equal("p\p", substitute('pPp', 'P', '\b', '')) call assert_equal("q\tq", substitute('qQq', 'Q', '\t', '')) @@ -480,7 +480,7 @@ func Test_sub_replace_1() call assert_equal("u\nu", substitute('uUu', 'U', "\n", '')) call assert_equal("v\v", substitute('vVv', 'V', "\b", '')) call assert_equal("w\\w", substitute('wWw', 'W', "\\", '')) - call assert_equal("x\rx", substitute('xXx', 'X', "\r", '')) + call assert_equal("x\x", substitute('xXx', 'X', "\r", '')) call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', '')) call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', '')) endfunc @@ -500,17 +500,17 @@ func Test_sub_replace_2() call assert_equal('iI', substitute('I', 'I', '\lII', '')) call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', '')) call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', '')) - call assert_equal("l\\rl", - \ substitute('lLl', 'L', "\\r", '')) - call assert_equal("m\rm", substitute('mMm', 'M', '\r', '')) - call assert_equal("n\\rn", - \ substitute('nNn', 'N', "\\\\r", '')) + call assert_equal("l\\l", + \ substitute('lLl', 'L', "\\", '')) + call assert_equal("m\m", substitute('mMm', 'M', '\r', '')) + call assert_equal("n\\n", + \ substitute('nNn', 'N', "\\\\", '')) call assert_equal("o\no", substitute('oOo', 'O', '\n', '')) call assert_equal("p\p", substitute('pPp', 'P', '\b', '')) call assert_equal("q\tq", substitute('qQq', 'Q', '\t', '')) call assert_equal('r\r', substitute('rRr', 'R', '\\', '')) call assert_equal('scs', substitute('sSs', 'S', '\c', '')) - call assert_equal("t\rt", substitute('tTt', 'T', "\r", '')) + call assert_equal("t\t", substitute('tTt', 'T', "\r", '')) call assert_equal("u\nu", substitute('uUu', 'U', "\n", '')) call assert_equal("v\v", substitute('vVv', 'V', "\b", '')) call assert_equal('w\w', substitute('wWw', 'W', "\\", '')) @@ -528,7 +528,7 @@ func Test_sub_replace_3() call assert_equal("e\\\\\re", substitute('eEe', 'E', "\\=\"\\\\\\\\\r\"", '')) call assert_equal('f\rf', substitute('fFf', 'F', '\="\\r"', '')) call assert_equal('j\nj', substitute('jJj', 'J', '\="\\n"', '')) - call assert_equal("k\rk", substitute('kKk', 'K', '\="\r"', '')) + call assert_equal("k\k", substitute('kKk', 'K', '\="\r"', '')) call assert_equal("l\nl", substitute('lLl', 'L', '\="\n"', '')) endfunc @@ -540,10 +540,10 @@ func Test_sub_replace_4() \ '\=substitute(submatch(0), ".", "\\", "")', '')) call assert_equal('b\b', substitute('bBb', 'B', \ '\=substitute(submatch(0), ".", "\\\\", "")', '')) - call assert_equal("c\\rc", substitute('cCc', 'C', '\=substitute(submatch(0), ".", "\\r", "")', '')) - call assert_equal("d\\rd", substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\\\r", "")', '')) - call assert_equal("e\\\\re", substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\\\r", "")', '')) - call assert_equal("f\rf", substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', '')) + call assert_equal("c\\c", substitute('cCc', 'C', '\=substitute(submatch(0), ".", "\\", "")', '')) + call assert_equal("d\\d", substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\\\", "")', '')) + call assert_equal("e\\\\e", substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\\\", "")', '')) + call assert_equal("f\f", substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', '')) call assert_equal("j\nj", substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', '')) call assert_equal("k\rk", substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', '')) call assert_equal("l\nl", substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', '')) -- cgit From 7029b4b44a1cea58af3f54a4d62757b29a8e6aeb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 26 Apr 2022 10:09:35 +0800 Subject: feat(input): delay all simplifications Avoid unsimplfied Ctrl-C in input buffer when it is not mapped. --- src/nvim/os/input.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 4c617c9031..a4b8735b9e 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -238,8 +238,9 @@ size_t input_enqueue(String keys) // but since the keys are UTF-8, so the first byte cannot be // K_SPECIAL(0x80). uint8_t buf[19] = { 0 }; + // Do not simplify the keys here. Simplification will be done later. unsigned int new_size - = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, false, true, NULL); + = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, false, false, NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); @@ -487,7 +488,12 @@ static void process_interrupts(void) size_t consume_count = 0; RBUFFER_EACH_REVERSE(input_buffer, c, i) { - if ((uint8_t)c == Ctrl_C) { + if ((uint8_t)c == Ctrl_C + || ((uint8_t)c == 'C' && i >= 3 + && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL + && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER + && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) { + *rbuffer_get(input_buffer, i) = Ctrl_C; got_int = true; consume_count = i; break; -- cgit From c3634a02613459c85c228c400513835361ecc44a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 31 Mar 2022 21:06:34 +0800 Subject: vim-patch:8.1.2159: some mappings are listed twice Problem: Some mappings are listed twice. Solution: Skip mappings duplicated for modifyOtherKeys. (closes vim/vim#5064) https://github.com/vim/vim/commit/fafb4b18cd4aa5897537f53003b31bb83d7362df --- src/nvim/getchar.c | 17 +++++++++++------ src/nvim/testdir/test_mapping.vim | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 89a9a1ea95..b25c59636f 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3065,7 +3065,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T } for (; mp != NULL && !got_int; mp = mp->m_next) { // check entries with the same mode - if ((mp->m_mode & mode) != 0) { + if (!mp->m_simplified && (mp->m_mode & mode) != 0) { if (!has_lhs) { // show all entries showmap(mp, true); did_local = true; @@ -3100,13 +3100,16 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mpp = &(map_table[hash]); } for (mp = *mpp; mp != NULL && !got_int; mp = *mpp) { - if (!(mp->m_mode & mode)) { // skip entries with wrong mode + if ((mp->m_mode & mode) == 0) { + // skip entries with wrong mode mpp = &(mp->m_next); continue; } if (!has_lhs) { // show all entries - showmap(mp, map_table != maphash); - did_it = true; + if (!mp->m_simplified) { + showmap(mp, map_table != maphash); + did_it = true; + } } else { // do we have a match? if (round) { // second round: Try unmap "rhs" string n = (int)STRLEN(mp->m_str); @@ -3132,8 +3135,10 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mp->m_mode &= ~mode; did_it = true; // remember we did something } else if (!has_rhs) { // show matching entry - showmap(mp, map_table != maphash); - did_it = true; + if (!mp->m_simplified) { + showmap(mp, map_table != maphash); + did_it = true; + } } else if (n != len) { // new entry is ambiguous mpp = &(mp->m_next); continue; diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index a9500f8f77..c46336460d 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -429,6 +429,22 @@ func Test_error_in_map_expr() exe buf .. 'bwipe!' endfunc +func Test_list_mappings() + inoremap CtrlM + inoremap AltS + inoremap ShiftSlash + call assert_equal([ + \ 'i * ShiftSlash', + \ 'i * AltS', + \ 'i * CtrlM', + \], execute('imap')->trim()->split("\n")) + iunmap + iunmap + call assert_equal(['i * ShiftSlash'], execute('imap')->trim()->split("\n")) + iunmap + call assert_equal(['No mapping found'], execute('imap')->trim()->split("\n")) +endfunc + func Test_expr_map_gets_cursor() new call setline(1, ['one', 'some w!rd']) -- cgit From b5837e55e69602ce9716c8c04b1e2cb3188be8a5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Apr 2022 14:38:28 +0800 Subject: vim-patch:8.1.2165: mapping test fails on Mac Problem: Mapping test fails on Mac. Solution: Remove the default Mac mapping. https://github.com/vim/vim/commit/4f2f61a014e80217a2d6ac476c8f94e250a3d0ff --- src/nvim/testdir/test_mapping.vim | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index c46336460d..604ae8a3f9 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -430,6 +430,9 @@ func Test_error_in_map_expr() endfunc func Test_list_mappings() + " Remove default Mac mapping + silent! iunmap + inoremap CtrlM inoremap AltS inoremap ShiftSlash -- cgit From 44269c73a32f13d39ead1fdc257a97fc18ae805c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Apr 2022 14:38:39 +0800 Subject: vim-patch:8.1.2167: mapping test fails on MS-Windows Problem: Mapping test fails on MS-Windows. Solution: Remove all the existing Insert-mode mappings. https://github.com/vim/vim/commit/2559a47823a6a7827631f2e6a0176d7afce2721c --- src/nvim/testdir/test_mapping.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index 604ae8a3f9..b1c2429511 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -430,8 +430,8 @@ func Test_error_in_map_expr() endfunc func Test_list_mappings() - " Remove default Mac mapping - silent! iunmap + " Remove default mappings + imapclear inoremap CtrlM inoremap AltS -- cgit From 212349c100e9ada0c976bdaf1daf1aebec65edac Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 13:02:55 +0800 Subject: feat(edit): insert an unsimplified key using CTRL-SHIFT-V This marks the following Vim patches as ported: vim-patch:8.1.2333: with modifyOtherKeys CTRL-^ doesn't work Problem: With modifyOtherKeys CTRL-^ doesn't work. Solution: Handle the exception. https://github.com/vim/vim/commit/828ffd596394f714270a01a55fc3f949a8bd9b35 vim-patch:8.1.2350: other text for CTRL-V in Insert mode with modifyOtherKeys Problem: Other text for CTRL-V in Insert mode with modifyOtherKeys. Solution: Convert the Escape sequence back to key as if modifyOtherKeys is not set, and use CTRL-SHIFT-V to get the Escape sequence itself. (closes vim/vim#5254) https://github.com/vim/vim/commit/fc4ea2a72d36de1196a3ce17352e72f8fe90f4bb vim-patch:8.2.2084: CTRL-V U doesn't work to enter a Unicode character Problem: CTRL-V U doesn't work to enter a Unicode character when modifyOtherKeys is effective. (Ken Takata) Solution: Add a flag to get_literal() for the shift key. (closes vim/vim#7413) https://github.com/vim/vim/commit/0684e36a7ee0743f2889698fb8e0e14f7acae423 Omit getcmdkeycmd() change as it depends on Vim patch 8.2.2062, which may introduce a potential breakage. --- src/nvim/edit.c | 20 ++++++++++++-------- src/nvim/ex_getln.c | 6 +++++- src/nvim/getchar.c | 35 ++++++++++++++++++++++------------- src/nvim/normal.c | 4 ++-- 4 files changed, 41 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 48436f1115..3e3648e61f 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1587,7 +1587,8 @@ static void ins_ctrl_v(void) add_to_showcmd_c(Ctrl_V); - c = get_literal(); + // Do not include modifiers into the key for CTRL-SHIFT-V. + c = get_literal(mod_mask & MOD_MASK_SHIFT); if (did_putchar) { // when the line fits in 'columns' the '^' is at the start of the next // line and will not removed by the redraw @@ -5612,13 +5613,13 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len) return m; } -/* - * Next character is interpreted literally. - * A one, two or three digit decimal number is interpreted as its byte value. - * If one or two digits are entered, the next character is given to vungetc(). - * For Unicode a character > 255 may be returned. - */ -int get_literal(void) +/// Next character is interpreted literally. +/// A one, two or three digit decimal number is interpreted as its byte value. +/// If one or two digits are entered, the next character is given to vungetc(). +/// For Unicode a character > 255 may be returned. +/// +/// @param no_simplify do not include modifiers into the key +int get_literal(bool no_simplify) { int cc; int nc; @@ -5636,6 +5637,9 @@ int get_literal(void) i = 0; for (;;) { nc = plain_vgetc(); + if (!no_simplify) { + nc = merge_modifiers(nc); + } if ((mod_mask & ~MOD_MASK_SHIFT) != 0) { // A character with non-Shift modifiers should not be a valid // character for i_CTRL-V_digit. diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b7d75855d6..ea5bfc9a36 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2208,7 +2208,11 @@ static int command_line_handle_key(CommandLineState *s) case Ctrl_Q: s->ignore_drag_release = true; putcmdline('^', true); - s->c = get_literal(); // get next (two) character(s) + + // Get next (two) characters. + // Do not include modifiers into the key for CTRL-SHIFT-V. + s->c = get_literal(mod_mask & MOD_MASK_SHIFT); + s->do_abbr = false; // don't do abbreviation now ccline.special_char = NUL; // may need to remove ^ when composing char was typed diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b25c59636f..f92aa14c78 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1442,6 +1442,27 @@ static void updatescript(int c) } } +/// Merge "mod_mask" into "c_arg" +int merge_modifiers(int c_arg) +{ + int c = c_arg; + + if (mod_mask & MOD_MASK_CTRL) { + if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) { + c &= 0x1f; + mod_mask &= ~MOD_MASK_CTRL; + if (c == 0) { + c = K_ZERO; + } + } else if (c == '6') { + // CTRL-6 is equivalent to CTRL-^ + c = 0x1e; + mod_mask &= ~MOD_MASK_CTRL; + } + } + return c; +} + /// Get the next input character. /// Can return a special key or a multi-byte character. /// Can return NUL when called recursively, use safe_vgetc() if that's not @@ -1603,19 +1624,7 @@ int vgetc(void) // A modifier was not used for a mapping, apply it to ASCII // keys. Shift would already have been applied. - if (mod_mask & MOD_MASK_CTRL) { - if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) { - c &= 0x1f; - mod_mask &= ~MOD_MASK_CTRL; - if (c == 0) { - c = K_ZERO; - } - } else if (c == '6') { - // CTRL-6 is equivalent to CTRL-^ - c = 0x1e; - mod_mask &= ~MOD_MASK_CTRL; - } - } + c = merge_modifiers(c); // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed // something with a meta- or alt- modifier that was not mapped, interpret diff --git a/src/nvim/normal.c b/src/nvim/normal.c index ed5f13d00a..73ea995d8f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -5154,7 +5154,7 @@ static void nv_replace(cmdarg_T *cap) // get another character if (cap->nchar == Ctrl_V) { had_ctrl_v = Ctrl_V; - cap->nchar = get_literal(); + cap->nchar = get_literal(false); // Don't redo a multibyte character with CTRL-V. if (cap->nchar > DEL) { had_ctrl_v = NUL; @@ -5369,7 +5369,7 @@ static void nv_vreplace(cmdarg_T *cap) emsg(_(e_modifiable)); } else { if (cap->extra_char == Ctrl_V) { // get another character - cap->extra_char = get_literal(); + cap->extra_char = get_literal(false); } stuffcharReadbuff(cap->extra_char); stuffcharReadbuff(ESC); -- cgit From 82a13a78bb26e91d9f81231ab5e725129cfd8757 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 26 Apr 2022 22:11:04 +0800 Subject: vim-patch:partial:8.2.0815: maparg() does not provide enough information for mapset() Problem: maparg() does not provide enough information for mapset(). Solution: Add "lhsraw" and "lhsrawalt" items. Drop "simplified" https://github.com/vim/vim/commit/9c65253fe702ea010afec11aa971acd542c35de2 This only includes the "lhs" value part. --- src/nvim/eval/funcs.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 71a090afed..00d725d393 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5648,6 +5648,8 @@ static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) { char_u *keys_buf = NULL; + char_u *alt_keys_buf = NULL; + bool did_simplify = false; char_u *rhs; LuaRef rhs_lua; int mode; @@ -5655,6 +5657,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) 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; @@ -5684,10 +5687,16 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) mode = get_map_mode((char_u **)&which, 0); - keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, REPTERM_FROM_PART | REPTERM_DO_LT, NULL, - CPO_TO_CPO_FLAGS); - rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua); - xfree(keys_buf); + char_u *keys_simplified + = 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), &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. @@ -5710,6 +5719,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true); } } + + xfree(keys_buf); + xfree(alt_keys_buf); } /// luaeval() function implementation -- cgit From 66747f18ded775e2c0b6bac73cee18a3752086af Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Apr 2022 21:40:46 +0800 Subject: vim-patch:8.2.0839: dropping modifier when putting a character back in typeahead Problem: Dropping modifier when putting a character back in typeahead. Solution: Add modifier to ins_char_typebuf(). (closes vim/vim#6158) https://github.com/vim/vim/commit/b42c0d54279b1fdb79652db0c84171e213458809 Vim's test doesn't seem to work properly as the hit-enter prompt seems to be delayed. Add a Lua screen test. --- src/nvim/getchar.c | 6 ++++++ src/nvim/globals.h | 3 +++ src/nvim/message.c | 2 +- src/nvim/normal.c | 2 +- src/nvim/terminal.c | 2 +- src/nvim/testdir/test_messages.vim | 8 ++++++++ 6 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index f92aa14c78..fbe503bcd4 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1499,6 +1499,8 @@ int vgetc(void) static size_t last_vgetc_recorded_len = 0; mod_mask = 0; + vgetc_mod_mask = 0; + vgetc_char = 0; // last_recorded_len can be larger than last_vgetc_recorded_len // if peeking records more @@ -1624,6 +1626,10 @@ int vgetc(void) // A modifier was not used for a mapping, apply it to ASCII // keys. Shift would already have been applied. + // Remember the character and mod_mask from before, in some + // cases they are put back in the typeahead buffer. + vgetc_mod_mask = mod_mask; + vgetc_char = c; c = merge_modifiers(c); // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed diff --git a/src/nvim/globals.h b/src/nvim/globals.h index e07a0e22ca..6e0b445656 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -129,6 +129,9 @@ typedef off_t off_T; // held down based on the MOD_MASK_* symbols that are read first. EXTERN int mod_mask INIT(= 0); // current key modifiers +// The value of "mod_mask" and the unmodified character before calling merge_modifiers(). +EXTERN int vgetc_mod_mask INIT(= 0); +EXTERN int vgetc_char INIT(= 0); // Cmdline_row is the row where the command line starts, just below the // last window. diff --git a/src/nvim/message.c b/src/nvim/message.c index 6708001495..90af920396 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1214,7 +1214,7 @@ void wait_return(int redraw) } else if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C) { // Put the character back in the typeahead buffer. Don't use the // stuff buffer, because lmaps wouldn't work. - ins_char_typebuf(c, mod_mask); + ins_char_typebuf(vgetc_char, vgetc_mod_mask); do_redraw = true; // need a redraw even though there is // typeahead } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 73ea995d8f..a04316f5e4 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -995,7 +995,7 @@ static int normal_execute(VimState *state, int key) // restart automatically. // Insert the typed character in the typeahead buffer, so that it can // be mapped in Insert mode. Required for ":lmap" to work. - int len = ins_char_typebuf(s->c, mod_mask); + int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask); // When recording and gotchars() was called the character will be // recorded again, remove the previous recording. diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index fd870361c7..5f536c0b7a 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -1348,7 +1348,7 @@ static bool send_mouse_event(Terminal *term, int c) } end: - ins_char_typebuf(c, mod_mask); + ins_char_typebuf(vgetc_char, vgetc_mod_mask); return true; } diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 82c4cc128b..2e9b0a8531 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -112,6 +112,14 @@ func Test_echospace() set ruler& showcmd& endfunc +func Test_mapping_at_hit_return_prompt() + nnoremap :echo "hit ctrl-b" + call feedkeys(":ls\", "xt") + call feedkeys("\", "xt") + call assert_match('hit ctrl-b', Screenline(&lines - 1)) + nunmap +endfunc + func Test_quit_long_message() CheckScreendump -- cgit From 6832b626ea1b3413c445dfc23f4d921335dfeaf3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Apr 2022 22:36:59 +0800 Subject: vim-patch:8.2.0851: can't distinguish from accented "a" in the GUI Problem: Can't distinguish from accented "a" in the GUI. Solution: Use another way to make mapping work. (closes vim/vim#6163) https://github.com/vim/vim/commit/f4ae6b245a54f11dd967d06b80f30e5abf55fb82 --- src/nvim/getchar.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index fbe503bcd4..9a89170a10 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1450,13 +1450,14 @@ int merge_modifiers(int c_arg) if (mod_mask & MOD_MASK_CTRL) { if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) { c &= 0x1f; - mod_mask &= ~MOD_MASK_CTRL; if (c == 0) { c = K_ZERO; } } else if (c == '6') { // CTRL-6 is equivalent to CTRL-^ c = 0x1e; + } + if (c != c_arg) { mod_mask &= ~MOD_MASK_CTRL; } } -- cgit From abe91e1efec84c47c03a69ab8a998bb16f628084 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 26 Apr 2022 15:05:56 +0800 Subject: vim-patch:8.2.0855: GUI tests fail because the test doesn't use a modifier Problem: GUI tests fail because the test doesn't use a modifier. Solution: Add "\{xxx}" to be able to encode a modifier. https://github.com/vim/vim/commit/ebe9d34aa07037cff2188a8dd424ee1f59cbb0bf Change macros to enums to use them in unit tests. --- src/nvim/eval.c | 13 +++++++-- src/nvim/keymap.c | 47 +++++++++++++++------------------ src/nvim/keymap.h | 17 ++++++++++++ src/nvim/option.c | 3 ++- src/nvim/os/input.c | 2 +- src/nvim/testdir/test_backspace_opt.vim | 4 +-- src/nvim/testdir/test_mapping.vim | 6 ++--- src/nvim/testdir/test_messages.vim | 2 +- src/nvim/vim.h | 6 ----- src/nvim/viml/parser/expressions.c | 14 +++++++--- 10 files changed, 69 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index af6e7e470d..4427179633 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4963,9 +4963,17 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) ++name; break; - // Special key, e.g.: "\" + // Special key, e.g.: "\" or "\{C-W}" case '<': - extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true, true, NULL); + case '{': { + int flags = FSK_KEYCODE | FSK_IN_STRING; + + if (*p == '<') { + flags |= FSK_SIMPLIFY; + } else { + flags |= FSK_CURLY; + } + extra = trans_special((const char_u **)&p, STRLEN(p), name, flags, NULL); if (extra != 0) { name += extra; if (name >= rettv->vval.v_string + len) { @@ -4973,6 +4981,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) } break; } + } FALLTHROUGH; default: diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 07975545be..11abe25255 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -568,25 +568,21 @@ char_u *get_special_key_name(int c, int modifiers) /// @param[in] src_len Length of the srcp. /// @param[out] dst Location where translation result will be kept. It must // be at least 19 bytes per "" form. -/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL. -/// @param[in] in_string Inside a double quoted string -/// @param[in] simplify simplify , etc. +/// @param[in] flags FSK_ values /// @param[out] did_simplify found , etc. /// /// @return Number of characters added to dst, zero for no match. unsigned int trans_special(const char_u **const srcp, const size_t src_len, char_u *const dst, - const bool keycode, const bool in_string, const bool simplify, - bool *const did_simplify) + const int flags, bool *const did_simplify) FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT { int modifiers = 0; - int key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string, simplify, - did_simplify); + int key = find_special_key(srcp, src_len, &modifiers, flags, did_simplify); if (key == 0) { return 0; } - return special_to_buf(key, modifiers, keycode, dst); + return special_to_buf(key, modifiers, flags & FSK_KEYCODE, dst); } /// Put the character sequence for "key" with "modifiers" into "dst" and return @@ -625,16 +621,12 @@ unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst) /// @param[in,out] srcp Translated <> name. Is advanced to after the <> name. /// @param[in] src_len srcp length. /// @param[out] modp Location where information about modifiers is saved. -/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL. -/// @param[in] keep_x_key Don鈥檛 translate xHome to Home key. -/// @param[in] in_string In string, double quote is escaped -/// @param[in] simplify simplify , etc. -/// @param[out] did_simplify found , etc. +/// @param[in] flags FSK_ values +/// @param[out] did_simplify FSK_SIMPLIFY and found , etc. /// /// @return Key and modifiers or 0 if there is no match. int find_special_key(const char_u **const srcp, const size_t src_len, int *const modp, - const bool keycode, const bool keep_x_key, const bool in_string, - const bool simplify, bool *const did_simplify) + const int flags, bool *const did_simplify) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { const char_u *last_dash; @@ -642,9 +634,11 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const const char_u *src; const char_u *bp; const char_u *const end = *srcp + src_len - 1; + const bool in_string = flags & FSK_IN_STRING; int modifiers; int bit; int key; + const int endchar = (flags & FSK_CURLY) ? '}' : '>'; uvarnumber_T n; int l; @@ -653,7 +647,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const } src = *srcp; - if (src[0] != '<') { + if (src[0] != ((flags & FSK_CURLY) ? '{' : '<')) { return 0; } @@ -667,16 +661,16 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const // Anything accepted, like . // or are not special in strings as " is // the string delimiter. With a backslash it works: - if (end - bp > l && !(in_string && bp[1] == '"') && bp[l+1] == '>') { + if (end - bp > l && !(in_string && bp[1] == '"') && bp[l + 1] == endchar) { bp += l; } else if (end - bp > 2 && in_string && bp[1] == '\\' - && bp[2] == '"' && bp[3] == '>') { + && bp[2] == '"' && bp[3] == endchar) { bp += 2; } } } if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { - bp += 3; // skip t_xx, xx may be '-' or '>' + bp += 3; // skip t_xx, xx may be '-' or '>'/'}' } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) { vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); if (l == 0) { @@ -688,7 +682,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const } } - if (bp <= end && *bp == '>') { // found matching '>' + if (bp <= end && *bp == endchar) { // found matching '>' or '}' end_of_name = bp + 1; // Which modifiers are given? @@ -724,11 +718,11 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const } else { l = utfc_ptr2len(last_dash + 1); } - if (modifiers != 0 && last_dash[l + 1] == '>') { + if (modifiers != 0 && last_dash[l + 1] == endchar) { key = utf_ptr2char(last_dash + off); } else { key = get_special_key_code(last_dash + off); - if (!keep_x_key) { + if (!(flags & FSK_KEEP_X_KEY)) { key = handle_x_keys(key); } } @@ -741,7 +735,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const // includes the modifier. key = simplify_key(key, &modifiers); - if (!keycode) { + if (!(flags & FSK_KEYCODE)) { // don't want keycode, use single byte code if (key == K_BS) { key = BS; @@ -753,7 +747,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const // Normal Key with modifier: // Try to make a single byte code (except for Alt/Meta modifiers). if (!IS_SPECIAL(key)) { - key = extract_modifiers(key, &modifiers, simplify, did_simplify); + key = extract_modifiers(key, &modifiers, flags & FSK_SIMPLIFY, did_simplify); } *modp = modifiers; @@ -945,8 +939,9 @@ char_u *replace_termcodes(const char_u *const from, const size_t from_len, char_ } } - slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, true, false, - (flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify); + slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, + FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY), + did_simplify); if (slen) { dlen += slen; continue; diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 9dff8ba333..5259bf3d52 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -507,6 +507,23 @@ enum key_extra { ? 0 \ : FLAG_CPO_BSLASH) +// Flags for replace_termcodes() +enum { + REPTERM_FROM_PART = 1, + REPTERM_DO_LT = 2, + REPTERM_NO_SPECIAL = 4, + REPTERM_NO_SIMPLIFY = 8, +}; + +// Flags for find_special_key() +enum { + FSK_KEYCODE = 0x01, ///< prefer key code, e.g. K_DEL in place of DEL + FSK_KEEP_X_KEY = 0x02, ///< don鈥檛 translate xHome to Home key + FSK_IN_STRING = 0x04, ///< in string, double quote is escaped + FSK_SIMPLIFY = 0x08, ///< simplify , etc. + FSK_CURLY = 0x10, ///< {C-x} instead of +}; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "keymap.h.generated.h" #endif diff --git a/src/nvim/option.c b/src/nvim/option.c index 79231385ad..068b779eb6 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5222,7 +5222,8 @@ int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) } else if (has_lt) { arg--; // put arg at the '<' modifiers = 0; - key = find_special_key(&arg, len + 1, &modifiers, true, true, false, true, NULL); + key = find_special_key(&arg, len + 1, &modifiers, + FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, NULL); if (modifiers) { // can't handle modifiers here key = 0; } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index a4b8735b9e..f68a1c08c8 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -240,7 +240,7 @@ size_t input_enqueue(String keys) uint8_t buf[19] = { 0 }; // Do not simplify the keys here. Simplification will be done later. unsigned int new_size - = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, false, false, NULL); + = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); diff --git a/src/nvim/testdir/test_backspace_opt.vim b/src/nvim/testdir/test_backspace_opt.vim index 11459991ea..64342fbdf8 100644 --- a/src/nvim/testdir/test_backspace_opt.vim +++ b/src/nvim/testdir/test_backspace_opt.vim @@ -76,7 +76,7 @@ func Test_backspace_ctrl_u() set cpo-=< inoremap - exe "normal Avim3\\\" + exe "normal Avim3\{C-U}\\" iunmap exe "normal Avim4\\\\" @@ -86,7 +86,7 @@ func Test_backspace_ctrl_u() exe "normal A vim6\Azwei\u\\\" inoremap - exe "normal A vim7\\\\" + exe "normal A vim7\{C-U}\{C-U}\\" call assert_equal([ \ "1 this shouldn't be deleted", diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index b1c2429511..c6f052ab44 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -62,7 +62,7 @@ func Test_map_ctrl_c_insert() inoremap cnoremap dummy cunmap - call feedkeys("GoTEST2: CTRL-C |\A|\", "xt") + call feedkeys("GoTEST2: CTRL-C |\{C-C}A|\", "xt") call assert_equal('TEST2: CTRL-C |A|', getline('$')) unmap! set nomodified @@ -71,7 +71,7 @@ endfunc func Test_map_ctrl_c_visual() " mapping of ctrl-c in Visual mode vnoremap :$put ='vmap works' - call feedkeys("GV\\", "xt") + call feedkeys("GV\{C-C}\", "xt") call assert_equal('vmap works', getline('$')) vunmap set nomodified @@ -221,7 +221,7 @@ endfunc func Test_map_meta_quotes() imap foo - call feedkeys("Go-\-\", "xt") + call feedkeys("Go-\{M-\"}-\", "xt") call assert_equal("-foo-", getline('$')) set nomodified iunmap diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 2e9b0a8531..7cb2a2f1fa 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -115,7 +115,7 @@ endfunc func Test_mapping_at_hit_return_prompt() nnoremap :echo "hit ctrl-b" call feedkeys(":ls\", "xt") - call feedkeys("\", "xt") + call feedkeys("\{C-B}", "xt") call assert_match('hit ctrl-b', Screenline(&lines - 1)) nunmap endfunc diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 2672d0b2bc..3c8a865fb1 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -318,10 +318,4 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() #define REPLACE_CR_NCHAR (-1) #define REPLACE_NL_NCHAR (-2) -// Flags for replace_termcodes() -#define REPTERM_FROM_PART 1 -#define REPTERM_DO_LT 2 -#define REPTERM_NO_SPECIAL 4 -#define REPTERM_NO_SIMPLIFY 8 - #endif // NVIM_VIM_H diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index ec747d56d4..1beae0d003 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1815,10 +1815,18 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no *v_p++ = (char)ch; break; } - // Special key, e.g.: "\" - case '<': { + // Special key, e.g.: "\" or "\{C-W}" + case '<': + case '{': { + int flags = FSK_KEYCODE | FSK_IN_STRING; + + if (*p == '<') { + flags |= FSK_SIMPLIFY; + } else { + flags |= FSK_CURLY; + } const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p), - (char_u *)v_p, true, true, true, NULL); + (char_u *)v_p, flags, NULL); if (special_len != 0) { v_p += special_len; } else { -- cgit From d531ef6813919dd6df8ca6927cd99ec3c0a65635 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 26 Apr 2022 15:31:29 +0800 Subject: vim-patch:8.2.0867: using \{xxx} for encoding a modifier is not nice Problem: Using \{xxx} for encoding a modifier is not nice. Solution: Use \<*xxx> instead, since it's the same as \ but producing a different code. https://github.com/vim/vim/commit/fccd93f0917234b962ce07d1df3adf9d7105936f Use this notation in langmap_spec. --- src/nvim/eval.c | 9 +++------ src/nvim/keymap.c | 16 +++++++++------- src/nvim/keymap.h | 1 - src/nvim/testdir/test_backspace_opt.vim | 4 ++-- src/nvim/testdir/test_mapping.vim | 6 +++--- src/nvim/testdir/test_messages.vim | 2 +- src/nvim/viml/parser/expressions.c | 9 +++------ 7 files changed, 21 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4427179633..f8e2f913bf 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4963,15 +4963,12 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) ++name; break; - // Special key, e.g.: "\" or "\{C-W}" - case '<': - case '{': { + // Special key, e.g.: "\" + case '<': { int flags = FSK_KEYCODE | FSK_IN_STRING; - if (*p == '<') { + if (p[1] != '*') { flags |= FSK_SIMPLIFY; - } else { - flags |= FSK_CURLY; } extra = trans_special((const char_u **)&p, STRLEN(p), name, flags, NULL); if (extra != 0) { diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 11abe25255..5c4fe13e39 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -638,7 +638,6 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const int modifiers; int bit; int key; - const int endchar = (flags & FSK_CURLY) ? '}' : '>'; uvarnumber_T n; int l; @@ -647,9 +646,12 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const } src = *srcp; - if (src[0] != ((flags & FSK_CURLY) ? '{' : '<')) { + if (src[0] != '<') { return 0; } + if (src[1] == '*') { // <*xxx>: do not simplify + src++; + } // Find end of modifier list last_dash = src; @@ -661,16 +663,16 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const // Anything accepted, like . // or are not special in strings as " is // the string delimiter. With a backslash it works: - if (end - bp > l && !(in_string && bp[1] == '"') && bp[l + 1] == endchar) { + if (end - bp > l && !(in_string && bp[1] == '"') && bp[l + 1] == '>') { bp += l; } else if (end - bp > 2 && in_string && bp[1] == '\\' - && bp[2] == '"' && bp[3] == endchar) { + && bp[2] == '"' && bp[3] == '>') { bp += 2; } } } if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { - bp += 3; // skip t_xx, xx may be '-' or '>'/'}' + bp += 3; // skip t_xx, xx may be '-' or '>' } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) { vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); if (l == 0) { @@ -682,7 +684,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const } } - if (bp <= end && *bp == endchar) { // found matching '>' or '}' + if (bp <= end && *bp == '>') { // found matching '>' end_of_name = bp + 1; // Which modifiers are given? @@ -718,7 +720,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const } else { l = utfc_ptr2len(last_dash + 1); } - if (modifiers != 0 && last_dash[l + 1] == endchar) { + if (modifiers != 0 && last_dash[l + 1] == '>') { key = utf_ptr2char(last_dash + off); } else { key = get_special_key_code(last_dash + off); diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 5259bf3d52..9febd472f9 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -521,7 +521,6 @@ enum { FSK_KEEP_X_KEY = 0x02, ///< don鈥檛 translate xHome to Home key FSK_IN_STRING = 0x04, ///< in string, double quote is escaped FSK_SIMPLIFY = 0x08, ///< simplify , etc. - FSK_CURLY = 0x10, ///< {C-x} instead of }; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/testdir/test_backspace_opt.vim b/src/nvim/testdir/test_backspace_opt.vim index 64342fbdf8..59e94d2898 100644 --- a/src/nvim/testdir/test_backspace_opt.vim +++ b/src/nvim/testdir/test_backspace_opt.vim @@ -76,7 +76,7 @@ func Test_backspace_ctrl_u() set cpo-=< inoremap - exe "normal Avim3\{C-U}\\" + exe "normal Avim3\<*C-U>\\" iunmap exe "normal Avim4\\\\" @@ -86,7 +86,7 @@ func Test_backspace_ctrl_u() exe "normal A vim6\Azwei\u\\\" inoremap - exe "normal A vim7\{C-U}\{C-U}\\" + exe "normal A vim7\<*C-U>\<*C-U>\\" call assert_equal([ \ "1 this shouldn't be deleted", diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index c6f052ab44..f03d157fac 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -62,7 +62,7 @@ func Test_map_ctrl_c_insert() inoremap cnoremap dummy cunmap - call feedkeys("GoTEST2: CTRL-C |\{C-C}A|\", "xt") + call feedkeys("GoTEST2: CTRL-C |\<*C-C>A|\", "xt") call assert_equal('TEST2: CTRL-C |A|', getline('$')) unmap! set nomodified @@ -71,7 +71,7 @@ endfunc func Test_map_ctrl_c_visual() " mapping of ctrl-c in Visual mode vnoremap :$put ='vmap works' - call feedkeys("GV\{C-C}\", "xt") + call feedkeys("GV\<*C-C>\", "xt") call assert_equal('vmap works', getline('$')) vunmap set nomodified @@ -221,7 +221,7 @@ endfunc func Test_map_meta_quotes() imap foo - call feedkeys("Go-\{M-\"}-\", "xt") + call feedkeys("Go-\<*M-\">-\", "xt") call assert_equal("-foo-", getline('$')) set nomodified iunmap diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 7cb2a2f1fa..8be0c79499 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -115,7 +115,7 @@ endfunc func Test_mapping_at_hit_return_prompt() nnoremap :echo "hit ctrl-b" call feedkeys(":ls\", "xt") - call feedkeys("\{C-B}", "xt") + call feedkeys("\<*C-B>", "xt") call assert_match('hit ctrl-b', Screenline(&lines - 1)) nunmap endfunc diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 1beae0d003..b0fbc586b2 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1815,15 +1815,12 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no *v_p++ = (char)ch; break; } - // Special key, e.g.: "\" or "\{C-W}" - case '<': - case '{': { + // Special key, e.g.: "\" + case '<': { int flags = FSK_KEYCODE | FSK_IN_STRING; - if (*p == '<') { + if (p[1] != '*') { flags |= FSK_SIMPLIFY; - } else { - flags |= FSK_CURLY; } const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p), (char_u *)v_p, flags, NULL); -- cgit From f6afc7c3246db6e5bd8feab717b3c0dbf0226803 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 09:03:09 +0800 Subject: revert: "refactor: Remove allow_keys global (#6346)" --- src/nvim/digraph.c | 4 ++++ src/nvim/edit.c | 6 ++++++ src/nvim/eval/funcs.c | 2 ++ src/nvim/ex_cmds.c | 2 ++ src/nvim/ex_getln.c | 2 ++ src/nvim/getchar.c | 5 +++++ src/nvim/globals.h | 1 + src/nvim/input.c | 4 ++++ src/nvim/message.c | 2 ++ src/nvim/normal.c | 12 ++++++++++++ src/nvim/window.c | 2 ++ 11 files changed, 42 insertions(+) (limited to 'src') diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 0e148543aa..2a6ccce79e 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1513,8 +1513,10 @@ char_u *get_digraph_for_char(int val_arg) int get_digraph(bool cmdline) { no_mapping++; + allow_keys++; int c = plain_vgetc(); no_mapping--; + allow_keys--; if (c != ESC) { // ESC cancels CTRL-K @@ -1531,8 +1533,10 @@ int get_digraph(bool cmdline) add_to_showcmd(c); } no_mapping++; + allow_keys++; int cc = plain_vgetc(); no_mapping--; + allow_keys--; if (cc != ESC) { // ESC cancels CTRL-K diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 3e3648e61f..b8f88895a4 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -762,8 +762,10 @@ static int insert_execute(VimState *state, int key) // may need to redraw when no more chars available now ins_redraw(false); no_mapping++; + allow_keys++; s->c = plain_vgetc(); no_mapping--; + allow_keys--; if (s->c != Ctrl_N && s->c != Ctrl_G && s->c != Ctrl_O) { // it's something else vungetc(s->c); @@ -9237,8 +9239,10 @@ static int ins_digraph(void) // don't map the digraph chars. This also prevents the // mode message to be deleted when ESC is hit no_mapping++; + allow_keys++; c = plain_vgetc(); no_mapping--; + allow_keys--; if (did_putchar) { // when the line fits in 'columns' the '?' is at the start of the next // line and will not be removed by the redraw @@ -9264,8 +9268,10 @@ static int ins_digraph(void) add_to_showcmd_c(c); } no_mapping++; + allow_keys++; cc = plain_vgetc(); no_mapping--; + allow_keys--; if (did_putchar) { // when the line fits in 'columns' the '?' is at the start of the // next line and will not be removed by a redraw diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 00d725d393..dfdabd511e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2975,6 +2975,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) bool error = false; no_mapping++; + allow_keys++; for (;;) { // Position the cursor. Needed after a message that ends in a space, // or if event processing caused a redraw. @@ -3012,6 +3013,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) break; } no_mapping--; + allow_keys--; set_vim_var_nr(VV_MOUSE_WIN, 0); set_vim_var_nr(VV_MOUSE_WINID, 0); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 7564b9326b..f059175c88 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3951,8 +3951,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle RedrawingDisabled = temp; no_mapping++; // don't map this key + allow_keys++; // allow special keys typed = plain_vgetc(); no_mapping--; + allow_keys--; // clear the question msg_didout = false; // don't scroll up diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index ea5bfc9a36..f9ce156eb2 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1335,8 +1335,10 @@ static int command_line_execute(VimState *state, int key) // mode when 'insertmode' is set, CTRL-\ e prompts for an expression. if (s->c == Ctrl_BSL) { no_mapping++; + allow_keys++; s->c = plain_vgetc(); no_mapping--; + allow_keys--; // CTRL-\ e doesn't work when obtaining an expression, unless it // is in a mapping. if (s->c != Ctrl_N diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 9a89170a10..63e26fd0a4 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1511,19 +1511,24 @@ int vgetc(void) bool did_inc = false; if (mod_mask) { // no mapping after modifier has been read no_mapping++; + allow_keys++; did_inc = true; // mod_mask may change value } c = vgetorpeek(true); if (did_inc) { no_mapping--; + allow_keys--; } // Get two extra bytes for special keys if (c == K_SPECIAL) { + int save_allow_keys = allow_keys; no_mapping++; + allow_keys = 0; // make sure BS is not found c2 = vgetorpeek(true); // no mapping for these chars c = vgetorpeek(true); no_mapping--; + allow_keys = save_allow_keys; if (c2 == KS_MODIFIER) { mod_mask = c; continue; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 6e0b445656..5983f18bb5 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -652,6 +652,7 @@ EXTERN int reg_recorded INIT(= 0); // last recorded register or zero EXTERN int no_mapping INIT(= false); // currently no mapping allowed EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed +EXTERN int allow_keys INIT(= false); // allow key codes when no_mapping is set EXTERN int no_u_sync INIT(= 0); // Don't call u_sync() EXTERN int u_sync_once INIT(= 0); // Call u_sync() once when evaluating // an expression. diff --git a/src/nvim/input.c b/src/nvim/input.c index ff6b559710..6827dcae87 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -42,6 +42,7 @@ int ask_yesno(const char *const str, const bool direct) State = CONFIRM; // Mouse behaves like with :confirm. setmouse(); // Disable mouse in xterm. no_mapping++; + allow_keys++; // no mapping here, but recognize keys int r = ' '; while (r != 'y' && r != 'n') { @@ -62,6 +63,7 @@ int ask_yesno(const char *const str, const bool direct) State = save_State; setmouse(); no_mapping--; + allow_keys--; return r; } @@ -172,6 +174,7 @@ int get_number(int colon, int *mouse_used) } no_mapping++; + allow_keys++; // no mapping here, but recognize keys for (;;) { ui_cursor_goto(msg_row, msg_col); c = safe_vgetc(); @@ -205,6 +208,7 @@ int get_number(int colon, int *mouse_used) } } no_mapping--; + allow_keys--; return n; } diff --git a/src/nvim/message.c b/src/nvim/message.c index 90af920396..3660dc20af 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1146,6 +1146,7 @@ void wait_return(int redraw) // Don't do mappings here, we put the character back in the // typeahead buffer. no_mapping++; + allow_keys++; // Temporarily disable Recording. If Recording is active, the // character will be recorded later, since it will be added to the @@ -1159,6 +1160,7 @@ void wait_return(int redraw) got_int = false; } no_mapping--; + allow_keys--; reg_recording = save_reg_recording; scriptout = save_scriptout; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index a04316f5e4..c5d7e603cd 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -638,6 +638,7 @@ static void normal_get_additional_char(NormalState *s) int lang; // getting a text character no_mapping++; + allow_keys++; // no mapping for nchar, but allow key codes // Don't generate a CursorHold event here, most commands can't handle // it, e.g., nv_replace(), nv_csearch(). did_cursorhold = true; @@ -676,6 +677,7 @@ static void normal_get_additional_char(NormalState *s) if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) { // Allow mappings defined with ":lmap". no_mapping--; + allow_keys--; if (repl) { State = LREPLACE; } else { @@ -689,6 +691,7 @@ static void normal_get_additional_char(NormalState *s) if (langmap_active) { // Undo the decrement done above no_mapping++; + allow_keys++; } State = NORMAL_BUSY; s->need_flushbuf |= add_to_showcmd(*cp); @@ -769,6 +772,7 @@ static void normal_get_additional_char(NormalState *s) no_mapping++; } no_mapping--; + allow_keys--; } static void normal_invert_horizontal(NormalState *s) @@ -826,6 +830,7 @@ static bool normal_get_command_count(NormalState *s) if (s->ctrl_w) { no_mapping++; + allow_keys++; // no mapping for nchar, but keys } no_zero_mapping++; // don't map zero here @@ -834,6 +839,7 @@ static bool normal_get_command_count(NormalState *s) no_zero_mapping--; if (s->ctrl_w) { no_mapping--; + allow_keys--; } s->need_flushbuf |= add_to_showcmd(s->c); } @@ -844,9 +850,11 @@ static bool normal_get_command_count(NormalState *s) s->ca.opcount = s->ca.count0; // remember first count s->ca.count0 = 0; no_mapping++; + allow_keys++; // no mapping for nchar, but keys s->c = plain_vgetc(); // get next character LANGMAP_ADJUST(s->c, true); no_mapping--; + allow_keys--; s->need_flushbuf |= add_to_showcmd(s->c); return true; } @@ -3407,9 +3415,11 @@ static void nv_zet(cmdarg_T *cap) n = nchar - '0'; for (;;) { no_mapping++; + allow_keys++; // no mapping for nchar, but allow key codes nchar = plain_vgetc(); LANGMAP_ADJUST(nchar, true); no_mapping--; + allow_keys--; (void)add_to_showcmd(nchar); if (nchar == K_DEL || nchar == K_KDEL) { n /= 10; @@ -3785,9 +3795,11 @@ dozet: case 'u': // "zug" and "zuw": undo "zg" and "zw" no_mapping++; + allow_keys++; // no mapping for nchar, but allow key codes nchar = plain_vgetc(); LANGMAP_ADJUST(nchar, true); no_mapping--; + allow_keys--; (void)add_to_showcmd(nchar); if (vim_strchr((char_u *)"gGwW", nchar) == NULL) { clearopbeep(cap->oap); diff --git a/src/nvim/window.c b/src/nvim/window.c index f68cfe4c9c..50921c8302 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -534,11 +534,13 @@ wingotofile: case Ctrl_G: CHECK_CMDWIN; no_mapping++; + allow_keys++; // no mapping for xchar, but allow key codes if (xchar == NUL) { xchar = plain_vgetc(); } LANGMAP_ADJUST(xchar, true); no_mapping--; + allow_keys--; (void)add_to_showcmd(xchar); switch (xchar) { case '}': -- cgit From 32da3e56cd12210cd567609f2ec7dd4f0c1ee4c6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 26 Apr 2022 23:13:26 +0800 Subject: vim-patch:8.2.0916: mapping with partly modifyOtherKeys code does not work Problem: Mapping with partly modifyOtherKeys code does not work. Solution: If there is no mapping with a separate modifier include the modifier in the key and then try mapping again. (closes vim/vim#6200) https://github.com/vim/vim/commit/975a880a1389e8ce6dea8d66a7c109140b2f94ec Cherry-pick applicable part of put_string_in_typebuf(). Revert related changes from 10a5825. Use KEYLEN_PART_KEY for incomplete modifier sequence. Omit test as it sends terminal codes. Use a Lua test instead. --- src/nvim/edit.c | 2 +- src/nvim/getchar.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 98 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b8f88895a4..076cf445cf 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -5640,7 +5640,7 @@ int get_literal(bool no_simplify) for (;;) { nc = plain_vgetc(); if (!no_simplify) { - nc = merge_modifiers(nc); + nc = merge_modifiers(nc, &mod_mask); } if ((mod_mask & ~MOD_MASK_SHIFT) != 0) { // A character with non-Shift modifiers should not be a valid diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 63e26fd0a4..b7894da206 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1442,12 +1442,12 @@ static void updatescript(int c) } } -/// Merge "mod_mask" into "c_arg" -int merge_modifiers(int c_arg) +/// Merge "modifiers" into "c_arg". +int merge_modifiers(int c_arg, int *modifiers) { int c = c_arg; - if (mod_mask & MOD_MASK_CTRL) { + if (*modifiers & MOD_MASK_CTRL) { if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) { c &= 0x1f; if (c == 0) { @@ -1458,7 +1458,7 @@ int merge_modifiers(int c_arg) c = 0x1e; } if (c != c_arg) { - mod_mask &= ~MOD_MASK_CTRL; + *modifiers &= ~MOD_MASK_CTRL; } } return c; @@ -1636,7 +1636,7 @@ int vgetc(void) // cases they are put back in the typeahead buffer. vgetc_mod_mask = mod_mask; vgetc_char = c; - c = merge_modifiers(c); + c = merge_modifiers(c, &mod_mask); // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed // something with a meta- or alt- modifier that was not mapped, interpret @@ -1752,6 +1752,55 @@ typedef enum { map_result_nomatch, // no matching mapping, get char } map_result_T; +/// Put "string[new_slen]" in typebuf. +/// Remove "slen" bytes. +/// @return FAIL for error, OK otherwise. +static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_slen) +{ + int extra = new_slen - slen; + string[new_slen] = NUL; + if (extra < 0) { + // remove matched chars, taking care of noremap + del_typebuf(-extra, offset); + } else if (extra > 0) { + // insert the extra space we need + ins_typebuf(string + slen, REMAP_YES, offset, false, false); + } + // Careful: del_typebuf() and ins_typebuf() may have reallocated + // typebuf.tb_buf[]! + memmove(typebuf.tb_buf + typebuf.tb_off + offset, string, (size_t)new_slen); + return OK; +} + +/// Check if typebuf.tb_buf[] contains a modifer plus key that can be changed +/// into just a key, apply that. +/// Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off + "max_offset"]. +/// @return the length of the replaced bytes, zero if nothing changed. +static int check_simplify_modifier(int max_offset) +{ + for (int offset = 0; offset < max_offset; offset++) { + if (offset + 3 >= typebuf.tb_len) { + break; + } + char_u *tp = typebuf.tb_buf + typebuf.tb_off + offset; + if (tp[0] == K_SPECIAL && tp[1] == KS_MODIFIER) { + int modifier = tp[2]; + int new_c = merge_modifiers(tp[3], &modifier); + + if (new_c != tp[3] && modifier == 0) { + char_u new_string[MB_MAXBYTES]; + int len = utf_char2bytes(new_c, new_string); + + if (put_string_in_typebuf(offset, 4, new_string, len) == FAIL) { + return -1; + } + return len; + } + } + } + return 0; +} + /// Handle mappings in the typeahead buffer. /// - When something was mapped, return map_result_retry for recursive mappings. /// - When nothing mapped and typeahead has a character: return map_result_get. @@ -1950,16 +1999,51 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } if ((mp == NULL || max_mlen >= mp_match_len) && keylen != KEYLEN_PART_MAP) { - // No matching mapping found or found a non-matching mapping that - // matches at least what the matching mapping matched - keylen = 0; - (void)keylen; // suppress clang/dead assignment - // If there was no mapping, use the character from the typeahead - // buffer right here. Otherwise, use the mapping (loop around). - if (mp == NULL) { + // When no matching mapping found or found a non-matching mapping that + // matches at least what the matching mapping matched: + // Try to include the modifier into the key, when: + // - mapping is allowed, + // - keys have not been mapped, + // - and when not timed out, + if ((no_mapping == 0 || allow_keys != 0) + && (typebuf.tb_maplen == 0 + || (p_remap && typebuf.tb_noremap[typebuf.tb_off] == RM_YES)) + && !*timedout) { + if (tb_c1 == K_SPECIAL + && (typebuf.tb_len < 2 + || (typebuf.tb_buf[typebuf.tb_off + 1] == KS_MODIFIER + && typebuf.tb_len < 4))) { + // Incomplete modifier sequence: cannot decide whether to simplify yet. + keylen = KEYLEN_PART_KEY; + // Don't simplify if 'pastetoggle' matched partially. + } else if (keylen != KEYLEN_PART_KEY) { + // Try to include the modifier into the key. + keylen = check_simplify_modifier(max_mlen + 1); + assert(keylen >= 0); + } + } else { + keylen = 0; + } + if (keylen == 0) { // no simplication has been done + // If there was no mapping at all use the character from the + // typeahead buffer right here. + if (mp == NULL) { + *keylenp = keylen; + return map_result_get; // get character from typeahead + } + } + + if (keylen > 0) { // keys have been simplified *keylenp = keylen; - return map_result_get; // get character from typeahead + return map_result_retry; // try mapping again + } + + if (keylen < 0) { + // Incomplete key sequence: get some more characters. + assert(keylen == KEYLEN_PART_KEY); } else { + assert(mp != NULL); + // When a matching mapping was found use that one. keylen = mp_match_len; } } -- cgit From 9660ddd512653090fc02ec3e84afa97c846f0d61 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 09:08:24 +0800 Subject: vim-patch:8.2.0919: merging modifier for modifyOtherKeys is done twice Problem: Merging modifier for modifyOtherKeys is done twice. Solution: Remove the merging done in vgetc(). https://github.com/vim/vim/commit/673fc3e23f09095d17f0095c4323958041b2d0d2 Omit ex_getln.c change as it was removed in patch 8.2.2084, so no_reduce_keys is still not needed in Nvim. --- src/nvim/getchar.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b7894da206..31cc1ed861 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1630,13 +1630,10 @@ int vgetc(void) c = utf_ptr2char(buf); } - // A modifier was not used for a mapping, apply it to ASCII - // keys. Shift would already have been applied. - // Remember the character and mod_mask from before, in some - // cases they are put back in the typeahead buffer. - vgetc_mod_mask = mod_mask; - vgetc_char = c; - c = merge_modifiers(c, &mod_mask); + if (vgetc_char == 0) { + vgetc_mod_mask = mod_mask; + vgetc_char = c; + } // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed // something with a meta- or alt- modifier that was not mapped, interpret @@ -1784,15 +1781,31 @@ static int check_simplify_modifier(int max_offset) } char_u *tp = typebuf.tb_buf + typebuf.tb_off + offset; if (tp[0] == K_SPECIAL && tp[1] == KS_MODIFIER) { + // A modifier was not used for a mapping, apply it to ASCII + // keys. Shift would already have been applied. int modifier = tp[2]; - int new_c = merge_modifiers(tp[3], &modifier); - - if (new_c != tp[3] && modifier == 0) { + int c = tp[3]; + int new_c = merge_modifiers(c, &modifier); + + if (new_c != c) { + if (offset == 0) { + // At the start: remember the character and mod_mask before + // merging, in some cases, e.g. at the hit-return prompt, + // they are put back in the typeahead buffer. + vgetc_char = c; + vgetc_mod_mask = tp[2]; + } char_u new_string[MB_MAXBYTES]; int len = utf_char2bytes(new_c, new_string); - - if (put_string_in_typebuf(offset, 4, new_string, len) == FAIL) { - return -1; + if (modifier == 0) { + if (put_string_in_typebuf(offset, 4, new_string, len) == FAIL) { + return -1; + } + } else { + tp[2] = (char_u)modifier; + if (put_string_in_typebuf(offset + 3, 1, new_string, len) == FAIL) { + return -1; + } } return len; } -- cgit From 78a7e2d55ccb589c26e45498ff501c64b0b17519 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 17:34:40 +0800 Subject: vim-patch:8.1.2346: CTRL-R CTRL-R doesn't work with modifyOtherKeys Problem: CTRL-R CTRL-R doesn't work with modifyOtherKeys. Solution: Allow key codes when fetching argument for CTRL-R. (closes vim/vim#5266) Also fix CTRL-G in Insert mode. https://github.com/vim/vim/commit/38571a04b4eb2853f46df8884750bcb9a8115db8 Omit test as it sends terminal codes. Use a Lua test instead. --- src/nvim/edit.c | 24 ++++++++++++------------ src/nvim/ex_getln.c | 4 +++- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 076cf445cf..251f55c6e7 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -7817,11 +7817,10 @@ static void ins_reg(void) } - /* - * Don't map the register name. This also prevents the mode message to be - * deleted when ESC is hit. - */ - ++no_mapping; + // Don't map the register name. This also prevents the mode message to be + // deleted when ESC is hit. + no_mapping++; + allow_keys++; regname = plain_vgetc(); LANGMAP_ADJUST(regname, TRUE); if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) { @@ -7831,7 +7830,8 @@ static void ins_reg(void) regname = plain_vgetc(); LANGMAP_ADJUST(regname, TRUE); } - --no_mapping; + no_mapping--; + allow_keys--; // Don't call u_sync() while typing the expression or giving an error // message for it. Only call it explicitly. @@ -7899,13 +7899,13 @@ static void ins_ctrl_g(void) // Right after CTRL-X the cursor will be after the ruler. setcursor(); - /* - * Don't map the second key. This also prevents the mode message to be - * deleted when ESC is hit. - */ - ++no_mapping; + // Don't map the second key. This also prevents the mode message to be + // deleted when ESC is hit. + no_mapping++; + allow_keys++; c = plain_vgetc(); - --no_mapping; + no_mapping--; + allow_keys--; switch (c) { // CTRL-G k and CTRL-G : cursor up to Insstart.col case K_UP: diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index f9ce156eb2..35fd900391 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1891,6 +1891,7 @@ static int command_line_handle_key(CommandLineState *s) case Ctrl_R: { // insert register putcmdline('"', true); no_mapping++; + allow_keys++; int i = s->c = plain_vgetc(); // CTRL-R if (i == Ctrl_O) { i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R @@ -1899,7 +1900,8 @@ static int command_line_handle_key(CommandLineState *s) if (i == Ctrl_R) { s->c = plain_vgetc(); // CTRL-R CTRL-R } - --no_mapping; + no_mapping--; + allow_keys--; // Insert the result of an expression. // Need to save the current command line, to be able to enter // a new one... -- cgit From 4531ddaa62c0958262b6983b04d72531abe8b337 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 12:31:24 +0800 Subject: vim-patch:8.2.2728: special key names don't work if 'isident' is cleared Problem: Special key names don't work if 'isident' is cleared. Solution: Add vim_isNormalIDc() and use it for special key names. (closes vim/vim#2389) https://github.com/vim/vim/commit/e3d1f4c982bd0fe05496448d7868268c75ff7bfb Code is N/A as Nvim already has ascii_isident(), so just port the test. --- src/nvim/testdir/test_mapping.vim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index f03d157fac..8c399ff3b1 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -433,9 +433,12 @@ func Test_list_mappings() " Remove default mappings imapclear - inoremap CtrlM + " reset 'isident' to check it isn't used + set isident= + inoremap CtrlM inoremap AltS inoremap ShiftSlash + set isident& call assert_equal([ \ 'i * ShiftSlash', \ 'i * AltS', -- cgit From 096923e99067ba81d1f8f6bc5927920a1f5cceee Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 12:37:34 +0800 Subject: vim-patch:8.2.3595: check for signed overflow might not work everywhere Problem: Check for signed overflow might not work everywhere. Solution: Limit to 32 bit int. (closes vim/vim#9043, closes vim/vim#9067) https://github.com/vim/vim/commit/0d5a12ea041c112b06b1aafde38846ae4cff8f4c --- src/nvim/getchar.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 31cc1ed861..42044f6378 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -872,10 +872,8 @@ void init_default_mappings(void) int ins_typebuf(char_u *str, int noremap, int offset, bool nottyped, bool silent) { char_u *s1, *s2; - int newlen; int addlen; int i; - int newoff; int val; int nrm; @@ -901,13 +899,15 @@ int ins_typebuf(char_u *str, int noremap, int offset, bool nottyped, bool silent // In typebuf.tb_buf there must always be room for 3 * (MAXMAPLEN + 4) // characters. We add some extra room to avoid having to allocate too // often. - newoff = MAXMAPLEN + 4; - newlen = typebuf.tb_len + addlen + newoff + 4 * (MAXMAPLEN + 4); - if (newlen < 0) { // string is getting too long + int newoff = MAXMAPLEN + 4; + int extra = addlen + newoff + 4 * (MAXMAPLEN + 4); + if (typebuf.tb_len > 2147483674 - extra) { + // string is getting too long for 32 bit int emsg(_(e_toocompl)); // also calls flush_buffers setcursor(); return FAIL; } + int newlen = typebuf.tb_len + extra; s1 = xmalloc((size_t)newlen); s2 = xmalloc((size_t)newlen); typebuf.tb_buflen = newlen; -- cgit From 04a437b280b13bd33c37e99c46403198126d5343 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 16:54:59 +0800 Subject: vim-patch:8.2.4504: when there is a partially matching map full map may not work Problem: When there is a partially matching map and modifyOtherKeys is active a full map may not work. Solution: Only simplify modifiers when there is no matching mapping. (closes vim/vim#8792) https://github.com/vim/vim/commit/196c3850dbe95247f7aa1b0000a5cae625a99ef2 Omit test as it sends terminal codes. Use a Lua test instead. --- src/nvim/getchar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 42044f6378..555eadb5d4 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1972,7 +1972,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } // If no partly match found, use the longest full match. - if (keylen != KEYLEN_PART_MAP) { + if (keylen != KEYLEN_PART_MAP && mp_match != NULL) { mp = mp_match; keylen = mp_match_len; } @@ -2011,7 +2011,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } } - if ((mp == NULL || max_mlen >= mp_match_len) && keylen != KEYLEN_PART_MAP) { + if ((mp == NULL || max_mlen > mp_match_len) && keylen != KEYLEN_PART_MAP) { // When no matching mapping found or found a non-matching mapping that // matches at least what the matching mapping matched: // Try to include the modifier into the key, when: -- cgit From c14d89f306e8ca49758f49f0e48aa3ce88130ac4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 20:21:04 +0800 Subject: vim-patch:8.2.4819: unmapping simplified keys also deletes other mapping Problem: Unmapping simplified keys also deletes other mapping. Solution: Only unmap a mapping with m_simplified set. (closes vim/vim#10270) https://github.com/vim/vim/commit/a4e3332650021921068ef12923b4501c5b9918cb --- src/nvim/getchar.c | 7 ++++++- src/nvim/testdir/test_mapping.vim | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 555eadb5d4..1fb3f827c1 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3248,6 +3248,9 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mpp = &(mp->m_next); continue; } + if (did_simplify && keyround == 1 && !mp->m_simplified) { + break; + } // We reset the indicated mode bits. If nothing // is left the entry is deleted below. mp->m_mode &= ~mode; @@ -3319,7 +3322,9 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T if (maptype == 1) { // delete entry if (!did_it) { - retval = 2; // no match + if (!did_simplify || keyround == 2) { + retval = 2; // no match + } } else if (*lhs == Ctrl_C) { // If CTRL-C has been unmapped, reuse it for Interrupting. if (map_table == buf->b_maphash) { diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index 8c399ff3b1..88735a34b8 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -761,4 +761,15 @@ func Test_mouse_drag_insert_map() set mouse& endfunc +func Test_unmap_simplfied() + map foo + map bar + call assert_equal('foo', maparg('')) + call assert_equal('bar', maparg('')) + unmap + call assert_equal('', maparg('')) + call assert_equal('bar', maparg('')) + unmap +endfunc + " vim: shiftwidth=2 sts=2 expandtab -- cgit From e38cddc98953c64a7c7cd01fb0841e41a8674727 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 20:23:02 +0800 Subject: vim-patch:8.2.4824: expression is evaluated multiple times Problem: Expression is evaluated multiple times. Solution: Evaluate expression once and store the result. (closes vim/vim#10278) https://github.com/vim/vim/commit/23d5770ef5e2f5c6d20d123303b81327045e5a1e --- src/nvim/getchar.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 1fb3f827c1..61020ccf05 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3074,6 +3074,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T for (int keyround = 1; keyround <= 2; keyround++) { bool did_it = false; bool did_local = false; + bool keyround1_simplfied = keyround == 1 && did_simplify; int len = (int)args->lhs_len; if (keyround == 2) { @@ -3248,7 +3249,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mpp = &(mp->m_next); continue; } - if (did_simplify && keyround == 1 && !mp->m_simplified) { + if (keyround1_simplfied && !mp->m_simplified) { break; } // We reset the indicated mode bits. If nothing @@ -3287,7 +3288,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mp->m_nowait = args->nowait; mp->m_silent = args->silent; mp->m_mode = mode; - mp->m_simplified = did_simplify && keyround == 1; + mp->m_simplified = keyround1_simplfied; mp->m_expr = args->expr; mp->m_script_ctx = current_sctx; mp->m_script_ctx.sc_lnum += sourcing_lnum; @@ -3322,7 +3323,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T if (maptype == 1) { // delete entry if (!did_it) { - if (!did_simplify || keyround == 2) { + if (!keyround1_simplfied) { retval = 2; // no match } } else if (*lhs == Ctrl_C) { @@ -3373,7 +3374,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mp->m_nowait = args->nowait; mp->m_silent = args->silent; mp->m_mode = mode; - mp->m_simplified = did_simplify && keyround == 1; + mp->m_simplified = keyround1_simplfied; // Notice this when porting patch 8.2.0807 mp->m_expr = args->expr; mp->m_script_ctx = current_sctx; mp->m_script_ctx.sc_lnum += sourcing_lnum; -- cgit From 11b5a376bc1594639a539f1789167f3d5ec3f775 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 20:27:07 +0800 Subject: vim-patch:8.2.4827: typo in variable name Problem: Typo in variable name. (Gabriel Dupras) Solution: Rename the variable. https://github.com/vim/vim/commit/87f74106f96737e7b8ceaafe1a131aa718077de6 --- src/nvim/getchar.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 61020ccf05..167898bb1e 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3074,7 +3074,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T for (int keyround = 1; keyround <= 2; keyround++) { bool did_it = false; bool did_local = false; - bool keyround1_simplfied = keyround == 1 && did_simplify; + bool keyround1_simplified = keyround == 1 && did_simplify; int len = (int)args->lhs_len; if (keyround == 2) { @@ -3249,7 +3249,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mpp = &(mp->m_next); continue; } - if (keyround1_simplfied && !mp->m_simplified) { + if (keyround1_simplified && !mp->m_simplified) { break; } // We reset the indicated mode bits. If nothing @@ -3288,7 +3288,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mp->m_nowait = args->nowait; mp->m_silent = args->silent; mp->m_mode = mode; - mp->m_simplified = keyround1_simplfied; + mp->m_simplified = keyround1_simplified; mp->m_expr = args->expr; mp->m_script_ctx = current_sctx; mp->m_script_ctx.sc_lnum += sourcing_lnum; @@ -3323,7 +3323,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T if (maptype == 1) { // delete entry if (!did_it) { - if (!keyround1_simplfied) { + if (!keyround1_simplified) { retval = 2; // no match } } else if (*lhs == Ctrl_C) { @@ -3374,7 +3374,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mp->m_nowait = args->nowait; mp->m_silent = args->silent; mp->m_mode = mode; - mp->m_simplified = keyround1_simplfied; // Notice this when porting patch 8.2.0807 + mp->m_simplified = keyround1_simplified; // Notice this when porting patch 8.2.0807 mp->m_expr = args->expr; mp->m_script_ctx = current_sctx; mp->m_script_ctx.sc_lnum += sourcing_lnum; -- cgit From f2b512ad75cace9126eb0ea644daedd758c238e6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 20:27:38 +0800 Subject: vim-patch:8.2.4828: fix for unmapping simplified key not fully tested Problem: Fix for unmapping simplified key not fully tested. Solution: Add a test case. (closes vim/vim#10292) https://github.com/vim/vim/commit/abeb09b2c53054513812d1e56716e2a5abe8f354 --- src/nvim/getchar.c | 2 ++ src/nvim/testdir/test_mapping.vim | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 167898bb1e..2fe732d6f4 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3249,6 +3249,8 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T mpp = &(mp->m_next); continue; } + // In keyround for simplified keys, don't unmap + // a mapping without m_simplified flag. if (keyround1_simplified && !mp->m_simplified) { break; } diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index 88735a34b8..6bb8d82021 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -761,7 +761,7 @@ func Test_mouse_drag_insert_map() set mouse& endfunc -func Test_unmap_simplfied() +func Test_unmap_simplifiable() map foo map bar call assert_equal('foo', maparg('')) @@ -770,6 +770,11 @@ func Test_unmap_simplfied() call assert_equal('', maparg('')) call assert_equal('bar', maparg('')) unmap + + map foo + unmap + " This should not error + unmap endfunc " vim: shiftwidth=2 sts=2 expandtab -- cgit From bf065d9bb654263e59949a68d0b90fd196ab1ab8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 20:28:58 +0800 Subject: vim-patch:8.2.4829: a key may be simplified to NUL Problem: A key may be simplified to NUL. Solution: Use K_ZERO instead. Use macros instead of hard coded values. (closes vim/vim#10290) https://github.com/vim/vim/commit/17c95d9608370559441bb73941ba6d9a4b6b26bd --- src/nvim/getchar.c | 4 ++-- src/nvim/keymap.c | 2 +- src/nvim/testdir/test_termcodes.vim | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 src/nvim/testdir/test_termcodes.vim (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 2fe732d6f4..9826317102 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1450,7 +1450,7 @@ int merge_modifiers(int c_arg, int *modifiers) if (*modifiers & MOD_MASK_CTRL) { if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) { c &= 0x1f; - if (c == 0) { + if (c == NUL) { c = K_ZERO; } } else if (c == '6') { @@ -2738,7 +2738,7 @@ int inchar(char_u *buf, int maxlen, long wait_time) for (;;) { len = os_inchar(dum, DUM_LEN, 0L, 0, NULL); - if (len == 0 || (len == 1 && dum[0] == 3)) { + if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) { break; } } diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 5c4fe13e39..db51237771 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -785,7 +785,7 @@ static int extract_modifiers(int key, int *modp, const bool simplify, bool *cons && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) { key = CTRL_CHR(key); modifiers &= ~MOD_MASK_CTRL; - if (key == 0) { // is + if (key == NUL) { // is key = K_ZERO; } if (did_simplify != NULL) { diff --git a/src/nvim/testdir/test_termcodes.vim b/src/nvim/testdir/test_termcodes.vim new file mode 100644 index 0000000000..ecd408264d --- /dev/null +++ b/src/nvim/testdir/test_termcodes.vim @@ -0,0 +1,9 @@ + +func Test_simplify_ctrl_at() + " feeding unsimplified CTRL-@ should still trigger i_CTRL-@ + call feedkeys("ifoo\A\<*C-@>", 'xt') + call assert_equal('foofoo', getline(1)) +endfunc + + +" vim: shiftwidth=2 sts=2 expandtab -- cgit From 1d97781dc53416072387b1d71aeaf11caecd8cf0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 20:30:52 +0800 Subject: vim-patch:8.2.4833: failure of mapping not checked for Problem: Failure of mapping not checked for. Solution: Check return value of ins_typebuf(). (closes vim/vim#10299) https://github.com/vim/vim/commit/12e21e387b5bbc928097abf1c189b7dc665838fc --- src/nvim/getchar.c | 22 ++++++++++++++++++---- src/nvim/testdir/test_termcodes.vim | 5 +++-- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 9826317102..5aba241d45 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1761,7 +1761,9 @@ static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_s del_typebuf(-extra, offset); } else if (extra > 0) { // insert the extra space we need - ins_typebuf(string + slen, REMAP_YES, offset, false, false); + if (ins_typebuf(string + slen, REMAP_YES, offset, false, false) == FAIL) { + return FAIL; + } } // Careful: del_typebuf() and ins_typebuf() may have reallocated // typebuf.tb_buf[]! @@ -1772,7 +1774,7 @@ static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_s /// Check if typebuf.tb_buf[] contains a modifer plus key that can be changed /// into just a key, apply that. /// Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off + "max_offset"]. -/// @return the length of the replaced bytes, zero if nothing changed. +/// @return the length of the replaced bytes, 0 if nothing changed, -1 for error. static int check_simplify_modifier(int max_offset) { for (int offset = 0; offset < max_offset; offset++) { @@ -1796,7 +1798,15 @@ static int check_simplify_modifier(int max_offset) vgetc_mod_mask = tp[2]; } char_u new_string[MB_MAXBYTES]; - int len = utf_char2bytes(new_c, new_string); + int len; + if (IS_SPECIAL(new_c)) { + new_string[0] = K_SPECIAL; + new_string[1] = (char_u)K_SECOND(new_c); + new_string[2] = (char_u)K_THIRD(new_c); + len = 3; + } else { + len = utf_char2bytes(new_c, new_string); + } if (modifier == 0) { if (put_string_in_typebuf(offset, 4, new_string, len) == FAIL) { return -1; @@ -1819,6 +1829,7 @@ static int check_simplify_modifier(int max_offset) /// - When nothing mapped and typeahead has a character: return map_result_get. /// - When there is no match yet, return map_result_nomatch, need to get more /// typeahead. +/// - On failure (out of memory) return map_result_fail. static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) { mapblock_T *mp = NULL; @@ -2032,7 +2043,10 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } else if (keylen != KEYLEN_PART_KEY) { // Try to include the modifier into the key. keylen = check_simplify_modifier(max_mlen + 1); - assert(keylen >= 0); + if (keylen < 0) { + // ins_typebuf() failed + return map_result_fail; + } } } else { keylen = 0; diff --git a/src/nvim/testdir/test_termcodes.vim b/src/nvim/testdir/test_termcodes.vim index ecd408264d..987889f33c 100644 --- a/src/nvim/testdir/test_termcodes.vim +++ b/src/nvim/testdir/test_termcodes.vim @@ -1,8 +1,9 @@ func Test_simplify_ctrl_at() " feeding unsimplified CTRL-@ should still trigger i_CTRL-@ - call feedkeys("ifoo\A\<*C-@>", 'xt') - call assert_equal('foofoo', getline(1)) + call feedkeys("ifoo\A\<*C-@>x", 'xt') + call assert_equal('foofo', getline(1)) + bw! endfunc -- cgit From 4adf2123dd94a3d5303fe200c7e909067e1cda34 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 28 Apr 2022 21:18:58 +0800 Subject: vim-patch:8.2.4837: modifiers not simplified when timed out Problem: Modifiers not simplified when timed out or using feedkeys() with 'n" flag. Solution: Adjust how mapped flag and timeout are used. (closes vim/vim#10305) https://github.com/vim/vim/commit/68a573ce2b996602a86b14d9b258ebb8c657604f --- src/nvim/getchar.c | 23 +++++++++++------------ src/nvim/testdir/test_termcodes.vim | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 5aba241d45..a26ca3f2c8 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2025,22 +2025,21 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) if ((mp == NULL || max_mlen > mp_match_len) && keylen != KEYLEN_PART_MAP) { // When no matching mapping found or found a non-matching mapping that // matches at least what the matching mapping matched: - // Try to include the modifier into the key, when: - // - mapping is allowed, - // - keys have not been mapped, - // - and when not timed out, - if ((no_mapping == 0 || allow_keys != 0) - && (typebuf.tb_maplen == 0 - || (p_remap && typebuf.tb_noremap[typebuf.tb_off] == RM_YES)) - && !*timedout) { + // Try to include the modifier into the key when mapping is allowed. + if (no_mapping == 0 || allow_keys != 0) { if (tb_c1 == K_SPECIAL && (typebuf.tb_len < 2 - || (typebuf.tb_buf[typebuf.tb_off + 1] == KS_MODIFIER - && typebuf.tb_len < 4))) { + || (typebuf.tb_buf[typebuf.tb_off + 1] == KS_MODIFIER && typebuf.tb_len < 4))) { // Incomplete modifier sequence: cannot decide whether to simplify yet. keylen = KEYLEN_PART_KEY; - // Don't simplify if 'pastetoggle' matched partially. - } else if (keylen != KEYLEN_PART_KEY) { + } else if (keylen == KEYLEN_PART_KEY && !*timedout) { + // If 'pastetoggle' matched partially, don't simplify. + // When the last characters were not typed, don't wait for a typed character to + // complete 'pastetoggle'. + if (typebuf.tb_len == typebuf.tb_maplen) { + keylen = 0; + } + } else { // Try to include the modifier into the key. keylen = check_simplify_modifier(max_mlen + 1); if (keylen < 0) { diff --git a/src/nvim/testdir/test_termcodes.vim b/src/nvim/testdir/test_termcodes.vim index 987889f33c..f3b10a922e 100644 --- a/src/nvim/testdir/test_termcodes.vim +++ b/src/nvim/testdir/test_termcodes.vim @@ -6,5 +6,21 @@ func Test_simplify_ctrl_at() bw! endfunc +func Test_simplify_noremap() + call feedkeys("i\<*C-M>", 'nx') + call assert_equal('', getline(1)) + call assert_equal([0, 2, 1, 0, 1], getcurpos()) + bw! +endfunc + +func Test_simplify_timedout() + inoremap a b + call feedkeys("i\<*C-M>", 'xt') + call assert_equal('', getline(1)) + call assert_equal([0, 2, 1, 0, 1], getcurpos()) + iunmap a + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab -- cgit From 3601cef1377937f01347b20a8c6c303f5f429f51 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 27 Apr 2022 21:27:58 +0800 Subject: feat(mappings): do not replace existing mapping for simplified form --- src/nvim/getchar.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index a26ca3f2c8..58daa9631a 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3279,6 +3279,11 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T } else if (n != len) { // new entry is ambiguous mpp = &(mp->m_next); continue; + } else if (keyround1_simplified && !mp->m_simplified) { + // In keyround for simplified keys, don't replace + // a mapping without m_simplified flag. + did_it = true; + break; } else if (args->unique) { if (is_abbrev) { semsg(_("E226: abbreviation already exists for %s"), p); -- cgit