aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/scripts/install_deps.sh2
-rw-r--r--.github/workflows/test.yml1
-rw-r--r--runtime/doc/builtin.txt74
-rw-r--r--runtime/doc/map.txt2
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt18
-rw-r--r--runtime/doc/options.txt6
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--runtime/doc/vim_diff.txt4
-rw-r--r--runtime/ftplugin/wget.vim4
-rw-r--r--runtime/ftplugin/wget2.vim4
-rw-r--r--runtime/lua/vim/_meta/options.lua4
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua80
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim66
-rw-r--r--runtime/syntax/wget.vim294
-rw-r--r--runtime/syntax/wget2.vim56
-rw-r--r--src/man/nvim.15
-rw-r--r--src/nvim/api/command.c2
-rw-r--r--src/nvim/api/private/helpers.h2
-rw-r--r--src/nvim/autocmd.c4
-rw-r--r--src/nvim/cmdexpand.c6
-rw-r--r--src/nvim/context.c2
-rw-r--r--src/nvim/digraph.c4
-rw-r--r--src/nvim/eval.c18
-rw-r--r--src/nvim/eval.lua82
-rw-r--r--src/nvim/eval/funcs.c9
-rw-r--r--src/nvim/eval/userfunc.c12
-rw-r--r--src/nvim/eval/vars.c2
-rw-r--r--src/nvim/ex_cmds.c2
-rw-r--r--src/nvim/ex_docmd.c4
-rw-r--r--src/nvim/file_search.c2
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/indent.c4
-rw-r--r--src/nvim/lua/executor.c2
-rw-r--r--src/nvim/mapping.c207
-rw-r--r--src/nvim/match.c2
-rw-r--r--src/nvim/menu.c4
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/ops.c6
-rw-r--r--src/nvim/option.c4
-rw-r--r--src/nvim/options.lua6
-rw-r--r--src/nvim/optionstr.c5
-rw-r--r--src/nvim/os/env.c9
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/sign.c12
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/spellsuggest.c2
-rw-r--r--src/nvim/state.c2
-rw-r--r--src/nvim/strings.c2
-rw-r--r--src/nvim/tag.c2
-rw-r--r--src/nvim/window.c2
-rw-r--r--test/functional/api/keymap_spec.lua92
-rw-r--r--test/functional/core/job_spec.lua38
-rw-r--r--test/functional/lua/vim_spec.lua2
-rw-r--r--test/functional/ui/inccommand_spec.lua28
-rw-r--r--test/functional/ui/messages_spec.lua59
-rw-r--r--test/functional/vimscript/map_functions_spec.lua8
-rw-r--r--test/old/testdir/setup.vim5
-rw-r--r--test/old/testdir/test_map_functions.vim (renamed from test/old/testdir/test_maparg.vim)265
-rw-r--r--test/old/testdir/test_mapping.vim1
-rw-r--r--test/old/testdir/test_modeline.vim2
-rw-r--r--test/old/testdir/test_statusline.vim21
-rw-r--r--test/old/testdir/test_termdebug.vim197
65 files changed, 1356 insertions, 419 deletions
diff --git a/.github/scripts/install_deps.sh b/.github/scripts/install_deps.sh
index 0533bd7fae..9a782e9698 100755
--- a/.github/scripts/install_deps.sh
+++ b/.github/scripts/install_deps.sh
@@ -30,7 +30,7 @@ if [[ $os == Linux ]]; then
fi
if [[ -n $TEST ]]; then
- sudo apt-get install -y locales-all cpanminus attr libattr1-dev
+ sudo apt-get install -y locales-all cpanminus attr libattr1-dev gdb
fi
elif [[ $os == Darwin ]]; then
brew update --quiet
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1ebb26d5c0..acf0f195b9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -23,7 +23,6 @@ env:
LOG_DIR: ${{ github.workspace }}/build/log
NVIM_LOG_FILE: ${{ github.workspace }}/build/.nvimlog
TSAN_OPTIONS: log_path=${{ github.workspace }}/build/log/tsan
- UBSAN_OPTIONS: log_path=${{ github.workspace }}/build/log/ubsan
VALGRIND_LOG: ${{ github.workspace }}/build/log/valgrind-%p.log
# TEST_FILE: test/functional/core/startup_spec.lua
# TEST_FILTER: foo
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 35c94d6c74..bc4d1f30c9 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -4133,7 +4133,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is omitted or zero: Return the rhs of mapping
{name} in mode {mode}. The returned String has special
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
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
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
"lhsraw" The {lhs} of the mapping as raw bytes
"lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
@@ -4180,9 +4181,16 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
(|mapmode-ic|)
"sid" The script local ID, used for <sid> mappings
(|<SID>|). Negative for special contexts.
+ "scriptversion" The version of the script, always 1.
"lnum" The line number in "sid", zero if unknown.
"nowait" Do not wait for other, longer mappings.
(|: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
|mapset()|.
@@ -4226,6 +4234,37 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()*
< This avoids adding the "_vv" mapping when there already is a
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()*
Like |map()| but instead of replacing items in {expr1} a new
List or Dictionary is created and returned. {expr1} remains
@@ -4233,9 +4272,17 @@ mapnew({expr1}, {expr2}) *mapnew()*
don't want that use |deepcopy()| first.
mapset({mode}, {abbr}, {dict}) *mapset()*
- Restore a mapping from a dictionary returned by |maparg()|.
- {mode} and {abbr} should be the same as for the call to
- |maparg()|. *E460*
+ Restore a mapping from a dictionary, possibly returned by
+ |maparg()| or |maplist()|. A buffer mapping, when dict.buffer
+ 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,
not the "mode" entry in {dict}.
Example for saving and restoring a mapping: >vim
@@ -4244,8 +4291,21 @@ mapset({mode}, {abbr}, {dict}) *mapset()*
" ...
call mapset('n', 0, save_map)
< 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
- them, since they can differ.
+ e.g. with `:map!`, you need to save/restore the mapping for
+ 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()*
When {expr} is a |List| then this returns the index of the
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 56e58baad8..6f61259af0 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -955,7 +955,7 @@ operator to add quotes around text in the current line: >
\ ->setline(".")}'<CR>g@
==============================================================================
-2. Abbreviations *abbreviations* *Abbreviations*
+2. Abbreviations *abbreviation* *abbreviations* *Abbreviations*
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
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index 2f7197e2ef..f038163ec2 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -399,18 +399,22 @@ Prompt mode can be used with: >vim
If there is no g:termdebug_config you can use: >vim
let g:termdebug_use_prompt = 1
<
- *termdebug_map_K*
-The K key is normally mapped to |:Evaluate|. If you do not want this use: >vim
+Mappings ~
+ *termdebug_map_K* *termdebug-mappings*
+The K key is normally mapped to |:Evaluate| unless a buffer local (|:map-local|)
+mapping to K already exists. If you do not want this use: >vim
let g:termdebug_config['map_K'] = 0
If there is no g:termdebug_config you can use: >vim
let g:termdebug_map_K = 0
<
*termdebug_map_minus*
-The - key is normally mapped to |:Down|. If you do not want this use: >vim
+The - key is normally mapped to |:Down| unless a buffer local mapping to the -
+key already exists. If you do not want this use: >vim
let g:termdebug_config['map_minus'] = 0
<
*termdebug_map_plus*
-The + key is normally mapped to |:Up|. If you do not want this use: >vim
+The + key is normally mapped to |:Up| unless a buffer local mapping to the +
+key already exists. If you do not want this use: >vim
let g:termdebug_config['map_plus'] = 0
<
*termdebug_disasm_window*
@@ -421,6 +425,9 @@ If you want the Asm window shown by default, set the "disasm_window" flag to
If there is no g:termdebug_config you can use: >vim
let g:termdebug_disasm_window = 15
Any value greater than 1 will set the Asm window height to that value.
+If the current window has enough horizontal space, it will be vertically split
+and the Asm window will be shown side by side with the source code window (and
+the height option won't be used).
*termdebug_variables_window*
If you want the Var window shown by default, set the "variables_window" flag
@@ -431,6 +438,9 @@ height: >vim
If there is no g:termdebug_config you can use: >vim
let g:termdebug_variables_window = 15
Any value greater than 1 will set the Var window height to that value.
+If the current window has enough horizontal space, it will be vertically split
+and the Var window will be shown side by side with the source code window (and
+the height options won't be used).
Communication ~
*termdebug-communication*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index b2a020cf9d..d92e528214 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2521,10 +2521,8 @@ A jump table for the options with a short description can be found at |Q_op|.
default to single-byte alternatives.
Example: >
- :set fillchars=stl:^,stlnc:=,vert:│,fold:·,diff:-
-< This is similar to the default, except that these characters will also
- be used when there is highlighting.
-
+ :set fillchars=stl:\ ,stlnc:\ ,vert:│,fold:·,diff:-
+<
For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
single-byte and multibyte characters are supported. But double-width
characters are not supported.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index c8b31b2d5b..e206a804f4 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1015,6 +1015,7 @@ Mappings and Menus: *mapping-functions*
hasmapto() check if a mapping exists
mapcheck() check if a matching mapping exists
maparg() get rhs of a mapping
+ maplist() get list of all mappings
mapset() restore a mapping
menu_info() get information about a menu item
wildmenumode() check if the wildmode is active
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index efebf46d85..1e12ccd7cc 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -550,10 +550,6 @@ Vimscript compatibility:
`shell_error` does not alias to |v:shell_error|
`this_session` does not alias to |v:this_session|
-UI/Display:
- 'statusline' always uses the "stl" and "stlnc" fields of 'fillchars', even
- if they are the same and |hl-StatusLine| and |hl-StatusLineNC| are equal.
-
Working directory (Vim implemented some of these after Nvim):
- |DirChanged| and |DirChangedPre| can be triggered when switching to another
window or tab.
diff --git a/runtime/ftplugin/wget.vim b/runtime/ftplugin/wget.vim
index 7a10221824..db3b62191e 100644
--- a/runtime/ftplugin/wget.vim
+++ b/runtime/ftplugin/wget.vim
@@ -1,5 +1,5 @@
" Vim filetype plugin file
-" Language: Wget configuration file (/etc/wgetrc ~/.wgetrc)
+" Language: Wget configuration file (/etc/wgetrc ~/.wgetrc)
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2022 Apr 28
@@ -18,7 +18,7 @@ setlocal formatoptions-=t formatoptions+=croql
let b:undo_ftplugin = "setl fo< com< cms<"
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
- let b:browsefilter = "Wget Configuration File (wgetrc, .wgetrc)\twgetrc;.wgetrc\n" .
+ let b:browsefilter = "Wget Configuration File (wgetrc, .wgetrc)\twgetrc;.wgetrc\n" ..
\ "All Files (*.*)\t*.*\n"
let b:undo_ftplugin ..= " | unlet! b:browsefilter"
endif
diff --git a/runtime/ftplugin/wget2.vim b/runtime/ftplugin/wget2.vim
index a6845f6df5..8cfcd514e5 100644
--- a/runtime/ftplugin/wget2.vim
+++ b/runtime/ftplugin/wget2.vim
@@ -1,5 +1,5 @@
" Vim filetype plugin file
-" Language: Wget2 configuration file (/etc/wget2rc ~/.wget2rc)
+" Language: Wget2 configuration file (/etc/wget2rc ~/.wget2rc)
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2022 Apr 28
@@ -18,7 +18,7 @@ setlocal formatoptions-=t formatoptions+=croql
let b:undo_ftplugin = "setl fo< com< cms<"
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
- let b:browsefilter = "Wget2 Configuration File (wget2rc, .wget2rc)\twget2rc;.wget2rc\n" .
+ let b:browsefilter = "Wget2 Configuration File (wget2rc, .wget2rc)\twget2rc;.wget2rc\n" ..
\ "All Files (*.*)\t*.*\n"
let b:undo_ftplugin ..= " | unlet! b:browsefilter"
endif
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index a986cd752c..53f7166b3d 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -2217,10 +2217,8 @@ vim.bo.ft = vim.bo.filetype
---
--- Example:
--- ```
---- :set fillchars=stl:^,stlnc:=,vert:│,fold:·,diff:-
+--- :set fillchars=stl:\ ,stlnc:\ ,vert:│,fold:·,diff:-
--- ```
---- This is similar to the default, except that these characters will also
---- be used when there is highlighting.
---
--- For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
--- single-byte and multibyte characters are supported. But double-width
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 0563f9dd5f..d1e676ef70 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -4994,7 +4994,8 @@ function vim.fn.map(expr1, expr2) end
--- When {dict} is omitted or zero: Return the rhs of mapping
--- {name} in mode {mode}. The returned String has special
--- 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
--- 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
--- 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
--- "lhsraw" The {lhs} of the mapping as raw bytes
--- "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
@@ -5041,9 +5042,16 @@ function vim.fn.map(expr1, expr2) end
--- (|mapmode-ic|)
--- "sid" The script local ID, used for <sid> mappings
--- (|<SID>|). Negative for special contexts.
+--- "scriptversion" The version of the script, always 1.
--- "lnum" The line number in "sid", zero if unknown.
--- "nowait" Do not wait for other, longer mappings.
--- (|: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
--- |mapset()|.
@@ -5099,6 +5107,39 @@ function vim.fn.maparg(name, mode, abbr, dict) end
--- @return any
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
--- List or Dictionary is created and returned. {expr1} remains
--- unchanged. Items can still be changed by {expr2}, if you
@@ -5109,9 +5150,17 @@ function vim.fn.mapcheck(name, mode, abbr) end
--- @return any
function vim.fn.mapnew(expr1, expr2) end
---- Restore a mapping from a dictionary returned by |maparg()|.
---- {mode} and {abbr} should be the same as for the call to
---- |maparg()|. *E460*
+--- Restore a mapping from a dictionary, possibly returned by
+--- |maparg()| or |maplist()|. A buffer mapping, when dict.buffer
+--- 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,
--- not the "mode" entry in {dict}.
--- 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)
--- <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
---- them, since they can differ.
+--- e.g. with `:map!`, you need to save/restore the mapping for
+--- 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 abbr any
---- @param dict any
+--- @param abbr? any
+--- @param dict? any
--- @return any
function vim.fn.mapset(mode, abbr, dict) end
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index a0710476a9..8beca8ffb3 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -2,7 +2,7 @@
"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"
-" Last Change: 2023 Aug 23
+" Last Change: 2023 Nov 02
"
" WORK IN PROGRESS - The basics works stable, more to come
" Note: In general you need at least GDB 7.12 because this provides the
@@ -894,7 +894,9 @@ func s:ParseVarinfo(varinfo)
let nameIdx = matchstrpos(a:varinfo, '{name="\([^"]*\)"')
let dict['name'] = a:varinfo[nameIdx[1] + 7 : nameIdx[2] - 2]
let typeIdx = matchstrpos(a:varinfo, ',type="\([^"]*\)"')
- let dict['type'] = a:varinfo[typeIdx[1] + 7 : typeIdx[2] - 2]
+ " 'type' maybe is a url-like string,
+ " try to shorten it and show only the /tail
+ let dict['type'] = (a:varinfo[typeIdx[1] + 7 : typeIdx[2] - 2])->fnamemodify(':t')
let valueIdx = matchstrpos(a:varinfo, ',value="\(.*\)"}')
if valueIdx[1] == -1
let dict['value'] = 'Complex value'
@@ -1022,7 +1024,9 @@ func s:InstallCommands()
endif
if map
let s:k_map_saved = maparg('K', 'n', 0, 1)
- nnoremap K :Evaluate<CR>
+ if !empty(s:k_map_saved) && !s:k_map_saved.buffer || empty(s:k_map_saved)
+ nnoremap K :Evaluate<CR>
+ endif
endif
let map = 1
@@ -1031,7 +1035,9 @@ func s:InstallCommands()
endif
if map
let s:plus_map_saved = maparg('+', 'n', 0, 1)
- nnoremap <expr> + $'<Cmd>{v:count1}Up<CR>'
+ if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer || empty(s:plus_map_saved)
+ nnoremap <expr> + $'<Cmd>{v:count1}Up<CR>'
+ endif
endif
let map = 1
@@ -1040,7 +1046,9 @@ func s:InstallCommands()
endif
if map
let s:minus_map_saved = maparg('-', 'n', 0, 1)
- nnoremap <expr> - $'<Cmd>{v:count1}Down<CR>'
+ if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer || empty(s:minus_map_saved)
+ nnoremap <expr> - $'<Cmd>{v:count1}Down<CR>'
+ endif
endif
@@ -1106,29 +1114,29 @@ func s:DeleteCommands()
delcommand Winbar
if exists('s:k_map_saved')
- if empty(s:k_map_saved)
+ if !empty(s:k_map_saved) && !s:k_map_saved.buffer
+ nunmap K
+ call mapset(s:k_map_saved)
+ elseif empty(s:k_map_saved)
nunmap K
- else
- " call mapset(s:k_map_saved)
- call mapset('n', 0, s:k_map_saved)
endif
unlet s:k_map_saved
endif
if exists('s:plus_map_saved')
- if empty(s:plus_map_saved)
+ if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer
+ nunmap +
+ call mapset(s:plus_map_saved)
+ elseif empty(s:plus_map_saved)
nunmap +
- else
- " call mapset(s:plus_map_saved)
- call mapset('n', 0, s:plus_map_saved)
endif
unlet s:plus_map_saved
endif
if exists('s:minus_map_saved')
- if empty(s:minus_map_saved)
+ if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer
+ nunmap -
+ call mapset(s:minus_map_saved)
+ elseif empty(s:minus_map_saved)
nunmap -
- else
- " call mapset(s:minus_map_saved)
- call mapset('n', 0, s:minus_map_saved)
endif
unlet s:minus_map_saved
endif
@@ -1556,8 +1564,15 @@ endfunc
func s:GotoAsmwinOrCreateIt()
if !win_gotoid(s:asmwin)
+ let mdf = ''
if win_gotoid(s:sourcewin)
- exe 'rightbelow new'
+ " 60 is approx spaceBuffer * 3
+ if winwidth(0) > (78 + 60)
+ let mdf = 'vert'
+ exe mdf .. ' ' .. 60 .. 'new'
+ else
+ exe 'rightbelow new'
+ endif
else
exe 'new'
endif
@@ -1579,7 +1594,7 @@ func s:GotoAsmwinOrCreateIt()
let s:asmbuf = bufnr('Termdebug-asm-listing')
endif
- if s:GetDisasmWindowHeight() > 0
+ if mdf != 'vert' && s:GetDisasmWindowHeight() > 0
exe 'resize ' .. s:GetDisasmWindowHeight()
endif
endif
@@ -1619,8 +1634,15 @@ endfunc
func s:GotoVariableswinOrCreateIt()
if !win_gotoid(s:varwin)
+ let mdf = ''
if win_gotoid(s:sourcewin)
- exe 'rightbelow new'
+ " 60 is approx spaceBuffer * 3
+ if winwidth(0) > (78 + 60)
+ let mdf = 'vert'
+ exe mdf .. ' ' .. 60 .. 'new'
+ else
+ exe 'rightbelow new'
+ endif
else
exe 'new'
endif
@@ -1641,7 +1663,7 @@ func s:GotoVariableswinOrCreateIt()
let s:varbuf = bufnr('Termdebug-variables-listing')
endif
- if s:GetVariablesWindowHeight() > 0
+ if mdf != 'vert' && s:GetVariablesWindowHeight() > 0
exe 'resize ' .. s:GetVariablesWindowHeight()
endif
endif
@@ -1910,3 +1932,5 @@ call s:InitAutocmd()
let &cpo = s:keepcpo
unlet s:keepcpo
+
+" vim: sw=2 sts=2 et
diff --git a/runtime/syntax/wget.vim b/runtime/syntax/wget.vim
index 8178d02bad..93206c2005 100644
--- a/runtime/syntax/wget.vim
+++ b/runtime/syntax/wget.vim
@@ -1,7 +1,7 @@
" Vim syntax file
-" Language: Wget configuration file (/etc/wgetrc ~/.wgetrc)
+" Language: Wget configuration file (/etc/wgetrc ~/.wgetrc)
" Maintainer: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2022 Apr 28
+" Last Change: 2023 Nov 05
" GNU Wget 1.21 built on linux-gnu.
@@ -12,7 +12,7 @@ endif
let s:cpo_save = &cpo
set cpo&vim
-syn match wgetComment "#.*$" contains=wgetTodo contained
+syn match wgetComment "#.*" contains=wgetTodo contained
syn keyword wgetTodo TODO NOTE FIXME XXX contained
@@ -21,208 +21,206 @@ syn region wgetString start=+'+ skip=+\\\\\|\\'+ end=+'+ contained oneline
syn case ignore
-syn keyword wgetBoolean on off yes no contained
-syn keyword wgetNumber inf contained
-
-syn match wgetNumber "\<\d\+>" contained
-syn match wgetQuota "\<\d\+[kmgt]\>" contained
-syn match wgetTime "\<\d\+[smhdw]\>" contained
+syn keyword wgetBoolean on off yes no contained
+syn keyword wgetNumber inf contained
+syn match wgetNumber "\<\d\+>" contained
+syn match wgetQuota "\<\d\+[kmgt]\>" contained
+syn match wgetTime "\<\d\+[smhdw]\>" contained
"{{{ Commands
let s:commands =<< trim EOL
accept
- accept_regex
- add_host_dir
- adjust_extension
- always_rest
- ask_password
- auth_no_challenge
+ accept-regex
+ add-host-dir
+ adjust-extension
+ always-rest
+ ask-password
+ auth-no-challenge
background
- backup_converted
+ backup-converted
backups
base
- bind_address
- bind_dns_address
- body_data
- body_file
- ca_certificate
- ca_directory
+ bind-address
+ bind-dns-address
+ body-data
+ body-file
+ ca-certificate
+ ca-directory
cache
certificate
- certificate_type
- check_certificate
- choose_config
+ certificate-type
+ check-certificate
+ choose-config
ciphers
compression
- connect_timeout
- content_disposition
- content_on_error
+ connect-timeout
+ content-disposition
+ content-on-error
continue
- convert_file_only
- convert_links
+ convert-file-only
+ convert-links
cookies
- crl_file
- cut_dirs
+ crl-file
+ cut-dirs
debug
- default_page
- delete_after
- dns_cache
- dns_servers
- dns_timeout
- dir_prefix
- dir_struct
+ default-page
+ delete-after
+ dns-cache
+ dns-servers
+ dns-timeout
+ dir-prefix
+ dir-struct
domains
- dot_bytes
- dots_in_line
- dot_spacing
- dot_style
- egd_file
- exclude_directories
- exclude_domains
- follow_ftp
- follow_tags
- force_html
- ftp_passwd
- ftp_password
- ftp_user
- ftp_proxy
- ftps_clear_data_connection
- ftps_fallback_to_ftp
- ftps_implicit
- ftps_resume_ssl
+ dot-bytes
+ dots-in-line
+ dot-spacing
+ dot-style
+ egd-file
+ exclude-directories
+ exclude-domains
+ follow-ftp
+ follow-tags
+ force-html
+ ftp-passwd
+ ftp-password
+ ftp-user
+ ftp-proxy
+ ftps-clear-data-connection
+ ftps-fallback-to-ftp
+ ftps-implicit
+ ftps-resume-ssl
hsts
- hsts_file
- ftp_stmlf
+ hsts-file
+ ftp-stmlf
glob
header
- html_extension
+ html-extension
htmlify
- http_keep_alive
- http_passwd
- http_password
- http_proxy
- https_proxy
- https_only
- http_user
- if_modified_since
- ignore_case
- ignore_length
- ignore_tags
- include_directories
- inet4_only
- inet6_only
+ http-keep-alive
+ http-passwd
+ http-password
+ http-proxy
+ https-proxy
+ https-only
+ http-user
+ if-modified-since
+ ignore-case
+ ignore-length
+ ignore-tags
+ include-directories
+ inet4-only
+ inet6-only
input
- input_meta_link
+ input-meta-link
iri
- keep_bad_hash
- keep_session_cookies
- kill_longer
- limit_rate
- load_cookies
+ keep-bad-hash
+ keep-session-cookies
+ kill-longer
+ limit-rate
+ load-cookies
locale
- local_encoding
+ local-encoding
logfile
login
- max_redirect
- metalink_index
- metalink_over_http
+ max-redirect
+ metalink-index
+ metalink-over-http
method
mirror
netrc
- no_clobber
- no_config
- no_parent
- no_proxy
+ no-clobber
+ no-config
+ no-parent
+ no-proxy
numtries
- output_document
- page_requisites
- passive_ftp
+ output-document
+ page-requisites
+ passive-ftp
passwd
password
- pinned_pubkey
- post_data
- post_file
- prefer_family
- preferred_location
- preserve_permissions
- private_key
- private_key_type
+ pinned-pubkey
+ post-data
+ post-file
+ prefer-family
+ preferred-location
+ preserve-permissions
+ private-key
+ private-key-type
progress
- protocol_directories
- proxy_passwd
- proxy_password
- proxy_user
+ protocol-directories
+ proxy-passwd
+ proxy-password
+ proxy-user
quiet
quota
- random_file
- random_wait
- read_timeout
- rec_level
+ random-file
+ random-wait
+ read-timeout
+ rec-level
recursive
referer
- regex_type
+ regex-type
reject
- rejected_log
- reject_regex
- relative_only
- remote_encoding
- remove_listing
- report_speed
- restrict_file_names
- retr_symlinks
- retry_connrefused
- retry_on_host_error
- retry_on_http_error
+ rejected-log
+ reject-regex
+ relative-only
+ remote-encoding
+ remove-listing
+ report-speed
+ restrict-file-names
+ retr-symlinks
+ retry-connrefused
+ retry-on-host-error
+ retry-on-http-error
robots
- save_cookies
- save_headers
- secure_protocol
- server_response
- show_all_dns_entries
- show_progress
- simple_host_check
- span_hosts
+ save-cookies
+ save-headers
+ secure-protocol
+ server-response
+ show-all-dns-entries
+ show-progress
+ simple-host-check
+ span-hosts
spider
- start_pos
- strict_comments
+ start-pos
+ strict-comments
sslcertfile
sslcertkey
timeout
timestamping
- use_server_timestamps
+ use-server-timestamps
tries
- trust_server_names
+ trust-server-names
unlink
- use_askpass
+ use-askpass
user
- use_proxy
- user_agent
+ use-proxy
+ user-agent
verbose
wait
- wait_retry
- warc_cdx
- warc_cdx_dedup
- warc_compression
- warc_digests
- warc_file
- warc_header
- warc_keep_log
- warc_max_size
- warc_temp_dir
+ wait-retry
+ warc-cdx
+ warc-cdx-dedup
+ warc-compression
+ warc-digests
+ warc-file
+ warc-header
+ warc-keep-log
+ warc-max-size
+ warc-temp-dir
wdebug
xattr
EOL
"}}}
-call map(s:commands, "substitute(v:val, '_', '[-_]\\\\=', 'g')")
-
for cmd in s:commands
- exe 'syn match wgetCommand "\<' . cmd . '\>" nextgroup=wgetAssignmentOperator skipwhite contained'
+ exe 'syn match wgetCommand "\<' .. substitute(cmd, '-', '[-_]\\=', "g") .. '\>" nextgroup=wgetAssignmentOperator skipwhite contained'
endfor
+unlet s:commands
syn case match
-syn match wgetStart "^" nextgroup=wgetCommand,wgetComment skipwhite
+syn match wgetLineStart "^" nextgroup=wgetCommand,wgetComment skipwhite
syn match wgetAssignmentOperator "=" nextgroup=wgetString,wgetBoolean,wgetNumber,wgetQuota,wgetTime skipwhite contained
hi def link wgetAssignmentOperator Special
diff --git a/runtime/syntax/wget2.vim b/runtime/syntax/wget2.vim
index a63c336f06..3e9abdf23d 100644
--- a/runtime/syntax/wget2.vim
+++ b/runtime/syntax/wget2.vim
@@ -1,9 +1,9 @@
" Vim syntax file
-" Language: Wget2 configuration file (/etc/wget2rc ~/.wget2rc)
+" Language: Wget2 configuration file (/etc/wget2rc ~/.wget2rc)
" Maintainer: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2022 Apr 28
+" Last Change: 2023 Nov 05
-" GNU Wget2 2.0.0 - multithreaded metalink/file/website downloader
+" GNU Wget2 2.1.0 - multithreaded metalink/file/website downloader
if exists("b:current_syntax")
finish
@@ -12,21 +12,20 @@ endif
let s:cpo_save = &cpo
set cpo&vim
-syn match wgetComment "#.*$" contains=wgetTodo contained
+syn match wget2Comment "#.*" contains=wget2Todo contained
-syn keyword wgetTodo TODO NOTE FIXME XXX contained
+syn keyword wget2Todo TODO NOTE FIXME XXX contained
-syn region wgetString start=+"+ skip=+\\\\\|\\"+ end=+"+ contained oneline
-syn region wgetString start=+'+ skip=+\\\\\|\\'+ end=+'+ contained oneline
+syn region wget2String start=+"+ skip=+\\\\\|\\"+ end=+"+ contained oneline
+syn region wget2String start=+'+ skip=+\\\\\|\\'+ end=+'+ contained oneline
syn case ignore
-syn keyword wgetBoolean on off yes no y n contained
-syn keyword wgetNumber infinity inf contained
-
-syn match wgetNumber "\<\d\+>" contained
-syn match wgetQuota "\<\d\+[kmgt]\>" contained
-syn match wgetTime "\<\d\+[smhd]\>" contained
+syn keyword wget2Boolean on off yes no y n contained
+syn keyword wget2Number infinity inf contained
+syn match wget2Number "\<\d\+>" contained
+syn match wget2Quota "\<\d\+[kmgt]\>" contained
+syn match wget2Time "\<\d\+[smhd]\>" contained
"{{{ Commands
let s:commands =<< trim EOL
@@ -67,6 +66,7 @@ let s:commands =<< trim EOL
cut-dirs
cut-file-get-vars
cut-url-get-vars
+ dane
debug
default-http-port
default-https-port
@@ -85,6 +85,7 @@ let s:commands =<< trim EOL
execute
filter-mime-type
filter-urls
+ follow-sitemaps
follow-tags
force-atom
force-css
@@ -221,28 +222,27 @@ let s:commands =<< trim EOL
EOL
"}}}
-call map(s:commands, "substitute(v:val, '_', '[-_]\\\\=', 'g')")
-
for cmd in s:commands
- exe 'syn match wgetCommand "\<' . cmd . '\>" nextgroup=wgetAssignmentOperator skipwhite contained'
+ exe 'syn match wget2Command "\<' .. substitute(cmd, '-', '[-_]\\=', "g") .. '\>" nextgroup=wget2AssignmentOperator skipwhite contained'
endfor
+unlet s:commands
syn case match
-syn match wgetStart "^" nextgroup=wgetCommand,wgetComment skipwhite
-syn match wgetAssignmentOperator "=" nextgroup=wgetString,wgetBoolean,wgetNumber,wgetQuota,wgetTime skipwhite contained
+syn match wget2LineStart "^" nextgroup=wget2Command,wget2Comment skipwhite
+syn match wget2AssignmentOperator "=" nextgroup=wget2String,wget2Boolean,wget2Number,wget2Quota,wget2Time skipwhite contained
-hi def link wgetAssignmentOperator Special
-hi def link wgetBoolean Boolean
-hi def link wgetCommand Identifier
-hi def link wgetComment Comment
-hi def link wgetNumber Number
-hi def link wgetQuota Number
-hi def link wgetString String
-hi def link wgetTime Number
-hi def link wgetTodo Todo
+hi def link wget2AssignmentOperator Special
+hi def link wget2Boolean Boolean
+hi def link wget2Command Identifier
+hi def link wget2Comment Comment
+hi def link wget2Number Number
+hi def link wget2Quota Number
+hi def link wget2String String
+hi def link wget2Time Number
+hi def link wget2Todo Todo
-let b:current_syntax = "wget"
+let b:current_syntax = "wget2"
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/src/man/nvim.1 b/src/man/nvim.1
index b846ed4ba6..4dc099f98c 100644
--- a/src/man/nvim.1
+++ b/src/man/nvim.1
@@ -339,6 +339,11 @@ Print version information and exit.
.El
.Sh ENVIRONMENT
.Bl -tag -width Fl
+.It Ev NVIM_APPNAME
+The name of sub-directories used within each XDG user directory.
+Defaults to
+.Cm nvim .
+:help $NVIM_APPNAME
.It Ev NVIM_LOG_FILE
Low-level log file, usually found at ~/.local/state/nvim/log.
:help $NVIM_LOG_FILE
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index f4c6f646eb..9d51f2a4dc 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -419,7 +419,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, {
goto end;
});
- data_str = xstrndup(elem.data.string.data, elem.data.string.size);
+ data_str = string_to_cstr(elem.data.string);
break;
default:
VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), {
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 9cf4620acd..8911e145e7 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -75,8 +75,6 @@
#define PUT_C(dict, k, v) \
kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v }))
-#define PUT_BOOL(dict, name, condition) PUT(dict, name, BOOLEAN_OBJ(condition));
-
#define ADD(array, item) \
kv_push(array, item)
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index bdb3983ab3..1a83dd30c0 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -1031,7 +1031,7 @@ int autocmd_register(int64_t id, event_T event, const char *pat, int patlen, int
}
ap->refcount = 0;
- ap->pat = xstrnsave(pat, (size_t)patlen);
+ ap->pat = xmemdupz(pat, (size_t)patlen);
ap->patlen = patlen;
// need to initialize last_mode for the first ModeChanged autocmd
@@ -2514,7 +2514,7 @@ static int arg_augroup_get(char **argp)
return AUGROUP_ALL;
}
- char *group_name = xstrnsave(arg, (size_t)(p - arg));
+ char *group_name = xmemdupz(arg, (size_t)(p - arg));
int group = augroup_find(group_name);
if (group == AUGROUP_ERROR) {
group = AUGROUP_ALL; // no match, use all groups
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 496c047a4a..6b83664339 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -804,7 +804,7 @@ static char *find_longest_match(expand_T *xp, int options)
}
}
- return xstrndup(xp->xp_files[0], len);
+ return xmemdupz(xp->xp_files[0], len);
}
/// Do wildcard expansion on the string "str".
@@ -3156,11 +3156,11 @@ static int ExpandUserDefined(const char *const pat, expand_T *xp, regmatch_T *re
if (match) {
if (!fuzzy) {
- GA_APPEND(char *, &ga, xstrnsave(s, (size_t)(e - s)));
+ GA_APPEND(char *, &ga, xmemdupz(s, (size_t)(e - s)));
} else {
GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){
.idx = ga.ga_len,
- .str = xstrnsave(s, (size_t)(e - s)),
+ .str = xmemdupz(s, (size_t)(e - s)),
.score = score,
}));
}
diff --git a/src/nvim/context.c b/src/nvim/context.c
index fe5a49faa2..9b1eee56c5 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -330,7 +330,7 @@ static inline msgpack_sbuffer array_to_sbuf(Array array)
typval_T list_tv;
Error err = ERROR_INIT;
- object_to_vim(ARRAY_OBJ(array), &list_tv, &err);
+ (void)object_to_vim(ARRAY_OBJ(array), &list_tv, &err);
if (!encode_vim_list_to_buf(list_tv.vval.v_list, &sbuf.size, &sbuf.data)) {
emsg(_("E474: Failed to convert list to msgpack string buffer"));
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 5f0dfb381d..de76d55977 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -2110,10 +2110,10 @@ void ex_loadkeymap(exarg_T *eap)
if ((*p != '"') && (*p != NUL)) {
kmap_T *kp = GA_APPEND_VIA_PTR(kmap_T, &curbuf->b_kmap_ga);
s = skiptowhite(p);
- kp->from = xstrnsave(p, (size_t)(s - p));
+ kp->from = xmemdupz(p, (size_t)(s - p));
p = skipwhite(s);
s = skiptowhite(p);
- kp->to = xstrnsave(p, (size_t)(s - p));
+ kp->to = xmemdupz(p, (size_t)(s - p));
if ((strlen(kp->from) + strlen(kp->to) >= KMAP_LLEN)
|| (*kp->from == NUL)
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a3ea5169fd..390cdbb377 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1633,7 +1633,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const
if (len == -1) {
lp->ll_newkey = xstrdup(key);
} else {
- lp->ll_newkey = xstrnsave(key, (size_t)len);
+ lp->ll_newkey = xmemdupz(key, (size_t)len);
}
tv_clear(&var1);
break;
@@ -1966,7 +1966,7 @@ bool next_for_item(void *fi_void, char *arg)
typval_T tv;
tv.v_type = VAR_STRING;
tv.v_lock = VAR_FIXED;
- tv.vval.v_string = xstrnsave(fi->fi_string + fi->fi_byte_idx, (size_t)len);
+ tv.vval.v_string = xmemdupz(fi->fi_string + fi->fi_byte_idx, (size_t)len);
fi->fi_byte_idx += len;
const int result
= ex_let_vars(arg, &tv, true, fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK;
@@ -4893,7 +4893,7 @@ static int get_literal_key(char **arg, typval_T *tv)
}
for (p = *arg; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; p++) {}
tv->v_type = VAR_STRING;
- tv->vval.v_string = xstrnsave(*arg, (size_t)(p - *arg));
+ tv->vval.v_string = xmemdupz(*arg, (size_t)(p - *arg));
*arg = skipwhite(p);
return OK;
@@ -5242,7 +5242,7 @@ static void filter_map_string(const char *str, filtermap_T filtermap, typval_T *
typval_T tv = {
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
- .vval.v_string = xstrnsave(p, (size_t)len),
+ .vval.v_string = xmemdupz(p, (size_t)len),
};
vimvars[VV_KEY].vv_nr = idx;
@@ -7483,7 +7483,7 @@ char *char_from_string(const char *str, varnumber_T index)
if (nbyte >= slen) {
return NULL;
}
- return xstrnsave(str + nbyte, (size_t)utf_ptr2len(str + nbyte));
+ return xmemdupz(str + nbyte, (size_t)utf_ptr2len(str + nbyte));
}
/// Get the byte index for character index "idx" in string "str" with length
@@ -7544,7 +7544,7 @@ char *string_slice(const char *str, varnumber_T first, varnumber_T last, bool ex
if (start_byte >= (ssize_t)slen || end_byte <= start_byte) {
return NULL;
}
- return xstrnsave(str + start_byte, (size_t)(end_byte - start_byte));
+ return xmemdupz(str + start_byte, (size_t)(end_byte - start_byte));
}
/// Handle:
@@ -8586,13 +8586,13 @@ repeat:
// find end of pattern
p = vim_strchr(s, sep);
if (p != NULL) {
- char *const pat = xstrnsave(s, (size_t)(p - s));
+ char *const pat = xmemdupz(s, (size_t)(p - s));
s = p + 1;
// find end of substitution
p = vim_strchr(s, sep);
if (p != NULL) {
- char *const sub = xstrnsave(s, (size_t)(p - s));
- char *const str = xstrnsave(*fnamep, *fnamelen);
+ char *const sub = xmemdupz(s, (size_t)(p - s));
+ char *const str = xmemdupz(*fnamep, *fnamelen);
*usedlen = (size_t)(p + 1 - src);
s = do_string_sub(str, pat, sub, NULL, flags);
*fnamep = s;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 221be492af..a2ba0f0189 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -6142,7 +6142,8 @@ M.funcs = {
When {dict} is omitted or zero: Return the rhs of mapping
{name} in mode {mode}. The returned String has special
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
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
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
"lhsraw" The {lhs} of the mapping as raw bytes
"lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
@@ -6189,9 +6190,16 @@ M.funcs = {
(|mapmode-ic|)
"sid" The script local ID, used for <sid> mappings
(|<SID>|). Negative for special contexts.
+ "scriptversion" The version of the script, always 1.
"lnum" The line number in "sid", zero if unknown.
"nowait" Do not wait for other, longer mappings.
(|: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
|mapset()|.
@@ -6254,6 +6262,43 @@ M.funcs = {
params = { { 'name', 'string' }, { 'mode', 'string' }, { 'abbr', 'any' } },
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 = {
args = 2,
base = 1,
@@ -6268,12 +6313,20 @@ M.funcs = {
signature = 'mapnew({expr1}, {expr2})',
},
mapset = {
- args = 3,
+ args = { 1, 3 },
base = 1,
desc = [=[
- Restore a mapping from a dictionary returned by |maparg()|.
- {mode} and {abbr} should be the same as for the call to
- |maparg()|. *E460*
+ Restore a mapping from a dictionary, possibly returned by
+ |maparg()| or |maplist()|. A buffer mapping, when dict.buffer
+ 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,
not the "mode" entry in {dict}.
Example for saving and restoring a mapping: >vim
@@ -6282,8 +6335,21 @@ M.funcs = {
" ...
call mapset('n', 0, save_map)
<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
- them, since they can differ.
+ e.g. with `:map!`, you need to save/restore the mapping for
+ 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',
params = { { 'mode', 'string' }, { 'abbr', 'any' }, { 'dict', 'any' } },
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 550d296093..2d8ad458f1 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2911,6 +2911,9 @@ static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
bool error = false;
const int called_emsg_before = called_emsg;
+ // Flush screen updates before blocking.
+ ui_flush();
+
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, timeout,
eval_expr_typval(&expr, false, &argv, 0, &exprval) != OK
|| tv_get_number_chk(&exprval, &error)
@@ -5669,7 +5672,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl
}
if (prevlen == 0) {
assert(len < INT_MAX);
- s = xstrnsave(start, len);
+ s = xmemdupz(start, len);
} else {
// Change "prev" buffer to be the right size. This way
// the bytes are only copied once, and very long lines are
@@ -6305,7 +6308,7 @@ static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv)
*rettv = (typval_T){
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
- .vval.v_string = xstrnsave(p, (size_t)len),
+ .vval.v_string = xmemdupz(p, (size_t)len),
};
p += len;
} else if (tv_check_for_string_arg(argvars, 2) == FAIL) {
@@ -6321,7 +6324,7 @@ static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv)
argv[1] = (typval_T){
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
- .vval.v_string = xstrnsave(p, (size_t)len),
+ .vval.v_string = xmemdupz(p, (size_t)len),
};
const int r = eval_expr_typval(expr, true, argv, 2, rettv);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 6e7b1e4d67..4b50710649 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -1625,7 +1625,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
if (fp == NULL) {
// Make a copy of the name, if it comes from a funcref variable it could
// be changed or deleted in the called function.
- name = xstrnsave(funcname, (size_t)len);
+ name = xmemdupz(funcname, (size_t)len);
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
}
@@ -2089,7 +2089,7 @@ char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi)
if (strncmp(p, "<lambda>", 8) == 0) {
p += 8;
(void)getdigits(&p, false, 0);
- saved = xstrndup(*name, (size_t)(p - *name));
+ saved = xmemdupz(*name, (size_t)(p - *name));
if (fudi != NULL) {
CLEAR_POINTER(fudi);
}
@@ -2573,12 +2573,12 @@ void ex_function(exarg_T *eap)
if (strncmp(p, "trim", 4) == 0) {
// Ignore leading white space.
p = skipwhite(p + 4);
- heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline));
+ heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline));
}
if (*p == NUL) {
skip_until = xstrdup(".");
} else {
- skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p));
+ skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p));
}
do_concat = false;
is_heredoc = true;
@@ -2598,7 +2598,7 @@ void ex_function(exarg_T *eap)
if (strncmp(p, "trim", 4) == 0) {
// Ignore leading white space.
p = skipwhite(p + 4);
- heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline));
+ heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline));
continue;
}
if (strncmp(p, "eval", 4) == 0) {
@@ -2608,7 +2608,7 @@ void ex_function(exarg_T *eap)
}
break;
}
- skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p));
+ skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p));
do_concat = false;
is_heredoc = true;
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 33256b78e1..ed79d8a681 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -274,7 +274,7 @@ list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get)
p++;
text_indent_len++;
}
- text_indent = xstrnsave(theline, (size_t)text_indent_len);
+ text_indent = xmemdupz(theline, (size_t)text_indent_len);
}
// with "trim": skip the indent matching the first line
if (text_indent != NULL) {
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 2857465db0..bb3284a6b8 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -2816,7 +2816,7 @@ void ex_append(exarg_T *eap)
if (p == NULL) {
p = eap->nextcmd + strlen(eap->nextcmd);
}
- theline = xstrnsave(eap->nextcmd, (size_t)(p - eap->nextcmd));
+ theline = xmemdupz(eap->nextcmd, (size_t)(p - eap->nextcmd));
if (*p != NUL) {
p++;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index c83b00f77f..ad09ee6bb1 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2033,7 +2033,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
while (ASCII_ISALNUM(*p)) {
p++;
}
- p = xstrnsave(ea.cmd, (size_t)(p - ea.cmd));
+ p = xmemdupz(ea.cmd, (size_t)(p - ea.cmd));
int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
xfree(p);
// If the autocommands did something and didn't cause an error, try
@@ -7121,7 +7121,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum
}
result = NULL;
} else {
- result = xstrnsave(result, resultlen);
+ result = xmemdupz(result, resultlen);
}
xfree(resultbuf);
return result;
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 796769d7ff..5bdaaa880e 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -293,7 +293,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
xstrlcpy(ff_expand_buffer, rel_fname, len + 1);
search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, false);
} else {
- search_ctx->ffsc_start_dir = xstrnsave(rel_fname, len);
+ search_ctx->ffsc_start_dir = xmemdupz(rel_fname, len);
}
if (*++path != NUL) {
path++;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 804c9cec11..424bd33b6c 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1993,7 +1993,7 @@ static char *next_fenc(char **pp, bool *alloced)
r = enc_canonize(*pp);
*pp += strlen(*pp);
} else {
- r = xstrnsave(*pp, (size_t)(p - *pp));
+ r = xmemdupz(*pp, (size_t)(p - *pp));
*pp = p + 1;
p = enc_canonize(r);
xfree(r);
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 8b1e2f9105..2370df916c 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1723,7 +1723,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
// getchar(): blocking wait.
// TODO(bfredl): deduplicate shared logic with state_enter ?
if (!char_avail()) {
- // flush output before waiting
+ // Flush screen updates before blocking.
ui_flush();
(void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
if (!multiqueue_empty(main_loop.events)) {
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 65eabd72c3..ff21b11abb 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -960,7 +960,7 @@ void ex_retab(exarg_T *eap)
return;
}
while (ascii_isdigit(*(eap->arg)) || *(eap->arg) == ',') {
- (eap->arg)++;
+ eap->arg++;
}
// This ensures that either new_vts_array and new_ts_str are freshly
@@ -970,7 +970,7 @@ void ex_retab(exarg_T *eap)
new_vts_array = curbuf->b_p_vts_array;
new_ts_str = NULL;
} else {
- new_ts_str = xstrnsave(new_ts_str, (size_t)(eap->arg - new_ts_str));
+ new_ts_str = xmemdupz(new_ts_str, (size_t)(eap->arg - new_ts_str));
}
for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) {
char *ptr = ml_get(lnum);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 3333c73bfd..876a5c34bd 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -463,7 +463,7 @@ static int nlua_wait(lua_State *lstate)
int pcall_status = 0;
bool callback_result = false;
- // Flush UI before blocking
+ // Flush screen updates before blocking.
ui_flush();
LOOP_PROCESS_EVENTS_UNTIL(&main_loop,
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index da98f5e6c0..b54b07fc20 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -123,6 +123,8 @@ static const char e_mapping_already_exists_for_str[]
= N_("E227: Mapping already exists for %s");
static const char e_entries_missing_in_mapset_dict_argument[]
= N_("E460: Entries missing in mapset() dict argument");
+static const char e_illegal_map_mode_string_str[]
+ = N_("E1276: Illegal map mode string: '%s'");
/// Get the start of the hashed map list for "state" and first character "c".
mapblock_T *get_maphash_list(int state, int c)
@@ -1652,7 +1654,7 @@ char *eval_map_expr(mapblock_T *mp, int c)
Array args = ARRAY_DICT_INIT;
Object ret = nlua_call_ref(mp->m_luaref, NULL, args, true, &err);
if (ret.type == kObjectTypeString) {
- p = xstrndup(ret.data.string.data, ret.data.string.size);
+ p = string_to_cstr(ret.data.string);
}
api_free_object(ret);
if (err.type != kErrorTypeNone) {
@@ -2070,17 +2072,18 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
///
/// @param mp The maphash that contains the mapping information
/// @param buffer_value The "buffer" value
+/// @param abbr True if abbreviation
/// @param compatible True for compatible with old maparg() dict
///
/// @return A Dictionary.
static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt,
- const int buffer_value, const bool compatible)
+ const int buffer_value, const bool abbr, const bool compatible)
FUNC_ATTR_NONNULL_ARG(1)
{
Dictionary dict = ARRAY_DICT_INIT;
char *const lhs = str2special_save(mp->m_keys, compatible, !compatible);
char *const mapmode = map_mode_to_chars(mp->m_mode);
- varnumber_T noremap_value;
+ int noremap_value;
if (compatible) {
// Keep old compatible behavior
@@ -2112,14 +2115,17 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
PUT(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0));
PUT(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0));
PUT(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0));
- PUT(dict, "sid", INTEGER_OBJ((varnumber_T)mp->m_script_ctx.sc_sid));
- PUT(dict, "lnum", INTEGER_OBJ((varnumber_T)mp->m_script_ctx.sc_lnum));
- PUT(dict, "buffer", INTEGER_OBJ((varnumber_T)buffer_value));
+ PUT(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid));
+ PUT(dict, "scriptversion", INTEGER_OBJ(1));
+ PUT(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum));
+ PUT(dict, "buffer", INTEGER_OBJ(buffer_value));
PUT(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0));
if (mp->m_replace_keycodes) {
PUT(dict, "replace_keycodes", INTEGER_OBJ(1));
}
PUT(dict, "mode", CSTR_AS_OBJ(mapmode));
+ PUT(dict, "abbr", INTEGER_OBJ(abbr ? 1 : 0));
+ PUT(dict, "mode_bits", INTEGER_OBJ(mp->m_mode));
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)) {
Dictionary dict = mapblock_fill_dict(mp,
did_simplify ? keys_simplified : NULL,
- buffer_local, true);
+ buffer_local, abbr, true);
(void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL);
api_free_dictionary(dict);
} else {
@@ -2205,21 +2211,99 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
xfree(alt_keys_buf);
}
+/// Get the mapping mode from the mode string.
+/// It may contain multiple characters, eg "nox", or "!", or ' '
+/// Return 0 if there is an error.
+static int get_map_mode_string(const char *const mode_string, const bool abbr)
+{
+ const char *p = mode_string;
+ const int MASK_V = MODE_VISUAL | MODE_SELECT;
+ const int MASK_MAP = MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING;
+ const int MASK_BANG = MODE_INSERT | MODE_CMDLINE;
+
+ if (*p == NUL) {
+ p = " "; // compatibility
+ }
+ int mode = 0;
+ int modec;
+ while ((modec = (uint8_t)(*p++))) {
+ int tmode;
+ switch (modec) {
+ case 'i':
+ tmode = MODE_INSERT; break;
+ case 'l':
+ tmode = MODE_LANGMAP; break;
+ case 'c':
+ tmode = MODE_CMDLINE; break;
+ case 'n':
+ tmode = MODE_NORMAL; break;
+ case 'x':
+ tmode = MODE_VISUAL; break;
+ case 's':
+ tmode = MODE_SELECT; break;
+ case 'o':
+ tmode = MODE_OP_PENDING; break;
+ case 't':
+ tmode = MODE_TERMINAL; break;
+ case 'v':
+ tmode = MASK_V; break;
+ case '!':
+ tmode = MASK_BANG; break;
+ case ' ':
+ tmode = MASK_MAP; break;
+ default:
+ return 0; // error, unknown mode character
+ }
+ mode |= tmode;
+ }
+ if ((abbr && (mode & ~MASK_BANG) != 0)
+ || (!abbr && (mode & (mode - 1)) != 0 // more than one bit set
+ && (
+ // false if multiple bits set in mode and mode is fully
+ // contained in one mask
+ !(((mode & MASK_BANG) != 0 && (mode & ~MASK_BANG) == 0)
+ || ((mode & MASK_MAP) != 0 && (mode & ~MASK_MAP) == 0))))) {
+ return 0;
+ }
+
+ return mode;
+}
+
/// "mapset()" function
void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
+ const char *which;
char buf[NUMBUFLEN];
- const char *which = tv_get_string_buf_chk(&argvars[0], buf);
- if (which == NULL) {
- return;
+ int is_abbr;
+ dict_T *d;
+
+ // If first arg is a dict, then that's the only arg permitted.
+ const bool dict_only = argvars[0].v_type == VAR_DICT;
+
+ if (dict_only) {
+ d = argvars[0].vval.v_dict;
+ which = tv_dict_get_string(d, "mode", false);
+ is_abbr = (int)tv_dict_get_bool(d, "abbr", -1);
+ if (which == NULL || is_abbr < 0) {
+ emsg(_(e_entries_missing_in_mapset_dict_argument));
+ return;
+ }
+ } else {
+ which = tv_get_string_buf_chk(&argvars[0], buf);
+ if (which == NULL) {
+ return;
+ }
+ is_abbr = (int)tv_get_bool(&argvars[1]);
+ if (tv_check_for_dict_arg(argvars, 2) == FAIL) {
+ return;
+ }
+ d = argvars[2].vval.v_dict;
}
- const int mode = get_map_mode((char **)&which, 0);
- const bool is_abbr = tv_get_number(&argvars[1]) != 0;
-
- if (tv_check_for_dict_arg(argvars, 2) == FAIL) {
+ const int mode = get_map_mode_string(which, is_abbr);
+ if (mode == 0) {
+ semsg(_(e_illegal_map_mode_string_str), which);
return;
}
- dict_T *d = argvars[2].vval.v_dict;
// Get the values in the same order as above in get_maparg().
char *lhs = tv_dict_get_string(d, "lhs", false);
@@ -2280,6 +2364,59 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
sid, lnum, false);
}
+/// "maplist()" function
+void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
+ const bool abbr = argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]);
+
+ tv_list_alloc_ret(rettv, kListLenUnknown);
+
+ // Do it twice: once for global maps and once for local maps.
+ for (int buffer_local = 0; buffer_local <= 1; buffer_local++) {
+ for (int hash = 0; hash < 256; hash++) {
+ mapblock_T *mp;
+ if (abbr) {
+ if (hash > 0) { // there is only one abbr list
+ break;
+ }
+ if (buffer_local) {
+ mp = curbuf->b_first_abbr;
+ } else {
+ mp = first_abbr;
+ }
+ } else if (buffer_local) {
+ mp = curbuf->b_maphash[hash];
+ } else {
+ mp = maphash[hash];
+ }
+ for (; mp; mp = mp->m_next) {
+ if (mp->m_simplified) {
+ continue;
+ }
+
+ char *keys_buf = NULL;
+ bool did_simplify = false;
+
+ char *lhs = str2special_save(mp->m_keys, true, false);
+ (void)replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify,
+ CPO_TO_CPO_FLAGS);
+ xfree(lhs);
+
+ Dictionary dict = mapblock_fill_dict(mp,
+ did_simplify ? keys_buf : NULL,
+ buffer_local, abbr, true);
+ typval_T d = TV_INITIAL_VALUE;
+ (void)object_to_vim(DICTIONARY_OBJ(dict), &d, NULL);
+ assert(d.v_type == VAR_DICT);
+ tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict);
+ api_free_dictionary(dict);
+ xfree(keys_buf);
+ }
+ }
+ }
+}
+
/// "maparg()" function
void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -2593,30 +2730,21 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
goto fail_and_free;
}
- bool is_abbrev = false;
- if (mode.size > 2) {
- api_set_error(err, kErrorTypeValidation, "Shortname is too long: %s", mode.data);
+ char *p = mode.size > 0 ? mode.data : "m";
+ bool forceit = *p == '!';
+ // integer value of the mapping mode, to be passed to do_map()
+ int mode_val = get_map_mode(&p, forceit);
+ if (forceit) {
+ assert(p == mode.data);
+ p++;
+ }
+ bool is_abbrev = (mode_val & (MODE_INSERT | MODE_CMDLINE)) != 0 && *p == 'a';
+ if (is_abbrev) {
+ p++;
+ }
+ if (mode.size > 0 && (size_t)(p - mode.data) != mode.size) {
+ api_set_error(err, kErrorTypeValidation, "Invalid mode shortname: \"%s\"", mode.data);
goto fail_and_free;
- } else if (mode.size == 2) {
- if ((mode.data[0] != '!' && mode.data[0] != 'i' && mode.data[0] != 'c')
- || mode.data[1] != 'a') {
- api_set_error(err, kErrorTypeValidation, "Shortname is too long: %s", mode.data);
- goto fail_and_free;
- }
- is_abbrev = true;
- }
- int mode_val; // integer value of the mapping mode, to be passed to do_map()
- char *p = (mode.size) ? mode.data : "m";
- if (*p == '!') {
- mode_val = get_map_mode(&p, true); // mapmode-ic
- } else {
- mode_val = get_map_mode(&p, false);
- if (mode_val == (MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING) && mode.size > 0) {
- // get_map_mode() treats unrecognized mode shortnames as ":map".
- // This is an error unless the given shortname was empty string "".
- api_set_error(err, kErrorTypeValidation, "Invalid mode shortname: \"%s\"", p);
- goto fail_and_free;
- }
}
if (parsed_args.lhs_len == 0) {
@@ -2706,7 +2834,8 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
// Check for correct mode
if (int_mode & current_maphash->m_mode) {
ADD(mappings,
- DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value, false)));
+ DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL,
+ buffer_value, false, false)));
}
}
}
diff --git a/src/nvim/match.c b/src/nvim/match.c
index e087d4f45d..d153ea042d 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -1216,7 +1216,7 @@ void ex_match(exarg_T *eap)
} else {
p = skiptowhite(eap->arg);
if (!eap->skip) {
- g = xstrnsave(eap->arg, (size_t)(p - eap->arg));
+ g = xmemdupz(eap->arg, (size_t)(p - eap->arg));
}
p = skipwhite(p);
if (*p == NUL) {
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 5eb8b41015..5fa731141e 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -1313,7 +1313,7 @@ static char *menu_text(const char *str, int *mnemonic, char **actext)
*actext = xstrdup(p + 1);
}
assert(p >= str);
- text = xstrnsave(str, (size_t)(p - str));
+ text = xmemdupz(str, (size_t)(p - str));
} else {
text = xstrdup(str);
}
@@ -1736,7 +1736,7 @@ void ex_menutranslate(exarg_T *eap)
from = xstrdup(from);
from_noamp = menu_text(from, NULL, NULL);
assert(arg >= to);
- to = xstrnsave(to, (size_t)(arg - to));
+ to = xmemdupz(to, (size_t)(arg - to));
menu_translate_tab_and_shift(from);
menu_translate_tab_and_shift(to);
menu_unescape_name(from);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 54e1e49d97..418097a82a 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -4232,7 +4232,7 @@ static void nv_brackets(cmdarg_T *cap)
clearop(cap->oap);
} else {
// Make a copy, if the line was changed it will be freed.
- ptr = xstrnsave(ptr, len);
+ ptr = xmemdupz(ptr, len);
find_pattern_in_path(ptr, 0, len, true,
cap->count0 == 0 ? !isupper(cap->nchar) : false,
(((cap->nchar & 0xf) == ('d' & 0xf))
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 9dbeed8658..b56d5e11ea 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1366,7 +1366,7 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg)
cnt = find_ident_under_cursor(argp, (regname == Ctrl_W
? (FIND_IDENT|FIND_STRING)
: FIND_STRING));
- *argp = cnt ? xstrnsave(*argp, cnt) : NULL;
+ *argp = cnt ? xmemdupz(*argp, cnt) : NULL;
*allocated = true;
return true;
@@ -2404,7 +2404,7 @@ void op_insert(oparg_T *oap, int count1)
}
int ins_len = (int)strlen(firstline) - pre_textlen - offset;
if (pre_textlen >= 0 && ins_len > 0) {
- char *ins_text = xstrnsave(firstline, (size_t)ins_len);
+ char *ins_text = xmemdupz(firstline, (size_t)ins_len);
// block handled here
if (u_save(oap->start.lnum, (linenr_T)(oap->end.lnum + 1)) == OK) {
block_insert(oap, ins_text, (oap->op_type == OP_INSERT), &bd);
@@ -3118,7 +3118,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
if (dir == FORWARD && *p != NUL) {
MB_PTR_ADV(p);
}
- ptr = xstrnsave(oldp, (size_t)(p - oldp));
+ ptr = xmemdupz(oldp, (size_t)(p - oldp));
ml_replace(curwin->w_cursor.lnum, ptr, false);
nr_lines++;
dir = FORWARD;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index b44dda67d6..7005b63cac 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -630,7 +630,7 @@ void set_init_3(void)
size_t len = 0;
char *p = (char *)invocation_path_tail(p_sh, &len);
- p = xstrnsave(p, len);
+ p = xmemdupz(p, len);
{
//
@@ -5749,7 +5749,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
// If more than one flags, split the flags up and expose each
// character as individual choice.
for (char *flag = option_val; *flag != NUL; flag++) {
- (*matches)[count++] = xstrnsave(flag, 1);
+ (*matches)[count++] = xmemdupz(flag, 1);
}
}
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index c244b83c9e..47cb8e7912 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2851,10 +2851,8 @@ return {
default to single-byte alternatives.
Example: >
- :set fillchars=stl:^,stlnc:=,vert:│,fold:·,diff:-
- < This is similar to the default, except that these characters will also
- be used when there is highlighting.
-
+ :set fillchars=stl:\ ,stlnc:\ ,vert:│,fold:·,diff:-
+ <
For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
single-byte and multibyte characters are supported. But double-width
characters are not supported.
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index b868c90108..be76688e92 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -635,7 +635,7 @@ static int expand_set_opt_listflag(optexpand_T *args, char *flags, int *numMatch
// existing flag. Just skip it to avoid duplicate.
continue;
}
- (*matches)[count++] = xstrnsave(flag, 1);
+ (*matches)[count++] = xmemdupz(flag, 1);
}
}
@@ -1569,6 +1569,9 @@ const char *did_set_iconstring(optset_T *args)
/// The 'inccommand' option is changed.
const char *did_set_inccommand(optset_T *args FUNC_ATTR_UNUSED)
{
+ if (cmdpreview) {
+ return e_invarg;
+ }
return did_set_opt_strings(p_icm, p_icm_values, false);
}
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 7de7168d62..dbea6f01df 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -292,12 +292,11 @@ char *os_getenvname_at_index(size_t index)
// Some Windows env vars start with =, so skip over that to find the
// separator between name/value
- const char * const end = strchr(utf8_str + (utf8_str[0] == '=' ? 1 : 0),
- '=');
+ const char *const end = strchr(utf8_str + (utf8_str[0] == '=' ? 1 : 0), '=');
assert(end != NULL);
ptrdiff_t len = end - utf8_str;
assert(len > 0);
- name = xstrndup(utf8_str, (size_t)len);
+ name = xmemdupz(utf8_str, (size_t)len);
xfree(utf8_str);
break;
}
@@ -328,7 +327,7 @@ char *os_getenvname_at_index(size_t index)
assert(end != NULL);
ptrdiff_t len = end - str;
assert(len > 0);
- return xstrndup(str, (size_t)len);
+ return xmemdupz(str, (size_t)len);
#endif
}
@@ -960,7 +959,7 @@ char *vim_getenv(const char *name)
// check that the result is a directory name
assert(vim_path_end >= vim_path);
- vim_path = xstrndup(vim_path, (size_t)(vim_path_end - vim_path));
+ vim_path = xmemdupz(vim_path, (size_t)(vim_path_end - vim_path));
if (!os_isdir(vim_path)) {
xfree(vim_path);
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index fa474b67dd..8ea30ff21e 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -127,7 +127,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
ret = "/tmp/";
}
size_t len = strlen(ret);
- ret = xstrndup(ret, len >= 2 ? len - 1 : 0); // Trim trailing slash.
+ ret = xmemdupz(ret, len >= 2 ? len - 1 : 0); // Trim trailing slash.
}
return ret;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 15a8762da1..8cc824337c 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1374,7 +1374,7 @@ static int expand_backtick(garray_T *gap, char *pat, int flags)
int cnt = 0;
// Create the command: lop off the backticks.
- char *cmd = xstrnsave(pat + 1, strlen(pat) - 2);
+ char *cmd = xmemdupz(pat + 1, strlen(pat) - 2);
if (*cmd == '=') { // `={expr}`: Expand expression
buffer = eval_to_string(cmd + 1, true);
diff --git a/src/nvim/search.c b/src/nvim/search.c
index e253abaa41..cee526d416 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1629,7 +1629,7 @@ static bool find_rawstring_end(char *linep, pos_T *startpos, pos_T *endpos)
for (p = linep + startpos->col + 1; *p && *p != '('; p++) {}
size_t delim_len = (size_t)((p - linep) - startpos->col - 1);
- char *delim_copy = xstrnsave(linep + startpos->col + 1, delim_len);
+ char *delim_copy = xmemdupz(linep + startpos->col + 1, delim_len);
bool found = false;
for (lnum = startpos->lnum; lnum <= endpos->lnum; lnum++) {
char *line = ml_get(lnum);
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 97164f2234..6a6adbd866 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -1209,27 +1209,27 @@ static void sign_define_cmd(char *sign_name, char *cmdline)
if (strncmp(arg, "icon=", 5) == 0) {
arg += 5;
XFREE_CLEAR(icon);
- icon = xstrnsave(arg, (size_t)(p - arg));
+ icon = xmemdupz(arg, (size_t)(p - arg));
} else if (strncmp(arg, "text=", 5) == 0) {
arg += 5;
XFREE_CLEAR(text);
- text = xstrnsave(arg, (size_t)(p - arg));
+ text = xmemdupz(arg, (size_t)(p - arg));
} else if (strncmp(arg, "linehl=", 7) == 0) {
arg += 7;
XFREE_CLEAR(linehl);
- linehl = xstrnsave(arg, (size_t)(p - arg));
+ linehl = xmemdupz(arg, (size_t)(p - arg));
} else if (strncmp(arg, "texthl=", 7) == 0) {
arg += 7;
XFREE_CLEAR(texthl);
- texthl = xstrnsave(arg, (size_t)(p - arg));
+ texthl = xmemdupz(arg, (size_t)(p - arg));
} else if (strncmp(arg, "culhl=", 6) == 0) {
arg += 6;
XFREE_CLEAR(culhl);
- culhl = xstrnsave(arg, (size_t)(p - arg));
+ culhl = xmemdupz(arg, (size_t)(p - arg));
} else if (strncmp(arg, "numhl=", 6) == 0) {
arg += 6;
XFREE_CLEAR(numhl);
- numhl = xstrnsave(arg, (size_t)(p - arg));
+ numhl = xmemdupz(arg, (size_t)(p - arg));
} else {
semsg(_(e_invarg2), arg);
failed = true;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 4b1f8afb15..864a55b12b 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2257,7 +2257,7 @@ static void use_midword(slang_T *lp, win_T *wp)
wp->w_s->b_spell_ismw[c] = true;
} else if (wp->w_s->b_spell_ismw_mb == NULL) {
// First multi-byte char in "b_spell_ismw_mb".
- wp->w_s->b_spell_ismw_mb = xstrnsave(p, (size_t)l);
+ wp->w_s->b_spell_ismw_mb = xmemdupz(p, (size_t)l);
} else {
// Append multi-byte chars to "b_spell_ismw_mb".
const int n = (int)strlen(wp->w_s->b_spell_ismw_mb);
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index 938e8cec8f..15ec652859 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -3146,7 +3146,7 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char *goodword, i
if (i < 0) {
// Add a suggestion.
stp = GA_APPEND_VIA_PTR(suggest_T, gap);
- stp->st_word = xstrnsave(goodword, (size_t)goodlen);
+ stp->st_word = xmemdupz(goodword, (size_t)goodlen);
stp->st_wordlen = goodlen;
stp->st_score = score;
stp->st_altscore = altscore;
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 61e8d8d2ff..d2466e4248 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -70,7 +70,7 @@ getkey:
update_screen();
setcursor(); // put cursor back where it belongs
}
- // Flush screen updates before blocking
+ // Flush screen updates before blocking.
ui_flush();
// Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index af82f5e578..26da38f284 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -2646,7 +2646,7 @@ void f_strcharpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = xstrndup(p + nbyte, (size_t)len);
+ rettv->vval.v_string = xmemdupz(p + nbyte, (size_t)len);
}
/// "strpart()" function
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 1d4c85de49..7a175926d2 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -707,7 +707,7 @@ void do_tag(char *tag, int type, int count, int forceit, int verbose)
&& tagp2.user_data) {
XFREE_CLEAR(tagstack[tagstackidx].user_data);
tagstack[tagstackidx].user_data =
- xstrnsave(tagp2.user_data, (size_t)(tagp2.user_data_end - tagp2.user_data));
+ xmemdupz(tagp2.user_data, (size_t)(tagp2.user_data_end - tagp2.user_data));
}
tagstackidx++;
diff --git a/src/nvim/window.c b/src/nvim/window.c
index eee500f695..d1b8d7c7b5 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -586,7 +586,7 @@ wingotofile:
}
// Make a copy, if the line was changed it will be freed.
- ptr = xstrnsave(ptr, len);
+ ptr = xmemdupz(ptr, len);
find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 953402ada3..3af1faaece 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -19,6 +19,20 @@ local sleep = helpers.sleep
local sid_api_client = -9
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()
before_each(clear)
@@ -32,9 +46,12 @@ describe('nvim_get_keymap', function()
rhs='bar',
expr=0,
sid=0,
+ scriptversion=1,
buffer=0,
nowait=0,
mode='n',
+ mode_bits=0x01,
+ abbr=0,
noremap=1,
lnum=0,
}
@@ -81,6 +98,7 @@ describe('nvim_get_keymap', function()
-- The table will be the same except for the mode
local insert_table = shallowcopy(foo_bar_map_table)
insert_table['mode'] = 'i'
+ insert_table['mode_bits'] = 0x10
eq({insert_table}, meths.get_keymap('i'))
end)
@@ -258,8 +276,10 @@ describe('nvim_get_keymap', function()
silent=0,
expr=0,
sid=0,
+ scriptversion=1,
buffer=0,
nowait=0,
+ abbr=0,
noremap=1,
lnum=0,
}
@@ -268,6 +288,7 @@ describe('nvim_get_keymap', function()
ret.lhs = lhs
ret.rhs = rhs
ret.mode = mode
+ ret.mode_bits = mode_bits_map[mode]
return ret
end
@@ -323,10 +344,13 @@ describe('nvim_get_keymap', function()
lhsraw='| |',
rhs='| |',
mode='n',
+ mode_bits=0x01,
+ abbr=0,
script=0,
silent=0,
expr=0,
sid=0,
+ scriptversion=1,
buffer=0,
nowait=0,
noremap=1,
@@ -365,15 +389,18 @@ describe('nvim_get_keymap', function()
silent=0,
expr=0,
sid=sid_lua,
+ scriptversion=1,
buffer=0,
nowait=0,
mode='n',
+ mode_bits=0x01,
+ abbr=0,
noremap=0,
lnum=0,
}, mapargs[1])
end)
- it ('can handle map descriptions', function()
+ it('can handle map descriptions', function()
meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
eq({
lhs='lhs',
@@ -383,9 +410,12 @@ describe('nvim_get_keymap', function()
silent=0,
expr=0,
sid=sid_api_client,
+ scriptversion=1,
buffer=0,
nowait=0,
mode='n',
+ mode_bits=0x01,
+ abbr=0,
noremap=0,
lnum=0,
desc='map description'
@@ -420,7 +450,10 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end
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.lhs = lhs
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.expr = not opts.expr and 0 or 1
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.lnum = not opts.lnum and 0 or opts.lnum
to_return.desc = opts.desc
@@ -487,35 +521,33 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
get_mapargs('', 'lhs'))
end)
- it('throws errors when given too-long mode shortnames', function()
- eq('Shortname is too long: map',
- pcall_err(meths.set_keymap, 'map', 'lhs', 'rhs', {}))
-
- eq('Shortname is too long: vmap',
- pcall_err(meths.set_keymap, 'vmap', 'lhs', 'rhs', {}))
-
- eq('Shortname is too long: xnoremap',
- pcall_err(meths.set_keymap, 'xnoremap', 'lhs', 'rhs', {}))
-
- eq('Shortname is too long: map', pcall_err(meths.del_keymap, 'map', 'lhs'))
- eq('Shortname is too long: vmap', pcall_err(meths.del_keymap, 'vmap', 'lhs'))
- eq('Shortname is too long: xnoremap', pcall_err(meths.del_keymap, 'xnoremap', 'lhs'))
- 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.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: "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: "!i"', pcall_err(meths.set_keymap, '!i', 'lhs', 'rhs', {}))
+ eq('Invalid mode shortname: "!!"', pcall_err(meths.set_keymap, '!!', '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: "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: "oa"', pcall_err(meths.del_keymap, 'oa', 'lhs'))
+ eq('Invalid mode shortname: "!o"', pcall_err(meths.del_keymap, '!o', 'lhs'))
+ eq('Invalid mode shortname: "!i"', pcall_err(meths.del_keymap, '!i', 'lhs'))
+ eq('Invalid mode shortname: "!!"', pcall_err(meths.del_keymap, '!!', 'lhs'))
+ eq('Invalid mode shortname: "map"', pcall_err(meths.del_keymap, 'map', 'lhs'))
+ eq('Invalid mode shortname: "vmap"', pcall_err(meths.del_keymap, 'vmap', 'lhs'))
+ eq('Invalid mode shortname: "xnoremap"', pcall_err(meths.del_keymap, 'xnoremap', 'lhs'))
end)
it('error on invalid optnames', function()
@@ -823,7 +855,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq(1, exec_lua[[return GlobalCount]])
end)
- it (':map command shows lua mapping correctly', function()
+ it(':map command shows lua mapping correctly', function()
exec_lua [[
vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end })
]]
@@ -835,7 +867,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
)
end)
- it ('mapcheck() returns lua mapping correctly', function()
+ it('mapcheck() returns lua mapping correctly', function()
exec_lua [[
vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end })
]]
@@ -843,7 +875,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
"^<Lua %d+>"))
end)
- it ('maparg() returns lua mapping correctly', function()
+ it('maparg() returns lua mapping correctly', function()
eq(0, exec_lua([[
GlobalCount = 0
vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index befbd4bc3b..038368c387 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -875,25 +875,41 @@ describe('jobs', function()
end)
end)
- it('hides cursor when waiting', function()
- local screen = Screen.new(30, 3)
+ it('hides cursor and flushes messages before blocking', function()
+ local screen = Screen.new(50, 6)
screen:set_default_attr_ids({
- [0] = {foreground = Screen.colors.Blue1, bold = true};
+ [0] = {foreground = Screen.colors.Blue, bold = true}; -- NonText
+ [1] = {bold = true, reverse = true}; -- MsgSeparator
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen}; -- MoreMsg
})
screen:attach()
command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]])
- feed_command('call jobwait([g:id], 300)')
+ source([[
+ func PrintAndWait()
+ echon "aaa\nbbb"
+ call jobwait([g:id], 300)
+ echon "\nccc"
+ endfunc
+ ]])
+ feed_command('call PrintAndWait()')
screen:expect{grid=[[
- |
- {0:~ }|
- :call jobwait([g:id], 300) |
+ |
+ {0:~ }|
+ {0:~ }|
+ {1: }|
+ aaa |
+ bbb |
]], timeout=100}
- funcs.jobstop(meths.get_var('id'))
screen:expect{grid=[[
- ^ |
- {0:~ }|
- :call jobwait([g:id], 300) |
+ |
+ {1: }|
+ aaa |
+ bbb |
+ ccc |
+ {2:Press ENTER or type command to continue}^ |
]]}
+ feed('<CR>')
+ funcs.jobstop(meths.get_var('id'))
end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 1ebfa9dd1d..a8a72f20c9 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -2559,7 +2559,6 @@ describe('lua stdlib', function()
]])
end)
-
it('should not block other events', function()
eq({time = true, wait_result = true}, exec_lua[[
start_time = get_time()
@@ -2601,6 +2600,7 @@ describe('lua stdlib', function()
}
]])
end)
+
it('should work with vim.defer_fn', function()
eq({time = true, wait_result = true}, exec_lua[[
start_time = get_time()
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index c9e004289d..3ee67a710c 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -3167,3 +3167,31 @@ it("with 'inccommand' typing :filter doesn't segfault or leak memory #19057", fu
feed('i')
assert_alive()
end)
+
+it("'inccommand' cannot be changed during preview #23136", function()
+ clear()
+ local screen = Screen.new(30, 6)
+ common_setup(screen, 'nosplit', 'foo\nbar\nbaz')
+ source([[
+ function! IncCommandToggle()
+ let prev = &inccommand
+
+ if &inccommand ==# 'split'
+ set inccommand=nosplit
+ elseif &inccommand ==# 'nosplit'
+ set inccommand=split
+ elseif &inccommand ==# ''
+ set inccommand=nosplit
+ else
+ throw 'unknown inccommand'
+ endif
+
+ return " \<BS>"
+ endfun
+
+ cnoremap <expr> <C-E> IncCommandToggle()
+ ]])
+
+ feed(':%s/foo/bar<C-E><C-E><C-E>')
+ assert_alive()
+end)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index a5b2474bc5..215e763fd1 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1312,17 +1312,54 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
]])
end)
- it('echo messages are shown correctly when getchar() immediately follows', function()
- feed([[:echo 'foo' | echo 'bar' | call getchar()<CR>]])
- screen:expect([[
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {3: }|
- foo |
- bar^ |
- ]])
+ describe('echo messages are shown when immediately followed by', function()
+ --- @param to_block string command to cause a blocking wait
+ --- @param to_unblock number|string number: timeout for blocking screen
+ --- string: keys to stop the blocking wait
+ local function test_flush_before_block(to_block, to_unblock)
+ local timeout = type(to_unblock) == 'number' and to_unblock or nil
+ exec(([[
+ func PrintAndWait()
+ echon "aaa\nbbb"
+ %s
+ echon "\nccc"
+ endfunc
+ ]]):format(to_block))
+ feed(':call PrintAndWait()<CR>')
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3: }|
+ aaa |
+ bbb^ |
+ ]], timeout=timeout}
+ if type(to_unblock) == 'string' then
+ feed(to_unblock)
+ end
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {3: }|
+ aaa |
+ bbb |
+ ccc |
+ {4:Press ENTER or type command to continue}^ |
+ ]]}
+ end
+
+ it('getchar()', function()
+ test_flush_before_block([[call getchar()]], 'k')
+ end)
+
+ it('wait()', function()
+ test_flush_before_block([[call wait(300, '0')]], 100)
+ end)
+
+ it('lua vim.wait()', function()
+ test_flush_before_block([[lua vim.wait(300, function() end)]], 100)
+ end)
end)
it('consecutive calls to win_move_statusline() work after multiline message #21014',function()
diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua
index 2c8fe69428..acba5e9708 100644
--- a/test/functional/vimscript/map_functions_spec.lua
+++ b/test/functional/vimscript/map_functions_spec.lua
@@ -26,9 +26,12 @@ describe('maparg()', function()
rhs='bar',
expr=0,
sid=0,
+ scriptversion=1,
buffer=0,
nowait=0,
mode='n',
+ mode_bits=0x01,
+ abbr=0,
noremap=1,
lnum=0,
}
@@ -155,10 +158,13 @@ describe('maparg()', function()
buffer = 0,
expr = 0,
mode = 'n',
+ mode_bits = 0x01,
+ abbr = 0,
noremap = 1,
nowait = 0,
- script=0,
+ script = 0,
sid = 0,
+ scriptversion = 1,
silent = 0,
lnum = 0,
}
diff --git a/test/old/testdir/setup.vim b/test/old/testdir/setup.vim
index b0c2a15a3f..7546b342e6 100644
--- a/test/old/testdir/setup.vim
+++ b/test/old/testdir/setup.vim
@@ -58,6 +58,11 @@ func Ntest_setmouse(row, col)
endif
endfunc
+" roughly equivalent to term_wait() in Vim
+func Nterm_wait(buf, time = 10)
+ execute $'sleep {a:time}m'
+endfunc
+
" Prevent Nvim log from writing to stderr.
let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
diff --git a/test/old/testdir/test_maparg.vim b/test/old/testdir/test_map_functions.vim
index 1837511990..2aeb470a0d 100644
--- a/test/old/testdir/test_maparg.vim
+++ b/test/old/testdir/test_map_functions.vim
@@ -1,4 +1,4 @@
-" Tests for maparg(), mapcheck() and mapset().
+" Tests for maparg(), mapcheck(), mapset(), maplist()
" Also test utf8 map with a 0x80 byte.
source shared.vim
@@ -19,28 +19,41 @@ func Test_maparg()
call assert_equal("is<F4>foo", maparg('foo<C-V>'))
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>',
\ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16",
- \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
- \ 'rhs': 'is<F4>foo', 'buffer': 0},
+ \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
+ \ 'lnum': lnum + 1,
+ \ 'rhs': 'is<F4>foo', 'buffer': 0, 'abbr': 0, 'mode_bits': 0x47},
\ maparg('foo<C-V>', '', 0, 1))
call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar',
\ 'lhsraw': 'bar', 'mode': 'v',
- \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
- \ 'rhs': 'isbar', 'buffer': 1},
+ \ 'nowait': 0, 'expr': 1, 'sid': sid, 'scriptversion': 1,
+ \ 'lnum': lnum + 2,
+ \ 'rhs': 'isbar', 'buffer': 1, 'abbr': 0, 'mode_bits': 0x42},
\ 'bar'->maparg('', 0, 1))
let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo',
\ 'lhsraw': 'foo', 'mode': ' ',
- \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
- \ 'buffer': 1},
+ \ 'nowait': 1, 'expr': 0, 'sid': sid, 'scriptversion': 1,
+ \ 'lnum': lnum + 1, 'rhs': 'bar',
+ \ 'buffer': 1, 'abbr': 0, 'mode_bits': 0x47},
\ maparg('foo', '', 0, 1))
let lnum = expand('<sflnum>')
tmap baz foo
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz',
\ 'lhsraw': 'baz', 'mode': 't',
- \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
- \ 'buffer': 0},
+ \ 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
+ \ 'lnum': lnum + 1, 'rhs': 'foo',
+ \ 'buffer': 0, 'abbr': 0, 'mode_bits': 0x80},
\ 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
call assert_equal("xrx", maparg('abc'))
@@ -274,6 +287,152 @@ func Test_mapset()
call assert_fails('call mapset("i", 0, {})', 'E460:')
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)
call assert_equal('<C-B>', a:d.lhs)
if a:check_alt
@@ -368,4 +527,92 @@ func Test_map_restore_negative_sid()
call delete('Xresult')
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
diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim
index 40d0b3e6f7..36a46684c1 100644
--- a/test/old/testdir/test_mapping.vim
+++ b/test/old/testdir/test_mapping.vim
@@ -1051,7 +1051,6 @@ func Test_map_cmdkey()
call assert_equal('t', m)
call assert_equal('t', mode(1))
call StopShellInTerminal(buf)
- call TermWait(buf)
close!
tunmap <F3>
endif
diff --git a/test/old/testdir/test_modeline.vim b/test/old/testdir/test_modeline.vim
index 613722fdbd..487a89e038 100644
--- a/test/old/testdir/test_modeline.vim
+++ b/test/old/testdir/test_modeline.vim
@@ -172,6 +172,8 @@ func Test_modeline_colon()
endfunc
func s:modeline_fails(what, text, error)
+ " Don't use CheckOption(), it would skip the whole test
+ " just for a single un-supported option
if !exists('+' .. a:what)
return
endif
diff --git a/test/old/testdir/test_statusline.vim b/test/old/testdir/test_statusline.vim
index fccfd46966..c48bac12b4 100644
--- a/test/old/testdir/test_statusline.vim
+++ b/test/old/testdir/test_statusline.vim
@@ -617,4 +617,25 @@ func Test_statusline_showcmd()
call StopVimInTerminal(buf)
endfunc
+func Test_statusline_highlight_group_cleared()
+ CheckScreendump
+
+ " the laststatus option is there to prevent
+ " the code-style test from complaining about
+ " trailing whitespace
+ let lines =<< trim END
+ set fillchars=stl:\ ,stlnc:\ laststatus=2
+ split
+ hi clear StatusLine
+ hi clear StatusLineNC
+ END
+ call writefile(lines, 'XTest_statusline_stl', 'D')
+
+ let buf = RunVimInTerminal('-S XTest_statusline_stl', {})
+
+ call VerifyScreenDump(buf, 'Test_statusline_stl_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_termdebug.vim b/test/old/testdir/test_termdebug.vim
new file mode 100644
index 0000000000..ab1a76000a
--- /dev/null
+++ b/test/old/testdir/test_termdebug.vim
@@ -0,0 +1,197 @@
+" Test for the termdebug plugin
+
+source shared.vim
+source check.vim
+
+CheckUnix
+" CheckFeature terminal
+CheckExecutable gdb
+CheckExecutable gcc
+
+let g:GDB = exepath('gdb')
+if g:GDB->empty()
+ throw 'Skipped: gdb is not found in $PATH'
+endif
+
+let g:GCC = exepath('gcc')
+if g:GCC->empty()
+ throw 'Skipped: gcc is not found in $PATH'
+endif
+
+packadd termdebug
+
+func Test_termdebug_basic()
+ let lines =<< trim END
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int isprime(int n)
+ {
+ if (n <= 1)
+ return 0;
+
+ for (int i = 2; i <= n / 2; i++)
+ if (n % i == 0)
+ return 0;
+
+ return 1;
+ }
+
+ int main(int argc, char *argv[])
+ {
+ int n = 7;
+
+ printf("%d is %s prime\n", n, isprime(n) ? "a" : "not a");
+
+ return 0;
+ }
+ END
+ call writefile(lines, 'XTD_basic.c', 'D')
+ call system($'{g:GCC} -g -o XTD_basic XTD_basic.c')
+
+ edit XTD_basic.c
+ Termdebug ./XTD_basic
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ let gdb_buf = winbufnr(1)
+ wincmd b
+ Break 9
+ call Nterm_wait(gdb_buf)
+ redraw!
+ call assert_equal([
+ \ {'lnum': 9, 'id': 1014, 'name': 'debugBreakpoint1.0',
+ \ 'priority': 110, 'group': 'TermDebug'}],
+ \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)
+ Run
+ call Nterm_wait(gdb_buf, 400)
+ redraw!
+ call WaitForAssert({-> assert_equal([
+ \ {'lnum': 9, 'id': 12, 'name': 'debugPC', 'priority': 110,
+ \ 'group': 'TermDebug'},
+ \ {'lnum': 9, 'id': 1014, 'name': 'debugBreakpoint1.0',
+ \ 'priority': 110, 'group': 'TermDebug'}],
+ "\ sign_getplaced('', #{group: 'TermDebug'})[0].signs)})
+ \ sign_getplaced('', #{group: 'TermDebug'})[0].signs->reverse())})
+ Finish
+ call Nterm_wait(gdb_buf)
+ redraw!
+ call WaitForAssert({-> assert_equal([
+ \ {'lnum': 9, 'id': 1014, 'name': 'debugBreakpoint1.0',
+ \ 'priority': 110, 'group': 'TermDebug'},
+ \ {'lnum': 20, 'id': 12, 'name': 'debugPC',
+ \ 'priority': 110, 'group': 'TermDebug'}],
+ \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)})
+ Continue
+
+ let cn = 0
+ " 60 is approx spaceBuffer * 3
+ if winwidth(0) <= 78 + 60
+ Var
+ call assert_equal(winnr(), winnr('$'))
+ call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]])
+ let cn += 1
+ bw!
+ Asm
+ call assert_equal(winnr(), winnr('$'))
+ call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]])
+ let cn += 1
+ bw!
+ endif
+ set columns=160
+ Var
+ call assert_equal(winnr(), winnr('$') - 1)
+ call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]])
+ let cn += 1
+ bw!
+ Asm
+ call assert_equal(winnr(), winnr('$') - 1)
+ call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]])
+ let cn += 1
+ bw!
+ set columns&
+
+ wincmd t
+ " Nvim: stop GDB process and process pending events
+ call chanclose(&channel)
+ call wait(0, '0')
+ quit!
+ redraw!
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ call assert_equal([], sign_getplaced('', #{group: 'TermDebug'})[0].signs)
+
+ call delete('XTD_basic')
+ %bw!
+endfunc
+
+func Test_termdebug_mapping()
+ %bw!
+ call assert_equal(maparg('K', 'n', 0, 1)->empty(), 1)
+ call assert_equal(maparg('-', 'n', 0, 1)->empty(), 1)
+ call assert_equal(maparg('+', 'n', 0, 1)->empty(), 1)
+ Termdebug
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ wincmd b
+ call assert_equal(maparg('K', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('-', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('+', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('K', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('-', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('+', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('K', 'n', 0, 1).rhs, ':Evaluate<CR>')
+ wincmd t
+ quit!
+ redraw!
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ call assert_equal(maparg('K', 'n', 0, 1)->empty(), 1)
+ call assert_equal(maparg('-', 'n', 0, 1)->empty(), 1)
+ call assert_equal(maparg('+', 'n', 0, 1)->empty(), 1)
+
+ %bw!
+ nnoremap K :echom "K"<cr>
+ nnoremap - :echom "-"<cr>
+ nnoremap + :echom "+"<cr>
+ Termdebug
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ wincmd b
+ call assert_equal(maparg('K', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('-', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('+', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('K', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('-', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('+', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('K', 'n', 0, 1).rhs, ':Evaluate<CR>')
+ wincmd t
+ quit!
+ redraw!
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ call assert_equal(maparg('K', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('-', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('+', 'n', 0, 1)->empty(), 0)
+ call assert_equal(maparg('K', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('-', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('+', 'n', 0, 1).buffer, 0)
+ call assert_equal(maparg('K', 'n', 0, 1).rhs, ':echom "K"<cr>')
+
+ %bw!
+ nnoremap <buffer> K :echom "bK"<cr>
+ nnoremap <buffer> - :echom "b-"<cr>
+ nnoremap <buffer> + :echom "b+"<cr>
+ Termdebug
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ wincmd b
+ call assert_equal(maparg('K', 'n', 0, 1).buffer, 1)
+ call assert_equal(maparg('-', 'n', 0, 1).buffer, 1)
+ call assert_equal(maparg('+', 'n', 0, 1).buffer, 1)
+ call assert_equal(maparg('K', 'n', 0, 1).rhs, ':echom "bK"<cr>')
+ wincmd t
+ quit!
+ redraw!
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ call assert_equal(maparg('K', 'n', 0, 1).buffer, 1)
+ call assert_equal(maparg('-', 'n', 0, 1).buffer, 1)
+ call assert_equal(maparg('+', 'n', 0, 1).buffer, 1)
+ call assert_equal(maparg('K', 'n', 0, 1).rhs, ':echom "bK"<cr>')
+
+ %bw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab