aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/rustfmt.vim7
-rw-r--r--runtime/doc/builtin.txt34
-rw-r--r--runtime/ftplugin/rust.vim16
-rw-r--r--runtime/lua/vim/_meta/builtin_types.lua4
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua42
-rw-r--r--src/nvim/drawline.c3
-rw-r--r--src/nvim/eval.lua42
-rw-r--r--src/nvim/mapping.c56
-rw-r--r--src/nvim/move.c10
-rw-r--r--src/nvim/window.c2
-rw-r--r--test/functional/api/keymap_spec.lua20
-rw-r--r--test/functional/ui/decorations_spec.lua34
-rw-r--r--test/functional/ui/winbar_spec.lua9
-rw-r--r--test/old/testdir/test_ins_complete.vim29
14 files changed, 226 insertions, 82 deletions
diff --git a/runtime/autoload/rustfmt.vim b/runtime/autoload/rustfmt.vim
index 8fd3858178..f325df2fda 100644
--- a/runtime/autoload/rustfmt.vim
+++ b/runtime/autoload/rustfmt.vim
@@ -1,5 +1,6 @@
" Author: Stephen Sugden <stephen@stephensugden.com>
" Last Modified: 2023-09-11
+" Last Change: 2025 Mar 31 by Vim project (rename s:RustfmtConfigOptions())
"
" Adapted from https://github.com/fatih/vim-go
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
@@ -61,7 +62,7 @@ function! s:RustfmtWriteMode()
endif
endfunction
-function! s:RustfmtConfigOptions()
+function! rustfmt#RustfmtConfigOptions()
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
if l:rustfmt_toml !=# ''
return '--config-path '.shellescape(fnamemodify(l:rustfmt_toml, ":p"))
@@ -84,7 +85,7 @@ function! s:RustfmtCommandRange(filename, line1, line2)
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
let l:write_mode = s:RustfmtWriteMode()
- let l:rustfmt_config = s:RustfmtConfigOptions()
+ let l:rustfmt_config = rustfmt#RustfmtConfigOptions()
" FIXME: When --file-lines gets to be stable, add version range checking
" accordingly.
@@ -99,7 +100,7 @@ endfunction
function! s:RustfmtCommand()
let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display'
- let config = s:RustfmtConfigOptions()
+ let config = rustfmt#RustfmtConfigOptions()
return join([g:rustfmt_command, write_mode, config, g:rustfmt_options])
endfunction
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 3ad5d83ac2..a4061e7228 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -110,7 +110,7 @@ append({lnum}, {text}) *append()*
<
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
• {text} (`string|string[]`)
Return: ~
@@ -1047,7 +1047,7 @@ cindent({lnum}) *cindent()*
To get or set indent of lines in a string, see |vim.text.indent()|.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -1637,7 +1637,7 @@ diff_filler({lnum}) *diff_filler()*
Returns 0 if the current window is not in diff mode.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -1654,7 +1654,7 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
syntax information about the highlighting.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
• {col} (`integer`)
Return: ~
@@ -2563,7 +2563,7 @@ foldclosed({lnum}) *foldclosed()*
line, "'m" mark m, etc.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -2576,7 +2576,7 @@ foldclosedend({lnum}) *foldclosedend()*
line, "'m" mark m, etc.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -2594,7 +2594,7 @@ foldlevel({lnum}) *foldlevel()*
line, "'m" mark m, etc.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -2629,7 +2629,7 @@ foldtextresult({lnum}) *foldtextresult()*
Useful when exporting folded text, e.g., to HTML.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`string`)
@@ -5706,7 +5706,7 @@ line2byte({lnum}) *line2byte()*
Also see |byte2line()|, |go| and |:goto|.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -5719,7 +5719,7 @@ lispindent({lnum}) *lispindent()*
When {lnum} is invalid, -1 is returned.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -6090,7 +6090,7 @@ mapset({dict})
<
Parameters: ~
- • {dict} (`boolean`)
+ • {dict} (`table<string,any>`)
Return: ~
(`any`)
@@ -6993,7 +6993,7 @@ nextnonblank({lnum}) *nextnonblank()*
See also |prevnonblank()|.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -7127,7 +7127,7 @@ prevnonblank({lnum}) *prevnonblank()*
Also see |nextnonblank()|.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -8940,7 +8940,7 @@ setline({lnum}, {text}) *setline()*
< Note: The '[ and '] marks are not set.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
• {text} (`any`)
Return: ~
@@ -10854,7 +10854,7 @@ synID({lnum}, {col}, {trans}) *synID()*
<
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
• {col} (`integer`)
• {trans} (`0|1`)
@@ -10959,7 +10959,7 @@ synconcealed({lnum}, {col}) *synconcealed()*
mechanisms |syntax-vs-match|.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
• {col} (`integer`)
Return: ~
@@ -10985,7 +10985,7 @@ synstack({lnum}, {col}) *synstack()*
valid positions.
Parameters: ~
- • {lnum} (`integer`)
+ • {lnum} (`integer|string`)
• {col} (`integer`)
Return: ~
diff --git a/runtime/ftplugin/rust.vim b/runtime/ftplugin/rust.vim
index 3e2741f919..53f7f83363 100644
--- a/runtime/ftplugin/rust.vim
+++ b/runtime/ftplugin/rust.vim
@@ -3,6 +3,7 @@
" Maintainer: Chris Morgan <me@chrismorgan.info>
" Last Change: 2024 Mar 17
" 2024 May 23 by Riley Bruins <ribru17@gmail.com ('commentstring')
+" 2025 Mar 31 by Vim project (set 'formatprg' option)
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("b:did_ftplugin")
@@ -57,6 +58,19 @@ setlocal includeexpr=rust#IncludeExpr(v:fname)
setlocal suffixesadd=.rs
+if executable(get(g:, 'rustfmt_command', 'rustfmt'))
+ if get(g:, "rustfmt_fail_silently", 0)
+ augroup rust.vim.FailSilently
+ autocmd! * <buffer>
+ autocmd ShellFilterPost <buffer> if v:shell_error | execute 'echom "shell filter returned error " . v:shell_error . ", undoing changes"' | undo | endif
+ augroup END
+ endif
+
+ let &l:formatprg = get(g:, 'rustfmt_command', 'rustfmt') . ' ' .
+ \ get(g:, 'rustfmt_options', '') . ' ' .
+ \ rustfmt#RustfmtConfigOptions()
+endif
+
if exists("g:ftplugin_rust_source_path")
let &l:path=g:ftplugin_rust_source_path . ',' . &l:path
endif
@@ -149,7 +163,7 @@ endif
let b:undo_ftplugin = "
\ compiler make |
- \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd<
+ \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd< formatprg<
\|if exists('b:rust_set_style')
\|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth<
\|endif
diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua
index 9dd0374486..763153f38d 100644
--- a/runtime/lua/vim/_meta/builtin_types.lua
+++ b/runtime/lua/vim/_meta/builtin_types.lua
@@ -184,14 +184,14 @@
--- @field signs vim.fn.sign[]
--- @class vim.fn.sign_place.dict
---- @field lnum? integer
+--- @field lnum? integer|string
--- @field priority? integer
--- @class vim.fn.sign_placelist.list.item
--- @field buffer integer|string
--- @field group? string
--- @field id? integer
---- @field lnum integer
+--- @field lnum? integer|string
--- @field name string
--- @field priority? integer
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 813a89898e..157799f36e 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -85,7 +85,7 @@ function vim.fn.api_info() end
--- let failed = append(0, ["Chapter 1", "the beginning"])
--- <
---
---- @param lnum integer
+--- @param lnum integer|string
--- @param text string|string[]
--- @return 0|1
function vim.fn.append(lnum, text) end
@@ -907,7 +907,7 @@ function vim.fn.chdir(dir) end
---
--- To get or set indent of lines in a string, see |vim.text.indent()|.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.cindent(lnum) end
@@ -1244,7 +1244,7 @@ function vim.fn.ctxset(context, index) end
--- @return any
function vim.fn.ctxsize() end
---- @param lnum integer
+--- @param lnum integer|string
--- @param col? integer
--- @param off? integer
--- @return any
@@ -1441,7 +1441,7 @@ function vim.fn.did_filetype() end
--- line, "'m" mark m, etc.
--- Returns 0 if the current window is not in diff mode.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.diff_filler(lnum) end
@@ -1455,7 +1455,7 @@ function vim.fn.diff_filler(lnum) end
--- The highlight ID can be used with |synIDattr()| to obtain
--- syntax information about the highlighting.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @param col integer
--- @return any
function vim.fn.diff_hlID(lnum, col) end
@@ -2282,7 +2282,7 @@ function vim.fn.fnamemodify(fname, mods) end
--- {lnum} is used like with |getline()|. Thus "." is the current
--- line, "'m" mark m, etc.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.foldclosed(lnum) end
@@ -2292,7 +2292,7 @@ function vim.fn.foldclosed(lnum) end
--- {lnum} is used like with |getline()|. Thus "." is the current
--- line, "'m" mark m, etc.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.foldclosedend(lnum) end
@@ -2307,7 +2307,7 @@ function vim.fn.foldclosedend(lnum) end
--- {lnum} is used like with |getline()|. Thus "." is the current
--- line, "'m" mark m, etc.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.foldlevel(lnum) end
@@ -2338,7 +2338,7 @@ function vim.fn.foldtext() end
--- line, "'m" mark m, etc.
--- Useful when exporting folded text, e.g., to HTML.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return string
function vim.fn.foldtextresult(lnum) end
@@ -3284,7 +3284,7 @@ function vim.fn.getjumplist(winnr, tabnr) end
--- @return string
function vim.fn.getline(lnum, end_) end
---- @param lnum integer
+--- @param lnum integer|string
--- @param end_ true|number|string|table
--- @return string|string[]
function vim.fn.getline(lnum, end_) end
@@ -5170,7 +5170,7 @@ function vim.fn.line(expr, winid) end
--- |getline()|. When {lnum} is invalid -1 is returned.
--- Also see |byte2line()|, |go| and |:goto|.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.line2byte(lnum) end
@@ -5180,7 +5180,7 @@ function vim.fn.line2byte(lnum) end
--- relevant. {lnum} is used just like in |getline()|.
--- When {lnum} is invalid, -1 is returned.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.lispindent(lnum) end
@@ -5479,7 +5479,7 @@ function vim.fn.mapnew(expr1, expr2) end
--- @param mode string
--- @param abbr? boolean
---- @param dict? boolean
+--- @param dict? table<string,any>
--- @return any
function vim.fn.mapset(mode, abbr, dict) end
@@ -5519,7 +5519,7 @@ function vim.fn.mapset(mode, abbr, dict) end
--- endfor
--- <
---
---- @param dict boolean
+--- @param dict table<string,any>
--- @return any
function vim.fn.mapset(dict) end
@@ -6355,7 +6355,7 @@ function vim.fn.msgpackparse(data) end
--- {lnum} is used like with |getline()|.
--- See also |prevnonblank()|.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.nextnonblank(lnum) end
@@ -6454,7 +6454,7 @@ function vim.fn.pow(x, y) end
--- {lnum} is used like with |getline()|.
--- Also see |nextnonblank()|.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @return integer
function vim.fn.prevnonblank(lnum) end
@@ -8063,7 +8063,7 @@ function vim.fn.setcmdline(str, pos) end
--- @return any
function vim.fn.setcmdpos(pos) end
---- @param lnum integer
+--- @param lnum integer|string
--- @param col? integer
--- @param off? integer
--- @return any
@@ -8142,7 +8142,7 @@ function vim.fn.setfperm(fname, mode) end
---
--- <Note: The '[ and '] marks are not set.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @param text any
--- @return any
function vim.fn.setline(lnum, text) end
@@ -9898,7 +9898,7 @@ function vim.fn.swapname(buf) end
--- echo synIDattr(synID(line("."), col("."), 1), "name")
--- <
---
---- @param lnum integer
+--- @param lnum integer|string
--- @param col integer
--- @param trans 0|1
--- @return integer
@@ -9994,7 +9994,7 @@ function vim.fn.synIDtrans(synID) end
--- since syntax and matching highlighting are two different
--- mechanisms |syntax-vs-match|.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @param col integer
--- @return [integer, string, integer]
function vim.fn.synconcealed(lnum, col) end
@@ -10017,7 +10017,7 @@ function vim.fn.synconcealed(lnum, col) end
--- character in a line and the first column in an empty line are
--- valid positions.
---
---- @param lnum integer
+--- @param lnum integer|string
--- @param col integer
--- @return integer[]
function vim.fn.synstack(lnum, col) end
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 43d9f67b5c..79cfc1ab2f 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -1163,7 +1163,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, b
}
}
- decor_providers_invoke_line(wp, lnum - 1);
+ decor_providers_invoke_line(wp, lnum - 1); // may invalidate wp->w_virtcol
+ validate_virtcol(wp);
has_decor = decor_redraw_line(wp, lnum - 1, &decor_state);
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index ffdbacb2b4..9f662c6457 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -153,7 +153,7 @@ M.funcs = {
]=],
name = 'append',
- params = { { 'lnum', 'integer' }, { 'text', 'string|string[]' } },
+ params = { { 'lnum', 'integer|string' }, { 'text', 'string|string[]' } },
returns = '0|1',
signature = 'append({lnum}, {text})',
},
@@ -1235,7 +1235,7 @@ M.funcs = {
]=],
name = 'cindent',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'cindent({lnum})',
},
@@ -1663,7 +1663,7 @@ M.funcs = {
args = { 1, 3 },
base = 1,
name = 'cursor',
- params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'off', 'integer' } },
+ params = { { 'lnum', 'integer|string' }, { 'col', 'integer' }, { 'off', 'integer' } },
signature = 'cursor({lnum}, {col} [, {off}])',
},
cursor__1 = {
@@ -1898,7 +1898,7 @@ M.funcs = {
]=],
name = 'diff_filler',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'diff_filler({lnum})',
},
@@ -1918,7 +1918,7 @@ M.funcs = {
]=],
name = 'diff_hlID',
- params = { { 'lnum', 'integer' }, { 'col', 'integer' } },
+ params = { { 'lnum', 'integer|string' }, { 'col', 'integer' } },
signature = 'diff_hlID({lnum}, {col})',
},
digraph_get = {
@@ -2915,7 +2915,7 @@ M.funcs = {
]=],
name = 'foldclosed',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'foldclosed({lnum})',
},
@@ -2931,7 +2931,7 @@ M.funcs = {
]=],
name = 'foldclosedend',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'foldclosedend({lnum})',
},
@@ -2952,7 +2952,7 @@ M.funcs = {
]=],
name = 'foldlevel',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'foldlevel({lnum})',
},
@@ -2993,7 +2993,7 @@ M.funcs = {
]=],
name = 'foldtextresult',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'string',
signature = 'foldtextresult({lnum})',
},
@@ -4126,7 +4126,7 @@ M.funcs = {
args = { 2 },
base = 1,
name = 'getline',
- params = { { 'lnum', 'integer' }, { 'end', 'true|number|string|table' } },
+ params = { { 'lnum', 'integer|string' }, { 'end', 'true|number|string|table' } },
returns = 'string|string[]',
},
getloclist = {
@@ -6374,7 +6374,7 @@ M.funcs = {
]=],
name = 'line2byte',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'line2byte({lnum})',
},
@@ -6390,7 +6390,7 @@ M.funcs = {
]=],
name = 'lispindent',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'lispindent({lnum})',
},
@@ -6762,7 +6762,7 @@ M.funcs = {
args = { 1, 3 },
base = 1,
name = 'mapset',
- params = { { 'mode', 'string' }, { 'abbr', 'boolean' }, { 'dict', 'boolean' } },
+ params = { { 'mode', 'string' }, { 'abbr', 'boolean' }, { 'dict', 'table<string,any>' } },
signature = 'mapset({mode}, {abbr}, {dict})',
},
mapset__1 = {
@@ -6806,7 +6806,7 @@ M.funcs = {
<
]=],
name = 'mapset',
- params = { { 'dict', 'boolean' } },
+ params = { { 'dict', 'table<string,any>' } },
signature = 'mapset({dict})',
},
match = {
@@ -7751,7 +7751,7 @@ M.funcs = {
]=],
name = 'nextnonblank',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'nextnonblank({lnum})',
},
@@ -7899,7 +7899,7 @@ M.funcs = {
]=],
name = 'prevnonblank',
- params = { { 'lnum', 'integer' } },
+ params = { { 'lnum', 'integer|string' } },
returns = 'integer',
signature = 'prevnonblank({lnum})',
},
@@ -9775,7 +9775,7 @@ M.funcs = {
args = { 1, 3 },
base = 1,
name = 'setcursorcharpos',
- params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'off', 'integer' } },
+ params = { { 'lnum', 'integer|string' }, { 'col', 'integer' }, { 'off', 'integer' } },
signature = 'setcursorcharpos({lnum}, {col} [, {off}])',
},
setcursorcharpos__1 = {
@@ -9870,7 +9870,7 @@ M.funcs = {
]=],
name = 'setline',
- params = { { 'lnum', 'integer' }, { 'text', 'any' } },
+ params = { { 'lnum', 'integer|string' }, { 'text', 'any' } },
signature = 'setline({lnum}, {text})',
},
setloclist = {
@@ -11939,7 +11939,7 @@ M.funcs = {
<
]=],
name = 'synID',
- params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'trans', '0|1' } },
+ params = { { 'lnum', 'integer|string' }, { 'col', 'integer' }, { 'trans', '0|1' } },
returns = 'integer',
signature = 'synID({lnum}, {col}, {trans})',
},
@@ -12046,7 +12046,7 @@ M.funcs = {
mechanisms |syntax-vs-match|.
]=],
name = 'synconcealed',
- params = { { 'lnum', 'integer' }, { 'col', 'integer' } },
+ params = { { 'lnum', 'integer|string' }, { 'col', 'integer' } },
returns = '[integer, string, integer]',
signature = 'synconcealed({lnum}, {col})',
},
@@ -12072,7 +12072,7 @@ M.funcs = {
valid positions.
]=],
name = 'synstack',
- params = { { 'lnum', 'integer' }, { 'col', 'integer' } },
+ params = { { 'lnum', 'integer|string' }, { 'col', 'integer' } },
returns = 'integer[]',
signature = 'synstack({lnum}, {col})',
},
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 3dc66f7dba..36369e1e57 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -681,12 +681,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
if ((mp->m_mode & mode) != 0
&& mp->m_keylen == len
&& strncmp(mp->m_keys, lhs, (size_t)len) == 0) {
- if (is_abbrev) {
- semsg(_(e_global_abbreviation_already_exists_for_str), mp->m_keys);
- } else {
- semsg(_(e_global_mapping_already_exists_for_str), mp->m_keys);
- }
- retval = 5;
+ retval = 6;
goto theend;
}
}
@@ -799,11 +794,6 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
did_it = true;
break;
} else if (args->unique) {
- if (is_abbrev) {
- semsg(_(e_abbreviation_already_exists_for_str), p);
- } else {
- semsg(_(e_mapping_already_exists_for_str), p);
- }
retval = 5;
goto theend;
} else {
@@ -962,6 +952,7 @@ theend:
/// - 2 for no match
/// - 4 for out of mem (deprecated, WON'T HAPPEN)
/// - 5 for entry not unique
+/// - 6 for buflocal unique entry conflicts with global entry
///
int do_map(int maptype, char *arg, int mode, bool is_abbrev)
{
@@ -2637,16 +2628,47 @@ static void do_exmap(exarg_T *eap, int isabbrev)
char *cmdp = eap->cmd;
int mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
- switch (do_map((*cmdp == 'n') ? MAPTYPE_NOREMAP
- : (*cmdp == 'u') ? MAPTYPE_UNMAP : MAPTYPE_MAP,
- eap->arg, mode, isabbrev)) {
+ int maptype;
+ if (*cmdp == 'n') {
+ maptype = MAPTYPE_NOREMAP;
+ } else if (*cmdp == 'u') {
+ maptype = MAPTYPE_UNMAP;
+ } else {
+ maptype = MAPTYPE_MAP;
+ }
+ MapArguments parsed_args;
+ int result = str_to_mapargs(eap->arg, maptype == MAPTYPE_UNMAP, &parsed_args);
+ switch (result) {
+ case 0:
+ break;
+ case 1:
+ emsg(_(e_invarg));
+ goto free_rhs;
+ break;
+ default:
+ assert(false && "Unknown return code from str_to_mapargs!");
+ goto free_rhs;
+ }
+ switch (buf_do_map(maptype, &parsed_args, mode, isabbrev, curbuf)) {
case 1:
emsg(_(e_invarg));
break;
case 2:
emsg(isabbrev ? _(e_noabbr) : _(e_nomap));
break;
+ case 5:
+ semsg(isabbrev ? _(e_abbreviation_already_exists_for_str)
+ : _(e_mapping_already_exists_for_str),
+ parsed_args.lhs);
+ break;
+ case 6:
+ semsg(isabbrev ? _(e_global_abbreviation_already_exists_for_str)
+ : _(e_global_mapping_already_exists_for_str),
+ parsed_args.lhs);
}
+free_rhs:
+ xfree(parsed_args.rhs);
+ xfree(parsed_args.orig_rhs);
}
/// ":abbreviate" and friends.
@@ -2808,6 +2830,12 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
is_abbrev ? e_abbreviation_already_exists_for_str
: e_mapping_already_exists_for_str, lhs.data);
goto fail_and_free;
+ break;
+ case 6:
+ api_set_error(err, kErrorTypeException,
+ is_abbrev ? e_global_abbreviation_already_exists_for_str
+ : e_global_mapping_already_exists_for_str, lhs.data);
+ goto fail_and_free;
default:
assert(false && "Unrecognized return code!");
goto fail_and_free;
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 89d2b69f51..55e724f38d 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1363,8 +1363,9 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold)
}
wp->w_botline -= wp->w_topline - first;
wp->w_topline = first;
+ } else if (decor_conceal_line(wp, wp->w_topline - 1, false)) {
+ todo++;
} else {
- todo += decor_conceal_line(wp, wp->w_topline - 1, false);
if (do_sms) {
int size = linetabsize_eol(wp, wp->w_topline);
if (size > width1) {
@@ -1386,6 +1387,13 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold)
wp->w_botline--; // approximate w_botline
invalidate_botline(wp);
}
+
+ // Adjust for concealed lines above w_topline
+ while (wp->w_topline > 1 && decor_conceal_line(wp, wp->w_topline - 2, false)) {
+ wp->w_topline--;
+ hasFolding(wp, wp->w_topline, &wp->w_topline, NULL);
+ }
+
wp->w_wrow += done; // keep w_wrow updated
wp->w_cline_row += done; // keep w_cline_row updated
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 916c193469..3022dccb1c 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6634,7 +6634,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor)
int prev_height = wp->w_height_inner;
int height = wp->w_height_request;
if (height == 0) {
- height = wp->w_height - wp->w_winbar_height;
+ height = MAX(0, wp->w_height - wp->w_winbar_height);
}
if (height != prev_height) {
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index acaccee4e5..2c44905274 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -1465,4 +1465,24 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
eq(1, exec_lua [[return GlobalCount]])
eq('\nNo mapping found', n.exec_capture('nmap <C-I>'))
end)
+
+ it('does not overwrite in <unique> mappings', function()
+ api.nvim_buf_set_keymap(0, 'i', 'lhs', 'rhs', {})
+ eq(
+ 'E227: Mapping already exists for lhs',
+ pcall_err(api.nvim_buf_set_keymap, 0, 'i', 'lhs', 'rhs', { unique = true })
+ )
+
+ api.nvim_buf_set_keymap(0, 'ia', 'lhs2', 'rhs2', {})
+ eq(
+ 'E226: Abbreviation already exists for lhs2',
+ pcall_err(api.nvim_buf_set_keymap, 0, 'ia', 'lhs2', 'rhs2', { unique = true })
+ )
+
+ api.nvim_set_keymap('n', 'lhs', 'rhs', {})
+ eq(
+ 'E225: Global mapping already exists for lhs',
+ pcall_err(api.nvim_buf_set_keymap, 0, 'n', 'lhs', 'rhs', { unique = true })
+ )
+ end)
end)
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 5ef1ef54bb..307f750175 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -811,6 +811,33 @@ describe('decorations providers', function()
|
]])
end)
+
+ it('inline virt_text does not result in wrong cursor column #33153', function()
+ insert("line1 with a lot of text\nline2 with a lot of text")
+ setup_provider([[
+ _G.do_win = false
+ vim.keymap.set('n', 'f', function()
+ _G.do_win = true
+ vim.cmd('redraw!')
+ end)
+ vim.o.concealcursor = 'n'
+ function on_do(event)
+ if event == 'win' and _G.do_win then
+ vim.api.nvim_buf_set_extmark(0, ns1, 1, 0, {
+ virt_text = { { 'virt_text ' } },
+ virt_text_pos = 'inline'
+ })
+ end
+ end
+ ]])
+ feed('f')
+ screen:expect([[
+ line1 with a lot of text |
+ virt_text line2 with a lot of tex^t |
+ {1:~ }|*5
+ |
+ ]])
+ end)
end)
describe('decoration_providers', function()
@@ -2978,6 +3005,13 @@ describe('extmark decorations', function()
{1:~ }|
|
]])
+ -- No asymmetric topline for <C-E><C-Y> #33182
+ feed('4<C-E>')
+ exec('set concealcursor=n')
+ api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = "" })
+ eq(5, n.fn.line('w0'))
+ feed('<C-E><C-Y>')
+ eq(5, n.fn.line('w0'))
end)
end)
diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
index d1fd273dc1..09338eb7d2 100644
--- a/test/functional/ui/winbar_spec.lua
+++ b/test/functional/ui/winbar_spec.lua
@@ -540,6 +540,15 @@ describe('winbar', function()
]])
eq('Vim(set):E36: Not enough room', pcall_err(command, 'set winbar=test'))
end)
+
+ it('does not crash due to negative grid height #33176', function()
+ screen:try_resize(screen._width, 20)
+ command('botright split | belowright vsplit | 2wincmd w')
+ api.nvim_set_option_value('winfixheight', true, { scope = 'local', win = 0 })
+ api.nvim_win_set_height(0, 8)
+ feed('q:')
+ n.assert_alive()
+ end)
end)
describe('local winbar with tabs', function()
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index 4bb537c081..0e4f051f5a 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -3420,4 +3420,33 @@ func Test_complete_multiline_marks()
delfunc Omni_test
endfunc
+func Test_complete_append_selected_match_default()
+ " when typing a normal character during completion,
+ " completion is ended, see
+ " :h popupmenu-completion ("There are three states:")
+ func PrintMenuWords()
+ let info = complete_info(["selected", "matches"])
+ call map(info.matches, {_, v -> v.word})
+ return info
+ endfunc
+
+ new
+ call setline(1, ["fo", "foo", "foobar", "fobarbaz"])
+ exe "normal! Gof\<c-n>\<c-r>=PrintMenuWords()\<cr>"
+ call assert_equal('fo{''matches'': [''fo'', ''foo'', ''foobar'', ''fobarbaz''], ''selected'': 0}', getline(5))
+ %d
+ call setline(1, ["fo", "foo", "foobar", "fobarbaz"])
+ exe "normal! Gof\<c-n>o\<c-r>=PrintMenuWords()\<cr>"
+ call assert_equal('foo{''matches'': [], ''selected'': -1}', getline(5))
+ %d
+ set completeopt=menu,noselect
+ call setline(1, ["fo", "foo", "foobar", "fobarbaz"])
+ exe "normal! Gof\<c-n>\<c-n>o\<c-r>=PrintMenuWords()\<cr>"
+ call assert_equal('foo{''matches'': [], ''selected'': -1}', getline(5))
+ bw!
+
+ set completeopt&
+ delfunc PrintMenuWords
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable