aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
Commit message (Collapse)AuthorAge
...
* fix(ui.open): use "start" instead of deprecated "rundll32" #36731ymich99632025-11-30
| | | | | | | | Problem: The rundll32 utility is a leftover from Windows 95, and it has been deprecated since at least Windows Vista. Solution: Use the start command through Command Prompt instead.
* feat(lsp): support `version` in `textDocument/publishDiagnostics` #36754Riley Bruins2025-11-29
| | | | This commit makes it so that push diagnostics received for an outdated document version are ignored.
* feat(lsp): lsp.enable() auto-escalates forced shutdown #36458Olivia Kinnear2025-11-29
| | | | | | | Problem: LSP server may not exit even after the client was stopped/disabled via enable(false). Solution: Automatically force-stop after a timeout, unless `client.flags.exit_timeout = false`.
* vim-patch:9.1.1934: filetype: not all starlark files are recognized (#36743)zeertzjq2025-11-29
| | | | | | | | | | | | | Problem: filetype: not all starlark files are recognized Solution: Detect *.sky files as starlark filetype (Bruno Belanyi) References: - https://docs.bazel.build/versions/0.17.1/skylark/spec.html closes: vim/vim#18807 https://github.com/vim/vim/commit/3ba6a97fea3e62857fe473d8c08415a05b9c316b Co-authored-by: Bruno Belanyi <bruno@belanyi.fr>
* vim-patch:9.1.1933: completion: complete_match() is not useful (#36726)zeertzjq2025-11-28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: completion: complete_match() Vim script function and 'isexpand' option are not that useful and confusing (after v9.1.1341) Solution: Remove function and option and clean up code and documentation (Girish Palya). complete_match() and 'isexpand' add no real functionality to Vim. They duplicate what `strridx()` already does, yet pretend to be part of the completion system. They have nothing to do with the completion mechanism. * `f_complete_match()` in `insexpand.c` does not call any completion code. It’s just a `STRNCMP()` wrapper with fluff logic. * `'isexpand'` exists only as a proxy argument to that function. It does nothing on its own and amounts to misuse of a new option. The following Vim script function can be used to implement the same functionality: ```vim func CompleteMatch(triggers, sep=',') let line = getline('.')->strpart(0, col('.') - 1) let result = [] for trig in split(a:triggers, a:sep) let idx = strridx(line, trig) if l:idx >= 0 call add(result, [idx + 1, trig]) endif endfor return result endfunc ``` related: vim/vim#16716 fixes: vim/vim#18563 closes: vim/vim#18790 https://github.com/vim/vim/commit/cbcbff871224115c45bbd14582749a487c6fad30 Co-authored-by: Girish Palya <girishji@gmail.com>
* vim-patch:b217ffb: runtime(doc): remove outdated help about 'completeopt' ↵zeertzjq2025-11-28
| | | | | | | | "fuzzy" closes: vim/vim#18815 https://github.com/vim/vim/commit/b217ffbef27c416d6c9b4b7e5a08f61f54013748
* vim-patch:9.1.1930: completion: 'completefuzzycollect' is too obscurezeertzjq2025-11-28
| | | | | | | | | | | | | | | | Problem: completion: 'completefuzzycollect' option is too obscure Solution: Deprecate the option, but don't error out for existing scripts, behave like 'completefuzzycollect' is set when fuzzy completion is enabled (Girish Palya). fixes: vim/vim#18498 closes: vim/vim#18788 https://github.com/vim/vim/commit/33fbfe003c17ad25bf3903aaa89a55fe372086ba Remove this option completely, as it's introduced in Nvim v0.12 cycle. Co-authored-by: Girish Palya <girishji@gmail.com>
* fix(health): git check and autocmd clean #36713glepnir2025-11-26
| | | | | Problem: Incorrect Git check and improper autocmd cleanup Solution: Add once to the autocmd and fix the Git check condition
* fix(lsp): ignore invalid fold ranges (#36708)Miika Tuominen2025-11-26
|
* feat(float): 'statusline' in floating windows #36521glepnir2025-11-26
| | | | | | | Problem: Can't show 'statusline' in floating windows. Solution: Use window-local 'statusline' to control floating window statusline visibility.
* feat(health): create a bug report #31842glepnir2025-11-25
| | | | | | | | | Problem: Creating a bug report is somewhat tedious for users. Bug reports sometimes are missing useful info. Solution: Add a feature to :checkhealth which automatically gets system info and includes it in a new bug report.
* feat(diagnostic): config.status #36693Maria Solano2025-11-25
| | | | | | | | Problem: `diagnostic.status()` is configured via `config.signs`, but users may want diagnostics only in statusline, not in the gutter (signs). Solution: Add `config.status`.
* feat(diagnostic): highlights in diagnostic.status() #36685Riley Bruins2025-11-25
| | | | Applies the appropriate `DiagnosticSign*` highlight to each group, resetting the highlights at the end of the expression.
* refactor(defaults): deduplicate selection_range() mappings #36686Riley Bruins2025-11-25
| | | | We don't need to specify the timeout ms here anymore, because the implementation was changed to use it by default.
* feat(lsp): incremental-selection operator-pending mode #36575Branden Call2025-11-24
| | | | | | | | | | Problem: LSP incremental selection provides default visual-mode keymaps for `an` and `in`. Operator-pending mode is not supported, so `dan` and `can` do not apply the operation. Solution: Modify selection_range() to be synchronous. Add operator-pending mappings.
* docs: vimdoc parsing errors #36681Justin M. Keyes2025-11-24
| | | | | | | | | | Error: .tests/neovim/runtime/doc/dev_test.txt (MISSING "`" [420, 79] - [420, 79]) Error: .tests/neovim/runtime/doc/news.txt (MISSING "`" [137, 80] - [137, 80]) Error: .tests/neovim/runtime/doc/nvim.txt (MISSING "<" [106, 0] - [106, 0]) Error: .tests/neovim/runtime/doc/vimfn.txt (MISSING "}" [2610, 26] - [2610, 26])
* vim-patch:2190036: runtime(doc): Add environment variable expansion note to ↵zeertzjq2025-11-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | options (#36675) Add "Environment variables are expanded |:set_env|" documentation to options that have the P_EXPAND flag but were missing this note. Updated options: - 'cdpath' - 'dictionary' - 'mkspellmem' - 'packpath' - 'runtimepath' - 'spellfile' - 'spellsuggest' - 'thesaurus' - 'ttytype' - 'undodir' - 'verbosefile' - 'viewdir' - 'viminfofile' These options support environment variable expansion in their values (e.g., $HOME, $USER) but the documentation didn't explicitly mention this capability. This brings their documentation in line with other options like backupdir, directory, and makeprg that already include this note. closes: vim/vim#18791 https://github.com/vim/vim/commit/2190036c8cfb1e94625756b8ffbb3aa65f04687e Co-authored-by: Alex Plate <AlexPl292@gmail.com>
* docs: miscJustin M. Keyes2025-11-23
| | | | | | | | | | Close #36441 Close #36631 Close #36656 Co-authored-by: Maria José Solano <majosolano99@gmail.com> Co-authored-by: glepnir <glephunter@gmail.com> Co-authored-by: "Mike J. McGuirk" <mike.j.mcguirk@gmail.com>
* docs: misc, build, lspJustin M. Keyes2025-11-22
|
* fix(ui2): unset Search highlighting (#36633)Oleh Volynets2025-11-20
| | | | | | | | | | | Problem: Trying to match the search highlight groups to the Normal highlight for the window can fail when the message highlighting contains a fg/bg that the Normal highlight doesn't (like an error message in cmd will have ErrorMsg highlight instead of MsgArea - which is Normal in cmd.) Solution: Link the search highlight groups to an empty group in 'winhighlight' thus disabling them instead of overriding them with Normal/MsgArea/etc.
* fix(input): discard following keys when discarding <Cmd>/K_LUA (#36498)zeertzjq2025-11-20
| | | | | | | | | | | Technically the current behavior does match documentation. However, the keys following <Cmd>/K_LUA aren't normally received by vim.on_key() callbacks either, so it does makes sense to discard them along with the preceding key. One may also argue that vim.on_key() callbacks should instead receive the following keys together with the <Cmd>/K_LUA, but doing that may cause some performance problems, and even in that case the keys should still be discarded together.
* fix(ui2): hide search highlights in msg window #36626luukvbaal2025-11-19
| | | | | | fix(ui2): hide search highlights in msg window. Problem: Search highlighting is shown in the msg (and dialog) window. Solution: Hide search highlighting in all but the pager window.
* fix(lsp): enable insertReplaceSupport for use in adjust_start_col #36569Jeff Martin2025-11-18
| | | | | | | | | | | | | | | | | Problem: With the typescript LSes typescript-language-server and vtsls, omnicompletion on partial tokens for certain types, such as array methods, and functions that are attached as attributes to other functions, either results in no entries populated in the completion menu (typescript-language-server), or an unfiltered completion menu with all array methods included, even if they don't share the same prefix as the partial token being completed (vtsls). Solution: Enable insertReplaceSupport and uses the insert portion of the lsp completion response in adjust_start_col if it's included in the response. Completion results are still filtered client side.
* docs(diagnostic): diagnostic.Opts.Float extend open_floating_preview.Opts #30058glepnir2025-11-18
| | | | | | | | Problem: the opts table also is param of util.open_floating_preview, vim.diagnostic.Opts.Float missing some fields of open_floating_preview. Solution: diagnostic.Opts.Float extend util.open_floating_preview.Opts Fix #29267
* feat(lsp): user-specified sorting of lsp.completion multi-server results #36401glepnir2025-11-18
| | | | | | Problem: No way to customize completion order across multiple servers. Solution: Add `cmp` function to `vim.lsp.completion.enable()` options for custom sorting logic.
* feat(api): nvim_win_set_config accepts unchanged "noautocmd" #36463glepnir2025-11-18
| | | | | | Problem: Cannot reuse same config with noautocmd for both window creation and updates, even when value is unchanged. Solution: Only reject noautocmd changes for existing windows.
* perf(treesitter): parse multiple ranges in languagetree, eliminate ↵Riley Bruins2025-11-18
| | | | | | | | | | | flickering #36503 **Problem:** Whenever `LanguageTree:parse()` is called, injection trees from previously parsed ranges are dropped. **Solution:** Allow the function to accept a list of ranges, so it can return injection trees for all the given ranges. Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
* fix(lsp): set concealcursor='' in LSP floating windows #36596skewb1k2025-11-17
| | | | | | | | | | | | Problem: Users often jump and navigate through LSP windows to yank text. Concealed markdown can make navigation through hyperlinks and code blocks more difficult. Solution: Change 'concealcursor' from 'n' to '' to preserve clean display while improving navigation and selection of the LSP response. Closes #36537
* fix(ui2): only redraw when necessary #36457luukvbaal2025-11-17
| | | | | | Problem: Until now the UI callback called nvim__redraw() liberally. It should only be needed when Nvim does not update the screen in its own event loop. Solution: Identify which UI events require immediate redrawing.
* Merge #36338 vim.pack: lockfile synchronizationJustin M. Keyes2025-11-17
|\
| * fix(pack): rename confirmation buffer to again use `nvim-pack://` schemeEvgeni Chasnovski2025-11-17
| | | | | | | | | | | | | | | | | | | | | | | | Problem: `nvim://` scheme feels more like a generalized interface that may be requested externally, and it acts like CLI args (roughly). This is how `vscode://` works. Anything that behaves like an "app" or a "protocol" deserves its own scheme. For such Nvim-owned things they will be called `nvim-xx://`. Solution: Use `nvim-pack://confirm#<bufnr>` template for confirmation buffer name instead of `nvim://pack-confirm#<bufnr>`.
| * feat(pack)!: synchronize lockfile with installed plugins when reading itEvgeni Chasnovski2025-11-17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Lockfile can become out of sync with what is actually installed on disk when user performs (somewhat reasonable) manual actions like: - Delete lockfile and expect it to regenerate. - Delete plugin directory without `vim.pack.del()`. - Manually edit lock data in a bad way. Solution: Synchronize lockfile data with installed plugins on every lockfile read. In particular: 1. Install immediately all missing plugins with valid lock data. This helps with "manually delete plugin directory" case by prompting user to figure out how to properly delete a plugin. 2. Repair lock data for properly installed plugins. This helps with "manually deleted lockfile", "manually edited lockfile in an unexpected way", "installation terminated due to timeout" cases. 3. Remove unrepairable corrupted lock data and their plugins. This includes bad lock data for missing plugins and any lock data for corrupted plugins (right now this only means that plugin path is not a directory, but can be built upon). Step 1 also improves usability in case there are lazy loaded plugins that are rarely loaded (like on `FileType` event, for example): - Previously starting with config+lockfile on a new machine only installs rare `vim.pack.add()` plugin after it is called (while an entry in lockfile would still be present). This could be problematic if there is no Internet connection, for example. - Now all plugins from the lockfile are installed before actually executing the first `vim.pack.add()` call in 'init.lua'. And later they are only loaded on a rare `vim.pack.add()` call. --- Synchronizing lockfile on its every read makes it work more robustly if other `vim.pack` functions are called without any `vim.pack.add()`. --- Performance for a regular startup (good lockfile, everything is installed) is not affected and usually even increased. The bottleneck in this area is figuring out which plugins need to be installed. Previously the check was done by `vim.uv.fs_stat()` for every plugin in `vim.pack.add()`. Now it is replaced with a single `vim.fs.dir()` traversal during lockfile sync while later using lockfile data to figure out if plugin needs to be installed. The single `vim.fs.dir` approach scales better than `vim.uv.fs_stat`, but might be less performant if there are many plugins that will be not loaded via `vim.pack.add()` during startup. Rough estimate of how long the same steps (read lockfile and normalize plugin array) take with a single `vim.pack.add()` filled with 43 plugins benchmarking: - Before commit: ~700 ms - After commit: ~550 ms
| * refactor(pack): rearrange lockfile code to be able to use other localsEvgeni Chasnovski2025-11-17
| |
| * fix(pack)!: ensure plugin is fully absent if not fully installedEvgeni Chasnovski2025-11-17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Currently it is possible to have plugin in a "partial install" state when `git clone` was successfull but `git checkout` was not. This was done to not checkout default branch by default in these situations (for security reasons). The problem is that it adds complexity when both dealing with lockfile (plugin's `rev` might be `nil`) and in how `src` and `version` are treated (wrong `src` - no plugin on disk; wrong `version` - "partial" plugin on disk). Solution: Treat plugin as "installed" if both `git clone` and `git checkout` are successful, while ensuring that not installed plugins are not on disk and in lockfile. This also means that if in 'init.lua' there is a `vim.pack.add()` with bad `version`, for first install there will be an informative error about it BUT next session will also try to install it. The solution is the same - adjust `version` beforehand.
| * fix(pack)!: adjust install confirm (no error on "No", show names)Evgeni Chasnovski2025-11-17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Installation confirmation has several usability issues: - Choosing "No" results in a `vim.pack.add()` error. This was by design to ensure that all later code that *might* reference presumably installed plugin will not get executed. However, this is often too restrictive since there might be no such code (like if plugin's effects are automated in its 'plugin/' directory). Instead the potential code using not installed plugin will throw an error. No error on "No" will also be useful for planned lockfile repair. - List of soon-to-be-installed plugins doesn't mention plugin names. This might be confusing if plugins are installed under different name. Solution: Silently drop installation step if user chose "No" and show plugin names in confirmation text (together with their pretty aligned sources).
* | feat(diagnostics): stack DiagnosticUnnecessary,DiagnosticDeprecated ↵Grzegorz Rozdzialik2025-11-17
|/ | | | | | | | | | | | | | | | | highlights #36590 Problem: unnecessary and deprecated diagnostics use their own highlight groups (`DiagnosticUnnecessary` and `DiagnosticDeprecated`) which override the typical severity-based highlight groups (like `DiagnosticUnderlineWarn`). This can be misleading, since diagnostics about unused variables which are warnings or errors, are shown like comments, since then only the `DiagnosticUnnecessary` highlight group is used. Users do not see the more eye-catching red/yellow highlight. Solution: Instead of overriding the highlight group to `DiagnosticUnnecessary` or `DiagnosticDeprecated`, set them in addition to the normal severity-based highlights.
* fix(vim.fs): abspath(".") returns "/…/." #36583Justin M. Keyes2025-11-16
|
* fix(vim.fs): root() should always return absolute path #36466Cameron Ring2025-11-16
|
* docs: misc #36580Justin M. Keyes2025-11-16
| | | | | | | | Co-authored-by: nguyenkd27 <nguyenkd27@gmail.com> Co-authored-by: dundargoc <gocdundar@gmail.com> Co-authored-by: Yochem van Rosmalen <git@yochem.nl> Co-authored-by: Tuure Piitulainen <tuure.piitulainen@gmail.com> Co-authored-by: Maria Solano <majosolano99@gmail.com> Co-authored-by: tao <2471314@gmail.com>
* feat(lsp): skip invalid header lines #36402tao2025-11-16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Some servers write log to stdout and there's no way to avoid it. See https://github.com/neovim/neovim/pull/35743#pullrequestreview-3379705828 Solution: We can extract `content-length` field byte by byte and skip invalid lines via a simple state machine (name/colon/value/invalid), with minimal performance impact. I chose byte parsing here instead of pattern. Although it's a bit more complex, it provides more stable performance and allows for more accurate error info when needed. Here is a bench result and script: parse header1 by pattern: 59.52377ms 45 parse header1 by byte: 7.531128ms 45 parse header2 by pattern: 26.06936ms 45 parse header2 by byte: 5.235724ms 45 parse header3 by pattern: 9.348495ms 45 parse header3 by byte: 3.452389ms 45 parse header4 by pattern: 9.73156ms 45 parse header4 by byte: 3.638386ms 45 Script: ```lua local strbuffer = require('string.buffer') --- @param header string local function get_content_length(header) for line in header:gmatch('(.-)\r?\n') do if line == '' then break end local key, value = line:match('^%s*(%S+)%s*:%s*(%d+)%s*$') if key and key:lower() == 'content-length' then return assert(tonumber(value)) end end error('Content-Length not found in header: ' .. header) end --- @param header string local function get_content_length_by_byte(header) local state = 'name' local i, len = 1, #header local j, name = 1, 'content-length' local buf = strbuffer.new() local digit = true while i <= len do local c = header:byte(i) if state == 'name' then if c >= 65 and c <= 90 then -- lower case c = c + 32 end if (c == 32 or c == 9) and j == 1 then -- skip OWS for compatibility only elseif c == name:byte(j) then j = j + 1 elseif c == 58 and j == 15 then state = 'colon' else state = 'invalid' end elseif state == 'colon' then if c ~= 32 and c ~= 9 then -- skip OWS normally state = 'value' i = i - 1 end elseif state == 'value' then if c == 13 and header:byte(i + 1) == 10 then -- must end with \r\n local value = buf:get() return assert(digit and tonumber(value), 'value of Content-Length is not number: ' .. value) else buf:put(string.char(c)) end if c < 48 and c ~= 32 and c ~= 9 or c > 57 then digit = false end elseif state == 'invalid' then if c == 10 then -- reset for next line state, j = 'name', 1 end end i = i + 1 end error('Content-Length not found in header: ' .. header) end --- @param fn fun(header: string): number local function bench(label, header, fn, count) local start = vim.uv.hrtime() local value --- @type number for _ = 1, count do value = fn(header) end local elapsed = (vim.uv.hrtime() - start) / 1e6 print(label .. ':', elapsed .. 'ms', value) end -- header starting with log lines local header1 = 'WARN: no common words file defined for Khmer - this language might not be correctly auto-detected\nWARN: no common words file defined for Japanese - this language might not be correctly auto-detected\nContent-Length: 45 \r\n\r\n' -- header starting with content-type local header2 = 'Content-Type: application/json-rpc; charset=utf-8\r\nContent-Length: 45 \r\n' -- regular header local header3 = ' Content-Length: 45\r\n' -- regular header ending with content-type local header4 = ' Content-Length: 45 \r\nContent-Type: application/json-rpc; charset=utf-8\r\n' local count = 10000 collectgarbage('collect') bench('parse header1 by pattern', header1, get_content_length, count) collectgarbage('collect') bench('parse header1 by byte', header1, get_content_length_by_byte, count) collectgarbage('collect') bench('parse header2 by pattern', header2, get_content_length, count) collectgarbage('collect') bench('parse header2 by byte', header2, get_content_length_by_byte, count) collectgarbage('collect') bench('parse header3 by pattern', header3, get_content_length, count) collectgarbage('collect') bench('parse header3 by byte', header3, get_content_length_by_byte, count) collectgarbage('collect') bench('parse header4 by pattern', header4, get_content_length, count) collectgarbage('collect') bench('parse header4 by byte', header4, get_content_length_by_byte, count) ``` Also, I removed an outdated test https://github.com/neovim/neovim/blob/accd392f4d14a114e378f84dc15cb24bc34a370a/test/functional/plugin/lsp_spec.lua#L1950 and tweaked the boilerplate in two other tests for reusability while keeping the final assertions the same. https://github.com/neovim/neovim/blob/accd392f4d14a114e378f84dc15cb24bc34a370a/test/functional/plugin/lsp_spec.lua#L5704 https://github.com/neovim/neovim/blob/accd392f4d14a114e378f84dc15cb24bc34a370a/test/functional/plugin/lsp_spec.lua#L5721
* fix(pack): show more informative error message if no `git` executableEvgeni Chasnovski2025-11-16
| | | | | | | | Problem: Relaxing minimal Git version did not fully preserve previous behavior in case there no `git` executable. Instead it showed the same error as if after `vim.system({ 'does_not_exist' })`. Solution: Show a more direct "No `git` executable" error message.
* docs(pack): add example workflow of how to revert after a bad updateEvgeni Chasnovski2025-11-16
| | | | | | | | | | Problem: No example workflow of how to revert after a bad update. Solution: Add example workflow of how to revert after a bad update. In future this might be improved by utilizing other `vim.pack` fe