diff options
29 files changed, 644 insertions, 165 deletions
diff --git a/MAINTAIN.md b/MAINTAIN.md index 3e31fde118..f80f9b92fb 100644 --- a/MAINTAIN.md +++ b/MAINTAIN.md @@ -145,6 +145,8 @@ These dependencies are "vendored" (inlined), we must update the sources manually * Run `scripts/update_terminfo.sh` to update these definitions. * `runtime/lua/vim/lsp/_meta/protocol.lua`: LSP specification * Run `scripts/gen_lsp.lua` to update. +* `runtime/lua/vim/_meta/lpeg.lua`: LPeg definitions. + * Refer to [`LuaCATS/lpeg`](https://github.com/LuaCATS/lpeg) for updates. * `src/bit.c`: only for PUC lua: port of `require'bit'` from luajit https://bitop.luajit.org/ * [treesitter parsers](https://github.com/neovim/neovim/blob/fcc24e43e0b5f9d801a01ff2b8f78ce8c16dd551/cmake.deps/CMakeLists.txt#L197-L210) * `runtime/lua/coxpcall.lua`: coxpcall (only needed for PUC lua, builtin to luajit) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 2dd290fef1..207bf817b0 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -7742,6 +7742,7 @@ strutf16len({string} [, {countcc}]) *strutf16len()* echo strutf16len('😊') " returns 2 echo strutf16len('ą́') " returns 1 echo strutf16len('ą́', v:true) " returns 3 +< strwidth({string}) *strwidth()* The result is a Number, which is the number of display cells diff --git a/runtime/doc/ft_rust.txt b/runtime/doc/ft_rust.txt index b912f732b6..083b6f579f 100644 --- a/runtime/doc/ft_rust.txt +++ b/runtime/doc/ft_rust.txt @@ -467,8 +467,8 @@ rust.vim Debugging ~ register. :RustInfoToFile [filename] *:RustInfoToFile* - Saves debugging info of the Vim Rust plugin to the the given - file, overwritting it. + Saves debugging info of the Vim Rust plugin to the given file, + overwriting it. ============================================================================== MAPPINGS *rust-mappings* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index a77cc3b565..7e888a2375 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1680,7 +1680,7 @@ vim.print({...}) *vim.print()* "Pretty prints" the given arguments and returns them unmodified. Example: >lua - local hl_normal = vim.print(vim.api.nvim_get_hl_by_name('Normal', true)) + local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' })) < Return: ~ diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index d0d535566d..0cfeb3dcb7 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -482,7 +482,7 @@ The function will be called with the list of arguments so far, and a second argument that is the name of the pty. *gdb-version* Only debuggers fully compatible with gdb will work. Vim uses the GDB/MI -interface. The "new-ui" command requires gdb version 7.12 or later. if you +interface. The "new-ui" command requires gdb version 7.12 or later. If you get this error: Undefined command: "new-ui". Try "help".~ Then your gdb is too old. diff --git a/runtime/lua/nvim/health.lua b/runtime/lua/nvim/health.lua index 7ccb082a40..6b6370fa19 100644 --- a/runtime/lua/nvim/health.lua +++ b/runtime/lua/nvim/health.lua @@ -54,15 +54,19 @@ local function check_config() health.start('Configuration') local ok = true - local vimrc = ( - empty(vim.env.MYVIMRC) and vim.fn.stdpath('config') .. '/init.vim' or vim.env.MYVIMRC - ) - if not filereadable(vimrc) then + local init_lua = vim.fn.stdpath('config') .. '/init.lua' + local init_vim = vim.fn.stdpath('config') .. '/init.vim' + local vimrc = empty(vim.env.MYVIMRC) and init_lua or vim.env.MYVIMRC + + if not filereadable(vimrc) and not filereadable(init_vim) then ok = false local has_vim = filereadable(vim.fn.expand('~/.vimrc')) health.warn( - (-1 == vim.fn.getfsize(vimrc) and 'Missing' or 'Unreadable') .. ' user config file: ' .. vimrc, - { has_vim and ':help nvim-from-vim' or ':help init.vim' } + ('%s user config file: %s'):format( + -1 == vim.fn.getfsize(vimrc) and 'Missing' or 'Unreadable', + vimrc + ), + { has_vim and ':help nvim-from-vim' or ':help config' } ) end diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index e4a2dadb09..7f09fc8038 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -888,7 +888,7 @@ end --- Example: --- --- ```lua ---- local hl_normal = vim.print(vim.api.nvim_get_hl_by_name('Normal', true)) +--- local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' })) --- ``` --- --- @see |vim.inspect()| diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 81fa7ce7ec..5c51fbd146 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -425,6 +425,7 @@ function vim.api.nvim_buf_get_number(buffer) end --- @return integer function vim.api.nvim_buf_get_offset(buffer, index) end +--- @deprecated --- @param buffer integer --- @param name string --- @return any @@ -632,6 +633,7 @@ function vim.api.nvim_buf_set_mark(buffer, name, line, col, opts) end --- @param name string Buffer name function vim.api.nvim_buf_set_name(buffer, name) end +--- @deprecated --- @param buffer integer --- @param name string --- @param value any @@ -1283,10 +1285,12 @@ function vim.api.nvim_get_mode() end --- @return table<string,any> function vim.api.nvim_get_namespaces() end +--- @deprecated --- @param name string --- @return any function vim.api.nvim_get_option(name) end +--- @deprecated --- @param name string --- @return table<string,any> function vim.api.nvim_get_option_info(name) end @@ -1912,6 +1916,7 @@ function vim.api.nvim_set_hl_ns_fast(ns_id) end --- "callback" is equivalent to returning an empty string. function vim.api.nvim_set_keymap(mode, lhs, rhs, opts) end +--- @deprecated --- @param name string --- @param value any function vim.api.nvim_set_option(name, value) end @@ -2115,6 +2120,7 @@ function vim.api.nvim_win_get_height(window) end --- @return integer function vim.api.nvim_win_get_number(window) end +--- @deprecated --- @param window integer --- @param name string --- @return any @@ -2197,6 +2203,7 @@ function vim.api.nvim_win_set_height(window, height) end --- @param ns_id integer the namespace to use function vim.api.nvim_win_set_hl_ns(window, ns_id) end +--- @deprecated --- @param window integer --- @param name string --- @param value any diff --git a/runtime/lua/vim/_meta/lpeg.lua b/runtime/lua/vim/_meta/lpeg.lua new file mode 100644 index 0000000000..415bffdfdc --- /dev/null +++ b/runtime/lua/vim/_meta/lpeg.lua @@ -0,0 +1,328 @@ +--- @meta + +-- These types were taken from https://github.com/LuaCATS/lpeg, with types being renamed to include +-- the vim namespace and with some descriptions made less verbose. + +--- *LPeg* is a new pattern-matching library for Lua, based on [Parsing Expression Grammars](https://bford.info/packrat/) (PEGs). +vim.lpeg = {} + +--- @class vim.lpeg.Pattern +--- @operator add(vim.lpeg.Pattern): vim.lpeg.Pattern +--- @operator mul(vim.lpeg.Pattern): vim.lpeg.Pattern +--- @operator mul(vim.lpeg.Capture): vim.lpeg.Pattern +--- @operator div(string): vim.lpeg.Capture +--- @operator div(number): vim.lpeg.Capture +--- @operator div(table): vim.lpeg.Capture +--- @operator div(function): vim.lpeg.Capture +--- @operator pow(number): vim.lpeg.Pattern +local Pattern = {} + +--- @alias vim.lpeg.Capture vim.lpeg.Pattern +--- @operator add(vim.lpeg.Capture): vim.lpeg.Pattern +--- @operator mul(vim.lpeg.Capture): vim.lpeg.Pattern +--- @operator mul(vim.lpeg.Pattern): vim.lpeg.Pattern +--- @operator div(string): vim.lpeg.Capture +--- @operator div(number): vim.lpeg.Capture +--- @operator div(table): vim.lpeg.Capture +--- @operator div(function): vim.lpeg.Capture +--- @operator pow(number): vim.lpeg.Pattern + +--- Matches the given `pattern` against the `subject` string. If the match succeeds, returns the index in the +--- subject of the first character after the match, or the captured values (if the pattern captured any value). +--- An optional numeric argument `init` makes the match start at that position in the subject string. As usual +--- in Lua libraries, a negative value counts from the end. Unlike typical pattern-matching functions, `match` +--- works only in anchored mode; that is, it tries to match the pattern with a prefix of the given subject +--- string (at position `init`), not with an arbitrary substring of the subject. So, if we want to find a +--- pattern anywhere in a string, we must either write a loop in Lua or write a pattern that +--- matches anywhere. +--- +--- Example: +--- ```lua +--- local pattern = lpeg.R("az") ^ 1 * -1 +--- assert(pattern:match("hello") == 6) +--- assert(lpeg.match(pattern, "hello") == 6) +--- assert(pattern:match("1 hello") == nil) +--- ``` +--- +--- @param pattern vim.lpeg.Pattern +--- @param subject string +--- @param init? integer +--- @return integer|vim.lpeg.Capture +function vim.lpeg.match(pattern, subject, init) end + +--- Matches the given `pattern` against the `subject` string. If the match succeeds, returns the +--- index in the subject of the first character after the match, or the captured values (if the +--- pattern captured any value). An optional numeric argument `init` makes the match start at +--- that position in the subject string. As usual in Lua libraries, a negative value counts from the end. +--- Unlike typical pattern-matching functions, `match` works only in anchored mode; that is, it tries +--- to match the pattern with a prefix of the given subject string (at position `init`), not with +--- an arbitrary substring of the subject. So, if we want to find a pattern anywhere in a string, +--- we must either write a loop in Lua or write a pattern that matches anywhere. +--- +--- Example: +--- ```lua +--- local pattern = lpeg.R("az") ^ 1 * -1 +--- assert(pattern:match("hello") == 6) +--- assert(lpeg.match(pattern, "hello") == 6) +--- assert(pattern:match("1 hello") == nil) +--- ``` +--- +--- @param subject string +--- @param init? integer +--- @return integer|vim.lpeg.Capture +function Pattern:match(subject, init) end + +--- Returns the string `"pattern"` if the given value is a pattern, otherwise `nil`. +--- +--- @return 'pattern'|nil +function vim.lpeg.type(value) end + +--- Returns a string with the running version of LPeg. +--- @return string +function vim.lpeg.version() end + +--- Sets a limit for the size of the backtrack stack used by LPeg to track calls and choices. +--- The default limit is `400`. Most well-written patterns need little backtrack levels and +--- therefore you seldom need to change this limit; before changing it you should try to rewrite +--- your pattern to avoid the need for extra space. Nevertheless, a few useful patterns may overflow. +--- Also, with recursive grammars, subjects with deep recursion may also need larger limits. +--- +--- @param max integer +function vim.lpeg.setmaxstack(max) end + +--- Converts the given value into a proper pattern. This following rules are applied: +--- * If the argument is a pattern, it is returned unmodified. +--- * If the argument is a string, it is translated to a pattern that matches the string literally. +--- * If the argument is a non-negative number `n`, the result is a pattern that matches exactly `n` characters. +--- * If the argument is a negative number `-n`, the result is a pattern that succeeds only if +--- the input string has less than `n` characters left: `lpeg.P(-n)` is equivalent to `-lpeg.P(n)` +--- (see the unary minus operation). +--- * If the argument is a boolean, the result is a pattern that always succeeds or always fails +--- (according to the boolean value), without consuming any input. +--- * If the argument is a table, it is interpreted as a grammar (see Grammars). +--- * If the argument is a function, returns a pattern equivalent to a match-time captureover the empty string. +--- +--- @param value vim.lpeg.Pattern|string|integer|boolean|table|function +--- @return vim.lpeg.Pattern +function vim.lpeg.P(value) end + +--- Returns a pattern that matches only if the input string at the current position is preceded by `patt`. +--- Pattern `patt` must match only strings with some fixed length, and it cannot contain captures. +--- Like the and predicate, this pattern never consumes any input, independently of success or failure. +--- +--- @param pattern vim.lpeg.Pattern +--- @return vim.lpeg.Pattern +function vim.lpeg.B(pattern) end + +--- Returns a pattern that matches any single character belonging to one of the given ranges. +--- Each `range` is a string `xy` of length 2, representing all characters with code between the codes of +--- `x` and `y` (both inclusive). As an example, the pattern `lpeg.R("09")` matches any digit, and +--- `lpeg.R("az", "AZ")` matches any ASCII letter. +--- +--- Example: +--- ```lua +--- local pattern = lpeg.R("az") ^ 1 * -1 +--- assert(pattern:match("hello") == 6) +--- ``` +--- +--- @param ... string +--- @return vim.lpeg.Pattern +function vim.lpeg.R(...) end + +--- Returns a pattern that matches any single character that appears in the given string (the `S` stands for Set). +--- As an example, the pattern `lpeg.S("+-*/")` matches any arithmetic operator. Note that, if `s` is a character +--- (that is, a string of length 1), then `lpeg.P(s)` is equivalent to `lpeg.S(s)` which is equivalent to +--- `lpeg.R(s..s)`. Note also that both `lpeg.S("")` and `lpeg.R()` are patterns that always fail. +--- +--- @param string string +--- @return vim.lpeg.Pattern +function vim.lpeg.S(string) end + +--- Creates a non-terminal (a variable) for a grammar. This operation creates a non-terminal (a variable) +--- for a grammar. The created non-terminal refers to the rule indexed by `v` in the enclosing grammar. +--- +--- Example: +--- ```lua +--- local b = lpeg.P({"(" * ((1 - lpeg.S "()") + lpeg.V(1)) ^ 0 * ")"}) +--- assert(b:match('((string))') == 11) +--- assert(b:match('(') == nil) +--- ``` +--- +--- @param v string|integer +--- @return vim.lpeg.Pattern +function vim.lpeg.V(v) end + +--- @class vim.lpeg.Locale +--- @field alnum userdata +--- @field alpha userdata +--- @field cntrl userdata +--- @field digit userdata +--- @field graph userdata +--- @field lower userdata +--- @field print userdata +--- @field punct userdata +--- @field space userdata +--- @field upper userdata +--- @field xdigit userdata + +--- Returns a table with patterns for matching some character classes according to the current locale. +--- The table has fields named `alnum`, `alpha`, `cntrl`, `digit`, `graph`, `lower`, `print`, `punct`, +--- `space`, `upper`, and `xdigit`, each one containing a correspondent pattern. Each pattern matches +--- any single character that belongs to its class. +--- If called with an argument `table`, then it creates those fields inside the given table and returns +--- that table. +--- +--- Example: +--- ```lua +--- lpeg.locale(lpeg) +--- local space = lpeg.space^0 +--- local name = lpeg.C(lpeg.alpha^1) * space +--- local sep = lpeg.S(",;") * space +--- local pair = lpeg.Cg(name * "=" * space * name) * sep^-1 +--- local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset) +--- local t = list:match("a=b, c = hi; next = pi") +--- assert(t.a == 'b') +--- assert(t.c == 'hi') +--- assert(t.next == 'pi') +--- local locale = lpeg.locale() +--- assert(type(locale.digit) == 'userdata') +--- ``` +--- +--- @param tab? table +--- @return vim.lpeg.Locale +function vim.lpeg.locale(tab) end + +--- Creates a simple capture, which captures the substring of the subject that matches `patt`. +--- The captured value is a string. If `patt` has other captures, their values are returned after this one. +--- +--- Example: +--- ```lua +--- local function split (s, sep) +--- sep = lpeg.P(sep) +--- local elem = lpeg.C((1 - sep)^0) +--- local p = elem * (sep * elem)^0 +--- return lpeg.match(p, s) +--- end +--- local a, b, c = split('a,b,c', ',') +--- assert(a == 'a') +--- assert(b == 'b') +--- assert(c == 'c') +--- ``` +--- +--- @param patt vim.lpeg.Pattern +--- @return vim.lpeg.Capture +function vim.lpeg.C(patt) end + +--- Creates an argument capture. This pattern matches the empty string and produces the value given as the +--- nth extra argument given in the call to `lpeg.match`. +--- @param n integer +--- @return vim.lpeg.Capture +function vim.lpeg.Carg(n) end + +--- Creates a back capture. This pattern matches the empty string and produces the values produced by the most recent +--- group capture named `name` (where `name` can be any Lua value). Most recent means the last complete outermost +--- group capture with the given name. A Complete capture means that the entire pattern corresponding to the capture +--- has matched. An Outermost capture means that the capture is not inside another complete capture. +--- In the same way that LPeg does not specify when it evaluates captures, it does not specify whether it reuses +--- values previously produced by the group or re-evaluates them. +--- +--- @param name any +--- @return vim.lpeg.Capture +function vim.lpeg.Cb(name) end + +--- Creates a constant capture. This pattern matches the empty string and produces all given values as its captured values. +--- +--- @param ... any +--- @return vim.lpeg.Capture +function vim.lpeg.Cc(...) end + +--- Creates a fold capture. If `patt` produces a list of captures C1 C2 ... Cn, this capture will produce the value +--- `func(...func(func(C1, C2), C3)...,Cn)`, that is, it will fold (or accumulate, or reduce) the captures from +--- `patt` using function `func`. This capture assumes that `patt` should produce at least one capture with at +--- least one value (of any type), which becomes the initial value of an accumulator. (If you need a specific +--- initial value, you may prefix a constant captureto `patt`.) For each subsequent capture, LPeg calls `func` +--- with this accumulator as the first argument and all values produced by the capture as extra arguments; +--- the first result from this call becomes the new value for the accumulator. The final value of the accumulator +--- becomes the captured value. +--- +--- Example: +--- ```lua +--- local number = lpeg.R("09") ^ 1 / tonumber +--- local list = number * ("," * number) ^ 0 +--- local function add(acc, newvalue) return acc + newvalue end +--- local sum = lpeg.Cf(list, add) +--- assert(sum:match("10,30,43") == 83) +--- ``` +--- +--- @param patt vim.lpeg.Pattern +--- @param func fun(acc, newvalue) +--- @return vim.lpeg.Capture +function vim.lpeg.Cf(patt, func) end + +--- Creates a group capture. It groups all values returned by `patt` into a single capture. +--- The group may be anonymous (if no name is given) or named with the given name (which +--- can be any non-nil Lua value). +--- +--- @param patt vim.lpeg.Pattern +--- @param name? string +--- @return vim.lpeg.Capture +function vim.lpeg.Cg(patt, name) end + +--- Creates a position capture. It matches the empty string and captures the position in the +--- subject where the match occurs. The captured value is a number. +--- +--- Example: +--- ```lua +--- local I = lpeg.Cp() +--- local function anywhere(p) return lpeg.P({I * p * I + 1 * lpeg.V(1)}) end +--- local match_start, match_end = anywhere("world"):match("hello world!") +--- assert(match_start == 7) +--- assert(match_end == 12) +--- ``` +--- +--- @return vim.lpeg.Capture +function vim.lpeg.Cp() end + +--- Creates a substitution capture. This function creates a substitution capture, which +--- captures the substring of the subject that matches `patt`, with substitutions. +--- For any capture inside `patt` with a value, the substring that matched the capture +--- is replaced by the capture value (which should be a string). The final captured +--- value is the string resulting from all replacements. +--- +--- Example: +--- ```lua +--- local function gsub (s, patt, repl) +--- patt = lpeg.P(patt) +--- patt = lpeg.Cs((patt / repl + 1)^0) +--- return lpeg.match(patt, s) +--- end +--- assert(gsub('Hello, xxx!', 'xxx', 'World') == 'Hello, World!') +--- ``` +--- +--- @param patt vim.lpeg.Pattern +--- @return vim.lpeg.Capture +function vim.lpeg.Cs(patt) end + +--- Creates a table capture. This capture returns a table with all values from all anonymous captures +--- made by `patt` inside this table in successive integer keys, starting at 1. +--- Moreover, for each named capture group created by `patt`, the first value of the group is put into +--- the table with the group name as its key. The captured value is only the table. +--- +--- @param patt vim.lpeg.Pattern|'' +--- @return vim.lpeg.Capture +function vim.lpeg.Ct(patt) end + +--- Creates a match-time capture. Unlike all other captures, this one is evaluated immediately when a match occurs +--- (even if it is part of a larger pattern that fails later). It forces the immediate evaluation of all its nested captures +--- and then calls `function`. The given function gets as arguments the entire subject, the current position +--- (after the match of `patt`), plus any capture values produced by `patt`. The first value returned by `function` +--- defines how the match happens. If the call returns a number, the match succeeds and the returned number +--- becomes the new current position. (Assuming a subject sand current position i, the returned number must be +--- in the range [i, len(s) + 1].) If the call returns true, the match succeeds without consuming any input +--- (so, to return true is equivalent to return i). If the call returns false, nil, or no value, the match fails. +--- Any extra values returned by the function become the values produced by the capture. +--- +--- @param patt vim.lpeg.Pattern +--- @param fn function +--- @return vim.lpeg.Capture +function vim.lpeg.Cmt(patt, fn) end diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 4113797759..6686661a27 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -9192,6 +9192,7 @@ function vim.fn.strtrans(string) end --- echo strutf16len('😊') " returns 2 --- echo strutf16len('ą́') " returns 1 --- echo strutf16len('ą́', v:true) " returns 3 +--- < --- --- @param string string --- @param countcc? 0|1 diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua index 6a3413b597..b83a8dd4b1 100644 --- a/runtime/lua/vim/_options.lua +++ b/runtime/lua/vim/_options.lua @@ -127,7 +127,7 @@ end --- @param name string local function get_options_info(name) - local info = api.nvim_get_option_info(name) + local info = api.nvim_get_option_info2(name, {}) info.metatype = get_option_metatype(name, info) return info end diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index 023b1c26be..fe06006108 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -32,8 +32,15 @@ function M.check() vim.health.start('vim.lsp: Active Clients') if next(clients) then for _, client in pairs(clients) do + local attached_to = table.concat(vim.tbl_keys(client.attached_buffers or {}), ',') report_info( - string.format('%s (id=%s, root_dir=%s)', client.name, client.id, client.config.root_dir) + string.format( + '%s (id=%s, root_dir=%s, attached_to=[%s])', + client.name, + client.id, + vim.fn.fnamemodify(client.config.root_dir, ':~'), + attached_to + ) ) end else diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index f5a77ece7e..f345edc52c 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -518,6 +518,7 @@ static int64_t convert_index(int64_t index) /// @return Option Information Dictionary nvim_get_option_info(String name, Error *err) FUNC_API_SINCE(7) + FUNC_API_DEPRECATED_SINCE(11) { return get_vimoption(name, OPT_GLOBAL, curbuf, curwin, err); } @@ -531,6 +532,7 @@ Dictionary nvim_get_option_info(String name, Error *err) /// @param[out] err Error details, if any void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); } @@ -543,6 +545,7 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) /// @return Option value (global) Object nvim_get_option(String name, Arena *arena, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { return get_option_from(NULL, SREQ_GLOBAL, name, err); } @@ -556,6 +559,7 @@ Object nvim_get_option(String name, Arena *arena, Error *err) /// @return Option value Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -577,6 +581,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) /// @param[out] err Error details, if any void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -596,6 +601,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object /// @return Option value Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { win_T *win = find_window_by_handle(window, err); @@ -617,6 +623,7 @@ Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) /// @param[out] err Error details, if any void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { win_T *win = find_window_by_handle(window, err); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 7a5c7cc181..78396edef5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1709,6 +1709,8 @@ static void write_msg(String message, bool to_err, bool writeln) msg_didout = true; \ kv_drop(line_buf, kv_size(line_buf)); \ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ + } else if (c == NUL) { \ + kv_push(line_buf, NL); \ } else { \ kv_push(line_buf, c); \ } diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 7d64d9fa3c..1e5798db32 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1539,6 +1539,25 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl cts.cts_vcol += charsize; prev_ptr = cts.cts_ptr; MB_PTR_ADV(cts.cts_ptr); + if (wp->w_p_list) { + in_multispace = *prev_ptr == ' ' && (*cts.cts_ptr == ' ' + || (prev_ptr > line && prev_ptr[-1] == ' ')); + if (!in_multispace) { + multispace_pos = 0; + } else if (cts.cts_ptr >= line + leadcol + && wp->w_p_lcs_chars.multispace != NULL) { + multispace_pos++; + if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) { + multispace_pos = 0; + } + } else if (cts.cts_ptr < line + leadcol + && wp->w_p_lcs_chars.leadmultispace != NULL) { + multispace_pos++; + if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) { + multispace_pos = 0; + } + } + } } wlv.vcol = cts.cts_vcol; ptr = cts.cts_ptr; @@ -2367,9 +2386,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } } - in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' '); - if (!in_multispace) { - multispace_pos = 0; + if (wp->w_p_list) { + in_multispace = c == ' ' && (*ptr == ' ' + || (prev_ptr > line && prev_ptr[-1] == ' ')); + if (!in_multispace) { + multispace_pos = 0; + } } // 'list': Change char 160 to 'nbsp' and space to 'space'. diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index ee1f03e296..04918e9979 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -471,7 +471,7 @@ int update_screen(void) // non-displayed part of msg_grid is considered invalid. for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) { grid_clear_line(&msg_grid, msg_grid.line_offset[i], - msg_grid.cols, false); + msg_grid.cols, i < p_ch); } } msg_grid.throttled = false; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index fe816ee8c2..858f7c8afd 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -10973,7 +10973,7 @@ M.funcs = { echo strutf16len('😊') " returns 2 echo strutf16len('ą́') " returns 1 echo strutf16len('ą́', v:true) " returns 3 - + < ]=], name = 'strutf16len', params = { { 'string', 'string' }, { 'countcc', '0|1' } }, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 0a0f7c244d..ea93d0fe91 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -906,7 +906,7 @@ void handle_did_throw(void) if (messages != NULL) { do { msglist_T *next = messages->next; - emsg(messages->msg); + emsg_multiline(messages->msg, messages->multiline); xfree(messages->msg); xfree(messages->sfile); xfree(messages); diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 1b150ef75d..0704b47d40 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -157,7 +157,7 @@ int aborted_in_try(void) /// When several messages appear in the same command, the first is usually the /// most specific one and used as the exception value. The "severe" flag can be /// set to true, if a later but severer message should be used instead. -bool cause_errthrow(const char *mesg, bool severe, bool *ignore) +bool cause_errthrow(const char *mesg, bool multiline, bool severe, bool *ignore) FUNC_ATTR_NONNULL_ALL { msglist_T *elem; @@ -249,6 +249,7 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore) elem = xmalloc(sizeof(msglist_T)); elem->msg = xstrdup(mesg); + elem->multiline = multiline; elem->next = NULL; elem->throw_msg = NULL; *plist = elem; diff --git a/src/nvim/ex_eval_defs.h b/src/nvim/ex_eval_defs.h index 6b3c426722..3ad3368900 100644 --- a/src/nvim/ex_eval_defs.h +++ b/src/nvim/ex_eval_defs.h @@ -1,6 +1,8 @@ #ifndef NVIM_EX_EVAL_DEFS_H #define NVIM_EX_EVAL_DEFS_H +#include <stdbool.h> + #include "nvim/pos.h" /// There is no CSF_IF, the lack of CSF_WHILE, CSF_FOR and CSF_TRY means ":if" @@ -41,11 +43,12 @@ enum { /// message in the list. See cause_errthrow(). typedef struct msglist msglist_T; struct msglist { + msglist_T *next; ///< next of several messages in a row char *msg; ///< original message, allocated char *throw_msg; ///< msg to throw: usually original one char *sfile; ///< value from estack_sfile(), allocated linenr_T slnum; ///< line number for "sfile" - msglist_T *next; ///< next of several messages in a row + bool multiline; ///< whether this is a multiline message }; /// The exception types. diff --git a/src/nvim/message.c b/src/nvim/message.c index 98e5a231b8..dba4dba600 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -640,7 +640,7 @@ int emsg_not_now(void) return false; } -static bool emsg_multiline(const char *s, bool multiline) +bool emsg_multiline(const char *s, bool multiline) { int attr; bool ignore = false; @@ -663,7 +663,7 @@ static bool emsg_multiline(const char *s, bool multiline) // be found, the message will be displayed later on.) "ignore" is set // when the message should be ignored completely (used for the // interrupt message). - if (cause_errthrow(s, severe, &ignore)) { + if (cause_errthrow(s, multiline, severe, &ignore)) { if (!ignore) { did_emsg++; } @@ -1907,10 +1907,13 @@ void msg_prt_line(const char *s, int list) continue; } else { attr = 0; - c = (unsigned char)(*s++); - in_multispace = c == ' ' && ((col > 0 && s[-2] == ' ') || *s == ' '); - if (!in_multispace) { - multispace_pos = 0; + c = (uint8_t)(*s++); + if (list) { + in_multispace = c == ' ' && (*s == ' ' + || (col > 0 && s[-2] == ' ')); + if (!in_multispace) { + multispace_pos = 0; + } } if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) { // tab amount depends on current column @@ -1950,7 +1953,7 @@ void msg_prt_line(const char *s, int list) // the same in plain text. attr = HL_ATTR(HLF_0); } else if (c == ' ') { - if (list && lead != NULL && s <= lead && in_multispace + if (lead != NULL && s <= lead && in_multispace && curwin->w_p_lcs_chars.leadmultispace != NULL) { c = curwin->w_p_lcs_chars.leadmultispace[multispace_pos++]; if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) { @@ -1963,7 +1966,7 @@ void msg_prt_line(const char *s, int list) } else if (trail != NULL && s > trail) { c = curwin->w_p_lcs_chars.trail; attr = HL_ATTR(HLF_0); - } else if (list && in_multispace + } else if (in_multispace && curwin->w_p_lcs_chars.multispace != NULL) { c = curwin->w_p_lcs_chars.multispace[multispace_pos++]; if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) { diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d82e5f66c9..09495fbaac 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2053,6 +2053,19 @@ describe('API', function() end) describe('nvim_out_write', function() + local screen + + before_each(function() + screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Blue}, + }) + end) + it('prints long messages correctly #20534', function() exec([[ set more @@ -2073,14 +2086,7 @@ describe('API', function() eq('\naaa\n' .. ('a'):rep(5002) .. '\naaa', meths.get_var('out')) end) - it('blank line in message works', function() - local screen = Screen.new(40, 8) - screen:attach() - screen:set_default_attr_ids({ - [0] = {bold = true, foreground = Screen.colors.Blue}, - [1] = {bold = true, foreground = Screen.colors.SeaGreen}, - [2] = {bold = true, reverse = true}, - }) + it('blank line in message', function() feed([[:call nvim_out_write("\na\n")<CR>]]) screen:expect{grid=[[ | @@ -2105,6 +2111,20 @@ describe('API', function() {1:Press ENTER or type command to continue}^ | ]]} end) + + it('NUL bytes in message', function() + feed([[:lua vim.api.nvim_out_write('aaa\0bbb\0\0ccc\nddd\0\0\0eee\n')<CR>]]) + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {2: }| + aaa{3:^@}bbb{3:^@^@}ccc | + ddd{3:^@^@^@}eee | + {1:Press ENTER or type command to continue}^ | + ]]} + end) end) describe('nvim_err_write', function() @@ -2193,6 +2213,20 @@ describe('API', function() ]]) feed('<cr>') -- exit the press ENTER screen end) + + it('NUL bytes in message', function() + nvim_async('err_write', 'aaa\0bbb\0\0ccc\nddd\0\0\0eee\n') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {3: }| + {1:aaa^@bbb^@^@ccc} | + {1:ddd^@^@^@eee} | + {2:Press ENTER or type command to continue}^ | + ]]} + end) end) describe('nvim_err_writeln', function() diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 6baad28dad..497b2e7f4c 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1021,6 +1021,26 @@ describe('cmdheight=0', function() screen:attach() end) + it("with redrawdebug=invalid resize -1", function() + command("set redrawdebug=invalid cmdheight=0 noruler laststatus=0") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + feed(":resize -1<CR>") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + assert_alive() + end) + it("with cmdheight=1 noruler laststatus=2", function() command("set cmdheight=1 noruler laststatus=2") screen:expect{grid=[[ diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua index b3f2c1bfeb..ab0ffccd4d 100644 --- a/test/functional/vimscript/eval_spec.lua +++ b/test/functional/vimscript/eval_spec.lua @@ -153,11 +153,6 @@ end) describe("uncaught exception", function() before_each(clear) - after_each(function() - os.remove('throw1.vim') - os.remove('throw2.vim') - os.remove('throw3.vim') - end) it('is not forgotten #13490', function() command('autocmd BufWinEnter * throw "i am error"') @@ -173,10 +168,45 @@ describe("uncaught exception", function() let result ..= 'X' ]]):format(i, i)) end + finally(function() + for i = 1, 3 do + os.remove('throw' .. i .. '.vim') + end + end) + command('set runtimepath+=. | let result = ""') eq('throw1', exc_exec('try | runtime! throw*.vim | endtry')) eq('123', eval('result')) end) + + it('multiline exception remains multiline #25350', function() + local screen = Screen.new(80, 11) + screen:set_default_attr_ids({ + [1] = {bold = true, reverse = true}; -- MsgSeparator + [2] = {foreground = Screen.colors.White, background = Screen.colors.Red}; -- ErrorMsg + [3] = {bold = true, foreground = Screen.colors.SeaGreen}; -- MoreMsg + }) + screen:attach() + exec_lua([[ + function _G.Oops() + error("oops") + end + ]]) + feed(':try\rlua _G.Oops()\rendtry\r') + screen:expect{grid=[[ + {1: }| + :try | + : lua _G.Oops() | + : endtry | + {2:Error detected while processing :} | + {2:E5108: Error executing lua [string "<nvim>"]:2: oops} | + {2:stack traceback:} | + {2: [C]: in function 'error'} | + {2: [string "<nvim>"]:2: in function 'Oops'} | + {2: [string ":lua"]:1: in main chunk} | + {3:Press ENTER or type command to continue}^ | + ]]} + end) end) describe('listing functions using :function', function() diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 9da20e662e..453ac10c00 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -3442,11 +3442,22 @@ func Test_closing_autocmd_window() END call CheckScriptFailure(lines, 'E814:') au! BufEnter - only! bwipe Xa.txt bwipe Xb.txt endfunc +func Test_switch_window_in_autocmd_window() + edit Xa.txt + tabnew Xb.txt + autocmd BufEnter Xa.txt wincmd w + doautoall BufEnter + au! BufEnter + bwipe Xa.txt + call assert_false(bufexists('Xa.txt')) + bwipe Xb.txt + call assert_false(bufexists('Xb.txt')) +endfunc + func Test_bufwipeout_changes_window() " This should not crash, but we don't have any expectations about what " happens, changing window in BufWipeout has unpredictable results. diff --git a/test/old/testdir/test_compiler.vim b/test/old/testdir/test_compiler.vim index ec7d143030..0b22bafabb 100644 --- a/test/old/testdir/test_compiler.vim +++ b/test/old/testdir/test_compiler.vim @@ -7,10 +7,8 @@ func Test_compiler() CheckExecutable perl CheckFeature quickfix - " $LANG changes the output of Perl. - if $LANG != '' - unlet $LANG - endif + let save_LC_ALL = $LC_ALL + let $LC_ALL= "C" " %:S does not work properly with 'shellslash' set let save_shellslash = &shellslash @@ -40,12 +38,13 @@ func Test_compiler() let &shellslash = save_shellslash call delete('Xfoo.pl') bw! + let $LC_ALL = save_LC_ALL endfunc func GetCompilerNames() return glob('$VIMRUNTIME/compiler/*.vim', 0, 1) - \ ->map({i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')}) - \ ->sort() + \ ->map({i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')}) + \ ->sort() endfunc func Test_compiler_without_arg() diff --git a/test/old/testdir/test_listchars.vim b/test/old/testdir/test_listchars.vim index 69f1df3098..5366f503fc 100644 --- a/test/old/testdir/test_listchars.vim +++ b/test/old/testdir/test_listchars.vim @@ -4,6 +4,36 @@ source check.vim source view_util.vim source screendump.vim +func Check_listchars(expected, end_lnum, end_scol = -1, leftcol = 0) + if a:leftcol > 0 + let save_wrap = &wrap + set nowrap + call cursor(1, 1) + exe 'normal! ' .. a:leftcol .. 'zl' + endif + + redraw! + for i in range(1, a:end_lnum) + if a:leftcol > 0 + let col = virtcol2col(0, i, a:leftcol) + let col += getline(i)->strpart(col - 1, 1, v:true)->len() + call cursor(i, col) + redraw + call assert_equal(a:leftcol, winsaveview().leftcol) + else + call cursor(i, 1) + end + + let end_scol = a:end_scol < 0 ? '$'->virtcol() - a:leftcol : a:end_scol + call assert_equal([a:expected[i - 1]->strcharpart(a:leftcol)], + \ ScreenLines(i, end_scol)) + endfor + + if a:leftcol > 0 + let &wrap = save_wrap + endif +endfunc + func Test_listchars() enew! set ff=unix @@ -24,11 +54,8 @@ func Test_listchars() \ 'dd........ee<<>-$', \ '<$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, '$'->virtcol())) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) set listchars-=trail:< let expected = [ @@ -38,11 +65,8 @@ func Test_listchars() \ 'dd........ee..>-$', \ '.$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) " tab with 3rd character. set listchars-=tab:>- @@ -54,11 +78,8 @@ func Test_listchars() \ 'dd........ee--<>$', \ '-$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) " tab with 3rd character and linebreak set set listchars-=tab:<=> @@ -71,11 +92,7 @@ func Test_listchars() \ 'dd........ee--<>$', \ '-$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) set nolinebreak set listchars-=tab:<·> set listchars+=tab:<=> @@ -88,11 +105,8 @@ func Test_listchars() \ 'dd........ee..<>$', \ '.$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) set listchars-=tab:<=> set listchars+=tab:>- @@ -110,7 +124,8 @@ func Test_listchars() \ '..fff>--<<$', \ '>-------gg>-----$', \ '.....h>-$', - \ 'iii<<<<><<$', '$'], l) + \ 'iii<<<<><<$', + \ '$'], l) " Test lead and trail normal ggdG @@ -132,14 +147,10 @@ func Test_listchars() \ 'h<<<<<<<<<<<$', \ '<<<<<<<<<<<<$', \ '>>>>0xx0<<<<$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test multispace @@ -162,14 +173,10 @@ func Test_listchars() \ ' hyYzZyYzZyY$', \ 'yYzZyYzZyYj $', \ 'yYzZ0yY0yYzZ$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace + multispace @@ -192,15 +199,14 @@ func Test_listchars() \ ' hyYzZyYzZyY$', \ '.-+*.-+*.-j $', \ '.-+*0yY0yYzZ$', - \ '$' + \ '$' \ ] - redraw! call assert_equal('eol:$,multispace:yYzZ,nbsp:S,leadmultispace:.-+*', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 1) + call Check_listchars(expected, 5, -1, 2) + call Check_listchars(expected, 5, -1, 3) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace without multispace @@ -223,16 +229,14 @@ func Test_listchars() \ '+h>>>>>>>>>>$', \ '.-+*.-+*.-j>$', \ '.-+*0++0>>>>$', - \ '$', + \ '$' \ ] - - redraw! call assert_equal('eol:$,nbsp:S,leadmultispace:.-+*,space:+,trail:>,eol:$', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 1) + call Check_listchars(expected, 5, -1, 2) + call Check_listchars(expected, 5, -1, 3) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace only @@ -255,14 +259,10 @@ func Test_listchars() \ ' h ', \ '.-+*.-+*.-j ', \ '.-+*0 0 ', - \ ' ', + \ ' ' \ ] - redraw! call assert_equal('leadmultispace:.-+*', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, 12)) - endfor + call Check_listchars(expected, 5, 12) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace and lead and space @@ -286,14 +286,14 @@ func Test_listchars() \ '<h----------$', \ '.-+*.-+*.-j-$', \ '.-+*0--0----$', - \ '$', + \ '$' \ ] - redraw! call assert_equal('eol:$,lead:<,space:-,leadmultispace:.-+*', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 1) + call Check_listchars(expected, 5, -1, 2) + call Check_listchars(expected, 5, -1, 3) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " the last occurrence of 'multispace:' is used @@ -307,15 +307,11 @@ func Test_listchars() \ 'xhXyYXyYXyYX$', \ 'XyYXyYXyYXjx$', \ 'XyYX0Xy0XyYX$', - \ '$' + \ '$' \ ] - redraw! call assert_equal('eol:$,multispace:yYzZ,space:x,multispace:XyY', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) set listchars+=lead:>,trail:< @@ -326,14 +322,10 @@ func Test_listchars() \ '>h<<<<<<<<<<$', \ '>>>>>>>>>>j<$', \ '>>>>0Xy0<<<<$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " removing 'multispace:' @@ -346,14 +338,10 @@ func Test_listchars() \ '>h<<<<<<<<<<$', \ '>>>>>>>>>>j<$', \ '>>>>0xx0<<<<$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " test nbsp @@ -365,15 +353,10 @@ func Test_listchars() call append(0, [ ">" .. nbsp .. "<" ]) let expected = '>X< ' - - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, virtcol('$'))) + call Check_listchars([expected], 1) set listchars=nbsp:X - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, virtcol('$'))) + call Check_listchars([expected], 1) " test extends normal ggdG @@ -383,16 +366,11 @@ func Test_listchars() call append(0, [ repeat('A', &columns + 1) ]) let expected = repeat('A', &columns) - - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, &columns)) + call Check_listchars([expected], 1, &columns) set list let expected = expected[:-2] . 'Z' - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, &columns)) + call Check_listchars([expected], 1, &columns) enew! set listchars& ff& @@ -411,19 +389,20 @@ func Test_listchars_unicode() let nbsp = nr2char(0xa0) call append(0, [" a\tb c" .. nbsp .. "d "]) let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔'] - redraw! - call cursor(1, 1) - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) + call Check_listchars(expected, 1, -1, 3) + call Check_listchars(expected, 1, -1, 13) set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192 - redraw! - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) + call Check_listchars(expected, 1, -1, 3) + call Check_listchars(expected, 1, -1, 13) set listchars+=lead:⇨,trail:⇦ let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔'] - redraw! - call cursor(1, 1) - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) + call Check_listchars(expected, 1, -1, 3) + call Check_listchars(expected, 1, -1, 13) let &encoding=oldencoding enew! @@ -515,9 +494,7 @@ func Test_listchars_composing() let expected = [ \ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$" \ ] - redraw! - call cursor(1, 1) - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) let &encoding=oldencoding enew! set listchars& ff& diff --git a/test/old/testdir/test_syntax.vim b/test/old/testdir/test_syntax.vim index c9ad4bb857..76a21adc57 100644 --- a/test/old/testdir/test_syntax.vim +++ b/test/old/testdir/test_syntax.vim @@ -41,9 +41,9 @@ func AssertHighlightGroups(lnum, startcol, expected, trans = 1, msg = "") for l:i in range(a:startcol, a:startcol + l:expectedGroups->len() - 1) let l:errors += synID(a:lnum, l:i, a:trans) - \ ->synIDattr("name") - \ ->assert_equal(l:expectedGroups[l:i - 1], - \ l:msg .. l:i) + \ ->synIDattr("name") + \ ->assert_equal(l:expectedGroups[l:i - 1], + \ l:msg .. l:i) endfor endfunc diff --git a/test/old/testdir/test_virtualedit.vim b/test/old/testdir/test_virtualedit.vim index 4ab69d89fe..4780faa706 100644 --- a/test/old/testdir/test_virtualedit.vim +++ b/test/old/testdir/test_virtualedit.vim @@ -598,6 +598,9 @@ func Test_virtualedit_mouse() call Ntest_setmouse(row, 21 + 15) call feedkeys("\<LeftMouse>", "xt") call assert_equal([0, 1, 10, 2, 15], getcurpos()) + call Ntest_setmouse(row, 21 + 20) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 10, 7, 20], getcurpos()) setlocal nowrap call setline(2, repeat('a', 19)) @@ -654,6 +657,23 @@ func Test_virtualedit_mouse() sign undefine Sign1 endif + wincmd h + 4wincmd > + normal! gg24I. + redraw + call Ntest_setmouse(row + 1, 12) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 24 + 9, 0, 24 + 12], getcurpos()) + call Ntest_setmouse(row + 1, 13) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 24 + 10, 0, 24 + 13], getcurpos()) + call Ntest_setmouse(row + 1, 15) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 24 + 10, 2, 24 + 15], getcurpos()) + call Ntest_setmouse(row + 1, 20) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 24 + 10, 7, 24 + 20], getcurpos()) + bwipe! let &mouse = save_mouse set virtualedit& |