Merge pull request #25951 from zeertzjq/vim-8.2.4140

vim-patch:8.2.{4140,4820,4825,4861,4932}
This commit is contained in:
zeertzjq 2023-11-09 21:53:34 +08:00 committed by GitHub
commit 267c346e2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 679 additions and 74 deletions

View File

@ -4133,7 +4133,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is omitted or zero: Return the rhs of mapping When {dict} is omitted or zero: Return the rhs of mapping
{name} in mode {mode}. The returned String has special {name} in mode {mode}. The returned String has special
characters translated like in the output of the ":map" command characters translated like in the output of the ":map" command
listing. listing. When {dict} is TRUE a dictionary is returned, see
below. To get a list of all mappings see |maplist()|.
When there is no mapping for {name}, an empty String is When there is no mapping for {name}, an empty String is
returned if {dict} is FALSE, otherwise returns an empty Dict. returned if {dict} is FALSE, otherwise returns an empty Dict.
@ -4161,7 +4162,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is there and it is |TRUE| return a dictionary When {dict} is there and it is |TRUE| return a dictionary
containing all the information of the mapping with the containing all the information of the mapping with the
following items: following items: *mapping-dict*
"lhs" The {lhs} of the mapping as it would be typed "lhs" The {lhs} of the mapping as it would be typed
"lhsraw" The {lhs} of the mapping as raw bytes "lhsraw" The {lhs} of the mapping as raw bytes
"lhsrawalt" The {lhs} of the mapping as raw bytes, alternate "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
@ -4180,9 +4181,16 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
(|mapmode-ic|) (|mapmode-ic|)
"sid" The script local ID, used for <sid> mappings "sid" The script local ID, used for <sid> mappings
(|<SID>|). Negative for special contexts. (|<SID>|). Negative for special contexts.
"scriptversion" The version of the script, always 1.
"lnum" The line number in "sid", zero if unknown. "lnum" The line number in "sid", zero if unknown.
"nowait" Do not wait for other, longer mappings. "nowait" Do not wait for other, longer mappings.
(|:map-<nowait>|). (|:map-<nowait>|).
"abbr" True if this is an |abbreviation|.
"mode_bits" Nvim's internal binary representation of "mode".
|mapset()| ignores this; only "mode" is used.
See |maplist()| for usage examples. The values
are from src/nvim/vim.h and may change in the
future.
The dictionary can be used to restore a mapping with The dictionary can be used to restore a mapping with
|mapset()|. |mapset()|.
@ -4226,6 +4234,37 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()*
< This avoids adding the "_vv" mapping when there already is a < This avoids adding the "_vv" mapping when there already is a
mapping for "_v" or for "_vvv". mapping for "_v" or for "_vvv".
maplist([{abbr}]) *maplist()*
Returns a |List| of all mappings. Each List item is a |Dict|,
the same as what is returned by |maparg()|, see
|mapping-dict|. When {abbr} is there and it is |TRUE| use
abbreviations instead of mappings.
Example to show all mappings with "MultiMatch" in rhs: >vim
echo maplist()->filter({_, m ->
\ match(get(m, 'rhs', ''), 'MultiMatch') >= 0
\ })
< It can be tricky to find mappings for particular |:map-modes|.
|mapping-dict|'s "mode_bits" can simplify this. For example,
the mode_bits for Normal, Insert or Command-line modes are
0x19. To find all the mappings available in those modes you
can do: >vim
let saved_maps = []
for m in maplist()
if and(m.mode_bits, 0x19) != 0
eval saved_maps->add(m)
endif
endfor
echo saved_maps->mapnew({_, m -> m.lhs})
< The values of the mode_bits are defined in Nvim's
src/nvim/vim.h file and they can be discovered at runtime
using |:map-commands| and "maplist()". Example: >vim
omap xyzzy <Nop>
let op_bit = maplist()->filter(
\ {_, m -> m.lhs == 'xyzzy'})[0].mode_bits
ounmap xyzzy
echo printf("Operator-pending mode bit: 0x%x", op_bit)
mapnew({expr1}, {expr2}) *mapnew()* mapnew({expr1}, {expr2}) *mapnew()*
Like |map()| but instead of replacing items in {expr1} a new Like |map()| but instead of replacing items in {expr1} a new
List or Dictionary is created and returned. {expr1} remains List or Dictionary is created and returned. {expr1} remains
@ -4233,9 +4272,17 @@ mapnew({expr1}, {expr2}) *mapnew()*
don't want that use |deepcopy()| first. don't want that use |deepcopy()| first.
mapset({mode}, {abbr}, {dict}) *mapset()* mapset({mode}, {abbr}, {dict}) *mapset()*
Restore a mapping from a dictionary returned by |maparg()|. Restore a mapping from a dictionary, possibly returned by
{mode} and {abbr} should be the same as for the call to |maparg()| or |maplist()|. A buffer mapping, when dict.buffer
|maparg()|. *E460* is true, is set on the current buffer; it is up to the caller
to ensure that the intended buffer is the current buffer. This
feature allows copying mappings from one buffer to another.
The dict.mode value may restore a single mapping that covers
more than one mode, like with mode values of '!', ' ', "nox",
or 'v'. *E1276*
In the first form, {mode} and {abbr} should be the same as
for the call to |maparg()|. *E460*
{mode} is used to define the mode in which the mapping is set, {mode} is used to define the mode in which the mapping is set,
not the "mode" entry in {dict}. not the "mode" entry in {dict}.
Example for saving and restoring a mapping: >vim Example for saving and restoring a mapping: >vim
@ -4244,8 +4291,21 @@ mapset({mode}, {abbr}, {dict}) *mapset()*
" ... " ...
call mapset('n', 0, save_map) call mapset('n', 0, save_map)
< Note that if you are going to replace a map in several modes, < Note that if you are going to replace a map in several modes,
e.g. with `:map!`, you need to save the mapping for all of e.g. with `:map!`, you need to save/restore the mapping for
them, since they can differ. all of them, when they might differ.
In the second form, with {dict} as the only argument, mode
and abbr are taken from the dict.
Example: >vim
let save_maps = maplist()->filter(
\ {_, m -> m.lhs == 'K'})
nnoremap K somethingelse
cnoremap K somethingelse2
" ...
unmap K
for d in save_maps
call mapset(d)
endfor
match({expr}, {pat} [, {start} [, {count}]]) *match()* match({expr}, {pat} [, {start} [, {count}]]) *match()*
When {expr} is a |List| then this returns the index of the When {expr} is a |List| then this returns the index of the

View File

@ -955,7 +955,7 @@ operator to add quotes around text in the current line: >
\ ->setline(".")}'<CR>g@ \ ->setline(".")}'<CR>g@
============================================================================== ==============================================================================
2. Abbreviations *abbreviations* *Abbreviations* 2. Abbreviations *abbreviation* *abbreviations* *Abbreviations*
Abbreviations are used in Insert mode, Replace mode and Command-line mode. Abbreviations are used in Insert mode, Replace mode and Command-line mode.
If you enter a word that is an abbreviation, it is replaced with the word it If you enter a word that is an abbreviation, it is replaced with the word it

View File

@ -1015,6 +1015,7 @@ Mappings and Menus: *mapping-functions*
hasmapto() check if a mapping exists hasmapto() check if a mapping exists
mapcheck() check if a matching mapping exists mapcheck() check if a matching mapping exists
maparg() get rhs of a mapping maparg() get rhs of a mapping
maplist() get list of all mappings
mapset() restore a mapping mapset() restore a mapping
menu_info() get information about a menu item menu_info() get information about a menu item
wildmenumode() check if the wildmode is active wildmenumode() check if the wildmode is active

View File

@ -4994,7 +4994,8 @@ function vim.fn.map(expr1, expr2) end
--- When {dict} is omitted or zero: Return the rhs of mapping --- When {dict} is omitted or zero: Return the rhs of mapping
--- {name} in mode {mode}. The returned String has special --- {name} in mode {mode}. The returned String has special
--- characters translated like in the output of the ":map" command --- characters translated like in the output of the ":map" command
--- listing. --- listing. When {dict} is TRUE a dictionary is returned, see
--- below. To get a list of all mappings see |maplist()|.
--- ---
--- When there is no mapping for {name}, an empty String is --- When there is no mapping for {name}, an empty String is
--- returned if {dict} is FALSE, otherwise returns an empty Dict. --- returned if {dict} is FALSE, otherwise returns an empty Dict.
@ -5022,7 +5023,7 @@ function vim.fn.map(expr1, expr2) end
--- ---
--- When {dict} is there and it is |TRUE| return a dictionary --- When {dict} is there and it is |TRUE| return a dictionary
--- containing all the information of the mapping with the --- containing all the information of the mapping with the
--- following items: --- following items: *mapping-dict*
--- "lhs" The {lhs} of the mapping as it would be typed --- "lhs" The {lhs} of the mapping as it would be typed
--- "lhsraw" The {lhs} of the mapping as raw bytes --- "lhsraw" The {lhs} of the mapping as raw bytes
--- "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate --- "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
@ -5041,9 +5042,16 @@ function vim.fn.map(expr1, expr2) end
--- (|mapmode-ic|) --- (|mapmode-ic|)
--- "sid" The script local ID, used for <sid> mappings --- "sid" The script local ID, used for <sid> mappings
--- (|<SID>|). Negative for special contexts. --- (|<SID>|). Negative for special contexts.
--- "scriptversion" The version of the script, always 1.
--- "lnum" The line number in "sid", zero if unknown. --- "lnum" The line number in "sid", zero if unknown.
--- "nowait" Do not wait for other, longer mappings. --- "nowait" Do not wait for other, longer mappings.
--- (|:map-<nowait>|). --- (|:map-<nowait>|).
--- "abbr" True if this is an |abbreviation|.
--- "mode_bits" Nvim's internal binary representation of "mode".
--- |mapset()| ignores this; only "mode" is used.
--- See |maplist()| for usage examples. The values
--- are from src/nvim/vim.h and may change in the
--- future.
--- ---
--- The dictionary can be used to restore a mapping with --- The dictionary can be used to restore a mapping with
--- |mapset()|. --- |mapset()|.
@ -5099,6 +5107,39 @@ function vim.fn.maparg(name, mode, abbr, dict) end
--- @return any --- @return any
function vim.fn.mapcheck(name, mode, abbr) end function vim.fn.mapcheck(name, mode, abbr) end
--- Returns a |List| of all mappings. Each List item is a |Dict|,
--- the same as what is returned by |maparg()|, see
--- |mapping-dict|. When {abbr} is there and it is |TRUE| use
--- abbreviations instead of mappings.
---
--- Example to show all mappings with "MultiMatch" in rhs: >vim
--- echo maplist()->filter({_, m ->
--- \ match(get(m, 'rhs', ''), 'MultiMatch') >= 0
--- \ })
--- <It can be tricky to find mappings for particular |:map-modes|.
--- |mapping-dict|'s "mode_bits" can simplify this. For example,
--- the mode_bits for Normal, Insert or Command-line modes are
--- 0x19. To find all the mappings available in those modes you
--- can do: >vim
--- let saved_maps = []
--- for m in maplist()
--- if and(m.mode_bits, 0x19) != 0
--- eval saved_maps->add(m)
--- endif
--- endfor
--- echo saved_maps->mapnew({_, m -> m.lhs})
--- <The values of the mode_bits are defined in Nvim's
--- src/nvim/vim.h file and they can be discovered at runtime
--- using |:map-commands| and "maplist()". Example: >vim
--- omap xyzzy <Nop>
--- let op_bit = maplist()->filter(
--- \ {_, m -> m.lhs == 'xyzzy'})[0].mode_bits
--- ounmap xyzzy
--- echo printf("Operator-pending mode bit: 0x%x", op_bit)
---
--- @return any
function vim.fn.maplist() end
--- Like |map()| but instead of replacing items in {expr1} a new --- Like |map()| but instead of replacing items in {expr1} a new
--- List or Dictionary is created and returned. {expr1} remains --- List or Dictionary is created and returned. {expr1} remains
--- unchanged. Items can still be changed by {expr2}, if you --- unchanged. Items can still be changed by {expr2}, if you
@ -5109,9 +5150,17 @@ function vim.fn.mapcheck(name, mode, abbr) end
--- @return any --- @return any
function vim.fn.mapnew(expr1, expr2) end function vim.fn.mapnew(expr1, expr2) end
--- Restore a mapping from a dictionary returned by |maparg()|. --- Restore a mapping from a dictionary, possibly returned by
--- {mode} and {abbr} should be the same as for the call to --- |maparg()| or |maplist()|. A buffer mapping, when dict.buffer
--- |maparg()|. *E460* --- is true, is set on the current buffer; it is up to the caller
--- to ensure that the intended buffer is the current buffer. This
--- feature allows copying mappings from one buffer to another.
--- The dict.mode value may restore a single mapping that covers
--- more than one mode, like with mode values of '!', ' ', "nox",
--- or 'v'. *E1276*
---
--- In the first form, {mode} and {abbr} should be the same as
--- for the call to |maparg()|. *E460*
--- {mode} is used to define the mode in which the mapping is set, --- {mode} is used to define the mode in which the mapping is set,
--- not the "mode" entry in {dict}. --- not the "mode" entry in {dict}.
--- Example for saving and restoring a mapping: >vim --- Example for saving and restoring a mapping: >vim
@ -5120,12 +5169,25 @@ function vim.fn.mapnew(expr1, expr2) end
--- " ... --- " ...
--- call mapset('n', 0, save_map) --- call mapset('n', 0, save_map)
--- <Note that if you are going to replace a map in several modes, --- <Note that if you are going to replace a map in several modes,
--- e.g. with `:map!`, you need to save the mapping for all of --- e.g. with `:map!`, you need to save/restore the mapping for
--- them, since they can differ. --- all of them, when they might differ.
---
--- In the second form, with {dict} as the only argument, mode
--- and abbr are taken from the dict.
--- Example: >vim
--- let save_maps = maplist()->filter(
--- \ {_, m -> m.lhs == 'K'})
--- nnoremap K somethingelse
--- cnoremap K somethingelse2
--- " ...
--- unmap K
--- for d in save_maps
--- call mapset(d)
--- endfor
--- ---
--- @param mode string --- @param mode string
--- @param abbr any --- @param abbr? any
--- @param dict any --- @param dict? any
--- @return any --- @return any
function vim.fn.mapset(mode, abbr, dict) end function vim.fn.mapset(mode, abbr, dict) end

View File

@ -1116,8 +1116,7 @@ func s:DeleteCommands()
if exists('s:k_map_saved') if exists('s:k_map_saved')
if !empty(s:k_map_saved) && !s:k_map_saved.buffer if !empty(s:k_map_saved) && !s:k_map_saved.buffer
nunmap K nunmap K
" call mapset(s:k_map_saved) call mapset(s:k_map_saved)
call mapset('n', 0, s:k_map_saved)
elseif empty(s:k_map_saved) elseif empty(s:k_map_saved)
nunmap K nunmap K
endif endif
@ -1126,8 +1125,7 @@ func s:DeleteCommands()
if exists('s:plus_map_saved') if exists('s:plus_map_saved')
if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer
nunmap + nunmap +
" call mapset(s:plus_map_saved) call mapset(s:plus_map_saved)
call mapset('n', 0, s:plus_map_saved)
elseif empty(s:plus_map_saved) elseif empty(s:plus_map_saved)
nunmap + nunmap +
endif endif
@ -1136,8 +1134,7 @@ func s:DeleteCommands()
if exists('s:minus_map_saved') if exists('s:minus_map_saved')
if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer
nunmap - nunmap -
" call mapset(s:minus_map_saved) call mapset(s:minus_map_saved)
call mapset('n', 0, s:minus_map_saved)
elseif empty(s:minus_map_saved) elseif empty(s:minus_map_saved)
nunmap - nunmap -
endif endif

View File

@ -6142,7 +6142,8 @@ M.funcs = {
When {dict} is omitted or zero: Return the rhs of mapping When {dict} is omitted or zero: Return the rhs of mapping
{name} in mode {mode}. The returned String has special {name} in mode {mode}. The returned String has special
characters translated like in the output of the ":map" command characters translated like in the output of the ":map" command
listing. listing. When {dict} is TRUE a dictionary is returned, see
below. To get a list of all mappings see |maplist()|.
When there is no mapping for {name}, an empty String is When there is no mapping for {name}, an empty String is
returned if {dict} is FALSE, otherwise returns an empty Dict. returned if {dict} is FALSE, otherwise returns an empty Dict.
@ -6170,7 +6171,7 @@ M.funcs = {
When {dict} is there and it is |TRUE| return a dictionary When {dict} is there and it is |TRUE| return a dictionary
containing all the information of the mapping with the containing all the information of the mapping with the
following items: following items: *mapping-dict*
"lhs" The {lhs} of the mapping as it would be typed "lhs" The {lhs} of the mapping as it would be typed
"lhsraw" The {lhs} of the mapping as raw bytes "lhsraw" The {lhs} of the mapping as raw bytes
"lhsrawalt" The {lhs} of the mapping as raw bytes, alternate "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
@ -6189,9 +6190,16 @@ M.funcs = {
(|mapmode-ic|) (|mapmode-ic|)
"sid" The script local ID, used for <sid> mappings "sid" The script local ID, used for <sid> mappings
(|<SID>|). Negative for special contexts. (|<SID>|). Negative for special contexts.
"scriptversion" The version of the script, always 1.
"lnum" The line number in "sid", zero if unknown. "lnum" The line number in "sid", zero if unknown.
"nowait" Do not wait for other, longer mappings. "nowait" Do not wait for other, longer mappings.
(|:map-<nowait>|). (|:map-<nowait>|).
"abbr" True if this is an |abbreviation|.
"mode_bits" Nvim's internal binary representation of "mode".
|mapset()| ignores this; only "mode" is used.
See |maplist()| for usage examples. The values
are from src/nvim/vim.h and may change in the
future.
The dictionary can be used to restore a mapping with The dictionary can be used to restore a mapping with
|mapset()|. |mapset()|.
@ -6254,6 +6262,43 @@ M.funcs = {
params = { { 'name', 'string' }, { 'mode', 'string' }, { 'abbr', 'any' } }, params = { { 'name', 'string' }, { 'mode', 'string' }, { 'abbr', 'any' } },
signature = 'mapcheck({name} [, {mode} [, {abbr}]])', signature = 'mapcheck({name} [, {mode} [, {abbr}]])',
}, },
maplist = {
args = { 0, 1 },
desc = [[
Returns a |List| of all mappings. Each List item is a |Dict|,
the same as what is returned by |maparg()|, see
|mapping-dict|. When {abbr} is there and it is |TRUE| use
abbreviations instead of mappings.
Example to show all mappings with "MultiMatch" in rhs: >vim
echo maplist()->filter({_, m ->
\ match(get(m, 'rhs', ''), 'MultiMatch') >= 0
\ })
<It can be tricky to find mappings for particular |:map-modes|.
|mapping-dict|'s "mode_bits" can simplify this. For example,
the mode_bits for Normal, Insert or Command-line modes are
0x19. To find all the mappings available in those modes you
can do: >vim
let saved_maps = []
for m in maplist()
if and(m.mode_bits, 0x19) != 0
eval saved_maps->add(m)
endif
endfor
echo saved_maps->mapnew({_, m -> m.lhs})
<The values of the mode_bits are defined in Nvim's
src/nvim/vim.h file and they can be discovered at runtime
using |:map-commands| and "maplist()". Example: >vim
omap xyzzy <Nop>
let op_bit = maplist()->filter(
\ {_, m -> m.lhs == 'xyzzy'})[0].mode_bits
ounmap xyzzy
echo printf("Operator-pending mode bit: 0x%x", op_bit)
]],
name = 'maplist',
params = {},
signature = 'maplist([{abbr}])'
},
mapnew = { mapnew = {
args = 2, args = 2,
base = 1, base = 1,
@ -6268,12 +6313,20 @@ M.funcs = {
signature = 'mapnew({expr1}, {expr2})', signature = 'mapnew({expr1}, {expr2})',
}, },
mapset = { mapset = {
args = 3, args = { 1, 3 },
base = 1, base = 1,
desc = [=[ desc = [=[
Restore a mapping from a dictionary returned by |maparg()|. Restore a mapping from a dictionary, possibly returned by
{mode} and {abbr} should be the same as for the call to |maparg()| or |maplist()|. A buffer mapping, when dict.buffer
|maparg()|. *E460* is true, is set on the current buffer; it is up to the caller
to ensure that the intended buffer is the current buffer. This
feature allows copying mappings from one buffer to another.
The dict.mode value may restore a single mapping that covers
more than one mode, like with mode values of '!', ' ', "nox",
or 'v'. *E1276*
In the first form, {mode} and {abbr} should be the same as
for the call to |maparg()|. *E460*
{mode} is used to define the mode in which the mapping is set, {mode} is used to define the mode in which the mapping is set,
not the "mode" entry in {dict}. not the "mode" entry in {dict}.
Example for saving and restoring a mapping: >vim Example for saving and restoring a mapping: >vim
@ -6282,8 +6335,21 @@ M.funcs = {
" ... " ...
call mapset('n', 0, save_map) call mapset('n', 0, save_map)
<Note that if you are going to replace a map in several modes, <Note that if you are going to replace a map in several modes,
e.g. with `:map!`, you need to save the mapping for all of e.g. with `:map!`, you need to save/restore the mapping for
them, since they can differ. all of them, when they might differ.
In the second form, with {dict} as the only argument, mode
and abbr are taken from the dict.
Example: >vim
let save_maps = maplist()->filter(
\ {_, m -> m.lhs == 'K'})
nnoremap K somethingelse
cnoremap K somethingelse2
" ...
unmap K
for d in save_maps
call mapset(d)
endfor
]=], ]=],
name = 'mapset', name = 'mapset',
params = { { 'mode', 'string' }, { 'abbr', 'any' }, { 'dict', 'any' } }, params = { { 'mode', 'string' }, { 'abbr', 'any' }, { 'dict', 'any' } },

View File

@ -123,6 +123,8 @@ static const char e_mapping_already_exists_for_str[]
= N_("E227: Mapping already exists for %s"); = N_("E227: Mapping already exists for %s");
static const char e_entries_missing_in_mapset_dict_argument[] static const char e_entries_missing_in_mapset_dict_argument[]
= N_("E460: Entries missing in mapset() dict argument"); = N_("E460: Entries missing in mapset() dict argument");
static const char e_illegal_map_mode_string_str[]
= N_("E1276: Illegal map mode string: '%s'");
/// Get the start of the hashed map list for "state" and first character "c". /// Get the start of the hashed map list for "state" and first character "c".
mapblock_T *get_maphash_list(int state, int c) mapblock_T *get_maphash_list(int state, int c)
@ -2070,11 +2072,12 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// ///
/// @param mp The maphash that contains the mapping information /// @param mp The maphash that contains the mapping information
/// @param buffer_value The "buffer" value /// @param buffer_value The "buffer" value
/// @param abbr True if abbreviation
/// @param compatible True for compatible with old maparg() dict /// @param compatible True for compatible with old maparg() dict
/// ///
/// @return A Dictionary. /// @return A Dictionary.
static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt, static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt,
const int buffer_value, const bool compatible) const int buffer_value, const bool abbr, const bool compatible)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
Dictionary dict = ARRAY_DICT_INIT; Dictionary dict = ARRAY_DICT_INIT;
@ -2113,6 +2116,7 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
PUT(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0)); PUT(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0));
PUT(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0)); PUT(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0));
PUT(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid)); PUT(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid));
PUT(dict, "scriptversion", INTEGER_OBJ(1));
PUT(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum)); PUT(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum));
PUT(dict, "buffer", INTEGER_OBJ(buffer_value)); PUT(dict, "buffer", INTEGER_OBJ(buffer_value));
PUT(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0)); PUT(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0));
@ -2120,6 +2124,8 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
PUT(dict, "replace_keycodes", INTEGER_OBJ(1)); PUT(dict, "replace_keycodes", INTEGER_OBJ(1));
} }
PUT(dict, "mode", CSTR_AS_OBJ(mapmode)); PUT(dict, "mode", CSTR_AS_OBJ(mapmode));
PUT(dict, "abbr", INTEGER_OBJ(abbr ? 1 : 0));
PUT(dict, "mode_bits", INTEGER_OBJ(mp->m_mode));
return dict; return dict;
} }
@ -2192,7 +2198,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) { if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
Dictionary dict = mapblock_fill_dict(mp, Dictionary dict = mapblock_fill_dict(mp,
did_simplify ? keys_simplified : NULL, did_simplify ? keys_simplified : NULL,
buffer_local, true); buffer_local, abbr, true);
(void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL); (void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL);
api_free_dictionary(dict); api_free_dictionary(dict);
} else { } else {
@ -2205,21 +2211,99 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
xfree(alt_keys_buf); xfree(alt_keys_buf);
} }
/// Get the mapping mode from the mode string.
/// It may contain multiple characters, eg "nox", or "!", or ' '
/// Return 0 if there is an error.
static int get_map_mode_string(const char *const mode_string, const bool abbr)
{
const char *p = mode_string;
const int MASK_V = MODE_VISUAL | MODE_SELECT;
const int MASK_MAP = MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING;
const int MASK_BANG = MODE_INSERT | MODE_CMDLINE;
if (*p == NUL) {
p = " "; // compatibility
}
int mode = 0;
int modec;
while ((modec = (uint8_t)(*p++))) {
int tmode;
switch (modec) {
case 'i':
tmode = MODE_INSERT; break;
case 'l':
tmode = MODE_LANGMAP; break;
case 'c':
tmode = MODE_CMDLINE; break;
case 'n':
tmode = MODE_NORMAL; break;
case 'x':
tmode = MODE_VISUAL; break;
case 's':
tmode = MODE_SELECT; break;
case 'o':
tmode = MODE_OP_PENDING; break;
case 't':
tmode = MODE_TERMINAL; break;
case 'v':
tmode = MASK_V; break;
case '!':
tmode = MASK_BANG; break;
case ' ':
tmode = MASK_MAP; break;
default:
return 0; // error, unknown mode character
}
mode |= tmode;
}
if ((abbr && (mode & ~MASK_BANG) != 0)
|| (!abbr && (mode & (mode - 1)) != 0 // more than one bit set
&& (
// false if multiple bits set in mode and mode is fully
// contained in one mask
!(((mode & MASK_BANG) != 0 && (mode & ~MASK_BANG) == 0)
|| ((mode & MASK_MAP) != 0 && (mode & ~MASK_MAP) == 0))))) {
return 0;
}
return mode;
}
/// "mapset()" function /// "mapset()" function
void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *which;
char buf[NUMBUFLEN]; char buf[NUMBUFLEN];
const char *which = tv_get_string_buf_chk(&argvars[0], buf); int is_abbr;
if (which == NULL) { dict_T *d;
return;
}
const int mode = get_map_mode((char **)&which, 0);
const bool is_abbr = tv_get_number(&argvars[1]) != 0;
if (tv_check_for_dict_arg(argvars, 2) == FAIL) { // If first arg is a dict, then that's the only arg permitted.
const bool dict_only = argvars[0].v_type == VAR_DICT;
if (dict_only) {
d = argvars[0].vval.v_dict;
which = tv_dict_get_string(d, "mode", false);
is_abbr = (int)tv_dict_get_bool(d, "abbr", -1);
if (which == NULL || is_abbr < 0) {
emsg(_(e_entries_missing_in_mapset_dict_argument));
return;
}
} else {
which = tv_get_string_buf_chk(&argvars[0], buf);
if (which == NULL) {
return;
}
is_abbr = (int)tv_get_bool(&argvars[1]);
if (tv_check_for_dict_arg(argvars, 2) == FAIL) {
return;
}
d = argvars[2].vval.v_dict;
}
const int mode = get_map_mode_string(which, is_abbr);
if (mode == 0) {
semsg(_(e_illegal_map_mode_string_str), which);
return; return;
} }
dict_T *d = argvars[2].vval.v_dict;
// Get the values in the same order as above in get_maparg(). // Get the values in the same order as above in get_maparg().
char *lhs = tv_dict_get_string(d, "lhs", false); char *lhs = tv_dict_get_string(d, "lhs", false);
@ -2280,6 +2364,59 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
sid, lnum, false); sid, lnum, false);
} }
/// "maplist()" function
void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
const bool abbr = argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]);
tv_list_alloc_ret(rettv, kListLenUnknown);
// Do it twice: once for global maps and once for local maps.
for (int buffer_local = 0; buffer_local <= 1; buffer_local++) {
for (int hash = 0; hash < 256; hash++) {
mapblock_T *mp;
if (abbr) {
if (hash > 0) { // there is only one abbr list
break;
}
if (buffer_local) {
mp = curbuf->b_first_abbr;
} else {
mp = first_abbr;
}
} else if (buffer_local) {
mp = curbuf->b_maphash[hash];
} else {
mp = maphash[hash];
}
for (; mp; mp = mp->m_next) {
if (mp->m_simplified) {
continue;
}
char *keys_buf = NULL;
bool did_simplify = false;
char *lhs = str2special_save(mp->m_keys, true, false);
(void)replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify,
CPO_TO_CPO_FLAGS);
xfree(lhs);
Dictionary dict = mapblock_fill_dict(mp,
did_simplify ? keys_buf : NULL,
buffer_local, abbr, true);
typval_T d = TV_INITIAL_VALUE;
(void)object_to_vim(DICTIONARY_OBJ(dict), &d, NULL);
assert(d.v_type == VAR_DICT);
tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict);
api_free_dictionary(dict);
xfree(keys_buf);
}
}
}
}
/// "maparg()" function /// "maparg()" function
void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
@ -2697,7 +2834,8 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
// Check for correct mode // Check for correct mode
if (int_mode & current_maphash->m_mode) { if (int_mode & current_maphash->m_mode) {
ADD(mappings, ADD(mappings,
DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value, false))); DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL,
buffer_value, false, false)));
} }
} }
} }

View File

@ -19,6 +19,20 @@ local sleep = helpers.sleep
local sid_api_client = -9 local sid_api_client = -9
local sid_lua = -8 local sid_lua = -8
local mode_bits_map = {
['n'] = 0x01,
['x'] = 0x02,
['o'] = 0x04,
['c'] = 0x08,
['i'] = 0x10,
['l'] = 0x20,
['s'] = 0x40,
['t'] = 0x80,
[' '] = 0x47,
['v'] = 0x42,
['!'] = 0x18,
}
describe('nvim_get_keymap', function() describe('nvim_get_keymap', function()
before_each(clear) before_each(clear)
@ -32,9 +46,12 @@ describe('nvim_get_keymap', function()
rhs='bar', rhs='bar',
expr=0, expr=0,
sid=0, sid=0,
scriptversion=1,
buffer=0, buffer=0,
nowait=0, nowait=0,
mode='n', mode='n',
mode_bits=0x01,
abbr=0,
noremap=1, noremap=1,
lnum=0, lnum=0,
} }
@ -81,6 +98,7 @@ describe('nvim_get_keymap', function()
-- The table will be the same except for the mode -- The table will be the same except for the mode
local insert_table = shallowcopy(foo_bar_map_table) local insert_table = shallowcopy(foo_bar_map_table)
insert_table['mode'] = 'i' insert_table['mode'] = 'i'
insert_table['mode_bits'] = 0x10
eq({insert_table}, meths.get_keymap('i')) eq({insert_table}, meths.get_keymap('i'))
end) end)
@ -258,8 +276,10 @@ describe('nvim_get_keymap', function()
silent=0, silent=0,
expr=0, expr=0,
sid=0, sid=0,
scriptversion=1,
buffer=0, buffer=0,
nowait=0, nowait=0,
abbr=0,
noremap=1, noremap=1,
lnum=0, lnum=0,
} }
@ -268,6 +288,7 @@ describe('nvim_get_keymap', function()
ret.lhs = lhs ret.lhs = lhs
ret.rhs = rhs ret.rhs = rhs
ret.mode = mode ret.mode = mode
ret.mode_bits = mode_bits_map[mode]
return ret return ret
end end
@ -323,10 +344,13 @@ describe('nvim_get_keymap', function()
lhsraw='| |', lhsraw='| |',
rhs='| |', rhs='| |',
mode='n', mode='n',
mode_bits=0x01,
abbr=0,
script=0, script=0,
silent=0, silent=0,
expr=0, expr=0,
sid=0, sid=0,
scriptversion=1,
buffer=0, buffer=0,
nowait=0, nowait=0,
noremap=1, noremap=1,
@ -365,15 +389,18 @@ describe('nvim_get_keymap', function()
silent=0, silent=0,
expr=0, expr=0,
sid=sid_lua, sid=sid_lua,
scriptversion=1,
buffer=0, buffer=0,
nowait=0, nowait=0,
mode='n', mode='n',
mode_bits=0x01,
abbr=0,
noremap=0, noremap=0,
lnum=0, lnum=0,
}, mapargs[1]) }, mapargs[1])
end) end)
it ('can handle map descriptions', function() it('can handle map descriptions', function()
meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"}) meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
eq({ eq({
lhs='lhs', lhs='lhs',
@ -383,9 +410,12 @@ describe('nvim_get_keymap', function()
silent=0, silent=0,
expr=0, expr=0,
sid=sid_api_client, sid=sid_api_client,
scriptversion=1,
buffer=0, buffer=0,
nowait=0, nowait=0,
mode='n', mode='n',
mode_bits=0x01,
abbr=0,
noremap=0, noremap=0,
lnum=0, lnum=0,
desc='map description' desc='map description'
@ -420,7 +450,10 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end end
local to_return = {} local to_return = {}
to_return.mode = normalize_mapmode(mode, true) local expected_mode = normalize_mapmode(mode, true)
to_return.mode = expected_mode
to_return.mode_bits = mode_bits_map[expected_mode]
to_return.abbr = mode:sub(-1) == 'a' and 1 or 0
to_return.noremap = not opts.noremap and 0 or 1 to_return.noremap = not opts.noremap and 0 or 1
to_return.lhs = lhs to_return.lhs = lhs
to_return.rhs = rhs to_return.rhs = rhs
@ -429,6 +462,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.nowait = not opts.nowait and 0 or 1 to_return.nowait = not opts.nowait and 0 or 1
to_return.expr = not opts.expr and 0 or 1 to_return.expr = not opts.expr and 0 or 1
to_return.sid = not opts.sid and sid_api_client or opts.sid to_return.sid = not opts.sid and sid_api_client or opts.sid
to_return.scriptversion = 1
to_return.buffer = not opts.buffer and 0 or opts.buffer to_return.buffer = not opts.buffer and 0 or opts.buffer
to_return.lnum = not opts.lnum and 0 or opts.lnum to_return.lnum = not opts.lnum and 0 or opts.lnum
to_return.desc = opts.desc to_return.desc = opts.desc
@ -487,7 +521,12 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
get_mapargs('', 'lhs')) get_mapargs('', 'lhs'))
end) end)
it('throws errors when given too-long mode shortnames', function() it('error on invalid mode shortname', function()
eq('Invalid mode shortname: " "', pcall_err(meths.set_keymap, ' ', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "m"', pcall_err(meths.set_keymap, 'm', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "?"', pcall_err(meths.set_keymap, '?', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "y"', pcall_err(meths.set_keymap, 'y', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "p"', pcall_err(meths.set_keymap, 'p', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "a"', pcall_err(meths.set_keymap, 'a', 'lhs', 'rhs', {})) eq('Invalid mode shortname: "a"', pcall_err(meths.set_keymap, 'a', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "oa"', pcall_err(meths.set_keymap, 'oa', 'lhs', 'rhs', {})) eq('Invalid mode shortname: "oa"', pcall_err(meths.set_keymap, 'oa', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "!o"', pcall_err(meths.set_keymap, '!o', 'lhs', 'rhs', {})) eq('Invalid mode shortname: "!o"', pcall_err(meths.set_keymap, '!o', 'lhs', 'rhs', {}))
@ -496,6 +535,11 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq('Invalid mode shortname: "map"', pcall_err(meths.set_keymap, 'map', 'lhs', 'rhs', {})) eq('Invalid mode shortname: "map"', pcall_err(meths.set_keymap, 'map', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "vmap"', pcall_err(meths.set_keymap, 'vmap', 'lhs', 'rhs', {})) eq('Invalid mode shortname: "vmap"', pcall_err(meths.set_keymap, 'vmap', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "xnoremap"', pcall_err(meths.set_keymap, 'xnoremap', 'lhs', 'rhs', {})) eq('Invalid mode shortname: "xnoremap"', pcall_err(meths.set_keymap, 'xnoremap', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: " "', pcall_err(meths.del_keymap, ' ', 'lhs'))
eq('Invalid mode shortname: "m"', pcall_err(meths.del_keymap, 'm', 'lhs'))
eq('Invalid mode shortname: "?"', pcall_err(meths.del_keymap, '?', 'lhs'))
eq('Invalid mode shortname: "y"', pcall_err(meths.del_keymap, 'y', 'lhs'))
eq('Invalid mode shortname: "p"', pcall_err(meths.del_keymap, 'p', 'lhs'))
eq('Invalid mode shortname: "a"', pcall_err(meths.del_keymap, 'a', 'lhs')) eq('Invalid mode shortname: "a"', pcall_err(meths.del_keymap, 'a', 'lhs'))
eq('Invalid mode shortname: "oa"', pcall_err(meths.del_keymap, 'oa', 'lhs')) eq('Invalid mode shortname: "oa"', pcall_err(meths.del_keymap, 'oa', 'lhs'))
eq('Invalid mode shortname: "!o"', pcall_err(meths.del_keymap, '!o', 'lhs')) eq('Invalid mode shortname: "!o"', pcall_err(meths.del_keymap, '!o', 'lhs'))
@ -506,22 +550,6 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq('Invalid mode shortname: "xnoremap"', pcall_err(meths.del_keymap, 'xnoremap', 'lhs')) eq('Invalid mode shortname: "xnoremap"', pcall_err(meths.del_keymap, 'xnoremap', 'lhs'))
end) end)
it('error on invalid mode shortname', function()
eq('Invalid mode shortname: " "',
pcall_err(meths.set_keymap, ' ', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "m"',
pcall_err(meths.set_keymap, 'm', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "?"',
pcall_err(meths.set_keymap, '?', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "y"',
pcall_err(meths.set_keymap, 'y', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "p"',
pcall_err(meths.set_keymap, 'p', 'lhs', 'rhs', {}))
eq('Invalid mode shortname: "?"', pcall_err(meths.del_keymap, '?', 'lhs'))
eq('Invalid mode shortname: "y"', pcall_err(meths.del_keymap, 'y', 'lhs'))
eq('Invalid mode shortname: "p"', pcall_err(meths.del_keymap, 'p', 'lhs'))
end)
it('error on invalid optnames', function() it('error on invalid optnames', function()
eq("Invalid key: 'silentt'", eq("Invalid key: 'silentt'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {silentt = true})) pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {silentt = true}))
@ -827,7 +855,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq(1, exec_lua[[return GlobalCount]]) eq(1, exec_lua[[return GlobalCount]])
end) end)
it (':map command shows lua mapping correctly', function() it(':map command shows lua mapping correctly', function()
exec_lua [[ exec_lua [[
vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end }) vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end })
]] ]]
@ -839,7 +867,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
) )
end) end)
it ('mapcheck() returns lua mapping correctly', function() it('mapcheck() returns lua mapping correctly', function()
exec_lua [[ exec_lua [[
vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end }) vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end })
]] ]]
@ -847,7 +875,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
"^<Lua %d+>")) "^<Lua %d+>"))
end) end)
it ('maparg() returns lua mapping correctly', function() it('maparg() returns lua mapping correctly', function()
eq(0, exec_lua([[ eq(0, exec_lua([[
GlobalCount = 0 GlobalCount = 0
vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })

View File

@ -26,9 +26,12 @@ describe('maparg()', function()
rhs='bar', rhs='bar',
expr=0, expr=0,
sid=0, sid=0,
scriptversion=1,
buffer=0, buffer=0,
nowait=0, nowait=0,
mode='n', mode='n',
mode_bits=0x01,
abbr=0,
noremap=1, noremap=1,
lnum=0, lnum=0,
} }
@ -155,10 +158,13 @@ describe('maparg()', function()
buffer = 0, buffer = 0,
expr = 0, expr = 0,
mode = 'n', mode = 'n',
mode_bits = 0x01,
abbr = 0,
noremap = 1, noremap = 1,
nowait = 0, nowait = 0,
script=0, script = 0,
sid = 0, sid = 0,
scriptversion = 1,
silent = 0, silent = 0,
lnum = 0, lnum = 0,
} }

View File

@ -1,4 +1,4 @@
" Tests for maparg(), mapcheck() and mapset(). " Tests for maparg(), mapcheck(), mapset(), maplist()
" Also test utf8 map with a 0x80 byte. " Also test utf8 map with a 0x80 byte.
source shared.vim source shared.vim
@ -19,28 +19,41 @@ func Test_maparg()
call assert_equal("is<F4>foo", maparg('foo<C-V>')) call assert_equal("is<F4>foo", maparg('foo<C-V>'))
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>', call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>',
\ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16", \ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16",
\ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
\ 'rhs': 'is<F4>foo', 'buffer': 0}, \ 'lnum': lnum + 1,
\ 'rhs': 'is<F4>foo', 'buffer': 0, 'abbr': 0, 'mode_bits': 0x47},
\ maparg('foo<C-V>', '', 0, 1)) \ maparg('foo<C-V>', '', 0, 1))
call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar',
\ 'lhsraw': 'bar', 'mode': 'v', \ 'lhsraw': 'bar', 'mode': 'v',
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2, \ 'nowait': 0, 'expr': 1, 'sid': sid, 'scriptversion': 1,
\ 'rhs': 'isbar', 'buffer': 1}, \ 'lnum': lnum + 2,
\ 'rhs': 'isbar', 'buffer': 1, 'abbr': 0, 'mode_bits': 0x42},
\ 'bar'->maparg('', 0, 1)) \ 'bar'->maparg('', 0, 1))
let lnum = expand('<sflnum>') let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar map <buffer> <nowait> foo bar
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo',
\ 'lhsraw': 'foo', 'mode': ' ', \ 'lhsraw': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar', \ 'nowait': 1, 'expr': 0, 'sid': sid, 'scriptversion': 1,
\ 'buffer': 1}, \ 'lnum': lnum + 1, 'rhs': 'bar',
\ 'buffer': 1, 'abbr': 0, 'mode_bits': 0x47},
\ maparg('foo', '', 0, 1)) \ maparg('foo', '', 0, 1))
let lnum = expand('<sflnum>') let lnum = expand('<sflnum>')
tmap baz foo tmap baz foo
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz',
\ 'lhsraw': 'baz', 'mode': 't', \ 'lhsraw': 'baz', 'mode': 't',
\ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo', \ 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
\ 'buffer': 0}, \ 'lnum': lnum + 1, 'rhs': 'foo',
\ 'buffer': 0, 'abbr': 0, 'mode_bits': 0x80},
\ maparg('baz', 't', 0, 1)) \ maparg('baz', 't', 0, 1))
let lnum = expand('<sflnum>')
iab A B
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'A',
\ 'lhsraw': 'A', 'mode': 'i',
\ 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
\ 'lnum': lnum + 1, 'rhs': 'B',
\ 'buffer': 0, 'abbr': 1, 'mode_bits': 0x0010},
\ maparg('A', 'i', 1, 1))
iuna A
map abc x<char-114>x map abc x<char-114>x
call assert_equal("xrx", maparg('abc')) call assert_equal("xrx", maparg('abc'))
@ -274,6 +287,152 @@ func Test_mapset()
call assert_fails('call mapset("i", 0, {})', 'E460:') call assert_fails('call mapset("i", 0, {})', 'E460:')
endfunc endfunc
func Test_mapset_arg1_dir()
" This test is mostly about get_map_mode_string.
" Once the code gets past that, it's common with the 3 arg mapset.
" GetModes() return list of modes for 'XZ' lhs using maplist.
" There is one list item per mapping
func s:GetModes(abbr = v:false)
return maplist(a:abbr)->filter({_, m -> m.lhs == 'XZ'})
\ ->mapnew({_, m -> m.mode})
endfunc
func s:UnmapAll(lhs)
const unmap_cmds = [ 'unmap', 'unmap!', 'tunmap', 'lunmap' ]
for cmd in unmap_cmds
try | call execute(cmd .. ' ' .. a:lhs) | catch /E31/ | endtry
endfor
endfunc
let tmap = {}
" some mapset(mode, abbr, dict) tests using get_map_mode_str
map XZ x
let tmap = maplist()->filter({_, m -> m.lhs == 'XZ'})[0]->copy()
" this splits the mapping into 2 mappings
call mapset('ox', v:false, tmap)
call assert_equal(2, len(s:GetModes()))
call mapset('o', v:false, tmap)
call assert_equal(3, len(s:GetModes()))
" test that '' acts like ' ', and that the 3 mappings become 1
call mapset('', v:false, tmap)
call assert_equal([' '], s:GetModes())
" dict's mode/abbr are ignored
call s:UnmapAll('XZ')
let tmap.mode = '!'
let tmap.abbr = v:true
call mapset('o', v:false, tmap)
call assert_equal(['o'], s:GetModes())
" test the 3 arg version handles bad mode string, dict not used
call assert_fails("call mapset('vi', v:false, {})", 'E1276:')
" get the abbreviations out of the way
abbreviate XZ ZX
let tmap = maplist(v:true)->filter({_, m -> m.lhs == 'XZ'})[0]->copy()
abclear
" 'ic' is the default ab command, shows up as '!'
let tmap.mode = 'ic'
call mapset(tmap)
call assert_equal(['!'], s:GetModes(v:true))
abclear
let tmap.mode = 'i'
call mapset(tmap)
call assert_equal(['i'], s:GetModes(v:true))
abclear
let tmap.mode = 'c'
call mapset(tmap)
call assert_equal(['c'], s:GetModes(v:true))
abclear
let tmap.mode = '!'
call mapset(tmap)
call assert_equal(['!'], s:GetModes(v:true))
call assert_fails("call mapset(#{mode: ' !', abbr: 1})", 'E1276:')
call assert_fails("call mapset(#{mode: 'cl', abbr: 1})", 'E1276:')
call assert_fails("call mapset(#{mode: 'in', abbr: 1})", 'E1276:')
" the map commands
map XZ x
let tmap = maplist()->filter({_, m -> m.lhs == 'XZ'})[0]->copy()
" try the combos
call s:UnmapAll('XZ')
" 'nxso' is ' ', the unadorned :map
let tmap.mode = 'nxso'
call mapset(tmap)
call assert_equal([' '], s:GetModes())
cal s:UnmapAll('XZ')
" 'ic' is '!'
let tmap.mode = 'ic'
call mapset(tmap)
call assert_equal(['!'], s:GetModes())
call s:UnmapAll('XZ')
" 'xs' is really 'v'
let tmap.mode = 'xs'
call mapset(tmap)
call assert_equal(['v'], s:GetModes())
" try the individual modes
call s:UnmapAll('XZ')
let tmap.mode = 'n'
call mapset(tmap)
call assert_equal(['n'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 'x'
call mapset(tmap)
call assert_equal(['x'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 's'
call mapset(tmap)
call assert_equal(['s'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 'o'
call mapset(tmap)
call assert_equal(['o'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 'i'
call mapset(tmap)
call assert_equal(['i'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 'c'
call mapset(tmap)
call assert_equal(['c'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 't'
call mapset(tmap)
call assert_equal(['t'], s:GetModes())
call s:UnmapAll('XZ')
let tmap.mode = 'l'
call mapset(tmap)
call assert_equal(['l'], s:GetModes())
call s:UnmapAll('XZ')
" get errors for modes that can't be in one mapping
call assert_fails("call mapset(#{mode: 'nxsoi', abbr: 0})", 'E1276:')
call assert_fails("call mapset(#{mode: ' !', abbr: 0})", 'E1276:')
call assert_fails("call mapset(#{mode: 'ix', abbr: 0})", 'E1276:')
call assert_fails("call mapset(#{mode: 'tl', abbr: 0})", 'E1276:')
call assert_fails("call mapset(#{mode: ' l', abbr: 0})", 'E1276:')
call assert_fails("call mapset(#{mode: ' t', abbr: 0})", 'E1276:')
endfunc
func Check_ctrlb_map(d, check_alt) func Check_ctrlb_map(d, check_alt)
call assert_equal('<C-B>', a:d.lhs) call assert_equal('<C-B>', a:d.lhs)
if a:check_alt if a:check_alt
@ -368,4 +527,92 @@ func Test_map_restore_negative_sid()
call delete('Xresult') call delete('Xresult')
endfunc endfunc
func Test_maplist()
new
func s:ClearMappingsAbbreviations()
mapclear | nmapclear | vmapclear | xmapclear | smapclear | omapclear
mapclear! | imapclear | lmapclear | cmapclear | tmapclear
mapclear <buffer> | nmapclear <buffer> | vmapclear <buffer>
xmapclear <buffer> | smapclear <buffer> | omapclear <buffer>
mapclear! <buffer> | imapclear <buffer> | lmapclear <buffer>
cmapclear <buffer> | tmapclear <buffer>
abclear | abclear <buffer>
endfunc
func s:AddMaps(new, accum)
if len(a:new) > 0 && a:new[0] != "No mapping found"
eval a:accum->extend(a:new)
endif
endfunc
call s:ClearMappingsAbbreviations()
call assert_equal(0, len(maplist()))
call assert_equal(0, len(maplist(v:true)))
" Set up some mappings.
map dup bar
map <buffer> dup bufbar
map foo<C-V> is<F4>foo
vnoremap <script> <buffer> <expr> <silent> bar isbar
tmap baz foo
omap h w
lmap i w
nmap j w
xmap k w
smap l w
map abc <Nop>
nmap <M-j> x
nmap <M-Space> y
" And abbreviations
abbreviate xy he
abbreviate xx she
abbreviate <buffer> x they
" Get a list of the mappings with the ':map' commands.
" Check maplist() return a list of the same size.
call assert_equal(13, len(maplist()))
call assert_equal(3, len(maplist(v:true)))
call assert_equal(13, len(maplist(v:false)))
" collect all the current maps using :map commands
let maps_command = []
call s:AddMaps(split(execute('map'), '\n'), maps_command)
call s:AddMaps(split(execute('map!'), '\n'), maps_command)
call s:AddMaps(split(execute('tmap'), '\n'), maps_command)
call s:AddMaps(split(execute('lmap'), '\n'), maps_command)
" Use maplist to get all the maps
let maps_maplist = maplist()
call assert_equal(len(maps_command), len(maps_maplist))
" make sure all the mode-lhs are unique, no duplicates
let map_set = {}
for d in maps_maplist
let map_set[d.mode .. "-" .. d.lhs .. "-" .. d.buffer] = 0
endfor
call assert_equal(len(maps_maplist), len(map_set))
" For everything returned by maplist, should be the same as from maparg.
" Except for "map dup", bacause maparg returns the <buffer> version
for d in maps_maplist
if d.lhs == 'dup' && d.buffer == 0
continue
endif
let d_maparg = maparg(d.lhs, d.mode, v:false, v:true)
call assert_equal(d_maparg, d)
endfor
" Check abbr matches maparg
for d in maplist(v:true)
" Note, d.mode is '!', but can't use that with maparg
let d_maparg = maparg(d.lhs, 'i', v:true, v:true)
call assert_equal(d_maparg, d)
endfor
call s:ClearMappingsAbbreviations()
call assert_equal(0, len(maplist()))
call assert_equal(0, len(maplist(v:true)))
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab