summaryrefslogtreecommitdiffstatshomepage
path: root/test/functional/lua
AgeCommit message (Collapse)AuthorFiles
2026-04-24fix(trust): always use "/" slashes in filepaths #39355Justin M. Keyes1
Problem: We should not use "\" (backslashes) except where absolutely required. See references in https://github.com/neovim/neovim/pull/37729 Solution: There is no reason to use "\" slashes in the trust db, so don't.
2026-04-23feat(excmd): add :uptime command #39331Olivia Kinnear1
Problem Nvim marks its v:starttime, but there is no user-friendly way to get Nvim's uptime. Solution Add :uptime (based loosely on uptime(1)).
2026-04-23refactor(test): deduplicate trust tests #39354Justin M. Keyes1
2026-04-23fix(trust): hash unchanged empty buffers as empty files #39027Barrett Ruth1
Problem: `vim.secure.trust()` hashes an unchanged empty buffer as a newline, so trusting an empty file by buffer never works. Solution: Hash unchanged empty-buffers `''` so buffer-based trust matches the on-disk empty file.
2026-04-20refactor(test): drop deprecated exc_exec #39242Justin M. Keyes7
2026-04-18fix(lua): make `vim._with()` work with `buf=0` and `win=0` context #39151Evgeni Chasnovski1
Problem: Using `buf=0`/`win=0` context in `vim._with` should be equivalent to using explicit buffer/window identifier respectively. Solution: Explicitly adjust context in case of `buf=0` or `win=0`.
2026-04-18fix(vim.filetype): match() fails if g:ft_ignore_pat is not defined #39158Evgeni Chasnovski1
Problem: Calling `vim.filetype.match({ filename = '...', buf = ... })` during startup results in an error due to not yet defined `g:ft_ignore_pat`. Solution: Add a guard to check `g:ft_ignore_pat` related properties only if the variable is defined. This also allows to simplify other tests which did not depend on `g:ft_ignore_pat` but required it explicitly set to work.
2026-04-17perf(vim.fn): call Lua-implemented vim.fn.xx() directly #39166Justin M. Keyes1
Problem: - Builtin "Vimscript" functions (f_xx) are mostly implemented in C. Partly that's because there is some boilerplate required to call out to Lua. - Calls to `vim.fn.foo()` always marshall over the Lua <=> Vimscript ("typval") bridge, even if `fn.foo()` is implemented entirely in Lua: ``` Lua => typval => Object => Lua => Object => typval => Lua. ``` Solution: Functions declared in eval.lua with `func_lua` are implemented in entirely in Lua (`_core/vimfn.lua`). - `gen_eval.lua` wires `func_lua` entries to `lua_wrapper`, which handles the typval conversion for Vimscript callers (slow path). - `nlua_call()` detects `func_lua` functions and calls the Lua implementation directly. This eliminates all conversion overhead for Lua callers (fast path). - Validate at build-time that `func`, `func_float`, and `func_lua` are mutually exclusive. - Migrate `hostname()` as a toy example, to show the idea.
2026-04-15refactor: update usages of deprecated "buffer" param #39089Justin M. Keyes2
2026-04-15refactor(api): rename "window" to "win" (positional parameters) #39083Justin M. Keyes1
continues d0af4cd9094f. This commit renames positional parameters. This is only "cosmetic", but is intended to make it extra clear which name is preferred, since people often copy existing code despite the guidelines in `:help dev-naming`.
2026-04-15refactor(diagnostic): split diagnostic moduleLewis Russell1
Extract the diagnostic implementation from runtime/lua/vim/diagnostic.lua into focused internal modules covering config, display, float rendering, jump/list helpers, namespace and storage management, severity/shared utilities, and statusline support. Move the builtin handlers into runtime/lua/vim/diagnostic/handlers/ and keep runtime/lua/vim/diagnostic.lua as the public facade that lazily dispatches to the split modules. This preserves the external vim.diagnostic API while making the implementation easier to navigate and reason about. AI-assisted: Codex
2026-04-15test: replace busted with local harnessLewis Russell3
Replace the busted-based Lua test runner with a repo-local harness. The new harness runs spec files directly under `nvim -ll`, ships its own reporter and lightweight `luassert` shim, and keeps the helper/preload flow used by the functional and unit test suites. Keep the file boundary model shallow and busted-like by restoring `_G`, `package.loaded`, `package.preload`, `arg`, and the process environment between files, without carrying extra reset APIs or custom assertion machinery. Update the build and test entrypoints to use the new runner, add black-box coverage for the harness itself, and drop the bundled busted/luacheck dependency path. AI-assisted: Codex
2026-04-15fix(lua): make vim.deep_equal cycle-safeLewis Russell1
AI-assisted: Codex
2026-04-10feat(snippet): support multiple sessions #29340Maria Solano1
2026-04-10feat(vim.net): custom request() headers #38837Ellison1
Problem Cannot specify headers in vim.net.request() call. Solution Support opts.headers in vim.net.request opts.
2026-04-09fix(messages): truncate warning messages only in display (#38901)zeertzjq1
For now, add a private "_truncate" flag to nvim_echo, using a truncation method similar to showmode().
2026-04-08feat(vim.version): add __eq to vim.VersionRange #38881ngicks1
Problem: vim.VersionRange had no __eq metamethod, so comparing 2 distinct but same value instances always returned false. In vim.pack.add this caused redundant lockfile rewrites, even when the resulting lockfile content was unchanged. Solution: Add __eq metamethod on vim.VersionRange
2026-04-06fix(diagnostic): virtual_lines should anchor at end_lnum, not lnum #38701glepnir1
Problem: Multi-line diagnostics always render virtual lines below lnum. Solution: Use end_lnum when placing the virt_lines extmark.
2026-04-06feat(vim.pos)!: require `buf` param on vim.pos, vim.range #38665Luis Calle2
Problem: `buf` is optional even though its needed to perform conversions and the ordering of `(buf, row, col)` is not consistent. Solution: make `buf` mandatory on `vim.range` and `vim.pos` and enforce the `buf, row, col` ordering
2026-04-05fix(net): handle remote archive URLs via tar/zip browse #38744Tom Ampuero1
Problem: Opening .tar.gz or .zip URLs shows raw binary instead of using the archive plugins. Solution: Similar to the original netrw implementation, the autocmd should detect archive URLs, download them to a temp file and the open them with tar/zip handlers already bundled as vim plugins.
2026-04-01docs: misc (#38578)zeertzjq1
2026-03-29test: failing "treesitter.get_parser() returns nil for >= 0.12"Justin M. Keyes1
2026-03-29feat: extend vim.Pos, vim.Range #36397Luis Calle2
Problem: Using nested `vim.Pos` objects to represent each `vim.Range` object requires 3 tables for each `vim.Range`, which may be undesirable in performance critical code. Using key-value tables performs worse than using array-like tables (lists). Solution: Use array-like indices for the internal fields of both `vim.Pos` and `vim.Range` objects. Use a metatable to allow users to access them like if they were key-value tables. --- Problem: The `vim.Pos` conversion interface for `extmark` indexing does not take into account the difference in how a position on top of a newline is represented in `vim.Pos` and `extmark`. - `vim.Pos`: for a newline at the end of row `n`, `row` takes the value `n + 1` and `col` takes the value `0`. - `extmark`: for a newline at the end of for `n`, `row` takes the value `n` and `col` takes the value `#row_text`. Solution: Handle this in the `extmark` interface. --- Problem: Not all `to_xxx` interfaces have wrapping objects like `to_lsp`. Solution: Return unwrapped values in `to_xxx` interfaces where it makes sense. Accept unwrapped values in "from" interfaces where it makes sense. --- Problem: `start` and `end` positions have different semantics, so they can't be compared. `vim.Range` relies on comparing the `end` and `start` of two ranges to decide which one is greater, which doesn't work as expected because this of the different semantics. For example, for the ranges: local a = { start = { row = 0, col = 22, }, end_ = { row = 0, col = 24, }, } local b = { start = { row = 0, col = 17, }, end_ = { row = 0, col = 22, }, } in this code: local foo, bar = "foo", "bar" -- |---||-| -- b a The range `b` is smaller than the range `a`, but the current implementation compares `b._end` (`col = 22`) and `a.start` (`col = 22`) and concludes that, since `b.col` is not smaller than `a.col`, `b` should be greater than `a`. Solution: - Use a `to_inclusive_pos` to normalize end positions inside of `vim.Range` whenever a comparison between a start and an end position is necessary.
2026-03-29test: fix s390x failuresJustin M. Keyes1
Problem: failures in s390x CI. Solution: - runtime/lua/man.lua: parse_path() can return nil but 3 callers didn't handle it. - skip some tests on s390x. TODO: - TODO: why "build/bin/xxd is not executable" on s390x? - TODO: other failures, not addressed (see below). OTHER FAILURES: FAILED test/functional/treesitter/fold_spec.lua @ 87: treesitter foldexpr recomputes fold levels after lines are added/removed test/functional/treesitter/fold_spec.lua:95: Expected objects to be the same. Passed in: (table: 0x4013c18940) { [1] = '0' [2] = '0' [3] = '0' *[4] = '0' [5] = '0' ... Expected: (table: 0x4005acf900) { [1] = '0' [2] = '0' [3] = '>1' *[4] = '1' [5] = '1' ... stack traceback: (tail call): ? test/functional/treesitter/fold_spec.lua:95: in function <test/functional/treesitter/fold_spec.lua:87> FAILED test/functional/treesitter/select_spec.lua @ 52: treesitter incremental-selection works test/functional/treesitter/select_spec.lua:63: Expected objects to be the same. Passed in: (string) 'bar(2)' Expected: (string) 'foo(1)' stack traceback: (tail call): ? test/functional/treesitter/select_spec.lua:63: in function <test/functional/treesitter/select_spec.lua:52> FAILED test/functional/treesitter/select_spec.lua @ 69: treesitter incremental-selection repeat test/functional/treesitter/select_spec.lua:82: Expected objects to be the same. Passed in: (string) '2' Expected: (string) '4' stack traceback: (tail call): ? test/functional/treesitter/select_spec.lua:82: in function <test/functional/treesitter/select_spec.lua:69> FAILED test/functional/treesitter/select_spec.lua @ 98: treesitter incremental-selection history test/functional/treesitter/select_spec.lua:111: Expected objects to be the same. Passed in: (string) 'bar(2)' Expected: (string) 'foo(1)' stack traceback: (tail call): ? test/functional/treesitter/select_spec.lua:111: in function <test/functional/treesitter/select_spec.lua:98> FAILED test/functional/treesitter/select_spec.lua @ 186: treesitter incremental-selection with injections works test/functional/treesitter/select_spec.lua:201: Expected objects to be the same. Passed in: (string) 'lua' Expected: (string) 'foo' stack traceback: (tail call): ? test/functional/treesitter/select_spec.lua:201: in function <test/functional/treesitter/select_spec.lua:186> FAILED test/functional/treesitter/select_spec.lua @ 216: treesitter incremental-selection with injections ignores overlapping nodes test/functional/treesitter/select_spec.lua:231: Expected objects to be the same. Passed in: (string) ' )' Expected: (string) ' foo(' stack traceback: (tail call): ? test/functional/treesitter/select_spec.lua:231: in function <test/functional/treesitter/select_spec.lua:216> FAILED test/functional/treesitter/select_spec.lua @ 307: treesitter incremental-selection with injections handles disjointed trees test/functional/treesitter/select_spec.lua:337: Expected objects to be the same. Passed in: (string) 'int' Expected: (string) '1}' stack traceback: (tail call): ? test/functional/treesitter/select_spec.lua:337: in function <test/functional/treesitter/select_spec.lua:307> ERROR test/functional/treesitter/parser_spec.lua @ 562: treesitter parser API can run async parses with string parsers test/functional/treesitter/parser_spec.lua:565: attempt to index a nil value stack traceback: test/functional/testnvim/exec_lua.lua:124: in function <test/functional/testnvim/exec_lua.lua:105> (tail call): ? (tail call): ? test/functional/treesitter/parser_spec.lua:563: in function <test/functional/treesitter/parser_spec.lua:562> FAILED test/functional/core/job_spec.lua @ 1157: jobs jobstop() kills entire process tree #6530 test/functional/core/job_spec.lua:1244: retry() attempts: 94 test/functional/core/job_spec.lua:1246: Expected objects to be the same. Passed in: (table: 0x401dd74b30) { [name] = 'sleep <defunct>' [pid] = 33579 [ppid] = 1 } Expected: (userdata) 'vim.NIL' stack traceback: test/testutil.lua:89: in function 'retry' test/functional/core/job_spec.lua:1244: in function <test/functional/core/job_spec.lua:1157>
2026-03-23feat(net): vim.net.request(outbuf) writes response to buffer #36164Yochem van Rosmalen1
Problem: Non-trivial to write output of vim.net.request to buffer. Requires extra code in plugin/net.lua which can't be reused by other plugin authors. ``` vim.net.request('https://neovim.io', {}, function(err, res) if not err then local buf = vim.api.nvim_create_buf(true, false) if res then local lines = vim.split(res.body, '\n', { plain = true }) vim.api.nvim_buf_set_lines(buf, 0, -1, true, lines) end end end) ``` Solution: Accept an optional `outbuf` argument to indicate the buffer to write output to, similar to `outpath`. vim.net.request('https://neovim.io', { outbuf = buf }) Other fixes / followups: - Make plugin/net.lua smaller - Return objection with close() method - vim.net.request.Opts class - vim.validate single calls - Use (''):format(...) instead of `..`
2026-03-23fix(lua): drop support for boolean `buf` in `vim.keymap` #38432skewb1k1
Problem: `vim.keymap.*.Opts.buf` allows `boolean` aliases for more widely used `integer?` values, `true` -> `0` and `false` -> `nil`. This conversion is unnecessary and can be handled at call sites. Solution: As a follow-up to deprecating the `buffer` option, drop support for boolean values for the new `buf` option. The deprecated `buffer` continues to support booleans for backward compatibility.
2026-03-21fix(mpack): boundary values for negative integer encoding #37255benarcher26911
Problem: libmpack encodes boundary values -129 and -32769 with wrong integer sizes: - -129 as int8 instead of int16 - -32769 as int16 instead of int32 because the boundary checks compare against the wrong values (e.g., lo < 0xffffff7f instead of lo < 0xffffff80). This caused data corruption: -129 would decode as 127. Solution: Fix off-by-one errors in the two's complement boundary constants: 0xffffff80 (-128, min int8) and 0xffff8000 (-32768, min int16). Fixes #37202 Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-21feat(lua): replace `buffer` with `buf` in vim.keymap.set/del #38360skewb1k1
The `buffer` option remains functional but is now undocumented. Providing both will raise an error. Since providing `buf` was disallowed before, there is no code that will break due to using `buffer` alongside `buf`.
2026-03-20feat(stdlib): vim.fs.ext() returns file extension #36997Yochem van Rosmalen1
Problem: Checking the extension of a file is done often, e.g. in Nvim's codebase for differentiating Lua and Vimscript files in the runtime. The current way to do this in Lua is (1) a Lua pattern match, which has pitfalls such as not considering filenames starting with a dot, or (2) fnamemodify() which is both hard to discover and hard to use / read if not very familiar with the possible modifiers. vim.fs.ext() returns the file extension including the leading dot of the extension. Similar to the "file extension" implementation of many other stdlibs (including fnamemodify(file, ":e")), a leading dot doesn't indicate the start of the extension. E.g.: the .git folder in a repository doesn't have the extension .git, but it simply has no extension, similar to a folder named git or any other filename without dot(s).
2026-03-18fix(options): vim.opt fails for 'fillchars' #37141Juan Pablo Briones1
Problem: When `to_vim_value[info.metatype](info, value)` is called, a list value such as `{'eob:a'}` is treated like a map, which generates `1:eob:a`. Note: commands like `:lua vim.opt.wildmode={'longest:full'}` are not an issue because only cases harcoded in `key_value_options` have metatype `map`. Solution: Check for array type and use the same logic as in array metatypes.
2026-03-16fix(api): use standard error messagesJustin M. Keyes1
2026-03-16fix(diagnostic): open_float() handles config.float function #31577glepnir1
Problem: The `float` field of vim.diagnostic.config can be a function, but diagnostic.open_float() does not handle it correctly. Solution: Add handling for it in open_float().
2026-03-13fix(normal): crash using :norm from vim.ui_attach shell message event #38283luukvbaal1
Problem: 'showcmd' buffer is being populated for :norm commands, which can result in a recursive uv_run() when called from a msg_show vim.ui_attach callback for a shell message. Solution: The 'showcmd' buffer is never displayed while executing a :normal command so prevent unnecessary work, avoiding the crash.
2026-03-13feat(diagnostic): custom status format function #36696Oleh Volynets1
Problem: Statusline component of diagnostics allows only the default format "sign:count". Solution: Extend vim.diagnostic.Opts.Status to allow a custom signs or formatting function that provides the status presentation.
2026-03-12docs: use "ev" convention in event-handlersJustin M. Keyes2
Problem: In autocmd examples, using "args" as the event-object name is vague and may be confused with a user-command. Solution: Use "ev" as the conventional event-object name.
2026-03-12test: fs_spec fails if home is a symlink #38258Willaaaaaaa1
2026-03-11docs: api, messages, lsp, trustJustin M. Keyes2
gen_vimdoc.lua: In prepare for the upcoming release, comment-out the "Experimental" warning for prerelease features.
2026-03-08fix(api): merge split window config only on successSean Dewar1
Problem: nvim_win_set_config may merge configs despite failing to configure a split, and without applying necessary side-effects (like setting style=minimal options). Plus, autocommands may apply a different config after the merge, causing side-effects to apply for an outdated config. Solution: merge configs last, only on success. Include fields only relevant to splits. Properly set _cmdline_offset for splits. Maybe better to disallow _cmdline_offset for splits instead, as the pum is relative to cmdline_row anyway? (I didn't want to change behaviour too much) Also use expect_unchanged in an unrelated test to quash a warning.
2026-02-27fix(vim.fs): joinpath() should ignore empty items #38077Yochem van Rosmalen1
Problem: vim.fs.joinpath treats empty string as a path segment (it adds a path separator for each empty item): print(vim.fs.joinpath('', 'after/lsp', '')) -- '/after/lsp/' print(vim.fs.joinpath('', '')) -- '/' Especially problematic if the empty segment is the first segment, as that converts the path to an absolute path. Solution: Ignore empty (length of 0) path segments. Benchmark: local function test(func) local t = vim.uv.hrtime() for _ = 1, 100000, 1 do func('', 'this/is', 'a/very/long/path', '', 'it', 'really', 'is') end print(math.floor((vim.uv.hrtime() - t) / 1e6), 'ms') end - with Iter():filter() --> 370 ms - building new segments table --> 208 ms - with vim.tbl_filter --> 232 ms - Instead of gsub split on `/` in all parts --> 1870 ms
2026-02-25feat(secure): allow 'path' parameter for trust action 'allow' (#38001)anondeveg1
2026-02-24fix(messages): unwanted ext_messages newlines for confirm() #38045luukvbaal1
Problem: Newlines emitted with ext_messages intended to position the message/prompt on the message grid. Solution: Don't emit these newlines with ext_messages, followup to 4260f73e.
2026-02-21test(ui): failure in lua/ui_spec.lua in headless OS (no GUI) #37975wjyoung651
2026-02-18test: support running functionaltests in parallel by directory (#37918)zeertzjq2
Define a CMake target for every subdirectory of test/functional that contains functional tests, and a functionaltest_parallel target that depends on all those targets, allowing multiple test runners to run in parallel. On CI, use at most 2 parallel test runners, as using more may increase system load and make tests unstable.
2026-02-17test: don't run test cases directly in describe() (#37915)zeertzjq1
2026-02-16fix(messages): message not flushed at end of command #37904luukvbaal1
Problem: Logic determining messages belonging to the last command to show with "g<" does not flush pending messages. This can result in clearing the temporary message history before a message still belonging to the previous command was emitted. Solution: Flush pending messages when marking the end of messages belonging to previous command.
2026-02-16feat(lua): support vim.Range:has(vim.pos) #37879Maria Solano1
2026-02-15fix(prompt): wrong changed lnum in init_promptSean Dewar1
Problem: if init_prompt replaces the prompt line at the ': mark, it calls inserted_bytes with the wrong lnum. Solution: use the correct lnum. Call appended_lines_mark instead when appending the prompt at the end.
2026-02-15fix(prompt): prompt_setprompt does not adjust extmarks, no on_bytesSean Dewar1
Problem: prompt_setprompt does not adjust extmarks or trigger on_bytes buffer-updates when fixing the prompt line. Solution: adjust them, trigger on_bytes. Notably, hides extmarks when replacing the entire line (and clearing user input). Otherwise, when just replacing the prompt text, hides extmarks there, but moves those after (in the user input area) to the correct spot.
2026-02-15fix(prompt): wrong cursor col after prompt_setprompt, no on_linesSean Dewar1
Problem: prompt_setprompt calls coladvance with a byte column, but it expects a screen column. on_lines buffer-updates aren't fired when fixing the prompt line. Solution: don't use coladvance. Call changed_lines, which also simplifies the redraw logic. (and calls changed_cline_bef_curs if needed; added test checks this) Unlike https://github.com/neovim/neovim/pull/37743/changes#r2775398744, this means &modified is set by prompt_setprompt if it fixes the prompt line. Not setting &modified is inconsistent anyway -- even init_prompt sets it if it fixes the prompt line.
2026-02-14feat(diagnostic): fromqflist({merge_lines}) #37416Dmytro Pletenskyi1
Problem: `vim.diagnostic.fromqflist` ignores lines that are `item.valid == 0` (see `getqflist`). Many qflists have messages that span multiple lines, which look like this: collection/src/Modelling/CdOd/Central.hs|496 col 80| error: [GHC-83865] || • Couldn't match expected type: InstanceWithForm || (FilePath || -> SelectValidCdInstWithForm ... calling `vim.diagnostic.fromqflist(vim.fn.getqflist)` gets a diagnostic message like this: error: [GHC-83865] only the first line is kept, but often, the remaing lines are useful as well. Solution: Introduce `merge_lines` option, which "squashes" lines from invalid qflist items into the error message of the previous valid item, so that we get this diagnostic message instead: error: [GHC-83865] • Couldn't match expected type: InstanceWithForm (FilePath -> SelectValidCdInstWithForm