Compare commits

...

342 Commits

Author SHA1 Message Date
Sean Dewar
8c311386c3 fix(window): don't add a hsep when out of room if global stl is off
Problem: a horizontal separator may be added to a window that doesn't need one
if there is no room when moving a different window.

Solution: only restore a hsep in winframe_restore when the global statusline is
enabled.

(cherry picked from commit bf5f7c1591)
2025-09-03 18:03:35 +00:00
Luna Razzaghipour
4c8486e1f2 perf: scheduler priority clamping on macOS #35488
Problem:
All of Nvim’s threads are clamped to the Default QoS class. This means
that Nvim is forced to compete for CPU time with compilers and other
batch work, and is even prioritized beneath user-initiated work in GUI
apps like e.g. file imports. This significantly harms responsiveness.

Solution:
Tell the kernel that the Nvim process takes part in rendering a UI.

Implementation:
Remove the process-wide QoS clamp. This doesn’t directly do anything to
the main thread, but rather has the side-effect of letting the main
thread run at its actual QoS (User Interactive QoS).

(cherry picked from commit f9ce939bf5)
2025-09-03 02:01:50 +00:00
Mike
d31953d532 fix(diagnostics): extend conversion support from/to quickfix format (#34006)
Use uppercase to check severity
Mark quickfix items as valid when converting from diagnostics
Support nr/code attribute between formats

(cherry picked from commit e4a100a1e1)
2025-09-02 15:47:15 +00:00
Justin M. Keyes
c5262c4ca8 Merge pull request #35598 from neovim/backport-29073-to-release-0.11
docs: add guide for developing Lua plugins
2025-09-01 22:10:02 -04:00
Justin M. Keyes
dd8e3d7aa5 docs: Lua plugin development guide
(cherry picked from commit a5e7ccc329)
2025-09-01 21:56:58 -04:00
Marc Jakobi
a7491e1457 docs: Lua plugin development guide
(cherry picked from commit 28ab656122)
2025-09-01 23:53:57 +00:00
Justin M. Keyes
1063aff643 ci(release): link to release notes #35585
fix #35580
2025-09-01 11:30:51 -04:00
Wise Man
e415fae42e ci: Windows arm64 packages #35345
Problem:
Neovim binaries are not provided for Windows ARM64.
GitHub Actions now offer native CI runners for Windows on ARM devices
(windows-11-arm), enabling automated builds and testing.

Solution:
- Modified CMake packaging to include packaging windows on arm binaries.
- Modified env script to install and initialize vs setup for arm64 arch. 

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-09-01 11:17:37 -04:00
Justin M. Keyes
7b099d2b2b version bump 2025-08-31 15:29:56 -04:00
Justin M. Keyes
cec0ecabd8 NVIM v0.11.4
See runtime/doc/news.txt (or `:help news` in Nvim).

Following is a list of fix/feature commits in this release.

FEATURES
--------------------------------------------------------------------------------
- 5551da79c1 lsp: improve signature help display #35190
- abfbd155da provider: detect venv python via "pynvim-python" tool #35273

BUILD
--------------------------------------------------------------------------------
- 3343ee971b deps: CMake generation fails when path contains spaces #35332

FIXES
--------------------------------------------------------------------------------
- 27282696fe api: fix not capturing output in cmdline mode (#35322)
- 09b0003d38 api: nvim_create_user_command addr option should allow ranges #35077
- 3ab06d5188 api: on_detach consistently before buf_freeall autocmds (#35369)
- 53db7fc3ef api,lsp: call on_detach before wiping out the buffer #35367
- 30b801eff2 checkhealth: wrong ABI version for treesitter parsers #35327
- a05b70baa6 clipboard: correct blockwise register width computation (#35038)
- 990b320592 cmdline: :checkhealth completion with multiple args (#35060)
- a3590afba5 diff: set default diff flags properly (#35450)
- f4b4c27a35 float: cursor visible in "hidden" floating window (#35219)
- 3cf9dac2ba folds: error when deleting lines at end of buffer #35396
- d70d469c04 health: accept TERM=tmux-direct #35511
- edfb447ff8 health: update advice for Python #35564
- 359d65c902 iter: ArrayIter:last returns nil when filtered to empty #34697
- 44b8255fa2 lsp: close floating preview window correctly #34946
- 6b820258cd lsp: don't override `config.title` in `vim.lsp.buf.signature_help()` #35075
- 8f2d6f7ce2 lsp: show title when global winborder is set (#35181)
- 1bea812953 lsp: update window title when cycling through signatures #35407
- 9261aef2f3 lsp/health: always use vim.inspect to show root_markers (#34667)
- d185057bc7 lsp/health: ensure valid table before concatenating (#34930)
- 09f702bc13 lua: report error in Lua Funcref callback properly (#35555)
- 7f1e112a32 pum: check for cmdline mode properly
- 41fa343484 snippet: jumping backwards to choice node (#35062)
- 2e4baa3679 snippet: setting end_right_gravity (#35061)
- 4b957a4d18 treesitter: inconsistent highlight of multiline combined injection #35307
- fa64f2d09b treesitter: run FileType autocmds in the context of `<abuf>`
- e841d653af treesitter: show capture-level priorities in :Inspect #35443
- e299430ff5 tui: do not remove SIGWINCH handler when resize events are enabled (#35221) (#35238)
- 64afa93187 tutor: use `invalidate` field in `nvim_buf_set_extmark()`
- 2124146164 tutor: use legacy syntax for lesson 3.1 of vim-01-beginner.tutor
- 6fd842a4fd ui: check for cmdline mode properly

VIM PATCHES
--------------------------------------------------------------------------------
- e68d3ef886 5ddcecf: runtime(help): Add better support for language annotation highlighting
- 35a66f74c7 6fea0a5: runtime(help): Add Vim lang annotation support for codeblocks
- 819e545c28 714671d: runtime(misc): use :hor :term to ensure new term window is split horizontally (#35064)
- a65c4be2de 8.1.0425: ml_get error and crash with appendbufline()
- 8dd88056f1 8.2.1672: v_lock is used when it is not initialized (#35416)
- 6c2f06b537 9.1.0748: :keep* commmands are sometimes misidentified as :k
- 54c2ea142a 9.1.1599: :bnext doesn't go to unlisted help buffers (#35216)
- 53a0d99702 9.1.1601: Patch v8.1.0425 was wrong
- ced4eed733 9.1.1607: :apple command detected as :append (#35237)
- bd4b45dd1b 9.1.1608: No command-line completion for :unsilent {command}
- d21db345ef 9.1.1611: possible undefined behaviour in mb_decompose() (#35275)
- 744d96bd76 9.1.1612: Ctrl-G/Ctrl-T do not ignore the end search delimiter
- 5ec7d98857 9.1.1613: tests: test_search leaves a few swapfiles behind
- 39ae9a9971 9.1.1633: Search pattern shown incorrectly with negative offset (#35337)
- e6ea97a691 9.1.1665: Outdated comment in eval.c (#35436)
- 6fd8ba05a6 9.1.1667: Another outdated comment in eval.c (#35438)
- 4c5cb950c6 9.1.1688: potential buffer overrun in bufwrite.c (#35497)
- 99817471d7 9.1.1700: Multiline ignorecase specific pattern does not match with 'ignorecase' (#35520)
- fb6c677d57 b9ea0a8: runtime(doc): tweak documentation style in helphelp.txt
2025-08-31 15:25:45 -04:00
Michael Henry
edfb447ff8 fix(health): update advice for Python #35564
Problem: `:checkhealth` advice for Python is out-of-date.

Solution: Update the advice to point to `:help provider-python`.
(cherry picked from commit f311c96973)
2025-08-31 18:51:33 +00:00
zeertzjq
b032c2b53f Merge pull request #35561 from zeertzjq/backport
fix(lua): report error in Lua Funcref callback properly (#35555)
2025-08-31 07:37:42 +08:00
zeertzjq
09f702bc13 fix(lua): report error in Lua Funcref callback properly (#35555) 2025-08-31 07:13:00 +08:00
glepnir
c4845f3a12 docs(lsp): mention lsp/after/ in faq #35534
(cherry picked from commit 1b3abfa688)
2025-08-30 22:56:57 +00:00
zeertzjq
a2603016ce Merge pull request #35546 from zeertzjq/vim-a07a2f4
vim-patch:a07a2f4: runtime(astro): catch json_decode() error when parsing tsconfig.json
(cherry picked from commit 8a2587be23)
2025-08-30 00:55:38 +00:00
Meriel Luna Mittelbach
d70d469c04 fix(health): accept TERM=tmux-direct #35511
tmux-direct is functionally the same as tmux-256color, except it
directly reports 24-bit color and how to set them (setaf/setab)
via ncurses 6.x's extended terminfo format.

(cherry picked from commit a33284c2c0)
2025-08-28 04:25:15 +00:00
zeertzjq
99817471d7 vim-patch:9.1.1700: Multiline ignorecase specific pattern does not match with 'ignorecase' (#35520)
Problem:  a pattern that involves a backref on a different line does not
          match when 'ignorecase' is set (QiWei, after v9.1.0645)
Solution: Use MB_STRNICMP when ignorecase is set, fix tests to close
          swapfiles

related: vim/vim#14756
fixes: vim/vim#17470
closes: vim/vim#18104

bf82e58a70

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 24020ef2dd)
2025-08-27 23:56:49 +00:00
zeertzjq
4c5cb950c6 vim-patch:9.1.1688: potential buffer overrun in bufwrite.c (#35497)
Problem:  potential buffer overrun in bufwrite.c
Solution: Use a temporary variable (John Marriott)

In my Windows 11 Pro 64-bit build MAXPATHL is 1024 and IOSIZE is 1025.
In my Archlinux Linux 64-bit build MAXPATHL is 4096 and IOSIZE is 1025.

In funuction buf_write():
There is a check (line 713) that makes sure the length of fname is less
than MAXPATHL. There is a call to STRCPY() (line 1208) which copies the
string at fname into IObuff (which has size IOSIZE). For Unix builds
fname is set to sfname which may or may not be shorter. However, if
sfname is NULL sfname is set to fname.

Therefore, in builds where MAXPATHL > IOSIZE (eg in my linux build), it
is theoretically possible for the STRCPY() call to exceed the bounds of
IObuff.

This PR addresses this by copying fname into a local variable that has
the same maximum size as fname.

In addition:
Given that the filename is unconditionally overwritten in the for loop,
only copy the directory portion of fname. Move variable i closer to
where it is used.

closes: vim/vim#18095

a19b019b87

Co-authored-by: John Marriott <basilisk@internode.on.net>
(cherry picked from commit 4263ec21c2)
2025-08-27 03:15:15 +00:00
zeertzjq
ec8900f1e6 Merge pull request #35451 from zeertzjq/backport
fix(diff): set default diff flags properly (#35450)
2025-08-24 15:22:22 +08:00
zeertzjq
a3590afba5 fix(diff): set default diff flags properly (#35450) 2025-08-24 14:43:19 +08:00
Riley Bruins
e841d653af fix(treesitter): show capture-level priorities in :Inspect #35443
(cherry picked from commit 29c5559ce1)
2025-08-23 23:18:41 +00:00
zeertzjq
6fd8ba05a6 vim-patch:9.1.1667: Another outdated comment in eval.c (#35438)
Problem:  Another outdated comment in eval.c (after 9.1.1665).
Solution: Remove that comment as well. Add a few more tests for mapnew()
          that fail without patch 8.2.1672 (zeertzjq).

closes: vim/vim#18089

6b56711804
(cherry picked from commit 639f9f4cda)
2025-08-23 11:10:29 +00:00
zeertzjq
e6ea97a691 vim-patch:9.1.1665: Outdated comment in eval.c (#35436)
Problem:  Outdated comment in eval.c.
Solution: Remove the comment, which is no longer true after 8.2.1672.
          Also fix a typo in version9.txt (zeertzjq).

closes: vim/vim#18077

5d3c39af2a
(cherry picked from commit b9699d5701)
2025-08-23 00:46:12 +00:00
tao
3cf9dac2ba fix(folds): error when deleting lines at end of buffer #35396
Problem:
with `foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr()
foldminlines=0`, deleting lines at the end of the buffer always
reports an invalid top error, because the top value (i.e. the
start line number of the deletion) is always 1 greater than
the total line number of the modified buffer.

Solution:
remove the ml_line_count validation

(cherry picked from commit d73cfefed5)
2025-08-22 03:22:33 +00:00
zeertzjq
8dd88056f1 vim-patch:8.2.1672: v_lock is used when it is not initialized (#35416)
Problem:    v_lock is used when it is not initialized. (Yegappan Lakshmanan)
Solution:   Initialize the typval in eval1().

4a091b9978

Co-authored-by: Bram Moolenaar <Bram@vim.org>
(cherry picked from commit 865a28155e)
2025-08-21 23:02:40 +00:00
Tiago Inaba
1bea812953 fix(lsp): update window title when cycling through signatures #35407
(cherry picked from commit 848c7a7894)
2025-08-21 00:51:35 +00:00
Sean Dewar
fa64f2d09b fix(treesitter): run FileType autocmds in the context of <abuf>
Problem: many FileType autocommands assume curbuf is the same as the target
buffer; this can cause &syntax to be restored for the wrong buffer in some cases
when TSHighlighter:destroy is called.

Solution: run nvim_exec_autocmds in the context of the target buffer via
nvim_buf_call.

(cherry picked from commit 3ec63cdab8)
2025-08-19 19:52:41 +00:00
neovim-backports[bot]
3ab06d5188 fix(api): on_detach consistently before buf_freeall autocmds (#35369)
Problem: on_detach may be called after buf_freeall and other important things,
plus its textlock restrictions are insufficient. This can cause issues such as
leaks, internal errors and crashes.

Solution: disable buffer updates in buf_freeall, before autocommands (like the
order after #35355 and when do_ecmd reloads a buffer). Don't do so in
free_buffer_stuff; it's not safe to run user code there, and buf_freeall already
runs before then; just free them to avoid leaks if buf_freeall autocommands
registered more for some reason.

(cherry picked from commit 2211953266)

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
2025-08-17 15:39:32 -07:00
neovim-backports[bot]
37b2d42459 refactor(tests): remove redundant test (#35368)
(cherry picked from commit 7eb9badd93)

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-08-17 15:14:31 -07:00
neovim-backports[bot]
53db7fc3ef fix(api,lsp): call on_detach before wiping out the buffer #35367
Problem:
Buffer-updates on_detach callback is invoked before buf_freeall(), which
deletes autocmds of the buffer (via apply_autocmds(EVENT_BUFWIPEOUT,
...)). Due to this, buffer-local autocmds executed in on_detach (e.g.,
LspDetach) are not actually invoked.

Solution:
Call buf_updates_unload() before buf_freeall().

(cherry picked from commit 285c04e2d0)

Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
2025-08-17 14:55:19 -07:00
MinimalEffort07
3343ee971b build(deps): CMake generation fails when path contains spaces #35332
Problem:
Additional include directories in DEPS_INCLUDE_FLAGS variable are not
quoted. Paths with spaces break the resulting compile command.

Solution:
Enclose values in double quotes.
Note: normally we should avoid manual quoting, but in this case we can't
because of how `DEPS_INCLUDE_FLAGS` is used in `BuildLuv.cmake`
and `BuildLpeg.cmake`.

(cherry picked from commit 77860f5418)
2025-08-16 23:46:28 +00:00
Michael Henry
abfbd155da feat(provider): detect venv python via "pynvim-python" tool #35273
Problem:
Detection of the pynvim module is currently done by finding the first
Python interpreter in the `PATH` and checking if it can import pynvim.
This has several problems:
- Activation of an unrelated Python virtual environment will break
  automatic detection, unless pynvim is also installed in that
  environment.
- Installing pynvim to the expected location is difficult. User
  installation into the system-wide or user-wide Python site area is now
  deprecated.  On Ubuntu 24.04 with Python 3.12, for example, the
  command `pip install --user pynvim` now fails with the error message
  `error: externally-managed-environment`.
- Users may create a dedicated virtual environment in which to install
  pynvim, but Nvim won't detect it; instead, they must either activate
  it before launching Nvim (which interferes with the user of other
  virtual environments) or else hard-code the variable
  `g:python3_host_prog` in their `init.vim` to the path of the correct
  Python interpreter.  Neither option is desirable.

Solution:
Expose pynvim's Python interpreter on the `PATH` under the
name `pynvim-python`.  Typical user-flow:

1. User installs either uv or pipx.
2. User installs pynvim via:
   ```
   uv tool install --upgrade pynvim
   # Or:
   pipx install --upgrade pynvim
   ```

With corresponding changes in pynvim https://github.com/neovim/pynvim/issues/593
the above user-flow is all that's needed for Nvim to detect the
installed location of pynvim, even if an unrelated Python virtual
environments is activated.  It uses standard Python tooling to automate
the necessary creation of a Python virtual environment for pyenv and the
publication of `pynvim-python` to a directory on `PATH`.

(cherry picked from commit 5f8d4a248a)
2025-08-16 22:32:55 +00:00
zeertzjq
39ae9a9971 vim-patch:9.1.1633: Search pattern shown incorrectly with negative offset (#35337)
Problem:  Search pattern shown incorrectly with negative offset.
          (lkintact)
Solution: Don't prepend a '+' sign to a negative offset (zeertzjq).

fixes: vim/vim#17993
closes: vim/vim#17994

ade0815856
(cherry picked from commit 8d154e5927)
2025-08-15 00:34:11 +00:00
zeertzjq
5ec7d98857 vim-patch:9.1.1613: tests: test_search leaves a few swapfiles behind
Problem:  tests: test_search leaves a few swapfiles behind
Solution: Use :bw! instead of :close to close the swapfile at the end of
          the test.

related: vim/vim#17933

a2bb21a895

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 9e8d551b1e)
2025-08-15 07:48:56 +08:00
zeertzjq
744d96bd76 vim-patch:9.1.1612: Ctrl-G/Ctrl-T do not ignore the end search delimiter
Problem:  Ctrl-G/Ctrl-T does not ignore the end search delimiter
          (irisjae)
Solution: Check if the pattern ends with a search delimiter and ignore
          it, unless it is part of the pattern.

fixes: vim/vim#17895
closes: vim/vim#17933

c03990d30f

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 1eca030fb2)
2025-08-15 07:48:56 +08:00
Jalil David Salamé Messina
30b801eff2 fix(checkhealth): wrong ABI version for treesitter parsers #35327
Don't print ABI version of duplicated parsers that are later in the
runtime path (see [#35326]).

Change the sorting from `name > path` to `name > rtpath_index`, this
ensures the first (loaded) parser is first in the list and any
subsequent parsers can be considered "not loaded".

This is fuzzy at best since `vim.treesitter.language.add` can take a
path to a parser and change the load order.

The correct solution is for `vim.treesitter.language.inspect` to return
the parser path so we can compare against it and/or for it to also be
able to take a path to a parser so we can inspect it without loading it
first.

(cherry picked from commit bd45e2be63)
2025-08-14 19:19:01 +00:00
zeertzjq
27282696fe fix(api): fix not capturing output in cmdline mode (#35322)
(cherry picked from commit 7b9512e613)
2025-08-13 12:40:07 +00:00
Steven Xu
4b957a4d18 fix(treesitter): inconsistent highlight of multiline combined injection #35307
Problem:
Combined injections not entirely highlighted.

Solution:
Reapply layer highlights on each line.

Co-authored-by: Artem <vanaigranov@gmail.com>
2025-08-12 14:14:29 -07:00
zeertzjq
819e545c28 vim-patch:714671d: runtime(misc): use :hor :term to ensure new term window is split horizontally (#35064)
Problem:  :term splits new window above in vim, but in nvim it change
          the buffer for current window
Solution: :hor term to ensure consistent splitting for Vim and Neovim

closes: vim/vim#17822

714671de35

Co-authored-by: phanium <91544758+phanen@users.noreply.github.com>
(cherry picked from commit 1f7432a272)
2025-08-10 23:17:58 +00:00
zeertzjq
d21db345ef vim-patch:9.1.1611: possible undefined behaviour in mb_decompose() (#35275)
Problem:  possible undefined behaviour in mb_decompose(), when using the
          same pointer as argument several times
Solution: use separate assignments to avoid reading and writing the same
          object at the same time (Áron Hárnási)

closes: vim/vim#17953

c43a0614d4

Co-authored-by: Áron Hárnási <aron.harnasi@gmail.com>
(cherry picked from commit 77500c5ad5)
2025-08-09 23:50:33 +00:00
zeertzjq
bd4b45dd1b vim-patch:9.1.1608: No command-line completion for :unsilent {command}
Problem:  No command-line completion for :unsilent {command}.
Solution: Add missing command arg completion (Doug Kearns).
          (author)

Add completion tests for all command modifiers.

closes: vim/vim#17524

126731c8fd

Co-authored-by: Doug Kearns <dougkearns@gmail.com>
(cherry picked from commit fe42c81f2e)
2025-08-09 01:25:25 +00:00
zeertzjq
6c2f06b537 vim-patch:9.1.0748: :keep* commmands are sometimes misidentified as :k
Problem:  The :keep{alt,jumps,marks,patterns} commmands are sometimes
          misidentified as :k.
Solution: Make sure one_letter_cmd() only returns true for :k and not
          other :keep* commands (Doug Kearns).

This currently manifests as missing completion for :keep* commands and
incorrect results from fullcommand().

E.g., fullcommand("keepmarks") returns "k" rather than "keepmarks".

The correct command, however, is executed as command modifiers are
handled specially in do_one_cmd() rather than using find_ex_command().

Fix exists(':k') so that it returns 2 for a full match.

closes: vim/vim#15742

ea84202372

Cherry-pick Test_ex_command_completion() from patch 9.1.0624.

Co-authored-by: Doug Kearns <dougkearns@gmail.com>
(cherry picked from commit 70bb7999f7)
2025-08-09 01:25:25 +00:00
brianhuster
fb6c677d57 vim-patch:b9ea0a8: runtime(doc): tweak documentation style in helphelp.txt
closes: vim/vim#16302

b9ea0a89fa

Co-authored-by: h-east <h.east.727@gmail.com>

I removed some parts that are not applicable to Nvim, like HelpTOC

(cherry picked from commit 7082367b3a)
2025-08-08 23:37:28 +00:00
brianhuster
e68d3ef886 vim-patch:5ddcecf: runtime(help): Add better support for language annotation highlighting
closes: vim/vim#16238

5ddcecf05f

Co-authored-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: h_east <h.east.727@gmail.com>
(cherry picked from commit 60b866049c)
2025-08-08 23:37:28 +00:00
brianhuster
35a66f74c7 vim-patch:6fea0a5: runtime(help): Add Vim lang annotation support for codeblocks
closes: vim/vim#16215

6fea0a5480

Co-authored-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
(cherry picked from commit 11ae879ebd)
2025-08-08 23:37:28 +00:00
zeertzjq
ced4eed733 vim-patch:9.1.1607: :apple command detected as :append (#35237)
Problem:  :apple command detected as :append (dai475694450)
Solution: Disallow to define a custom command with lower-case letter,
          correctly detect :insert/:change/:append ex commands
          (Hirohito Higashi).

fixes: vim/vim#17893
closes: vim/vim#17930

efd83d441b

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
(cherry picked from commit e7dfbf1343)
2025-08-08 14:21:31 +00:00
Gregory Anders
e299430ff5 fix(tui): do not remove SIGWINCH handler when resize events are enabled (#35221) (#35238)
When Nvim is started in one terminal emulator,
suspended, and later resumed in a different terminal emulator (as can
happen when using e.g. a multiplexer), the new terminal emulator will
not have all of the same modes enabled that the original terminal
emulator had. This is a problem in particular for in-band resize events
because we were disabling the SIGWINCH signal handler when we determined
that the terminal supported this mode.

However, if the new terminal does not support this mode then the
SIGWINCH handler remains disabled, and Neovim no longer properly
resizes. Instead of disabling the SIGWINCH handler, we track the state
of the resize events mode internally. If the mode is enabled then we
return early from the SIGWINCH handler before performing any ioctls or
other system calls. But if the mode is not enabled we proceed as normal.

(cherry picked from commit b1679f0ab6)
2025-08-08 13:50:02 +00:00
zeertzjq
53a0d99702 vim-patch:9.1.1601: Patch v8.1.0425 was wrong
Problem:  Patch v8.1.0425 was wrong
Solution: Revert that patch (Hirohito Higashi)

This is because the root cause was fixed in 8.1.0786 and a regression
occurred elsewhere.

related: vim/vim#3455
related: vim/vim#3830
fixes: vim/vim#11558
closes: vim/vim#17899

6abe5e4904

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
(cherry picked from commit 7230296bdb)
2025-08-08 00:12:27 +00:00
zeertzjq
a65c4be2de vim-patch:8.1.0425: ml_get error and crash with appendbufline()
Problem:    ml_get error and crash with appendbufline(). (Masashi Iizuka)
Solution:   Set per-window buffer info. (Hirohito Higashi, closes vim/vim#3455)

9cea87c577

Co-authored-by: Bram Moolenaar <Bram@vim.org>
(cherry picked from commit c6f0a19206)
2025-08-08 00:12:27 +00:00
zeertzjq
30db74de66 Merge pull request #35224 from zeertzjq/backport
Backport #35198 #35202 #35210
2025-08-08 06:31:10 +08:00
zeertzjq
6fd842a4fd fix(ui): check for cmdline mode properly
Backport of #35202
2025-08-08 06:11:28 +08:00
zeertzjq
7f1e112a32 fix(pum): check for cmdline mode properly
Backport of #35198 and #35210
2025-08-08 06:11:25 +08:00
zeertzjq
54c2ea142a vim-patch:9.1.1599: :bnext doesn't go to unlisted help buffers (#35216)
Problem:  :bnext doesn't go to unlisted help buffers when cycling
          through help buffers (after 9.1.0557).
Solution: Don't check if a help buffer is listed (zeertzjq).

From <https://github.com/vim/vim/issues/4478#issuecomment-498831057>:

> I think we should fix that, since once you get to a non-help buffer
> all unlisted buffers are skipped, thus you won't encounter another
> help buffer.

This implies that cycling through help buffers should work even if help
buffers are unlisted. Otherwise this part of :bnext isn't really useful,
as :h makes help buffers unlisted by default.

related: vim/vim#4478
related: vim/vim#15198
closes: vim/vim#17913

9662f33480
(cherry picked from commit 53ac2ad20a)
2025-08-07 16:47:04 +00:00
neovim-backports[bot]
f4b4c27a35 fix(float): cursor visible in "hidden" floating window (#35219)
Problem:
Cursor is visible in "hidden" floating window.

Solution:
Hide cursor when curwin is a hidden floating window.
Show cursor after returning to a normal (non-hidden) window.

(cherry picked from commit d4f2b9050d)

Co-authored-by: glepnir <glephunter@gmail.com>
2025-08-07 16:18:32 +00:00
skewb1k
5551da79c1 feat(lsp): improve signature help display #35190
- Add delimiter between function signature and documentation, matching hover formatting
- Show title only if there are multiple clients or multiple signatures
- Avoid duplicating the title inside the window if it's already shown in the border

(cherry picked from commit d26db4bfbf)
2025-08-07 03:29:04 +00:00
glepnir
8f2d6f7ce2 fix(lsp): show title when global winborder is set (#35181)
Problem: make_floating_popup_options only shows when opts.border is explicitly set, ignoring global winborder setting

Solution: check both opts.border and vim.o.winborder when determining whether to show title
(cherry picked from commit 5b1b46ea5a)
2025-08-07 03:01:03 +00:00
glepnir
09b0003d38 fix(api): nvim_create_user_command addr option should allow ranges #35077
Problem: Using `addr` without `range` in nvim_create_user_command gives
"No range allowed" error, inconsistent with `:command -addr` behavior.

Solution: Set EX_RANGE flag when `addr` option is specified to match
`:command` behavior.

(cherry picked from commit 22df649210)
2025-08-03 03:40:46 +00:00
TheBlob42
41fa343484 fix(snippet): jumping backwards to choice node (#35062)
Avoid duplicate text when jumping back to a choice node. Set cursor to
end of tabstop range and prioritize current choice in completion items.

(cherry picked from commit 628d569a59)
2025-07-28 00:35:42 +00:00
TheBlob42
2e4baa3679 fix(snippet): setting end_right_gravity (#35061)
When right_gravity is set to true for deactivating tabstop expansion we
have to set end_right_gravity to false to avoid expanding the tabstop
region on the right side. Vice versa for activating tabstop expansion
again.

(cherry picked from commit dff78f580d)
2025-07-28 00:24:44 +00:00
Maria José Solano
6b820258cd fix(lsp): don't override config.title in vim.lsp.buf.signature_help() #35075
(cherry picked from commit afebbd0f34)
2025-07-27 03:17:18 +00:00
zeertzjq
990b320592 fix(cmdline): :checkhealth completion with multiple args (#35060)
(cherry picked from commit 5de2ec76a3)
2025-07-25 23:29:54 +00:00
zeertzjq
a05b70baa6 fix(clipboard): correct blockwise register width computation (#35038)
(cherry picked from commit 95dfb063da)
2025-07-23 03:18:38 +00:00
glepnir
359d65c902 fix(iter): ArrayIter:last returns nil when filtered to empty #34697
Problem: After filtering out all elements, ArrayIter:last still returns a stale element.
Solution: Add check for self._head == self._tail and return nil early.

Fix #34696

(cherry picked from commit 4fe51dfdae)
2025-07-23 02:33:18 +00:00
Phạm Bình An
62aae1084f docs: update usr_02.txt #35031
Problem:
- There is reference to gVim in the usr_02.txt file, even though Nvim
  has no built-in GUI.
- `:h help-summary` has a section about optional features (e.g.
  `+conceal`) even though such thing does not exist in Nvim (`:h
  +conceal` will give E149 error).

Solution:
- Remove reference to gVim.
- Replace the section about optional features with a section about Lua.

(cherry picked from commit d591275db7)
2025-07-22 23:15:21 +00:00
Justin M. Keyes
e534afa5ab Merge #34986 from brianhuster/release-0.11 2025-07-22 07:46:18 -07:00
brianhuster
2124146164 fix(tutor): use legacy syntax for lesson 3.1 of vim-01-beginner.tutor
Problem:
- Extmark breaks lesson 3.1 of vim-01-beginner.tutor because when users
  delete the line and put it elsewhere, the extmark doesn't move to the
  put location.
- This doesn't mean the extmark implementation is bad though (note that
  thanks to extmark, for the first time, we can make lesson 2.6 really
  interactive), it's just that the tutor format has never been made for
  kinds of lessons like lesson 3.1, which is why all "expected" in that
  lesson are -1, which also means that lesson is not interactive in the
  first place. Also see lesson 2.1.3 in vim-02-beginner, where the mark
  is just used to mark the first line of the exercise, which also prove
  my point.

Solution:
- For a not-really-interactive lesson like lesson 3.1, just use legacy
  syntax. I borrow the old vimtutor's `--->` to mark the exercises of
  the lesson.
- Less redundant interactive marks also make the json files smaller and
  more maintainable.
2025-07-19 22:40:28 +07:00
brianhuster
64afa93187 fix(tutor): use invalidate field in nvim_buf_set_extmark()
Problem:
If users delete a line containing extmark, it will move to the next
line, which could highlight the next line in an unwanted way.

Solution:
- Use `invalidate` field in `nvim_buf_set_extmark()` to prevent the
extmark from moving.
- Also save from "priority" hacking, since we can check if the extmark
  is valid in `nvim_buf_get_extmarks()` now.
2025-07-19 09:42:16 +07:00
brianhuster
e6a0f0ee71 test(tutor_spec): remove test description("Tutor: tutor")
Problem:
It is redundant since we have another test that test interactive marks
in lesson 2.6 of tutor 1
2025-07-18 16:45:25 +07:00
brianhuster
685302682a refactor(tutor): reimplement interactive marks as extmark in Lua
Problem:
From https://matrix.to/#/!cylwlNXSwagQmZSkzs:matrix.org/$Ofj-TFIsEMbp0O9OhE8xuZSNi-nhRLtZTOgs6JRLNrs?via=matrix.org&via=gitter.im&via=mozilla.org

In lesson 2.6, users are asked to remove the second, forth and fifth
lines with `dd` command, then they are asked to undo twice to make the
text go back to original state. But after that, the mark ✗ appears
again, which confuses the user because they think they do something
wrong. This is a limitation with the current implementation, which is
based on line number only.

Solution:
Reimplement interactive marks as extmarks in Lua. This also make the
feature less fragile, as users can remove, add some arbitrary lines
without breaking the interactive marks.

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-07-18 16:45:06 +07:00
PilgrimLyieu
5e7021eb1b docs(tutor): Chinese (zh-CN) translation #34803
Co-authored-by: glepnir <glephunter@gmail.com>
2025-07-18 16:44:14 +07:00
Donatas
44b8255fa2 fix(lsp): close floating preview window correctly #34946
Problem:
After 28b7c2d (found with bisect) the hover preview window does not
close when :edit'ing another file, even when you move the cursor.

Solution:
Change the BufLeave to target the original buffer, not the preview
buffer.

(cherry picked from commit ace254c9ff)
2025-07-16 03:46:59 +00:00
Phạm Bình An
407fc0bb16 revert: "fix(runtime): set 'foldmethod' for Lua ftplugin #34929" (#34947)
This reverts commit 12276832ab.

(cherry picked from commit 9789a3b854)
2025-07-15 22:59:33 +00:00
Phạm Bình An
657540945c fix(runtime): set 'foldmethod' for Lua ftplugin #34929
Problem:
Neovim's Lua ftplugin doesn't set `'foldmethod'`, though Vim one sets it 1341176e7b/runtime/ftplugin/lua.vim (L66-L68)

Solution:
Set it

(cherry picked from commit 12276832ab)
2025-07-14 22:04:30 +00:00
Gregory Anders
9261aef2f3 fix(lsp/health): always use vim.inspect to show root_markers (#34667)
In https://github.com/neovim/neovim/pull/34092 we changed the
healthcheck to display root markers as a concatenated list if the first
item in root_markers is a string (not a table). However, this does not
solve the general case, because root_markers can contain a string as the
first element, but a table as the 2nd element.

Because root_markers has a more complex structure we should always just
display it using vim.inspect, rather than adding a special case for when
all items are a string.

(cherry picked from commit f0c0c24ed7)
2025-07-14 12:59:40 +00:00
neovim-backports[bot]
d185057bc7 fix(lsp/health): ensure valid table before concatenating (#34930)
The root_markers field can now contain a table of tables (as of
https://github.com/neovim/neovim/pull/33485) and :checkhealth will show
an error in that case since Lua cannot concatenate a table of tables.

Ensure that tables contain strings before concatenating and if not, fall
back to using vim.inspect().

(cherry picked from commit 5ad01184f3)

Co-authored-by: Gregory Anders <greg@gpanders.com>
2025-07-14 05:15:27 -07:00
Justin M. Keyes
6cfaa9c204 version bump 2025-07-12 14:36:34 -04:00
Justin M. Keyes
b2684d9f66 NVIM v0.11.3
For notable changes, see runtime/doc/news.txt (or `:help news` in Nvim).

Following is a list of fixes/features.

FEATURES
--------------------------------------------------------------------------------
- db3b856779 defaults: map "grt" to LSP type_definition #34663
- ecf5164d2d lsp: pass resolved config to cmd() #34560
- 5d0766ddce vim.fs: vim.fs.root() can control priority #34413

FIXES
--------------------------------------------------------------------------------
- f2c4305114 api: add missing nargs field to user command Lua callbacks #34210
- aa6136f956 api: adjust fix for reconfiguring float "relative" (#34287)
- 6889f9168b api: populate lhsrawalt in nvim_get_keymap response
- 0d66963089 api: reconfiguring float "relative" does not clear "win" (#34271)
- 8d3b7b57c8 api: update topline when flushing with nvim__redraw() (#34346)
- 77eb278adf clipboard: enable cache for function providers #34470
- 0613faf596 column: missing redraw with virt_lines_leftcol (#34650)
- 4303337c77 diagnostics: validate opts.signs #34565
- 902c946bcd editorconfig: a custom property is treated as a section (#34445)
- 7b2119dbd9 exrc: exrc knows its own location #34638
- 7da0c46e1b health: bad format() call #34906
- c97ad3cb41 health: floating window closes when opening TOC (gO)
- 68d204462c health: highlight group conflicts with help #34616
- 282f9fb816 incsearch: include compsing characters with Ctrl-L
- d0a24ea03e lsp: _cancel_all_requests() tries to cancel completed requests #34105
- 4621527f59 lsp: add `RequestFailed` error code constant #34645
- 1077374380 lsp: advertise supported fold kinds (#34461)
- 0f1cada0f7 lsp: announce diagnostic tag support (#34436)
- ff8acfffd2 lsp: include client ID when receiving unknown fold kind (#34535)
- c13eba5254 lsp: only auto-detach lsp.config enabled clients #34325
- ea8db9003b lsp: use correct deprecation function (#34518)
- f7b1b0595d menu: fix listing of submenus (#34315)
- adf31505d8 messages: make swapfile attention message part of prompt (#34414)
- 89959ab9dc messages: recognize cmdline one_key/number prompt State (#34206)
- ec84c8df0e msgpack: flush incomplete big UI event before packing RPC event
- d9c10ea753 redraw: update curswant for Visual selection (#34241)
- 388b559848 runtime: no conceal in qf on :lopen #34854
- d9b9514e8e startup: make startup windows if there are only floating windows (#34349)
- ef68eae09a term: terminal attr index may exceed TERM_ATTRS_MAX #34318
- c4a760c734 terminal: don't disable scrolloff for non-terminal buffers (#34451)
- 36c6f488e4 terminal: fix OSC 8 parsing (#34424)
- 68677eb477 terminal: stack overflow when too many csi args (#34012)
- 3d5be364bc treesitter: enable a gc for wasmtime
- a80bdf0d9b treesitter: ensure TSLuaTree is always immutable
- 07d9197840 treesitter: ensure TSNode's tree is immutable
- 7184230e94 treesitter: ensure window is valid in async parsing #34385
- 8183eb32e1 treesitter: scope highlight state per window
- dfeec113be treesitter: support multiple `@injection.content` captures
- 70b4e7948f tui: avoid memory leak and compiler warning on Windows (#34225)
- 6f8efea940 tui: check for title support correctly (#34866)
- 43804477ca tui: don't crash when nvim__screenshot() is called with bad path (#34594)
- 0eec4a8ecc tui: wait for embedded server's exit code
- bfcf541a9e tutor: cannot find tutors in pack/*/start/* #34689
- f9f0345eba vim.json: loss of precision on integers >14 digits #34876
- 203d4f916d vim.system: clear_env=true gives an invalid env to uv.spawn #33955
- e732cbe36c vim.system: env=nil passes env=nil to uv.spawn
- 7286e514f2 vim.version: vim.VersionRange:has(<prerelease>) (#33324)
- 742ea00742 window: don't enter unfocusable or hidden prevwin (#34486)
- e0ddf93bb0 windows: don't set window icon on SIGHUP #34260

VIM PATCHES
--------------------------------------------------------------------------------
- ae05e0399b 0fb6cea: runtime(lua): update 'path' option in filetype plugin #33876
- 7ef602d470 2323f22: runtime(new-tutor): add chapter two to the interactive tutorial
- 2d13ae0dd4 7a734b7: tests: fix typo in comment (after v9.1.1511)
- d32a4dd4b0 9.1.1404: wrong link to Chapter 2 in new-tutor
- 28531d18f0 9.1.1421: tests: need a test for the new-style tutor.tutor (#34267)
- d28ad6e03f 9.1.1450: Session has wrong arglist with :tcd and :arglocal (#34430)
- 9ffa94b07b 9.1.1463: Integer overflow in getmarklist() after linewise operation (#34532)
- d5cbc99358 9.1.1482: scrolling with 'splitkeep' and line() (#34670)
- 2df746e4e8 9.1.1506: tests: missing cleanup in Test_search_cmdline_incsearch_highlight() (#34748)
- 730a5e0599 9.1.1511: tests: two edit tests change v:testing from 1 to 0
- 87ba1d7465 9.1.1521: completion: pum does not reset scroll pos on reopen with 'noselect' (#34836)
- 222b3d5021 bfeefc4: runtime(doc): clarify the effect of exclusive single char selections (#34289)
- 9d8c5119e2 eb59129: runtime(typescript): remove Fixedgq() function from indent script (#34334)
2025-07-12 14:34:12 -04:00
neovim-backports[bot]
7da0c46e1b fix(health): bad format() call #34906
Problem:
Bad format() call on PUC Lua

    Error: Failed to run healthcheck for "vim.health" plugin. Exception:
    runtime/lua/vim/health/health.lua:89: bad argument #1 to 'format' (string expected, got nil)

Solution:
Avoid passing nil.

(cherry picked from commit 2422fbdd5f)

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-07-12 11:32:56 -07:00
Christian Clason
91ef8606f2 build(deps): update tree-sitter parsers and queries #34905
bump
* tree-sitter to v0.25.6
* tree-sitter-c to v0.24.1
* tree-sitter-lua to v0.4.0
* tree-sitter-vim to v0.7.0 (and update queries)
* tree-sitter-vimdoc to v4.0.0
* tree-sitter-query to v0.6.2
* tree-sitter-markdown to v0.5.0
2025-07-12 11:27:31 -07:00
luukvbaal
89959ab9dc fix(messages): recognize cmdline one_key/number prompt State (#34206)
Problem:  Since 48e2a736, prompt messages are handled by an actual
          active cmdline, resulting in `State` no longer being equal
          to `MODE_CONFIRM` which is used in some places. E.g. to
          specify the current `mode()` or to re-emit a confirm message.
Solution: Replace `MODE_CONFIRM` with a new `MODE_CMDLINE` sub-mode when
          `ccline.one_key/mouse_used` is set. Use it to avoid clearing
          mouse_used prompt messages, and to re-emit one_key messages
          (when ext_messages is inactive, for which this is unnecessary).
(cherry picked from commit e876a739ee)
2025-07-12 14:45:29 +00:00
luukvbaal
adf31505d8 fix(messages): make swapfile attention message part of prompt (#34414)
Problem:  The swapfile attention message is not repeated after clearing
          the screen.
          After clearing the screen `msg_scrolled` is reset without
          clearing other related variables, causing an assert.
Solution: Make the attention message part of the confirm prompt.
          Call `msg_reset_scroll()`.
(cherry picked from commit d86d4bacc1)
2025-07-12 14:14:40 +00:00
jade
f9f0345eba fix(vim.json): loss of precision on integers >14 digits #34876
Problem: multiple DAP servers keep assuming they can have internal IDs
         up to 2**52, which get corrupted by the Neovim JSON encoder.
Solution: change (1) constant and add a test so nobody breaks it while
          updating the library.

Fixes: https://github.com/neovim/neovim/issues/24532
Fixes: https://github.com/mfussenegger/nvim-dap/issues/1534
Fixes: https://github.com/facebook/buck2/issues/1032
(cherry picked from commit 7a69fefdb9)
2025-07-11 02:55:34 +00:00
zeertzjq
6f8efea940 fix(tui): check for title support correctly (#34866)
(cherry picked from commit e65c0a0810)
2025-07-10 07:06:22 +00:00
phanium
388b559848 fix(runtime): no conceal in qf on :lopen #34854
Problem:
No conceal in qf on `lopen` since 74fcc945. Repro:

    nvim --clean +'tab Man ls' +'norm gO' +lclose +lopen

Solution:
Consider "Table of contents" title.

(cherry picked from commit 76f6868e0a)
2025-07-09 17:07:07 +00:00
neovim-backports[bot]
c97ad3cb41 fix(health): floating window closes when opening TOC (gO)
fix(health): floating window closes when opening TOC (gO) #34794

Problem: Health check floating window gets closed when pressing 'gO' to show TOC because LSP floating preview system auto-closes on BufEnter events triggered by :lopen.

Solution: Temporarily disable BufEnter event for the current window during TOC operations and adjust window layout to prevent overlap.
(cherry picked from commit 28b7c2df52)

Co-authored-by: glepnir <glephunter@gmail.com>
2025-07-08 23:10:18 +00:00
zeertzjq
2ddb5d21bb test(api): nvim_get_keymap returns correct lhsraw and lhsrawalt
(cherry picked from commit 0c973bf442)
2025-07-08 00:29:05 +00:00
ncrpy
6889f9168b fix(api): populate lhsrawalt in nvim_get_keymap response
Problem:
The `nvim_get_keymap()` function is missing the `lhsrawalt` field in its response for mappings with an alternate key representation. This makes its return value inconsistent with its documented `maparg()`-like structure and its formal type definition.

Solution:
Corrects the `keymap_array` function to pass the alternate mapping keys (`current_maphash->m_alt->m_keys`) to `mapblock_fill_dict`. The argument responsible for this was previously hardcoded to `NULL`.

For example, for a mapping of `<C-x>`, the API will now correctly return both `lhsraw` (`<80><fc>^DX`) and `lhsrawalt` (the alternate form, e.g., `^X`).

(cherry picked from commit d523750de0)
2025-07-08 00:29:05 +00:00
zeertzjq
2d3a4154c5 Merge pull request #34839 from zeertzjq/backport
vim-patch:9.1.1521: completion: pum does not reset scroll pos on reopen with 'noselect' (#34836)
2025-07-08 07:36:36 +08:00
zeertzjq
87ba1d7465 vim-patch:9.1.1521: completion: pum does not reset scroll pos on reopen with 'noselect' (#34836)
Problem:  When 'wildmode' is set to include "noselect", the popup menu (pum)
          incorrectly retained its scroll position when reopened. This
          meant that after scrolling down through the menu with `<C-n>`,
          reopening the menu (e.g., by retyping the command and
          triggering completion again) would show the menu starting from
          the previously scrolled position, rather than from the top.
          This could confuse users, as the first visible item would not
          be the first actual match in the list.

Solution: Ensure that the popup menu resets its scroll position to the
          top when reopened (Girish Palya).

closes: vim/vim#17673

0cd7f3536b

Co-authored-by: Girish Palya <girishji@gmail.com>
2025-07-08 06:49:27 +08:00
Maria José Solano
0ab089add4 refactor(lsp): consistent usage of vim.notify #34802
(cherry picked from commit 580b8cfac7)
2025-07-06 14:40:39 +00:00
zeertzjq
2d13ae0dd4 vim-patch:7a734b7: tests: fix typo in comment (after v9.1.1511)
related: vim/vim#17660

7a734b7148
(cherry picked from commit 8a4977e286)
2025-07-06 10:11:30 +00:00
zeertzjq
730a5e0599 vim-patch:9.1.1511: tests: two edit tests change v:testing from 1 to 0
Problem:  tests: two edit tests change v:testing from 1 to 0.
Solution: Don't change v:testing in these two tests, since it's already
          set to 1 in runtest.vim (zeertzjq).

closes: vim/vim#17660

96076bf41e
(cherry picked from commit 11e967d5af)
2025-07-06 10:11:30 +00:00
zeertzjq
85c9014c09 refactor(getchar): rename test variable (#34769)
Also, test_disable_char_avail() is superseded by test_override() in Vim,
so remove that from vim_diff.txt.

(cherry picked from commit 0c02c9c70b)
2025-07-04 22:22:35 +00:00
zeertzjq
282f9fb816 fix(incsearch): include compsing characters with Ctrl-L
Cherry-picked from Vim patch 8.1.0579.

(cherry picked from commit f348c0ebba)
2025-07-04 04:36:00 +00:00
zeertzjq
d1214da08f test(old): emulate test_override('char_avail') using FFI
Add a non-static variable for this, otherwise it'll be really hacky.
This avoid having to rewrite many incsearch tests in Lua.

(cherry picked from commit c925e7b8ba)
2025-07-04 04:36:00 +00:00
zeertzjq
f0f163b267 test(editor/defaults_spec): fix flakiness (#34752)
(cherry picked from commit 17ecb2b988)
2025-07-04 03:21:14 +00:00
zeertzjq
2df746e4e8 vim-patch:9.1.1506: tests: missing cleanup in Test_search_cmdline_incsearch_highlight() (#34748)
Problem:  tests: missing cleanup test_override('char_avail', 0) in
          Test_search_cmdline_incsearch_highlight().
Solution: Add the missing cleanup (zeertzjq).

closes: vim/vim#17655

29b29c6b30
(cherry picked from commit eef62e815d)
2025-07-03 23:22:07 +00:00
zeertzjq
b9dbdfef0e test(old): emulate test_override('starting') with FFI (#34742)
I was initially trying to port several cmdline tests from Vim involving
test_override('char_avail') without having to rewrite entire tests in
Lua, but haven't figured out a good way achieve that yet. Nevertheless
emulating test_override('starting') is easier.

(cherry picked from commit 715c28d67f)
2025-07-03 23:15:36 +00:00
Alex Díaz
0f81af53b0 build: support static build #34728
(cherry picked from commit e91224bfaa)
2025-07-02 22:47:42 +00:00
Rodrigodd
a80bdf0d9b fix(treesitter): ensure TSLuaTree is always immutable
Problem:

The previous fix in #34314 relies on copying the tree in `tree_root` to
ensure the `TSNode`'s tree cannot be mutated. But that causes the
problem where two calls to `tree_root` return nodes from different
copies of a tree, which do not compare as equal. This has broken at
least one plugin.

Solution:

Make all `TSTree`s on the Lua side always immutable, avoiding the need
to copy the tree in `tree_root`, and make the only mutation point,
`tree_edit`, copy the tree instead.

(cherry picked from commit 168bf0024e)
2025-07-02 17:03:47 +00:00
Rodrigodd
37fb09c162 test(treesitter): test tree:root() is idempotent
Test for regression #34605

(cherry picked from commit 94f44d58fd)
2025-07-02 17:03:47 +00:00
Lewis Russell
e732cbe36c fix(vim.system): env=nil passes env=nil to uv.spawn
731e616a79 made it so passing `{env = nil, clear_env = true }` would
pass `{env = {}}` to `vim.uv.spawn`.

However this is not what `clear_env` is (arguably) supposed to do.
If `env=nil` then that implies the uses wants `vim.uv.spawn()` to use
the default environment. Adding `clear_env = true` simply prevents
`NVIM` (the base environment) from being added.

Fixes #34730

(cherry picked from commit 4eebc46930)
2025-07-02 16:53:26 +00:00
Justin M. Keyes
2d3517012a Merge #34722 from justinmk/release 2025-07-01 04:34:05 -07:00
Yochem van Rosmalen
41ceefe804 test(exrc): lua exrc knows its location #34713
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
(cherry picked from commit 99873296be)
2025-07-01 12:54:59 +02:00
Yochem van Rosmalen
7b2119dbd9 fix(exrc): exrc knows its own location #34638
Problem:
'exrc' files are inherently bound to their location / workspace and
therefore require to "know" their location on the filesystem. However,
currently using `debug.getinfo(1, 'S')` returns `"<nvim>"`.

Solution:
Include the filepath as chunkname in `loadstring()` and `nlua_exec()`.

(cherry picked from commit f7c939fa7a)
2025-07-01 12:53:39 +02:00
Gabriel Ford
ef68eae09a fix(term): terminal attr index may exceed TERM_ATTRS_MAX #34318
Problem: Currently terminal highlight attribute buffers are statically allocated
be the size of `TERM_ATTRS_MAX`. This unique case isn't respected in
some places in the ui_compositor. Due to this, when a terminal window
has lines longer them `TERM_ATTRS_MAX`, the compositor will go past the
end of the buffer causing a crash due to out of bounds access.

Solution: Add check to ensure we don't query terminal highlight attrs
past `TERM_ATTRS_MAX` in `win_line()`.

Fixes #30374

(cherry picked from commit d6d1bfd20d)
2025-06-30 13:58:31 +00:00
Gabriel Ford
43804477ca fix(tui): don't crash when nvim__screenshot() is called with bad path (#34594)
Problem: Currently `vim.api.nvim__screenshot()` crashes when called with an
invalid path. This is because we don't check if `fopen()` returns a null
pointer.

Solution: Bail out if `fopen()` returns a null pointer.

Fixes: https://github.com/neovim/neovim/issues/34593
(cherry picked from commit 331de6afa6)
2025-06-29 12:04:03 +00:00
Phạm Bình An
bfcf541a9e fix(tutor): cannot find tutors in pack/*/start/* #34689
Problems:
- Unlike in Vim, Neovim does not report pack/*/start/* in the resolved value of 'rtp' (see `:help packages-runtimepath`)
- This means that the tutor plugin cannot find the tutors in pack/*/start/*

Solution:
- Use nvim_list_runtime_paths() instead of &rtp

(cherry picked from commit bff7d3fd9f)
2025-06-28 17:06:05 +00:00
Phạm Bình An
28531d18f0 vim-patch:9.1.1421: tests: need a test for the new-style tutor.tutor (#34267)
Problem:  tests: need a test for the new-style tutor.tutor, patch
          9.1.1384 broke the expected positions for the signs
Solution: Update all number keys in tutor.tutor.json to match the
          correct line numbers in tutor.tutor, replace tabs by spaces,
          add a screen-dump test to verify it does not regress
          (Pham Bình An)

closes: vim/vim#17416

a541f1de2b
(cherry picked from commit f1f106be3d)
2025-06-28 09:37:37 +00:00
luukvbaal
d5cbc99358 vim-patch:9.1.1482: scrolling with 'splitkeep' and line() (#34670)
Problem:  Topline is preemptively updated by line() in WinResized
          autocmd with 'splitkeep' != "cursor".
Solution: Set `skip_update_topline` when 'splitkeep' != "cursor".
          (Luuk van Baal)

fe803c8c04
(cherry picked from commit 0b91e9f83b)
2025-06-27 09:48:40 +00:00
Justin M. Keyes
db3b856779 feat(defaults): map "grt" to LSP type_definition #34663
backport #34642

(cherry picked from commit 5d06eade25)

Co-authored-by: Caleb White <cdwhite3@pm.me>
2025-06-26 18:45:02 +00:00
Justin M. Keyes
e6eb910496 Merge pull request #34668 from brianhuster/release-0.11 2025-06-26 11:32:41 -07:00
Phạm Bình An
7286e514f2 fix(vim.version): vim.VersionRange:has(<prerelease>) (#33324)
Problem:
`vim.version.range('>=0.10'):has('0.12.0-dev')` returns false, which is
wrong per semver.

Solution:
`vim.VersionRange:has()` shouldn't have special handling for prereleases
(Why would we need it when `__eq`, `__lt`, `__le` already handle
 prereleases?).

Closes #33316
2025-06-27 01:05:23 +07:00
Phạm Bình An
ae05e0399b vim-patch:0fb6cea: runtime(lua): update 'path' option in filetype plugin #33876
Problem:  Lua doesn't support importing module in path related to current
          file like JS does (https://www.reddit.com/r/lua/comments/wi0bau/whats_the_correct_way_to_run_a_lua_file_that_uses/)
Solution: Remove `.` from Lua buffer-local option `'path'`

closes: vim/vim#17267

0fb6ceac4c
2025-06-27 00:59:40 +07:00
Maria José Solano
4621527f59 fix(lsp): add RequestFailed error code constant #34645
Also remove `serverErrorStart/End` as [the spec](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#errorCodes)
says that they're deprecated and don't even represent a real error code.

(cherry picked from commit 3eaa6c5a66)
2025-06-26 09:59:01 +00:00
zeertzjq
638bc951b2 Merge pull request #34651 from zeertzjq/backport
fix(column): missing redraw with virt_lines_leftcol (#34650)
2025-06-26 13:45:47 +08:00
zeertzjq
0613faf596 fix(column): missing redraw with virt_lines_leftcol (#34650)
Problem:  Missing number column redraw with virt_lines_leftcol.
Solution: Set virt_line_index to -1 when skipping a virtual line.
2025-06-26 13:20:47 +08:00
Birdee
203d4f916d fix(vim.system): clear_env=true gives an invalid env to uv.spawn #33955
Problem:
In setup_env, some needed logic is bypassed when clear_env=true.

Solution:
Drop the early return in setup_env().

Co-authored-by: BirdeeHub <birdee@localhost>
(cherry picked from commit 731e616a79)
2025-06-25 22:44:52 +00:00
Dmytro Meleshko
68d204462c fix(health): highlight group conflicts with help #34616
(cherry picked from commit 6942dec9b2)
2025-06-23 17:04:55 +00:00
Axel
70b4e7948f fix(tui): avoid memory leak and compiler warning on Windows (#34225)
Problem:  On Windows, the value of `term` is overwritten without freeing
          the old allocated value, which may lead to a memory leak.
	  GCC also gives a "incompatible pointer type" warning about
	  passing `*term` to os_tty_guess_term().
Solution: Don't override the old allocated value, and copy the guessed
          value to `term` if its old value is NULL.
(cherry picked from commit fb5a51e775)
2025-06-23 14:47:37 +00:00
Gabriel Ford
ee06d0e64d build(msvc): suppress msvc build warning for different enum types (#34591)
Problem: Currently our CI is failing due to msvc warning 5287. This
warning tells us that we are performing a binary expression with enums
of two different types. In this case however, this is clearly intended
and valid.

Solution: Suppress warning 5287 on the line this occurs.
(cherry picked from commit 0980617c0d)
2025-06-23 00:27:08 +00:00
Oskar Haarklou Veileborg
1976ca68b5 fix(lsp) type annotation for vim.lsp.Config.cmd #34574
The type annotation for `vim.lsp.ClientConfig.cmd` was changed,
but the update was not propagated to `vim.lsp.Config`.

(cherry picked from commit 150513a163)
2025-06-19 11:07:22 +00:00
Bruce Wen
4303337c77 fix(diagnostics): validate opts.signs #34565
(cherry picked from commit 3594c213a7)
2025-06-18 17:53:10 +00:00
Justin M. Keyes
ecf5164d2d backport: feat(lsp): pass resolved config to cmd() #34560
Problem:
In LSP configs, the function form of `cmd()` cannot easily get the
resolved root dir (workspace). One of the main use-cases of a dynamic
`cmd()` is to be able to start a new server  whose binary may be located
*in the workspace* ([example](https://github.com/neovim/nvim-lspconfig/pull/3912)).

Compare `reuse_client()`, which also receives the resolved config.

Solution:
Pass the resolved config to `cmd()`.


(cherry picked from commit 32f30c4874)

Co-authored-by: Julian Visser <12615757+justmejulian@users.noreply.github.com>
2025-06-18 12:46:53 +00:00
phanium
6396bfb29f docs: vim.fs.dir.Opts type #34546
Follow the pattern of vim.fs.find.Opts

(cherry picked from commit 496691f985)
2025-06-17 14:38:36 +00:00
Maria José Solano
ea8db9003b fix(lsp): use correct deprecation function (#34518)
(cherry picked from commit 00ad477419)
2025-06-17 03:14:09 +00:00
Maria José Solano
ff8acfffd2 fix(lsp): include client ID when receiving unknown fold kind (#34535)
(cherry picked from commit cd06e0c9d6)
2025-06-17 03:04:36 +00:00
zeertzjq
9ffa94b07b vim-patch:9.1.1463: Integer overflow in getmarklist() after linewise operation (#34532)
Problem:  Integer overflow in getmarklist() after linewise operation.
Solution: Don't add 1 to MAXCOL (zeertzjq)

related: neovim/neovim#34524
closes: vim/vim#17552

93318a9933
(cherry picked from commit 3e984cf02b)
2025-06-16 23:45:02 +00:00
Riley Bruins
1077374380 fix(lsp): advertise supported fold kinds (#34461)
This commit also makes it so that folds which have an unsupported fold
kind have their `kind` ignored.

(cherry picked from commit 35756022cb)
2025-06-16 20:52:17 +00:00
Lewis Russell
3d5be364bc fix(treesitter): enable a gc for wasmtime
(cherry picked from commit 5fe582448c)
2025-06-16 08:48:29 +00:00
zeertzjq
ce292026ea docs(meta): fix incorrect bar -> backtick replacement (#34520)
(cherry picked from commit 4b2c2eb120)
2025-06-16 01:43:41 +00:00
luukvbaal
742ea00742 fix(window): don't enter unfocusable or hidden prevwin (#34486)
Problem:  When closing a floating window, the next window to be entered
          may be unfocusable or hidden.
Solution: Don't enter prevwin when it is unfocusable or hidden. Enter
          firstwin instead (like for when prevwin is no longer valid).
(cherry picked from commit 0d658660c2)
2025-06-14 22:19:32 +00:00
Justin M. Keyes
a34b8e42df docs: vim.fs., diagnostics, lsp #34488
backport of #34402

(cherry picked from commit 8001276bd0)
2025-06-13 16:22:10 +00:00
Antoine
77eb278adf fix(clipboard): enable cache for function providers #34470
Problem:
With these settings, copy/pasting `blockwise-visual` (with `CTRL+V`)
incorrectly pastes as a `linewise` mode because `regtype` is ignored:

    vim.opt.clipboard = 'unnamedplus'
    vim.g.clipboard = 'osc52'

To reproduce: press `CTRL+V` and select some characters press `p` and
observe that it is pasted in `linewise` mode.

Solution:
Enable the [clipboard.vim](https://github.com/neovim/neovim/blob/master/runtime/autoload/provider/clipboard.vim#L281-L283))
cache for function providers, so that `regtype` is maintained for the OSC52
clipboard provider.

(cherry picked from commit ac12dc49cc)
2025-06-12 23:08:24 +00:00
Andre Toerien
d0a24ea03e fix(lsp): _cancel_all_requests() tries to cancel completed requests #34105
Problem:
The cancel function returned by `vim.lsp.buf_request` tries to cancel
all the requests, including those that have already been completed,
causing "Cannot find request with id ... whilst attempting to cancel"
errors to be logged when it is called.

Solution:
Only cancel the requests that are present in `client.requests`.

(cherry picked from commit a9b8a8dc6c)
2025-06-12 17:00:27 +00:00
bfredl
ec84c8df0e fix(msgpack): flush incomplete big UI event before packing RPC event
This might happen, e.g. if we send a fast RPC reply in a os_breakcheck()
in the middle of redrawing and big ui_ext events are produced.

fixes #31316

(cherry picked from commit b8ee354f12)
2025-06-12 13:28:41 +00:00
zeertzjq
c4a760c734 fix(terminal): don't disable scrolloff for non-terminal buffers (#34451)
(cherry picked from commit 6a71239cd5)
2025-06-11 15:21:19 +00:00
fortime
902c946bcd fix(editorconfig): a custom property is treated as a section (#34445)
Problem: A custom property containing a pair of square brackets will be
treated as a section.
Solution: Change the logic parsing a section, remove the first match
regex `%b[]`.

Signed-off-by: fortime <palfortime@gmail.com>
(cherry picked from commit 966b1da183)
2025-06-11 14:21:32 +00:00
Riley Bruins
0f1cada0f7 fix(lsp): announce diagnostic tag support (#34436)
This commit also adds a type annotation to the returned client
capabilities table, because without it lua_ls does not provide
autocompletion for the fields within the table.

(cherry picked from commit bac133e4b6)
2025-06-11 04:53:05 +00:00
zeertzjq
c5bc0289ed test(screen): still match by full row when {MATCH:} is present (#34437)
Add '^' and '$' around the pattern. This makes it less likely to make
mistakes of when writing tests with {MATCH:}, as most such tests have
text before and after {MATCH:}.

(cherry picked from commit 37d6ac8a15)
2025-06-11 02:41:36 +00:00
zeertzjq
d28ad6e03f vim-patch:9.1.1450: Session has wrong arglist with :tcd and :arglocal (#34430)
Problem:  Session has wrong arglist with :tcd and :arglocal.
Solution: Also use absolute path for :argadd when there is tabpage-local
          directory (zeertzjq).

related: neovim/neovim#34405
closes: vim/vim#17503

a304e49790
(cherry picked from commit 612f8e7c9e)
2025-06-11 00:05:59 +00:00
zeertzjq
b0ced63e43 Merge pull request #34428 from zeertzjq/backport
fix(tui): wait for embedded server's exit code
2025-06-11 07:14:39 +08:00
zeertzjq
0eec4a8ecc fix(tui): wait for embedded server's exit code
Uses the undocumented "error_exit" UI event for a different purpose:
When :detach is used on the server, send an "error_exit" with 0 `status`
to indicate that the server shouldn't wait for client exit.
2025-06-11 06:33:03 +08:00
Gregory Anders
36c6f488e4 fix(terminal): fix OSC 8 parsing (#34424)
vterm does not send us the terminator in the string fragment. Our OSC 8
parser assumed that it was and therefore treated short strings as
invalid (as it assumed it was missing a terminator).

(cherry picked from commit b5aef05b8f)
2025-06-10 22:26:56 +00:00
Siddhant Agarwal
5d0766ddce backport: feat(vim.fs): vim.fs.root() can control priority #34413
feat(vim.fs): vim.fs.root() can control priority

Adds the capability of controlling the priority of searched markers in
vim.fs.root() by nesting lists.

(cherry picked from commit 0f0b96dd0f)
2025-06-10 07:19:51 -07:00
Mtende
718b3ffe74 docs(diagnostics): default keymaps #34400
(cherry picked from commit 2d980e37c8)
2025-06-09 16:10:53 +00:00
notomo
7184230e94 fix(treesitter): ensure window is valid in async parsing #34385
Problem: Error occurs if window is invalid in the middle of parsing.

Solution: Check if window is valid in parsing.

- Error
```
vim.schedule callback: ...im/share/nvim/runtime/lua/vim/treesitter/highlighter.lua:485: Invalid window id: 1037
stack traceback:
	[C]: in function 'nvim__redraw'
	...im/share/nvim/runtime/lua/vim/treesitter/highlighter.lua:485: in function 'cb'
	...m/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:494: in function '_run_async_callbacks'
	...m/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:550: in function <...m/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:529>
```

- Reproduce script
```lua
local bufnr = vim.api.nvim_create_buf(false, true)
local many_lines = vim.fn["repeat"]({ "local test = 'a'" }, 100000)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, many_lines)
local window = vim.api.nvim_open_win(bufnr, true, {
  relative = "editor",
  row = 0,
  col = 0,
  width = 10,
  height = 10,
})
vim.bo.filetype = "lua"
vim.schedule(function()
  vim.api.nvim_win_close(window, true)
end)
```

(cherry picked from commit 58d85cd03d)
2025-06-09 00:10:20 +00:00
luukvbaal
d9b9514e8e fix(startup): make startup windows if there are only floating windows (#34349)
Problem:  If user init creates a floating window, startup windows
          (e.g. to accomodate arglist files) are no longer created.
Solution: Check that firstwin->w_next is not floating when deciding
          whether to make startup windows.
(cherry picked from commit c8c78b531b)
2025-06-08 23:30:27 +02:00
Riley Bruins
dfeec113be fix(treesitter): support multiple @injection.content captures
Before, only the last capture's range would be counted for injection.
Now all captured ranges will be counted in the ranges array. This is
more intuitive, and also provides a nice solution/alternative to the
"scoped injections" issue.

(cherry picked from commit 8b41df185c)
2025-06-08 16:55:19 +00:00
Riley Bruins
8183eb32e1 fix(treesitter): scope highlight state per window
**Problem:** There is a lot of distracting highlight flickering when
editing a buffer with multiple open windows. This is because the
parsing/highlighting state is shared across all windows.

**Solution:** Greatly reduce flicker in window splits by scoping the
highlighter state object and the `parsing` state object to each
individual window, so there is no cross-window interference.
2025-06-08 11:01:50 +02:00
luukvbaal
8d3b7b57c8 fix(api): update topline when flushing with nvim__redraw() (#34346)
Problem:  nvim__redraw may update the screen with an invalid topline.
Solution: Update the topline before calling `update_screen()` (as
          :redraw does).
(cherry picked from commit af82f36108)
2025-06-07 11:35:59 +00:00
zeertzjq
c0201909c7 test(tui_spec): avoid dangling process in OSC 52 test (#34356)
(cherry picked from commit 22389159f5)
2025-06-07 09:17:04 +00:00
Rodrigodd
a03057560a test(treesitter): test node access after tree edit
(cherry picked from commit 4c333fdbb7)
2025-06-06 15:04:39 +00:00
Rodrigodd
95e5c9f33e refactor(treesitter): avoid unnecessarily copying tree
node:tree() now already copies the tree before returning it, for memory
safety reasons.

(cherry picked from commit 744674900f)
2025-06-06 15:04:39 +00:00
Rodrigodd
07d9197840 fix(treesitter): ensure TSNode's tree is immutable
Problem:

TSNode contains a `const TSTree*` and a `const void *id`. The `id`
points to Tree-sitter's internal type `Subtree`, which resides inside
the `TSTree` but may be deallocated if the `TSTree` is mutated (which
is likely why it is `const`).

The Lua method `TSTree:edit()` mutates the tree, which can deallocate
`id`.

See #25254 and #31758.

Solution:

To avoid this, we now make a copy of the tree before pushing its root to
the Lua stack. This also removes the fenv from TSLuaTree, as it was only
used when pushing the tree root to the Lua stack.

We also copy the tree in `node_tree`.

`ts_tree_copy()` just increments a couple of reference counters, so it's
relatively cheap to call.

(cherry picked from commit 99e6294819)
2025-06-06 15:04:39 +00:00
Kai-Hsiang Hsu
c13eba5254 fix(lsp): only auto-detach lsp.config enabled clients #34325
Problem: A custom server (initialized through `vim.lsp.start`) gets
         unexpectedly detached.

Solution: Only auto-detach the clients enabled through `vim.lsp.enable`
          to prevent unexpected behavior.
(cherry picked from commit e5c5b563ec)
2025-06-06 14:07:14 +00:00
brianhuster
d32a4dd4b0 vim-patch:9.1.1404: wrong link to Chapter 2 in new-tutor
Problem:  wrong link to Chapter 2 in vim-01-beginner.tutor
Solution: Fix the link to Chapter 2, add test for links in tutor files
          (Phạm Bình An)

In order to write the test, I exposed the function `s:GlobTutorials` as
`tutor#GlobTutorials` and make it also accept a `locale` argument.

closes: vim/vim#17356

e8302da74a

Co-authored-by: Phạm Bình An <111893501+brianhuster@users.noreply.github.com>
(cherry picked from commit f791ae82e5)
2025-06-06 04:01:34 +00:00
brianhuster
7ef602d470 vim-patch:2323f22: runtime(new-tutor): add chapter two to the interactive tutorial
closes: vim/vim#16803

2323f225ca

Co-authored-by: RestorerZ <restorer@mail2k.ru>
(cherry picked from commit 41c850e2c8)
2025-06-06 04:01:34 +00:00
Phạm Bình An
9d8c5119e2 vim-patch:eb59129: runtime(typescript): remove Fixedgq() function from indent script (#34334)
Problem:
1. The `Fixedgq()` function is broken (see vim/vim#17412)
2. The `'formatexpr'` for Typescript is not documented, which causes
   confusion to users when they try to set `'formatprg'`, since
   `'formatexpr'` always takes precedence over `'formatprg'`. See also
   https://github.com/HerringtonDarkholme/yats.vim/issues/209
3. Typescript already has a very good and popular formatter called
   `prettier`, that can be easily integrated to Vim via `'formatprg'`
   (see vim/vim#16989). I don't think there are any good reasons to reinvent a
   half-baked version in Vim.

Solution:  Remove the Fixedgq() 'formatexpr' function.

fixes: vim/vim#17412
closes: vim/vim#17452

eb59129d2c
(cherry picked from commit 4e71d3bfab)
2025-06-06 03:20:45 +00:00
zeertzjq
f7b1b0595d fix(menu): fix listing of submenus (#34315)
Problem:  Listing submenus with :menu doesn't work.
Solution: Don't go to the parent of the return value of find_menu(), and
          handle empty path at the caller.

Related #8194, which actually only fixed the problem for menu_get(), not
for :menu Ex command.

(cherry picked from commit 5e470c7af5)
2025-06-05 01:48:42 +00:00
Justin M. Keyes
25a869a097 Merge pull request #34305
backport: fix(windows): don't set window icon on SIGHUP
2025-06-04 10:20:05 -07:00
Christian Clason
243c15ea83 ci(release): drop manual shasum collection
This is now included for all GH release assets out-of-the-box, see
https://github.blog/changelog/2025-06-03-releases-now-expose-digests-for-release-assets/

These can be accessed programmatically through
  `gh release view --json assets <release tag>`
and then looking at the `digest` key.
2025-06-04 19:03:35 +02:00
Emanuel Krollmann
33cec55a26 refactor(windows): redundant icon messages #34274
Problem:  Two separate window messages are used to get
          the original console icon and set a new
          one on windows, although the `WM_SETICON`
          message returns the original icon itself.

Solution: Replace the two `WM_GETICON` messages with
          two `WM_SETICON` messages, save the return
          values and remove the call to `os_icon_set`.
          Also, replace `os_icon_set` with `os_icon_reset`
          as its only usage is now resetting the
          icon to the original one.
(cherry picked from commit 7e393ff4f2)
2025-06-04 18:31:31 +02:00
Emanuel Krollmann
e0ddf93bb0 fix(windows): don't set window icon on SIGHUP #34260
Problem:  When using conhost and pressing the 'x' button
          to close it while nvim is open, nvim hangs up
          while trying to reset the window icon, causing a big
          delay before the terminal actually closes. #34171

Solution: Set the window handle to NULL after receiving SIGHUP
          so that nvim will not try resetting the icon.

(cherry picked from commit 52991d8728)
2025-06-04 18:31:30 +02:00
luukvbaal
aa6136f956 fix(api): adjust fix for reconfiguring float "relative" (#34287)
Problem:  "win" is cleared in float config after 96330843, even with
          unchanged "relative".
Solution: Don't clear "win". Avoid erroring for deleted "win" by setting
          the parent win to curwin directly when "win" is zero or not
          present in config.
(cherry picked from commit eeacd7bd71)
2025-06-03 11:55:51 +00:00
zeertzjq
222b3d5021 vim-patch:bfeefc4: runtime(doc): clarify the effect of exclusive single char selections (#34289)
closes: vim/vim#17410

bfeefc474a

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit aa4fa24963)
2025-06-03 00:36:20 +00:00
luukvbaal
0d66963089 fix(api): reconfiguring float "relative" does not clear "win" (#34271)
Problem:  Unable to change the "relative" of a flag after its target
          "win" no longer exists.
Solution: Unset target window if it is not present in config and
          reconfigured "relative" no longer expects a target window.
(cherry picked from commit 963308439a)
2025-06-02 14:09:14 +00:00
glepnir
f2c4305114 fix(api): add missing nargs field to user command Lua callbacks #34210
Problem: nvim_create_user_command() Lua callbacks were missing the documented nargs field in the options table passed to the callback function.

Solution: Add nargs field derivation from command argument type flags in nlua_do_ucmd(), using the same logic as nvim_parse_cmd().
(cherry picked from commit 5cfbc35aa8)
2025-06-01 23:18:32 +00:00
Justin M. Keyes
d519b77d2b docs: news, intro, lsp, api #34264 2025-06-01 23:16:54 +00:00
zeertzjq
d9c10ea753 fix(redraw): update curswant for Visual selection (#34241)
Problem:  Blockwise Visual selection not redrawn correctly when moving
          cursor for more than 1 cells with 'virtualedit'.
Solution: Restore the curswant update removed in 6679687bb3.
(cherry picked from commit 7ed8e96994)
2025-05-31 00:11:49 +00:00
Christian Clason
1eb33f7d00 ci(release): bump windows runner to windows-2022
Windows-20219 runner will be retired June 30, 2025 and receive several
brownouts before then.

(cherry picked from commit 9e81408b69)
2025-05-30 17:08:05 +00:00
Phạm Bình An
92dc936ca7 docs: rename builtin.txt, eval.txt #34212
Problem:
Despite the name, `builtin.txt` only includes Vimscript functions, which
is confusing, especially to people who only use Lua to configure Nvim

Solution: From justinmk's suggestion
- Rename `builtin.txt` to `vimfn.txt`
- Rename `eval.txt` to `vimeval.txt`
- The tags `*builtin.txt*` and `*eval.txt*` should be kept for Vim-patches

Closes #33743

(cherry picked from commit 9d5eb3eda5)
2025-05-30 16:27:49 +00:00
phanium
68677eb477 fix(terminal): stack overflow when too many csi args (#34012)
fix: stack overflow when too many csi args

Problem:
Crash when csi contains > 16 args. It's easy to trigger
when you attempt to pipe external terminal scrollback buffer.
```sh
nvim --clean --cmd "term printf
'\e[38:2:59:66:97;48:2:36:40:59;58:2:224:175:104;4:3m'"
```

Solution:
Increase buffer size.

(cherry picked from commit 756751afa3)
2025-05-30 12:28:38 +00:00
bfredl
f4a79230c8 version bump 2025-05-30 11:41:44 +02:00
bfredl
a73904168a NVIM 0.11.2
This is a maintenance release, focusing on bug fixes. Some enhancements related
to vim.lsp.enable are also included.

FEATURES
--------------------------------------------------------------------------------
- 4e43264cd3 lsp: vim.lsp.is_enabled() #33703
- c4b9bdbdf4 lsp: start/stop LSPs as necessary during vim.lsp.enable() #33702
- 216c56b7e0 lsp: detach LSP clients when 'filetype' changes #33707
- 533ec6d492 lsp: `root_markers` can control priority
- ad7211ac8f checkhealth: trigger FileType event after showing report
- f25f6c8d13 health: summary in section heading #33388

FIXES
--------------------------------------------------------------------------------
- 710d561f88 lsp: don't eagerly enable LSP configs during startup #33762
- 0ed06d7271 lsp: check if client is stopping before reuse #33796
- f184c562c5 lsp: detect if Client:request resolved synchronously #33624
- b868257ef9 lsp: fix error with InsertReplaceEdit events #33973
- 6b69b3217b lsp: improper diagnostic end_col computation
- e512c9589e lsp: improve error completion message #33812
- 47686a1454 lsp: only auto-detach lsp.config clients #33834
- 901eeeb2e6 lsp: use `bufnr` when getting clients in `symbols_to_items` (#33760)
- a242902430 :print: don't use schar_from_ascii() for illegal byte (#34046)
- 4b6caa913c cmdline: do not move UI cursor when entering cmdline #33729
- fd8e0ae62d decor: extmark highlight not applied (#33858)
- 81233a41d7 display: adjust setting winline info for concealed lines (#33717)
- 4cb2b19197 folds: adjust filler text drawing for transparent folds
- bdd8498ed7 folds: avoid unnecessary loop with horizontal scrolling (#33932)
- 32842b0ee3 health: checkhealth float opens extra empty buffer #33648
- dc87a0d80a lua: vim.validate `message` param #33675
- 334d8f506f move: consume skipcol before revealing filler lines (#34143)
- 6a87b57c06 runtime: 'includeexpr' with non-Nvim-style Lua modules #33867
- 2b2a3449f7 runtime: conceal paths in help, man ToC loclist #33764
- 3db39ed21f runtime: cpoptions is reset in Lua file #33671
- cefc91a82e system: don't treat NUL at start as no input (#34167)
- 8daffd0cbb terminal: check size when switching buffers
- 0db89468d7 termkey: out-of-bounds write in array #33868
- 6563c6bde7 treesitter: close `:InspectTree` with `q`
- 5c6ee251a6 treesitter: eliminate flicker for single windows #33842
- 3b3cf1d7ef treesitter: invalidate conceal_lines marks (#33832)
- 58460e2d52 treesitter: parser metadata annotations
- 034d3c8f6c treesitter: proper tree `contains()` logic with combined injections
- 560c6ca947 trust: support for trusting directories #33735
- 12ae7aa846 tui: clear primary device callback before invoking it (#34032)
- 4296511087 tui: don't process UI events when suspending or stopping (#33710)
- cf73f21c07 tui: don't try to add unsupported modifiers (#33799)
- 465c181581 tui: forward C0 control codes literally (#33759)
- 0c2bf55e90 tutor: l:lang is undefined
- 3a0d37681f vim.system: improve error message when cwd does not exist
- 9b3426691c window: skip unfocusable and hidden floats with "{count}<C-W>w" #33810

VIM PATCHES
--------------------------------------------------------------------------------
- 9965cfb84c 9.1.1361: [security]: possible use-after-free when closing a buffer (#33820)
- 3c102303f5 9.1.1375: [security]: possible heap UAF with quickfix dummy buffer
- 1921dda92e 3704b5b: runtime(tutor): improve tutor.vim plugin and filetype plugin
- 4e5af2f5a6 5a8f995: runtime(doc): remove outdated Contribution section in pi_tutor (#34094)
- 3273c595c0 829eda7: runtime(new-tutor): update tutor and correct comandline completion
- 3e83a33108 9.1.1297: Ctrl-D scrolling can get stuck #33453
- 6417ba0c2f 9.1.1376: quickfix dummy buffer may remain as dummy buffer
- 30fa1c5f8c 9.1.1380: 'eventignorewin' only checked for current buffer
- 6b140ae899 9.1.1384: still some problem with the new tutors filetype plugin
- f623fad9c4 9.1.1385: inefficient loop for 'nosmoothscroll' scrolling (#33992)
- d50f71d2f1 9.1.1387: memory leak when buflist_new() fails to reuse curbuf
- 27abf5c81b 9.1.1388: Scrolling one line too far with 'nosmoothscroll' page scrolling (#34023)
- 917f496f75 9.1.1395: search_stat not reset when pattern differs in case (#34058)
- b07bffdc47 9.1.1402: multi-byte mappings not properly stored in session file (#34131)
- ff83c712cf 9.1.1405: tests: no test for mapping with special keys in session file (#34146)
- d1ca551983 9.1.1407: Can't use getpos('v') in OptionSet when using setbufvar() (#34177)

DOCUMENTATION
--------------------------------------------------------------------------------
- e5e69f758d add missing change to getcharstr() signature (#33797)
- 95ee908c40 backport #33549 and #33524 to 0.11 (#33678)
- 472d41b5b6 default mappings #33706
- 3a4d3934c4 fixups (#33815)
- fa292e6f61 lsp, emoji, startup #33683
- 714622fb45 lsp, lua #33682
- d68d212ad4 provide example_init.lua #33524
- 968947b3c3 lua: typing for vim.fn.winlayout #33817
- e304677993 tutor: move lesson 7.2 below lesson 7.3 #33662
2025-05-30 11:39:24 +02:00
Christian Clason
58460e2d52 fix(treesitter): parser metadata annotations
Problem: `TSLangInfo` annotation does not reflect the structure returned
by `vim.treesitter.language.inspect()`.

Solution: Move version information under new (optional since ABI 15 only)
`TSLangMetadata` field.

(cherry picked from commit f82219c490)
2025-05-29 15:28:00 +00:00
Lewis Russell
3a0d37681f fix(vim.system): improve error message when cwd does not exist
Problem:
vim.uv.spawn will emit ENOENT for either when the cmd or cwd do not
exist and does not tell you which.

Solution:
If an error occurs, check if cwd was supplied and included in the error
message if it does not exist.

(cherry picked from commit 532610388b)
2025-05-29 13:29:23 +00:00
Sean Dewar
4cb2b19197 fix(folds): adjust filler text drawing for transparent folds
Problem: Search highlighting is applied strangely to the filler text of
transparent folds, and EOL list characters are not shown.

Solution: Don't apply search highlighting to the last column of the window row
if the last text char on the line is highlighted. Display the EOL list char if
needed. Don't highlight the entire filler text when matching EOL, just highlight
the EOL list char or the first filler char.

(cherry picked from commit 66dddd8b51)
2025-05-27 09:40:55 +01:00
zeertzjq
d1ca551983 vim-patch:9.1.1407: Can't use getpos('v') in OptionSet when using setbufvar() (#34177)
Problem:  Can't use getpos('v') in OptionSet when using setbufvar().
Solution: Don't reset Visual selection when switching to the same
          buffer (zeertzjq).

closes: vim/vim#17373

5717ee33db
(cherry picked from commit bd01bd6564)
2025-05-25 23:17:15 +00:00
zeertzjq
5e0ef6afc7 Merge pull request #34168 from zeertzjq/backport
fix(system): don't treat NUL at start as no input (#34167)
2025-05-25 10:21:25 +08:00
zeertzjq
cefc91a82e fix(system): don't treat NUL at start as no input (#34167) 2025-05-25 09:32:45 +08:00
luukvbaal
334d8f506f fix(move): consume skipcol before revealing filler lines (#34143)
Problem:  When scrolling (the text) down with 'smoothscroll', filler
          lines are revealed before the text skipped with `w_skipcol`.
Solution: Check `w_skipcol` before filler lines.

(cherry picked from commit 6ce2877327)
2025-05-23 23:14:18 +00:00
zeertzjq
ff83c712cf vim-patch:9.1.1405: tests: no test for mapping with special keys in session file (#34146)
Problem:  tests: no test for mapping with special keys in session file.
Solution: Add a special keys to an existing test.  Also test with UTF-8
          characters containing 0x80 or 0x9b bytes (zeertzjq).

closes: vim/vim#17360

9ff1e598e8
(cherry picked from commit 071dcab68f)
2025-05-23 23:04:01 +00:00
zeertzjq
b07bffdc47 vim-patch:9.1.1402: multi-byte mappings not properly stored in session file (#34131)
Problem:  multi-byte mappings not properly stored in session file
Solution: unescape the mapping before writing out the mapping, prefer
          single-byte mapping name if possible (Miguel Barro)

closes: vim/vim#17355

5b07aff2f6

Co-authored-by: GuyBrush <miguel.barro@live.com>
(cherry picked from commit 153a910897)
2025-05-23 00:15:14 +00:00
Evan Hahn
b868257ef9 fix(lsp): fix error with InsertReplaceEdit events #33973
Problem:
Some LSPs cause the following completion error (reformatted slightly):

    Error executing vim.schedule lua callback:
    .../runtime/lua/vim/lsp/completion.lua:373
    attempt to index field 'range' (a nil value)

This is because an internal function assumes edits are either missing
or of type `TextEdit`, but there's a third [possibility][0] that's not
handled: the `InsertReplaceEdit`.

This was previously reported in at least two issues:

- https://github.com/neovim/neovim/issues/33142
- https://github.com/neovim/neovim/issues/33224

Solution:
Don't assume the edit is a `TextEdit`. This implicitly handles
`InsertReplaceEdit`s.

Also, add a test case for this, which previously caused an error.

[0]: 2c07428966/runtime/lua/vim/lsp/_meta/protocol.lua (L1099)

(cherry picked from commit 927927e143)
2025-05-22 13:50:07 +00:00
Phạm Bình An
e304677993 docs(tutor): move lesson 7.2 below lesson 7.3 #33662
Problem:

- Lesson 7.3 (Cmdline Completion) teaches an important way to discover
  Nvim features. I think users should learn it before they start
  configuring Nvim
- Nvim can be configured in Lua as well, but lesson 7.2 (Configuring
  Nvim) only mentions init.vim. And I think Nvim is promoting Lua more

Solution:

- Move lesson 7.2 to be after lesson 7.3
- Lesson 7.2 should teach about init.lua

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
(cherry picked from commit dd43eb445a)
2025-05-21 09:51:16 +00:00
Phạm Bình An
4e5af2f5a6 vim-patch:5a8f995: runtime(doc): remove outdated Contribution section in pi_tutor (#34094)
Problem:  The Github repo link in the Contribution section has been
          archived for 5 years. So people who want to contribute to the
          tutor plugin should just send PR to Vim repo, similar to most
          other Vim features, so there is no need for a Contribution
          section in the plugin doc.

Solution: Replace it with an Original Author note at the beginning of
          the help document.

closes: vim/vim#17341

5a8f9958e2
(cherry picked from commit 1524868711)
2025-05-20 01:16:27 +00:00
zeertzjq
917f496f75 vim-patch:9.1.1395: search_stat not reset when pattern differs in case (#34058)
Problem:  search_stat not reset when pattern differs in case
          (tahzibijafar)
Solution: use STRNCMP instead of MB_STRNICMP macro

There was a long standing todo comment, that using MB_STRNICMP is wrong.
So let's change it to STRNCMP() instead. Even if it not handle
multi-byte characters correctly, then Vim will rather recompute the
search stat, instead of re-using the old (and possibly wrong) value.

fixes: vim/vim#17312
closes: vim/vim#17314

670d0c1468

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit ec5f054dc9)
2025-05-17 00:12:13 +00:00
zeertzjq
a242902430 fix(:print): don't use schar_from_ascii() for illegal byte (#34046)
(cherry picked from commit 6af1b7e5e8)
2025-05-16 23:03:09 +00:00
zeertzjq
12ae7aa846 fix(tui): clear primary device callback before invoking it (#34032)
A primary device callback may set a new callback (e.g. when suspending),
so clearing it after invoking it is too late.

While at it, add missing reset of did_set_grapheme_cluster_mode in
terminfo_start().

(cherry picked from commit 17e13ce3b6)
2025-05-15 13:13:02 +00:00
luukvbaal
27abf5c81b vim-patch:9.1.1388: Scrolling one line too far with 'nosmoothscroll' page scrolling (#34023)
Problem:  One-off error in "count" to make "w_skipcol" zero with
          'nosmoothscroll' page scrolling when last virtual line
          in a buffer line is exactly the entire window width.
          (Hirohito Higashi)
Solution: Properly compute the smallest integer value necessary
          to make "w_skipcol" zero (Luuk van Baal)

c6c72d165c
(cherry picked from commit f87b6230f1)
2025-05-15 08:24:06 +00:00
Sean Dewar
d50f71d2f1 vim-patch:9.1.1387: memory leak when buflist_new() fails to reuse curbuf
Problem:  buflist_new() leaks ffname and fails to reuse curbuf when
          autocommands from buf_freeall change curbuf. Plus, a new
          buffer is not allocated in this case, despite what the comment
          above claims.
Solution: Remove the condition so ffname is not leaked and so a new
          buffer is allocated like before v8.2.4791. It should not be
          possible for undo_ftplugin or buf_freeall autocommands to
          delete the buffer as they set b_locked, but to stay consistent
          with other uses of buf_freeall, guard against that anyway
          (Sean Dewar).

Note that buf is set to NULL if it was deleted to guard against the (rare)
possibility of messing up the "buf != curbuf" condition below if a new buffer
happens to be allocated at the same address.

closes: vim/vim#17319

0077282c82

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
(cherry picked from commit 6b9665a507)
2025-05-15 08:14:43 +00:00
neovim-backports[bot]
f623fad9c4 vim-patch:9.1.1385: inefficient loop for 'nosmoothscroll' scrolling (#33992)
Problem:  Loop that ensures "w_skipcol" is zero with 'nosmoothscroll'
	  for (half)-page scrolling is inefficient.
Solution: Calculate the required "count" instead of looping until
	  "w_skipcol" is zero (Luuk van Baal).

acf0ebe8a8
(cherry picked from commit d539a952da)
---------

Co-authored-by: luukvbaal <luukvbaal@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2025-05-13 10:43:25 +02:00
luukvbaal
3e83a33108 vim-patch:9.1.1297: Ctrl-D scrolling can get stuck #33453
Problem:  cursor_correct() calculates a valid cursor position which
	  is later changed by update_topline() and causes Ctrl-D
          scrolling to be stuck (Daniel Steinberg, after v9.1.0258).
Solution: Update the valid cursor position before validating topline
          (Luuk van Baal).

c98250377d
(cherry picked from commit aa47c8efa9)
2025-05-13 07:02:50 +00:00
brianhuster
0c2bf55e90 fix(tutor): l:lang is undefined
Problem:
The scope `elseif $LC_MESSAGES =~ '\a\a' || $LC_MESSAGES ==# "C"` in
function `s:Locale` in file `runtime/autoload/tutor.vim` leaves a case
when l:lang is not defined.

Solution:
Define `l:lang` at function scope instead of `if` scope

(cherry picked from commit e5665754d1)
2025-05-13 02:35:41 +00:00
brianhuster
6b140ae899 vim-patch:9.1.1384: still some problem with the new tutors filetype plugin
Problem:  still some problem with the new tutors filetype plugin
Solution: refactor code to enable/disable tutor mode into
          tutor#EnableInteractive() function, include a test
          (Phạm Bình An)

I find it annoying that Tutor's interactive mode is always on (or debug
mode is off) even when I open a tutor file with :edit command.
I think it makes more sense to make this "interactive mode":

- Always on when it is opened with :Tutor command
- Off otherwise

For more references, see `:help` feature, it is a much better than
:Tutor, since I don't have to run `:let g:help_debug = 1` just to be able
to edit and save a help file

Therefore, I remove `g:tutor_debug`

closes: vim/vim#17299

13bea589a2

Co-authored-by: Phạm Bình An <phambinhanctb2004@gmail.com>
(cherry picked from commit e01f196e44)
2025-05-13 02:35:41 +00:00
brianhuster
1921dda92e vim-patch:3704b5b: runtime(tutor): improve tutor.vim plugin and filetype plugin
- Set g:tutor_debug on startup if it doesn't exist so that users can get
  cmdline completion when interactively setting it.
- set b:undo_ftplugin in filetype plugin
- set default runtime file headers

closes: vim/vim#17274

3704b5b58a

Co-authored-by: Phạm Bình An <phambinhanctb2004@gmail.com>
(cherry picked from commit 238e1d6ecc)
2025-05-13 02:35:41 +00:00
Sean Dewar
30fa1c5f8c vim-patch:9.1.1380: 'eventignorewin' only checked for current buffer
Problem:  When an autocommand executes for a non-current buffer,
          'eventignorewin' is only checked from the buffer's last
          wininfo (overwrites win_ignore in the loop), not from the
          value of 'eventignorewin' in all windows showing the buffer as
          described (after v9.1.1084)

Solution: Fix the check and don't use wininfo, as that may only contain
          windows that recently showed the buffer. Consider all the
          buffer's windows in all tabpages (Sean Dewar).

closes: vim/vim#17294

d4110e0695

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
(cherry picked from commit ef5c5dc99b)
2025-05-11 22:48:42 +00:00
Sean Dewar
6417ba0c2f vim-patch:9.1.1376: quickfix dummy buffer may remain as dummy buffer
Problem:  when failing to wipeout a quickfix dummy buffer, it will
          remain as a dummy buffer, despite being kept.
Solution: clear its dummy BF_DUMMY flag in this case (Sean Dewar).

closes: vim/vim#17283

270124f46a

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
(cherry picked from commit d95b0a5396)
2025-05-11 16:38:20 +01:00
Sean Dewar
3c102303f5 vim-patch:9.1.1375: [security]: possible heap UAF with quickfix dummy buffer
Problem:  heap use-after-free possible when autocommands switch away from the
          quickfix dummy buffer, but leave it open in a window.
Solution: close its windows first before attempting the wipe.
          (Sean Dewar)

related: vim/vim#17283

b4074ead5c

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
(cherry picked from commit 05dab80d8d)
2025-05-11 16:38:20 +01:00
Riley Bruins
034d3c8f6c fix(treesitter): proper tree contains() logic with combined injections
**Problem:** `LanguageTree:contains()` considers any range within the
start of the first tree and end of the last tree as "within" the
language tree. In the case of combined injections, this is problematic
because we only want to consider ranges within any of the combined trees
as "contained" (as opposed to any range within the entire range spanned
by all combined trees).

**Solution:** Use a more discriminative check in
`LanguageTree:contains()`.

(cherry picked from commit de45b8e275)
2025-05-11 07:32:19 +00:00
Sean Dewar
9965cfb84c vim-patch:9.1.1361: [security]: possible use-after-free when closing a buffer (#33820)
Problem:  [security]: Possible to open more windows into a closing
          buffer without splitting, bypassing existing "b_locked_split"
          checks and triggering use-after-free
Solution: Disallow switching to a closing buffer. Editing a closing
          buffer (via ":edit", etc.) was fixed in v9.1.0764, but add an
          error message and check just "b_locked_split", as "b_locked"
          is necessary only when the buffer shouldn't be wiped, and may
          be set for buffers that are in-use but not actually closing.
          (Sean Dewar)

closes: vim/vim#17246

6cb1c82840
(cherry picked from commit 627c648252)
2025-05-10 17:07:31 +00:00
zeertzjq
bdd8498ed7 fix(folds): avoid unnecessary loop with horizontal scrolling (#33932)
Fix #33931

(cherry picked from commit 1d9990daac)
2025-05-10 03:21:57 +00:00
Sean Dewar
8daffd0cbb fix(terminal): check size when switching buffers
Problem: terminal not always resized when switching to its buffer.
Solution: add missing calls to terminal_check_size.

Adjust screen test for v0.11.
(cherry picked from commit e56292071a)
2025-05-09 17:49:50 +00:00
Artem
fd8e0ae62d fix(decor): extmark highlight not applied (#33858)
Problem: If the only highlight present in the buffer is an extmark, and its end
position is outside the screen, redraws that start on lines after the
first line of the mark will consider the buffer as not having any highlights,
and skip drawing the mark's highlight.
Solution: Check the updated number of decor ranges.

(cherry picked from commit 6adf48b66d)
2025-05-09 11:02:31 +00:00
zeertzjq
a56dcbbad7 test(swapfile): don't check for line with full file path (#33896)
Wrapping can happen anywhere where in the full file path, breaking the
matching. Match a line with the "Xswaptest" line instead.

(cherry picked from commit 1b8ae4336d)
2025-05-08 02:45:56 +00:00
Phạm Bình An
6a87b57c06 fix(runtime): 'includeexpr' with non-Nvim-style Lua modules #33867
Closes #33862

(cherry picked from commit db2b774a16)
2025-05-07 01:06:12 +00:00
Riley Bruins
5c6ee251a6 fix(treesitter): eliminate flicker for single windows #33842
This commit will eliminate flicker while editing one open window. It
works by querying previously calculated trees for highlight marks, in
the case that we are still asynchronously parsing in `on_win`.

It will not fully solve the case of flicker when there are multiple open
windows, since the parser will drop previously parsed injection trees
whenever it receives a call to parse a different region of the buffer.
This will require a refactor of `languagetree.lua`.

(cherry picked from commit 8d75910ef9)
2025-05-06 15:22:43 +00:00
gcrtnst
0db89468d7 fix(termkey): out-of-bounds write in array #33868
Problem:
termkey crashes due to an out-of-bounds write in an array when it
received a CSI sequence with 17 or more arguments. This could be
observed on startup with certain terminal emulators like [RLogin], which
send a response to the `CSI c` query containing 17 parameters.

The termkey code has a boundary check, but its comparison operator is
incorrect.

Solution:
Correct the comparison operator to ensure proper boundary checking.

With this change, I have confirmed that the crash no longer occurs on
RLogin. https://github.com/kmiya-culti/RLogin

Fixes #24356

(cherry picked from commit 8707ec2644)
2025-05-06 12:54:26 +00:00
Justin M. Keyes
dc87a0d80a fix(lua): vim.validate message param #33675
Problem:
vim.validate does not handle `message` param.

Solution:
Add the missing logic.

(cherry picked from commit 40351bbbbe)
2025-05-05 00:09:31 +00:00
zeertzjq
c753e70abb test(lua/secure_spec): avoid magic number (#33700)
Avoid magic number in skipping condition by moving the expected message
to a variable.

(cherry picked from commit c489b5a3e3)
2025-05-04 23:50:15 +00:00
Eike
0ed06d7271 fix(lsp): check if client is stopping before reuse #33796
Problem:
Stopping a language server and then calling vim.lsp.start() with the same name/root will return the old language server that's in the middle of shutting down. vim.lsp.start() won't return a new server until the old process has terminated.

Solution:
Introducing a client._is_stopping field that tracks the shutdown phase, preventing the client from being reused.

(cherry picked from commit 0862c1036a)
2025-05-04 22:26:30 +00:00
glepnir
e512c9589e fix(lsp): improve error completion message #33812
problem: Error notifications from LSP responses were difficult to read due to
inconsistent formatting and missing critical information like client name and error codes.

solution: Implemented a more structured error notification format using pipe separators to
clearly display client name, error code (when available), and error message.

(cherry picked from commit 5c15df449a)
2025-05-04 17:38:54 +00:00
glepnir
47686a1454 fix(lsp): only auto-detach lsp.config clients #33834
Problem:
enable() routine detaches clients even if they were manually started
and not managed by vim.lsp.config.

Solution:
Skip clients that aren't managed by vim.lsp.config.

(cherry picked from commit 91e116f3a6)
2025-05-04 13:39:40 +00:00
luukvbaal
3b3cf1d7ef fix(treesitter): invalidate conceal_lines marks (#33832)
Problem:  Spliced conceal_lines marks after changing the buffer text are
          left valid, concealing lines that shouldn't be.
Solution: Set the `invalidate` extmark property.
(cherry picked from commit 9274532615)
2025-05-03 23:41:23 +00:00
Phạm Bình An
472d41b5b6 docs: default mappings #33706
Problem:
Docs don't mention that `gc` is just a mapping, not
a builtin normal-mode command.

Solution:
Update docs for all "default mappings".

(cherry picked from commit 2c1f5a6aa5)
2025-05-03 23:07:06 +00:00
Jeremy Fleischman
216c56b7e0 feat(lsp): detach LSP clients when 'filetype' changes #33707
Problem:
When the buffer 'filetype' changes, invalid or non-applicable LSP
clients are not detached.

https://github.com/neovim/neovim/issues/33443
https://github.com/neovim/nvim-lspconfig/issues/3326

Solution:
In the enable() routine, check can_start() on _existing_ clients.

(cherry picked from commit b877aa34cf)
2025-05-03 22:49:53 +00:00
PRIZ ;]
968947b3c3 docs(lua): typing for vim.fn.winlayout #33817
Problem:
`any[]` means nothing, and the return value is not the same as what's
documented in the comment (eg, Lua returns `{ "row", { { "leaf", 1000 },
{ "leaf", 1001 } } }`, not `{ "row", { "leaf", 1000, "leaf", 1001 } }`)

Solution:
Create two classes (vim.fn.winlayout.leaf and vim.fn.winlayout.branch)
and one alias that links the two together.

Also: Due to LuaLS limitations, there is an empty class,
vim.fn.winlayout.empty

Signed-Off-By: VoxelPrismatic <voxelprismatic@pm.me>
(cherry picked from commit 902b689c4d)
2025-05-03 19:10:02 +00:00
Sean Dewar
9b3426691c fix(window): skip unfocusable and hidden floats with "{count}<C-W>w" #33810
Problem: Using `<C-W>w`, `<C-W>W` or the ":wincmd" variants with a count can
enter unfocusable or hidden floating windows. This is especially problematic
when using the new in-development extui, which creates many unfocusable floats
for various UI elements.

Solution: Skip unfocusable and hidden floating windows. Instead, skip to the
next focusable, non-hidden window in the current tabpage's window list. Reword
the documentation a bit (hopefully an improvement?)

(cherry picked from commit 403fcacfc1)
2025-05-03 19:02:39 +00:00
Jeremy Fleischman
4e43264cd3 feat(lsp): vim.lsp.is_enabled() #33703
Problem:
No way to check if a LSP config is enabled without causing it to
resolve. E.g. `vim.lsp.config['…'] ~= nil` will resolve the config,
which could be an unwanted and somewhat expensive side-effect.

Solution:
Introduce `vim.lsp.is_enabled()`.

(cherry picked from commit 03d378fda6)
2025-05-03 17:45:39 +00:00
Sean Dewar
3a4d3934c4 docs: fixups (#33815)
- Add missing diagnostics virtual lines hl groups.
- Fix LSP dynamic registration example; curbuf may not actually be attached to
  the client, and it may be attached to many such buffers.

(cherry picked from commit 94bc7f47bf)
2025-05-03 17:23:08 +01:00
Michele Campeotto
2b2a3449f7 fix(runtime): conceal paths in help, man ToC loclist #33764
Problem:
The check for concealing paths in TOCs in the qf syntax file fails
because the TOC tile has changed.

Solution:
Force the qf syntax file to be reloaded after the qf_toc variable
has been set, so that the it can apply the correct settings.

Using the explicit qf_toc key, already used in the syntax file, instead
of the title is less prone to breaking.

It was also already being set for man pages but it had no effect because
the syntax file had already been loaded when the variable was set.

Fixes #33733

(cherry picked from commit f048298e9a)
2025-05-03 14:33:34 +00:00
Riley Bruins
6b69b3217b fix(lsp): improper diagnostic end_col computation
**Problem:** For multiline diagnostics, the end column was improperly
calculated by checking the byte index of the character position on the
*start* line.

**Solution:** Calculate the byte index for end_col using the *end* line.

(cherry picked from commit 5d1fd4aca5)
2025-05-03 08:28:03 +00:00
zeertzjq
cf73f21c07 fix(tui): don't try to add unsupported modifiers (#33799)
Problem:  The TUI doesn't forward a key properly when it has unsupported
          modifiers like NumLock.
Solution: Don't try to add modifiers when only unsupported modifiers are
          present.

Related #33791

(cherry picked from commit adbd33027f)
2025-05-03 04:37:40 +00:00
zeertzjq
e5e69f758d docs: add missing change to getcharstr() signature (#33797)
(cherry picked from commit 862e676efc)
2025-05-03 00:51:46 +00:00
Maria José Solano
901eeeb2e6 fix(lsp): use bufnr when getting clients in symbols_to_items (#33760)
(cherry picked from commit 34c769dd89)
2025-05-02 21:07:05 +00:00
Christian Clason
6563c6bde7 fix(treesitter): close :InspectTree with q
Problem: `:InspectTree` window does not follow precedent for focused
"info windows" (like `checkhealth`, `Man`, etc.).

Solution: Map `q` to `<C-w>c`.
(cherry picked from commit 5a2edc483d)
2025-05-02 20:06:26 +00:00
zeertzjq
465c181581 fix(tui): forward C0 control codes literally (#33759)
This fixes the problem that sending a raw C0 control code to trigger a
mapping for it does not work in Terminal mode.

Note: this isn't done for 00 or 7F, as that'll be backward-incompatible.
(cherry picked from commit 4b5364b423)
2025-05-02 10:16:30 +00:00
Phạm Bình An
710d561f88 fix(vim.lsp.enable): don't eagerly enable LSP configs during startup #33762
closes #33761

(cherry picked from commit 1fb0126a08)
2025-05-02 09:59:07 +00:00
luukvbaal
81233a41d7 fix(display): adjust setting winline info for concealed lines (#33717)
Problem:  Wrong winline info after partial redraw. Setting
          `conceal_cursor_used` is unnecessarily spread out.
Solution: Rather than adjusting `wl_lastlnum` for the previous
          winline, adjust it when setting the current winline.
          Set `conceal_cursor_used` when the current window is redrawn.
(cherry picked from commit 97a6259442)
2025-05-01 12:05:15 +02:00
Jeremy Fleischman
c4b9bdbdf4 feat(lsp): start/stop LSPs as necessary during vim.lsp.enable() #33702
Problem:
enable() could be more flexible, so that it works even if called "late".

Solution:
- enable(true) calls `doautoall nvim.lsp.enable FileType`.
- enable(false) calls `client:stop()` on matching clients.

This will be useful for e.g. :LspStop/:LspStart also.

(cherry picked from commit 4bc7bac884)
2025-05-01 00:24:08 +00:00
Jeremy Fleischman
560c6ca947 fix(trust): support for trusting directories #33735
Problem:
Directories that are "trusted" by `vim.secure.read()`, are not detectable later
(they will prompt again). https://github.com/neovim/neovim/discussions/33587#discussioncomment-12925887

Solution:
`vim.secure.read()` returns `true` if the user trusts a directory.

Also fix other bugs:

- If `f:read('*a')` returns `nil`, we treat that as a successful read of
  the file, and hash it. `f:read` returns `nil` for directories, but
  it's also documented as returning `nil` "if it cannot read data with the
  specified format". I reworked the implementation so we explicitly
  treat directories differently. Rather than hashing `nil` to put in the
  trust database, we now put "directory" in there explicitly*.
- `vim.secure.trust` (used by `:trust`) didn't actually work for
  directories, as it would blindly read the contents of a netrw buffer
  and hash it. Now it uses the same codepath as `vim.secure.read`, and
  as a result, works correctly for directories.

(cherry picked from commit 272dba7f07)
2025-04-30 14:35:41 -07:00
luukvbaal
4b6caa913c fix(cmdline): do not move UI cursor when entering cmdline #33729
Problem:  Cursor is still moved to curwin when entering cmdline (after d41b8d47).

Solution: Remove call to `setcursor()`.
(cherry picked from commit 0015a105ca)
2025-04-30 14:38:40 +00:00
Justin M. Keyes
0fbc78caa1 Merge #33734 from justinmk/release
backport: LSP root_markers, docs
2025-04-30 07:21:21 -07:00
Lorenzo Bellina
533ec6d492 feat(lsp): root_markers can control priority
Problem:
root_markers cannot specify "equal priority filenames.

Solution:
Support nesting:

    {
      ...
      root_markers = { { ".stylua.toml", ".luarc.json" }, { ".git "} }
      ...
    }

Co-authored-by: Maria José Solano <majosolano99@gmail.com>
Co-authored-by: Gregory Anders <github@gpanders.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-04-30 15:59:00 +02:00
Justin M. Keyes
9dfb429e93 test: drop redundant clear() #33654
followup to #33647 after overlapping merge
2025-04-30 15:58:03 +02:00
Justin M. Keyes
051e14d347 test: drop redundant clear() #33647
Problem:
Tests call `clear()` even though `clear_notrace()` is already called in
a `before_each()` handler, wasting precious milliseconds!

Solution:
Remove redundant `clear()` calls.
2025-04-30 15:57:55 +02:00
Justin M. Keyes
714622fb45 docs: lsp, lua #33682
- sort fields alphabetically.
- in the `vim.lsp.Client` docs, reference `vim.lsp.ClientConfig` instead
  of duplicating its docs.
- cleanup lots of redundant-yet-drifted field docs.
2025-04-30 15:51:38 +02:00
zeertzjq
4296511087 fix(tui): don't process UI events when suspending or stopping (#33710)
When the TUI is suspending or stopping, redraw events should not be
processed, as when it next processes redraw events it's already waiting
for a DA1 response after having disabled some terminal modes.

Fix #33708

(cherry picked from commit c35dde03c8)
2025-04-29 10:04:38 +00:00
Justin M. Keyes
f9c7a69cec Revert "fix(desktop): cannot open filename with spaces using OS file manager" #33684
This reverts commit 6e12ef4a7b

> Paths with spaces were already working. The original bug is most
> likely with user's terminal desktop entry, file manager or DE, and has
> nothing to do with nvim.desktop.

These are 3 different implementations that work correctly with unquoted %F and spaces:
```
$ DE=generic xdg-open "D I R/F I L E.txt" # pure bash
$ gio open "D I R/F I L E.txt" # glib2
$ handlr open "D I R/F I L E.txt" # rust
```

(cherry picked from commit 07a207a5f1)
2025-04-27 23:20:07 +00:00
Justin M. Keyes
fa292e6f61 docs: lsp, emoji, startup #33683
Co-authored-by: Maria José Solano <majosolano99@gmail.com>
2025-04-27 23:00:36 +00:00
Justin M. Keyes
bc66a5ff6f Merge pull request #33680 from justinmk/release 2025-04-27 15:32:22 -07:00
Yochem van Rosmalen
f25f6c8d13 feat(health): summary in section heading #33388
Problem:
As checkhealth grows, it is increasingly hard to quickly glance through
the information.

Solution:
Show a summary of ok, warn, and error outputs per section.
2025-04-27 22:35:39 +02:00
Justin M. Keyes
ad7211ac8f feat(checkhealth): trigger FileType event after showing report
Problem:
`FileType` event is fired before checkhealth report is finished, so
user can't override report settings or contents.
https://github.com/neovim/neovim/pull/33172#issuecomment-2833513916

Solution:
- Trigger FileType event later.
- Document how to remove emojis.
2025-04-27 20:39:14 +02:00
Justin M. Keyes
95ee908c40 docs: backport #33549 and #33524 to 0.11 (#33678)
* vim-patch:829eda7: runtime(new-tutor): update tutor and correct comandline completion

Problem: Some parts of the tutor are outdated.

- For example, pressing `<Tab>` after typing `:e` does not complete the
command `:edit`, but shows a completion menu with the first entry being
`:earlier`.

closes: vim/vim#17107

829eda7d38

Co-authored-by: Phạm Bình An <phambinhanctb2004@gmail.com>

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
(cherry picked from commit 374e52a7ee)

* docs: provide example_init.lua #33524

Problem:
There are some "boilerplate" steps for new users. Although we are
constantly improving defaults and lifting patterns into core, users
eventually want to know how to start their own config, add plugins, etc.

Solution:
Add `runtime/example_init.lua` and refer to it from docs.

(cherry picked from commit 86b34ad073)

---------

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2025-04-27 10:33:37 -07:00
Phạm Bình An
d68d212ad4 docs: provide example_init.lua #33524
Problem:
There are some "boilerplate" steps for new users. Although we are
constantly improving defaults and lifting patterns into core, users
eventually want to know how to start their own config, add plugins, etc.

Solution:
Add `runtime/example_init.lua` and refer to it from docs.

(cherry picked from commit 86b34ad073)
2025-04-28 00:01:50 +07:00
brianhuster
3273c595c0 vim-patch:829eda7: runtime(new-tutor): update tutor and correct comandline completion
Problem: Some parts of the tutor are outdated.

- For example, pressing `<Tab>` after typing `:e` does not complete the
command `:edit`, but shows a completion menu with the first entry being
`:earlier`.

closes: vim/vim#17107

829eda7d38

Co-authored-by: Phạm Bình An <phambinhanctb2004@gmail.com>

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
(cherry picked from commit 374e52a7ee)
2025-04-27 23:44:37 +07:00
Phạm Bình An
3db39ed21f fix(runtime): cpoptions is reset in Lua file #33671
closes #33670

(cherry picked from commit 923efaea28)
2025-04-27 12:19:58 +00:00
Bartłomiej Maryńczak
f184c562c5 fix(lsp): detect if Client:request resolved synchronously #33624
Problem:
In cases when the (in-process) LSP server responds to the request
immediately and calls `notify_reply_callback` the request will still be
marked as pending, because the code assumes that the response will occur
asynchronously. Then the request will be pending forever, because it was
already set as "completed" before we even set it as "pending".

A workaround is to wrap `notify_replay_callback` in `vim.shedule` ([like
so](https://github.com/neovim/neovim/pull/24338#issuecomment-2809568617)]
but that seems counterintuitive.

Solution:
Handle this case in Client:request().

(cherry picked from commit 8315697449)
2025-04-27 00:54:11 +00:00
Andre Toerien
32842b0ee3 fix(health): checkhealth float opens extra empty buffer #33648
(cherry picked from commit d927a87ed6)
2025-04-26 16:37:46 +00:00
Justin M. Keyes
4f0e828190 version bump 2025-04-26 16:31:02 +02:00
Justin M. Keyes
a9a3981669 NVIM v0.11.1
For notable changes, see runtime/doc/news.txt (or `:help news` in Nvim).

Following is a list of fixes/features commits.

BREAKING
--------------------------------------------------------------------------------
- bbf912d72f provider: drop Python 3.7, 3.8 support #33088

FEATURES
--------------------------------------------------------------------------------
- 66953b16a2 lsp: workspace_required (#33608)
- 7efb3ba6f7 checkhealth: use emoji for OK/WARN/ERROR (#33195)
- 91d11c8bc1 clipboard: g:clipboard="foo" forces the "foo" clipboard tool #33235
- 12da443930 float: 'winborder' "bold" style #33189
- 5829b5de0a vim.hl: allow multiple timed highlights simultaneously #33283

FIXES
--------------------------------------------------------------------------------
- 91481ae7d5 bug in stylize_markdown
- 5fc6bd6454 api: nvim_set_keymap() throws error even in pcall() #33228
- 2b2a90051e api: use E226 instead of E227 for duplicate abbreviation (#33159)
- 056dbf3ea7 api: use original LHS in keymap error message #33135
- fb71d631a5 api: wrong return value with reverse range + overlap #32956
- fcee5df0fc checkhealth: check g:loaded_xx_provider for all providers #33168
- 89e0ea1788 checkhealth: check outdated pynvim version properly #33175
- adfd4b9f4f checkhealth: don't override user "q" keymap #33132
- 06df3e0c0d cmdline: avoid empty @: register after :<CR> (#33126)
- 53def2a877 cmdline: empty ext_cmdline block events for :<CR> #33118
- b8e5fd51fd column: don't count signs on lines beyond eob #33410
- e4007551c4 completion: avoid freeing uninitialized value (#33459)
- 6e51d39696 decor: enable decoration provider in on_start #33337
- 837c9d0409 defaults: enable :terminal [[,]] motion in operator-pending mode #33217
- 2182272139 defaults: keywordprg=:help on Windows #33336
- 7e884b78bf defaults: visual-mode [[,]] for :terminal shell prompts #33203
- 2a04161a35 desktop: cannot open filename with spaces using OS file manager #33161
- 2cd735d159 display: scroll logic does not take into account concealed topline (#33054)
- c4a19bff4e display: scroll redrawing doesn't account for virt_lines above fold #33374
- 02123bac0d display: wrong cursor column with 'concealcursor' = "n" and virt_text (#33218)
- 837faf7065 editor: respect [+cmd] when executing :drop #33339
- 155529b91a events: avoid superfluous CursorMovedI on first autocmd (#33588)
- c158d41cec health: expecting nonexistent "inotifywait" function #33312
- 06c2886569 health: message should mention "vim.provider" #33095
- 279a0e78c9 highlight: no match highlight during :substitute prompt #33262
- b5158e8e92 lsp: "bold" border for vim.lsp.buf.hover #33395
- 1e8e74dbff lsp: better handling of "*" configs
- 478f5d0070 lsp: cycling signatures with the default `config.focusable`
- 2435d72283 lsp: opts.reuse_win does not jump if buf is already open #33476
- 95f96a3d1b lsp: prioritize showing active signature
- a9afa6b152 lsp: warn on missing config in :checkhealth #33087
- 2b14447803 man.lua: noisy "ENOENT" error on Windows #33435
- 8aa49a8e9b man.lua: useless executability check #33438
- 4d87229789 marks: clamp conceal_lines corrected line number #33464
- 9da90af0f7 marks: wrong display after inserting/deleting lines #33389
- 3b0c88a537 messages: single msg_show event for multiple :set options #33555
- 3df9db58dc messages: verbose message emitted without kind #33305
- c61e8c6e70 mouse: crash with click on win-separator in statusline (#33091)
- dcd5e4574a mouse: do not fetch clipboard twice when pasting with middle button #33494
- 526444c4ff mouse: mouseclick after conceal_lines is miscalculated #33451
- 326eacef93 move: adjust for concealed lines above topline after scrolling up (#33211)
- 649bce6e73 provider: misleading :checkhealth if user sets g:loaded_python3_provider=1 #32696
- c57a36cd59 pum: fix heap-buffer-overflow with 'rightleft' (#33146)
- c1d3777db2 snippet: use <cmd>call cursor() for visual range
- 70f3e15298 treesitter: don't memoize modified headings (#33186)
- e342b9a25a treesitter: fix `:InspectTree` incorrect injections
- 4c1121bd33 treesitter: not refreshing virtualtext contents #33361
- 646a8f663e tui: ensure all pending escape sequences are processed before exiting #32151
- 9909580df2 ui: exclude unfocusable windows from 'complete' "w" completion
- ccb078bbb0 ui: wincmd _ should not increase 'cmdheight' above 0 (#33056)
- 29011e4d45 vim.hl: nvim_buf_del_extmark on invalid buffer #33331
- 9056c01a95 vim.lsp.inlay_hint: requesting inlay_hints even when disabled #32999
- 4422b9bbd0 vim.system: unclear non-executable message #33455
- a4b6705e87 window: crash on negative window height with 'winbar' #33250

PERFORMANCE
--------------------------------------------------------------------------------
- b9c9b15ad7 snippet: use "[count]|" to move cursor #33571

VIM PATCHES
--------------------------------------------------------------------------------
- a97713485d 9.0.1653: Amiga: default 'viewdir' may not work
- cdd3f2a2e6 9.0.1654: MS-Windows: test for default 'viewdir' fails
- b7de104d86 9.1.0721: tests: test_mksession does not consider XDG_CONFIG_HOME
- 6514e2c7ba 9.1.1247: fragile setup to get (preferred) keys from key_name_entry (#33102)
- 2084cda6f9 9.1.1260: Hang when filtering buffer with NUL bytes (#33192)
- 02bf23b4bf 9.1.1269: completion: compl_shown_match is updated when starting keyword completion
- e3506ede27 9.1.1272: completion: in keyword completion Ctrl_P cannot go back after Ctrl_N
- a92155b86b 9.1.1286: filetype: help files not detected when 'iskeyword' includes ":" (#33377)
- b694131c3b 9.1.1303: missing out-of-memory check in linematch.c (#33487)
- 0c315feddf 9.1.1305: completion menu active after switching windows/tabs (#33488)
- 12298be0fe 9.1.1310: completion: redundant check for preinsert effect (#33505)
- 4205fdee1d 9.1.1314: max allowed string width too small
- 248528c907 9.1.1317: noisy error when restoring folds from session fails
- 1a6ddeee41 9.1.1318: tests: test_format fails
- 448c2cec9d 9.1.1337: Undo corrupted with 'completeopt' "preinsert" when switching buffer (#33600)
2025-04-26 16:29:18 +02:00
Yi Ming
478f5d0070 fix(lsp): cycling signatures with the default config.focusable
(cherry picked from commit 342974773c)
2025-04-26 13:55:12 +00:00
Yi Ming
95f96a3d1b fix(lsp): prioritize showing active signature
(cherry picked from commit 9e93bfdb5f)
2025-04-26 13:55:12 +00:00
Luuk van Baal
9909580df2 fix(ui): exclude unfocusable windows from 'complete' "w" completion
Problem:  As in f85bc41, assume unfocusable windows to be UI windows
          whose buffer content is unexpectedly included in 'complete'
          "w" completion.
Solution: Exclude unfocusable windows when looping over windows.
(cherry picked from commit d01b2611a6)
2025-04-25 23:19:28 +00:00
Justin M. Keyes
66953b16a2 feat(lsp): workspace_required (#33608)
Problem:
Some language servers do not work properly without a workspace folder.

Solution:
Add `workspace_required`, which skips starting the lsp client if no
workspace folder is found.

Co-authored-by: Michael Strobel <71396679+Kibadda@users.noreply.github.com>
2025-04-24 07:06:30 -07:00
zeertzjq
448c2cec9d vim-patch:9.1.1337: Undo corrupted with 'completeopt' "preinsert" when switching buffer (#33600)
Problem:  Undo corrupted with 'completeopt' "preinsert" when switching
          buffer or window.
Solution: Do not delete preinsert text when switching buffer or window.
          (zeertzjq)

related: neovim/neovim#33581
closes: vim/vim#17193

1343681aba
(cherry picked from commit 63689deb45)
2025-04-24 00:45:04 +00:00
Luuk van Baal
c1d3777db2 fix(snippet): use <cmd>call cursor() for visual range
Problem:  Change applied in d3e495ce uses a byte-offset where a virtual
          column is expected.
Solution: Set the cursor directly through a <Cmd> mapping, while making
          sure the commands are ordered correctly by adding them to the
          type-ahead buffer.
(cherry picked from commit 019b2050e1)
2025-04-23 09:24:54 +00:00
zeertzjq
155529b91a fix(events): avoid superfluous CursorMovedI on first autocmd (#33588)
(cherry picked from commit 1dbede5b93)
2025-04-23 03:47:35 +00:00
zeertzjq
c633250cc0 Merge pull request #33589 from zeertzjq/backport
vim-patch:9.1.1305: completion menu active after switching windows/tabs (#33488)
2025-04-23 11:42:36 +08:00
zeertzjq
0c315feddf vim-patch:9.1.1305: completion menu active after switching windows/tabs (#33488)
Problem:  When switching to another window or tab page while the
          completion menu is active, the menu stays visible, although it
          belongs to the previous window/tab page context (Evgeni
          Chasnovski).
Solution: Track the window and tab page where completion started. Detect
          changes in the main editing loop and cancel completion mode if
          the current window or tab page differs from where completion
          started.

fixes: vim/vim#17090
closes: vim/vim#17101

cf7f01252f

Co-authored-by: glepnir <glephunter@gmail.com>
2025-04-23 11:09:01 +08:00
Gregory Anders
646a8f663e fix(tui): ensure all pending escape sequences are processed before exiting #32151
Problem:
Neovim disables a number of terminal modes when it exits, some of which
cause the terminal to send asynchronous events to Neovim. It's possible
that Neovim exits before the terminal has received and processed all of
the sequences to disable these modes, causing the terminal to emit one
of these asynchronous sequences after Neovim has already exited. If this
happens, then the sequence is received by the user's shell (or some
other program that is not Neovim).

Solution:
When Neovim exits, it now emits a Device Attributes request (DA1)
after disabling all of the different modes. When the terminal responds
to this request we know that it has already received all of our other
sequences disabling the other modes. At that point, it should not be
emitting any further asynchronous sequences. This means the process of
exiting Neovim is now asynchronous as well since it depends on receiving
the DA1 response from the terminal.

(cherry picked from commit 82f08f33c1)
2025-04-22 12:51:47 +00:00
luukvbaal
b9c9b15ad7 perf(snippet): use "[count]|" to move cursor #33571
Problem:
Flicker when using vim.snippet.jump().

Solution:
Pass count instead of multiple <right> keys.

(cherry picked from commit d3e495ce03)
2025-04-22 12:21:35 +00:00
luukvbaal
fb71d631a5 fix(api): wrong return value with reverse range + overlap #32956
Problem:  When iterating in reverse with {start} > {end} in
          `nvim_buf_get_extmarks()`, marks that overlap {start} and are
          greater than {end} are included in the return value twice.
          Marks that overlap {end} and do not overlap {start} are not
          not included in the return value at all. Marks are not
          actually returned in a meaningful "traversal order".

Solution: Rather than actually iterating in reverse, (also possible but
          requires convoluted conditions and would require fetching
          overlapping marks for both the {start} and {end} position,
          while still ending up with non-traversal ordered marks),
          iterate normally and reverse the return value.
(cherry picked from commit 65170e8dad)
2025-04-21 23:49:27 +00:00
luukvbaal
3b0c88a537 fix(messages): single msg_show event for multiple :set options #33555
Problem:  :set opt1 opt2... emits a separate event for each option.

Solution: Only set the kind for the first printed option value.
(cherry picked from commit 986b92eb07)
2025-04-21 16:23:38 +00:00
zeertzjq
1a6ddeee41 vim-patch:9.1.1318: tests: test_format fails
Problem:  tests: test_format fails (after 9.1.1314).
Solution: Increase the string size.  Add missing test_format.res in
          NEW_TESTS_RES (zeertzjq).

closes: vim/vim#17144

e9a27ef373
(cherry picked from commit 0251a25541)
2025-04-19 00:12:55 +00:00
zeertzjq
4205fdee1d vim-patch:9.1.1314: max allowed string width too small
Problem:  max allowed string width too small
Solution: increased MAX_ALLOWED_STRING_WIDTH from 6400 to 1MiB
          (Hirohito Higashi)

closes: vim/vim#17138

06fdfa11c5

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: John Marriott <basilisk@internode.on.net>
(cherry picked from commit ccdb37b075)
2025-04-19 00:12:55 +00:00
zeertzjq
248528c907 vim-patch:9.1.1317: noisy error when restoring folds from session fails
Problem:  noisy error when restoring folds from session fails
Solution: ignore errors silently when sourcing session file.
          (Igor Lacerda)

fixes: vim/vim#15813
closes: vim/vim#17127

cca5dea76e

Co-authored-by: Igor Lacerda <igorlfs@ufmg.br>
(cherry picked from commit e2e6c159d3)
2025-04-18 01:04:01 +00:00
zeertzjq
b7de104d86 vim-patch:9.1.0721: tests: test_mksession does not consider XDG_CONFIG_HOME
Problem:  tests: test_mksession does not consider XDG_CONFIG_HOME
Solution: allow to match $HOME/.vim/ and $HOME/.config/vim for &viewdir
          (John M Devin)

closes: vim/vim#15639

5b9237c2e7

Co-authored-by: John M Devin <john.m.devin@gmail.com>
(cherry picked from commit 0eb708aa8a)
2025-04-18 01:04:01 +00:00
zeertzjq
cdd3f2a2e6 vim-patch:9.0.1654: MS-Windows: test for default 'viewdir' fails
Problem:    MS-Windows: test for default 'viewdir' fails.
Solution:   Escape the pattern.

813b7a85f2

Co-authored-by: Bram Moolenaar <Bram@vim.org>
(cherry picked from commit bd0555ecd4)
2025-04-18 01:04:01 +00:00
zeertzjq
a97713485d vim-patch:9.0.1653: Amiga: default 'viewdir' may not work
Problem:    Amiga: default 'viewdir' may not work.
Solution:   Use "home:" instead of "$VIM". Add a test. (Christian Brabandt,
            closes vim/vim#12576)

b8b1c8ebd4

Cherry-pick Test_mkview_manual_fold() changes from 9.0.{0363,0626}.

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 827cfe4a76)
2025-04-18 01:04:01 +00:00
zeertzjq
12298be0fe vim-patch:9.1.1310: completion: redundant check for preinsert effect (#33505)
Problem:  Duplicate check for preinsert effect, particularly for Ctrl_w
          and Ctrl_U.
Solution: Remove the specific check for Ctrl_w and Ctrl_U to eliminate
          redundancy (glepnir).

closes: vim/vim#17129

1c2b258250

Co-authored-by: glepnir <glephunter@gmail.com>
(cherry picked from commit f9f6dc4262)
2025-04-17 23:25:23 +00:00
Au.
2435d72283 fix(lsp): opts.reuse_win does not jump if buf is already open #33476
Problem:
`vim.lsp.buf.[implementation|definition|...]({ reuse_win = true })` does not
jump cursor to existing window if buffer is already open.

Steps to reproduce:
1. `nvim repro.lua`
2. Insert anything that lsp can read to open the library definition/implementation, e.g., `vim.keymap.set`
3. open `repro.lua` buffer and the library buffer side by side.
4. type `gd` over `set` to jump to the library definition.

The open buffer is scrolled to the target line, but cursor does not jump.

Solution:
Call nvim_set_current_win if necessary.

(cherry picked from commit 6926fc1615)
2025-04-17 15:12:46 +00:00
yuukibarns
e342b9a25a fix(treesitter): fix :InspectTree incorrect injections
(cherry picked from commit 284b0e4fa2)
2025-04-16 14:31:32 +00:00
Justin M. Keyes
4422b9bbd0 fix(vim.system): unclear non-executable message #33455
Problem:
When a command is not found or not executable, the error message gives
no indication about what command was actually tried.

Solution:
Always append the command name to the error message.

BEFORE:

    E5108: Error executing lua …/_system.lua:248: ENOENT: no such file or directory

AFTER:

    E5108: Error executing lua …/_system.lua:249: ENOENT: no such file or directory: "foo"

fix #33445

(cherry picked from commit 223ac7782e)
2025-04-16 12:38:46 +00:00
Dmitry Torokhov
dcd5e4574a fix(mouse): do not fetch clipboard twice when pasting with middle button #33494
Problem:
When doing paste operation mouse code tries to figure out it it is
dealing with a multi-line register by calling yank_register_mline(),
which fetches register data and checks its type. Later the code calls
either do_put() or insert_reg() which fetch register data again. This is
unnoticeable when working with internal neovim registers, but starts
hurting when dealing with clipboards, especially remote one (forwarded X
or socket tunnel or similar).

Solution:
Change yank_register_mline() to also return pointer to the
register structure prepared for pasting, and insert_reg() to accept
such register pointer and use it if it is supplied. do_put() already
has support for accepting a register structure to be used for pasting.

Fixes #33493

(cherry picked from commit 7432781e71)
2025-04-16 10:50:01 +00:00
zeertzjq
b694131c3b vim-patch:9.1.1303: missing out-of-memory check in linematch.c (#33487)
Problem:  missing out-of-memory check in linematch.c
Solution: return early in case of memory allocation failure, move the
          pow() calculation ouside of the for() loop
          (John Marriott)

closes: vim/vim#17118

2137710b43

Co-authored-by: John Marriott <basilisk@internode.on.net>
(cherry picked from commit d2d1b5e944)
2025-04-15 23:37:37 +00:00
luukvbaal
4d87229789 fix(marks): clamp conceal_lines corrected line number #33464
Problem:  Line number corrected for conceal_lines may be set beyond eob
          when the last buffer line is concealed, causing ml_get errors.

Solution: Avoid setting line number beyond eob.
(cherry picked from commit 3341ab0776)
2025-04-14 11:38:29 +00:00
zeertzjq
e4007551c4 fix(completion): avoid freeing uninitialized value (#33459)
(cherry picked from commit 51caf0a3af)
2025-04-14 05:31:00 +00:00
luukvbaal
526444c4ff fix(mouse): mouseclick after conceal_lines is miscalculated #33451
Problem:  Computed buffer line for mouse position does not take into
          account concealed lines on the reached row.

Solution: Adjust for concealed lines at the end of the loop computing
          the buffer position.
(cherry picked from commit 2f8fb4f28a)
2025-04-13 21:57:00 +00:00
Emanuel Krollmann
8aa49a8e9b fix(man.lua): useless executability check #33438
Problem:
executability check using `uv.fs_access`
doesn't work currently and can't work on windows

Solution:
only check for executable with `vim.fn.executable`

(cherry picked from commit b8763cb215)
2025-04-12 23:53:54 +00:00
neovim-backports[bot]
2b14447803 fix(man.lua): noisy "ENOENT" error on Windows #33435
Problem:
:Man shows noisy "ENOENT: no such file or directory" error on Windows.

Solution:
Do some checks before calling `vim.system`.

(cherry picked from commit a8dd5c7e41)

Co-authored-by: Emanuel Krollmann <115734183+Sodastream11@users.noreply.github.com>
2025-04-12 15:53:32 -07:00
Justin M. Keyes
7384983721 docs: clipboard, eval #33328 2025-04-12 10:56:28 -07:00
luukvbaal
b8e5fd51fd fix(column): don't count signs on lines beyond eob #33410
Problem:  Computed previous buffer line count may be beyond end of
          buffer. This results in signs being removed from `b_signcols`
          that were never included in it, tripping an assertion.

Solution: Store the previous line count as it was before appending or
          deleting lines. Use it to clamp the edited region when
          clearing signs before a splice, after which it is reset.
(cherry picked from commit 4a706a7092)
2025-04-11 12:28:22 +00:00
luukvbaal
9da90af0f7 fix(marks): wrong display after inserting/deleting lines #33389
Problem:  Lines to/from which virt_lines or inline virt_text may have
          moved are left valid. Similarly the modified region may be
          too small to account for moved decorations after inserting
          or deleting lines. `redrawOneLine()` can be replaced with
          a call to `changed_lines_redraw_buf()`.

Solution: Invalidate the line after a change if there is virt_lines, or
          inline virt_text in the buffer with 'wrap' enabled. Extend the
          modified region for inserted or deleted lines if there may be
          decorations in the buffer. Remove `redrawOneLine()`.
          Simplify the logic for `changed_lines_invalidate_win()`.

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
(cherry picked from commit 064ff74cdb)
2025-04-11 12:03:53 +00:00
Siddhant Agarwal
b5158e8e92 fix(lsp): "bold" border for vim.lsp.buf.hover #33395
Problem: vim.lsp.buf.hover allows a bold border size which hasn't been
defined

Solution: Define the bold border size for vim.lsp.buf.hover
(cherry picked from commit f068386c9f)
2025-04-09 11:57:22 +00:00
jyn
837faf7065 fix(editor): respect [+cmd] when executing :drop #33339
Problem:
Normally, `:drop +41 foo.txt` will open foo.txt with the cursor on line
41. But if foo.txt is already open, it instead is a no-op, even if the
cursor is on a different line.

Steps to reproduce:

    nvim --clean foo.txt
    :drop +30 foo.txt

Solution:
Handle +cmd in ex_drop().

(cherry picked from commit 3647b821ea)
2025-04-08 13:47:08 +00:00
luukvbaal
c4a19bff4e fix(display): scroll redrawing doesn't account for virt_lines above fold #33374
Problem:  Logic computing the new height of the modified area does not
          take into account virtual lines attached to a folded line.

Solution: Remove `hasFolding()` branch and let `plines_win_full()` do its job.
(cherry picked from commit 5b1561bb71)
2025-04-08 13:20:27 +00:00
zeertzjq
a92155b86b vim-patch:9.1.1286: filetype: help files not detected when 'iskeyword' includes ":" (#33377)
Problem:  Help files not detected when 'iskeyword' includes ":".
Solution: Do not use \< and \> in the pattern (zeertzjq).

fixes: vim/vim#17069
closes: vim/vim#17071

e370141bf4
(cherry picked from commit 8af9f8ab5e)
2025-04-08 00:52:17 +00:00
luukvbaal
6e51d39696 fix(decor): enable decoration provider in on_start #33337
Problem:  An on_win-disabled decoration provider is left disabled for
          the on_buf callback during the next redraw (if the provider
          does not subscribe to on_end).

Solution: Move re-activation of the provider from after the on_end
          callback to before the on_start callback.
(cherry picked from commit ca16b54c86)
2025-04-07 11:33:43 +00:00
Dmitry Zolotukhin
4c1121bd33 fix(treesitter): not refreshing virtualtext contents #33361
Problem: In some cases, when treesitter is enabled, deleting a
line below virtualtext will not refresh all updated lines.
https://github.com/neovim/neovim/issues/33358

Solution: Revert a part of https://github.com/neovim/neovim/pull/31324
to ensure that the full range (with virtual lines) is refreshed.

(cherry picked from commit cf59631f65)
2025-04-07 11:30:12 +00:00
Felipe Lema
c158d41cec fix(health): expecting nonexistent "inotifywait" function #33312
Problem:
55e4301036 changed the program name but not the function name.

Solution:
Fix the healthcheck.

(cherry picked from commit bd37348939)
2025-04-07 09:40:09 +00:00
Emanuel Krollmann
2182272139 fix(defaults): keywordprg=:help on Windows #33336
Problem:
As `:h kp` says, the default value for keywordprg
should be ':help' on Windows. It is currently
always ':Man'.

Solution:
Add condition to options.lua which sets keywordprg
to ':help' if running on windows.

(cherry picked from commit 3ebde5ea14)
2025-04-07 09:35:36 +00:00
phanium
29011e4d45 fix(vim.hl): nvim_buf_del_extmark on invalid buffer #33331
Problem:
nvim_buf_del_extmark error if buffer is destroyed before timer stops

Solution:
check nvim_buf_is_valid.

(cherry picked from commit 28e8190185)
2025-04-05 23:19:19 +00:00
Lewis Russell
91481ae7d5 fix: bug in stylize_markdown
`stripped` and `markdown_lines` are iterated together so must have the same length.

(cherry picked from commit 379c37fa0b)
2025-04-04 14:08:52 +00:00
luukvbaal
3df9db58dc fix(messages): verbose message emitted without kind #33305
Problem:  Successive autocmd verbose messages may be emitted without a kind.

Solution: Always set the kind when preparing to emit a verbose message.
(cherry picked from commit 98f5aa2564)
2025-04-04 12:53:23 +00:00
glepnir
e3506ede27 vim-patch:9.1.1272: completion: in keyword completion Ctrl_P cannot go back after Ctrl_N
Problem:  completion: in keyword completion Ctrl_P cannot go back after
          Ctrl_N
Solution: in find_compl_when_fuzzy() always return first match of array, after Ctrl_P
          use compl_shown_match->cp_next instead of compl_first_match.
          (glepnir)

closes: vim/vim#17043

3e50a28a03

Co-authored-by: glepnir <glephunter@gmail.com>
(cherry picked from commit b01921cb55)
2025-04-04 06:40:34 +00:00
glepnir
02bf23b4bf vim-patch:9.1.1269: completion: compl_shown_match is updated when starting keyword completion
Problem:  compl_shown_match is updated when starting keyword completion
          and does not include fuzzy matching.
Solution: Do not update compl_shown_match when starting keyword
          completion, since it is the one already selected by the
          keyword completion direction. (glepnir)

closes: vim/vim#17033

e4e4d1c381

Co-authored-by: glepnir <glephunter@gmail.com>
(cherry picked from commit 8cf413e450)
2025-04-04 06:40:34 +00:00
tstsrt
cbf4906c11 test(plugin/shada_spec): failure if timezone isn't a whole hour ahead of UTC (#33257)
Problem: When running functional tests locally, test `syntax/shada.vim works`
fails if the local timezone is not a whole number of hours ahead of UTC.

Solution: Use '!%M' for minute format so that UTC is used in the expected
timestamp instead of the local timezone, just like '%H' for hours.

(cherry picked from commit d9405c7935)
2025-04-04 04:24:11 +00:00
zeertzjq
4cc97cf009 Merge pull request #33295 from siddhantdev/backport-33283-to-release-0.11
feat(vim.hl): allow multiple timed highlights simultaneously #33283
2025-04-04 09:50:29 +08:00
zeertzjq
c6ef13dc45 test(lua/hl_spec): fix hang on exit with ASAN (#33298) 2025-04-04 09:25:39 +08:00
zeertzjq
1a2d0484ac docs: news.txt 2025-04-04 09:25:14 +08:00
Siddhant Agarwal
5829b5de0a feat(vim.hl): allow multiple timed highlights simultaneously #33283
Problem: Currently vim.hl.range only allows one timed highlight.
Creating another one, removes the old one.

Solution: vim.hl.range now returns a timer and a function. The timer
keeps track of how much time is left in the highlight and the function
allows you to clear it, letting the user decide what to do with old
highlights.

(cherry picked from commit eae2d3b145)
2025-04-04 00:14:43 +05:30
Evgeni Chasnovski
dd547ef1ea docs(diagnostic): mention severity in Opts.VirtualLines (#33293)
Problem: `severity` field is recognized by
  `vim.diagnostic.Opts.VirtualLines`, but it is not explicitly
  documented.

Solution: document it.
(cherry picked from commit 71e133e5e6)
2025-04-03 16:49:58 +00:00
Deveshi Dwivedi
91d11c8bc1 feat(clipboard): g:clipboard="foo" forces the "foo" clipboard tool #33235
(cherry picked from commit 9722bd7b1b)
2025-04-03 14:26:45 +00:00
zeertzjq
1daea6e1fd test(lua/secure_spec): fix failure with long path (#33280)
Ref #33278

(cherry picked from commit 974a3aa2c4)
2025-04-03 13:56:49 +00:00
luukvbaal
279a0e78c9 fix(highlight): no match highlight during :substitute prompt #33262
Problem:  Redrawing during a substitute confirm prompt causes the match
          highlight to disappear.
Solution: Unset `highlight_match` after the prompt has returned.
          Use global highlight definitions in searchhl_spec.lua.
(cherry picked from commit 3af43cffa0)
2025-04-02 12:48:35 +00:00
tstsrt
5fc6bd6454 fix(api): nvim_set_keymap() throws error even in pcall() #33228
Problem: When `nvim_set_keymap` tries to overwrite a `<unique>` mapping,
it throws an error even when called in `pcall`.

Solution: src/nvim/mapping.c:buf_do_map no longer calls `semsg`. Its
callers now decide whether to ignore the error, or use
`semsg` (not caught)/`api_set_error` (caught by `pcall`).

(cherry picked from commit ec18ebcb41)
2025-04-01 15:50:54 +00:00
zeertzjq
2b2a90051e fix(api): use E226 instead of E227 for duplicate abbreviation (#33159)
(cherry picked from commit 99529577cc)
2025-04-01 15:04:03 +00:00
Lewis Russell
1e8e74dbff fix(lsp): better handling of "*" configs
Problem:

If a config name contains "*" it causes rtp discovery of `lsp/` to
consider the `*` as a wildcard and could lead to strange and unintended
behaviour. For example, accessing the `'*'` config from a `lsp/` file
would cause an infinite loop.

Solution:

- Explicitly disallow a config name from containing wildcards, with the
  exception of `'*'`.
- When Resolving `'*'` config, skip the rtp step.

(cherry picked from commit 2ee896201c)
2025-04-01 13:54:47 +01:00
luukvbaal
a4b6705e87 fix(window): crash on negative window height with 'winbar' #33250
Problem:  Negative window and grid height with 'winbar'.
Solution: Clamp the height when subtracting the 'winbar' height.
(cherry picked from commit 0e7479bb76)
2025-04-01 12:28:28 +00:00
Sean Dewar
f68e0fed26 docs(eval): fix dict param type of mapset
Match maparg's return type.

(cherry picked from commit ec6670080a)
2025-04-01 10:21:42 +00:00
Sean Dewar
09fd22d5d7 docs(eval): fix lnum type for functions using tv_get_lnum
These occurrences also accept string, which is used like in getline.

Also make the lnum field of vim.fn.sign_placelist.list.item optional, as it can
be omitted like vim.fn.sign_place.dict's.

(cherry picked from commit 4a36f234ac)
2025-04-01 10:21:42 +00:00
luukvbaal
326eacef93 fix(move): adjust for concealed lines above topline after scrolling up (#33211)
Problem:  Scrolling up does not adjust `w_topline` for concealed lines
          directly above it, resulting in (non-visual) asymmetry when
          scrolling up/down.
Solution: Adjust `w_topline` for concealed lines after scrolling up.
(cherry picked from commit 32325a66ca)
2025-04-01 06:34:00 +00:00
luukvbaal
02123bac0d fix(display): wrong cursor column with 'concealcursor' = "n" and virt_text (#33218)
Problem:  Inline virtual text placed in a decor provider callback
          invalidates `w_virtcol`, which must be valid for `win_line()`.
Solution: Call `validate_virtcol()` after "line" decor provider callbacks.
(cherry picked from commit 7e8b7bba21)
2025-04-01 06:31:29 +00:00
zeertzjq
8d9b4d8c14 test(float): restore border tests (#33222)
(cherry picked from commit 04901f4ee7)
2025-04-01 00:01:17 +00:00
zeertzjq
55be20316a docs: remove duplicate news file (#33227) 2025-03-31 15:16:51 +00:00
glepnir
12da443930 feat(float): 'winborder' "bold" style #33189
(cherry picked from commit 216cc893bf)
2025-03-31 14:06:11 +00:00
Ghjuvan Lacambre
837c9d0409 fix(defaults): enable :terminal [[,]] motion in operator-pending mode #33217
This enables y]] to copy a command and its output.

(cherry picked from commit 57b4fb5c53)
2025-03-31 13:42:29 +00:00
Tan, Long
70f3e15298 fix(treesitter): don't memoize modified headings (#33186)
Problem: repeated gO in markdown etc. adds extra toc indentation

Solution: don't memoize heading table which gets modified
(cherry picked from commit 28eaec5e15)
2025-03-31 09:49:39 +00:00
neovim-backports[bot]
7e884b78bf fix(defaults): visual-mode [[,]] for :terminal shell prompts #33203
Problem:
:terminal shell prompt jump mappings ]]/[[ don't work in visual mode.

Solution:
Also define them for in visual mode.

(cherry picked from commit cb247e06f0)

Co-authored-by: msaher <77233589+msaher@users.noreply.github.com>
2025-03-30 13:17:46 -07:00
zeertzjq
89e0ea1788 fix(checkhealth): check outdated pynvim version properly #33175
Fixes #33174, a regression from #22962.

(cherry picked from commit e87d2ae383)
2025-03-30 17:01:35 +00:00
Bartłomiej Maryńczak
9056c01a95 fix(vim.lsp.inlay_hint): requesting inlay_hints even when disabled #32999
Problem:
Nvim needlessly requests inlay_hints even if they are disabled for a given buffer.

Solution:
Add the missing `enabled` check in `on_refresh`.
Rest of the code has this check already so that's the only needed one to fix this.

(cherry picked from commit 49756ebc70)
2025-03-30 16:07:09 +00:00
Phạm Bình An
d2dd403693 docs: faq, lua packages #33183
Problem:
- `health#check()` seems to have been removed for a while, but `:h faq`
  still refers to it.
- `news-0.11.txt` doesn't mention #33044
2025-03-30 17:22:52 +02:00
zeertzjq
2084cda6f9 vim-patch:9.1.1260: Hang when filtering buffer with NUL bytes (#33192)
Problem:  Hang when filtering buffer with NUL bytes (after 9.1.1050).
Solution: Don't subtract "written" from "lplen" repeatedly (zeertzjq).

related: neovim/neovim#33173
closes: vim/vim#17011

53fed23cb7
(cherry picked from commit 431c037709)
2025-03-30 14:34:33 +00:00
neovim-backports[bot]
7efb3ba6f7 feat(checkhealth): use emoji for OK/WARN/ERROR (#33195)
Problem:
Health status can be much more visually distinct.

Solution:
Use emoji next to each status.

(cherry picked from commit 75fe540500)

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-03-30 07:04:01 -07:00
neovim-backports[bot]
649bce6e73 fix(provider): misleading :checkhealth if user sets g:loaded_python3_provider=1 #32696
Problem:
:checkhealth shows a confusing message if user sets
g:loaded_python3_provider=1.

Solution:
- Show a warning if that var is set to 1.
- Update provider modules to default to 0. Any user code that is
  checking for 1, is like already broken because these may be set to 2.

(cherry picked from commit b4906577c9)

Co-authored-by: Sathya Pramodh <94102031+sathya-pramodh@users.noreply.github.com>
2025-03-30 08:09:07 +08:00
Justin M. Keyes
fcee5df0fc fix(checkhealth): check g:loaded_xx_provider for all providers #33168
(cherry picked from commit 5f9f5bc04d)
2025-03-29 21:09:55 +00:00
Daniel Kusai
2a04161a35 fix(desktop): cannot open filename with spaces using OS file manager #33161
Problem:
When activated from OS "filetype handling", Nvim cannot handle filenames containing spaces.

Solution:
Quote the filename in the .desktop config.

(cherry picked from commit 6e12ef4a7b)
2025-03-29 16:17:04 +00:00
phanium
adfd4b9f4f fix(checkhealth): don't override user "q" keymap #33132
(cherry picked from commit 78d2e0b43e)
2025-03-29 13:58:03 +00:00
Gregory Anders
056dbf3ea7 fix(api): use original LHS in keymap error message #33135
When setting a keymap with "unique" that already exists the error
message contains the LHS of the keymap with termcodes replaced. In
particular this means that keys like <Tab> show as an actual tab
character, meaning the error message displays as "Mapping already exists
for ", which is hard to debug for users.

Instead, display the original LHS (without any simplification or parsed
termcodes). This rperesents exactly what the user passed to the `lhs`
argument of `nvim_set_keymap`, which makes it easier to find where the
offending keymap is.

(cherry picked from commit 0d73ec5834)
2025-03-29 13:48:06 +00:00
zeertzjq
c57a36cd59 fix(pum): fix heap-buffer-overflow with 'rightleft' (#33146)
(cherry picked from commit 2681e1fce3)
2025-03-29 02:58:38 +00:00
luukvbaal
06df3e0c0d fix(cmdline): avoid empty @: register after :<CR> (#33126)
Fix https://github.com/neovim/neovim/issues/33125

(cherry picked from commit f4ee0ab2f1)
2025-03-28 21:57:24 +00:00
Micah Halter
a9afa6b152 fix(lsp): warn on missing config in :checkhealth #33087
Problem
When calling `:checkhealth vim.lsp` after the user has enabled a language
server with `vim.lsp.enable` that has no configuration a runtime error
is hit because the code expects for a configuration to exist.

Solution:
Check if a configuration was returned before parsing it, if it isn't
returned then warn the user that the server has been enabled but a
configuration was not found.

(cherry picked from commit 5554fcc286)
2025-03-28 13:17:38 +00:00
v1nh1shungry
bbf912d72f fix(provider)!: drop Python 3.7, 3.8 support #33088
Problem: #33022 didn't update `min_version` to 3.9, therefore Python 3.7
and 3.8 are still available.

Solution: Update `min_version` to 3.9.
(cherry picked from commit ade58885c4)
2025-03-28 12:36:02 +00:00
luukvbaal
53def2a877 fix(cmdline): empty ext_cmdline block events for :<CR> #33118
Problem:  An ext_cmdline block event that should be empty after :<CR>
          re-emits the previous cmdline.
Solution: Clear `last_cmdline` even when `new_last_cmdline == NULL`.
(cherry picked from commit 95ab723995)
2025-03-28 12:11:56 +00:00
Shadman
c61e8c6e70 fix(mouse): crash with click on win-separator in statusline (#33091)
Problem: Clicking on window separator in statusline crashes Nvim due
to out of bound memory access

Solution: Check if the click location is within clicking range before
applying it.

(cherry picked from commit 18fa61049a)
2025-03-28 07:32:24 +00:00
zeertzjq
6514e2c7ba vim-patch:9.1.1247: fragile setup to get (preferred) keys from key_name_entry (#33102)
Problem:  fragile setup to get (preferred) keys from key_name_entry
          (after v9.1.1179)
Solution: refactor the code further, fix a bug with "pref_name" key
          entry introduced in v9.1.1180 (Yee Cheng Chin)

The optimization introduced for using bsearch() with key_name_entry
in vim/vim#16788 was fragile as it required synchronizing a non-obvious index
(e.g. IDX_KEYNAME_SWU) with the array that could be accidentally changed
by any one adding a key to it. Furthermore, the "pref_name" that was
introduced in that change was unnecessary, and in fact introduced a bug,
as we don't always want to use the canonical name.

The bug is triggered when the user triggers auto-complete using a
keycode, such as `:set <Scroll<Tab>`. The bug would end up showing two
copies of `<ScrollWheelUp>` because both entries end up using the
canonical name.

In this change, remove `pref_name`, and simply use a boolean to track
whether an entry is an alt name or not and modify logic to respect that.

Add test to make sure auto-complete works with alt names

closes: vim/vim#16987

7d8e7df551

In Nvim there is no `enabled` field, so put `is_alt` before `name` to
reduce the size of the struct.

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
(cherry picked from commit ae98d0a560)
2025-03-28 00:28:03 +00:00
Eisuke Kawashima
06c2886569 fix(health): message should mention "vim.provider" #33095
(cherry picked from commit 07f048a8d7)
2025-03-27 23:49:03 +00:00
luukvbaal
2cd735d159 fix(display): scroll logic does not take into account concealed topline (#33054)
(cherry picked from commit ce0c0c31a0)
2025-03-27 13:55:34 +00:00
luukvbaal
ccb078bbb0 fix(ui): wincmd _ should not increase 'cmdheight' above 0 (#33056)
(cherry picked from commit 703f4037c4)
2025-03-27 13:08:16 +00:00
Justin M. Keyes
5e4365b83d version bump 2025-03-26 15:13:05 +01:00
343 changed files with 11170 additions and 3962 deletions

View File

@@ -1,9 +1,17 @@
# This script enables Developer Command Prompt
# See https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt#using-powershell
$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($installationPath -and (Test-Path "$installationPath\Common7\Tools\vsdevcmd.bat")) {
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | ForEach-Object {
$name, $value = $_ -split '=', 2
"$name=$value" >> $env:GITHUB_ENV
}
if ($env:BUILD_ARCH -eq "arm64") {
$arch = "arm64"
$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.arm64 -property installationPath
} else {
$arch = "x64"
$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
}
if ($installationPath) {
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=$arch -no_logo && set" |
ForEach-Object {
$name, $value = $_ -split '=', 2
"$name=$value" >> $env:GITHUB_ENV
}
}

View File

@@ -2,21 +2,26 @@
${NVIM_VERSION}
```
## Release notes
- [Changelog](https://github.com/neovim/neovim/commit/${NVIM_COMMIT}) (fixes + features)
- [News](./runtime/doc/news.txt) (`:help news` in Nvim)
## Install
### Windows
#### Zip
1. Download **nvim-win64.zip**
1. Download **nvim-win64.zip** (or **nvim-win-arm64.zip** for ARM)
2. Extract the zip
3. Run `nvim.exe` on your CLI of choice
3. Run `nvim.exe` in your terminal
#### MSI
1. Download **nvim-win64.msi**
1. Download **nvim-win64.msi** (or **nvim-win-arm64.msi** for ARM)
2. Run the MSI
3. Run `nvim.exe` on your CLI of choice
3. Run `nvim.exe` in your terminal
Note: On Windows "Server" you may need to [install vcruntime140.dll](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
@@ -75,5 +80,3 @@ If your system does not have the [required glibc version](https://neovim.io/doc/
### Other
- Install by [package manager](https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-package)
## SHA256 Checksums

View File

@@ -132,27 +132,44 @@ jobs:
windows:
needs: setup
runs-on: windows-2019
strategy:
matrix:
include:
- runner: windows-2022
arch: x86_64
archive_name: nvim-win64
- runner: windows-11-arm
arch: arm64
archive_name: nvim-win-arm64
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
with:
# Perform a full checkout #13471
fetch-depth: 0
- run: .github/scripts/env.ps1
env:
BUILD_ARCH: ${{ matrix.arch }}
- name: Install Wix
run: |
Invoke-WebRequest -Uri "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip" -OutFile "wix314-binaries.zip"
Expand-Archive -Path "wix314-binaries.zip" -DestinationPath "C:/wix"
echo "C:\wix" >> $env:GITHUB_PATH
- name: Build deps
run: |
cmake -S cmake.deps -B .deps -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}
cmake --build .deps
- name: build package
- name: Build package
run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}
cmake --build build --target package
- uses: actions/upload-artifact@v4
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: nvim-win64
name: nvim-win-${{ matrix.arch }}
path: |
build/nvim-win64.msi
build/nvim-win64.zip
build/${{ matrix.archive_name }}.zip
build/${{ matrix.archive_name }}.msi
retention-days: 1
publish:
@@ -193,25 +210,14 @@ jobs:
echo 'PRERELEASE=') >> $GITHUB_ENV
gh release delete stable --yes || true
git push origin :stable || true
# `sha256sum` outputs <sha> <path>, so we cd into each dir to drop the
# containing folder from the output.
- run: |
for i in nvim-*; do
(
cd $i || exit
sha256sum * >> $GITHUB_WORKSPACE/shasum.txt
)
done
- name: Publish release
env:
NVIM_VERSION: ${{ needs.linux.outputs.version }}
NVIM_COMMIT: ${{ github.sha }}
DEBUG: api
run: |
envsubst < "$GITHUB_WORKSPACE/.github/workflows/notes.md" > "$RUNNER_TEMP/notes.md"
echo '```' >> "$RUNNER_TEMP/notes.md"
cat shasum.txt >> "$RUNNER_TEMP/notes.md"
echo '```' >> "$RUNNER_TEMP/notes.md"
if [ "$TAG_NAME" != "nightly" ]; then
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/* shasum.txt
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win-x86_64/* nvim-win-arm64/*
fi
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/* shasum.txt
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win-x86_64/* nvim-win-arm64/*

View File

@@ -259,6 +259,29 @@ cmake --build build
- Using `ninja` is strongly recommended.
4. If treesitter parsers are not bundled, they need to be available in a `parser/` runtime directory (e.g. `/usr/share/nvim/runtime/parser/`).
### How to build static binary (on Linux)
1. Use a linux distribution which uses musl C. We will use Alpine Linux but any distro with musl should work. (glibc does not support static linking)
2. Run make passing the `STATIC_BUILD` variable: `make CMAKE_EXTRA_FLAGS="-DSTATIC_BUILD=1"`
In case you are not using Alpine Linux you can use a container to do the build the binary:
```bash
podman run \
--rm \
-it \
-v "$PWD:/workdir" \
-w /workdir \
alpine:latest \
bash -c 'apk add build-base cmake coreutils curl gettext-tiny-dev && make CMAKE_EXTRA_FLAGS="-DSTATIC_BUILD=1"'
```
The resulting binary in `build/bin/nvim` will have all the dependencies statically linked:
```
build/bin/nvim: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[sha1]=b93fa8e678d508ac0a76a2e3da20b119105f1b2d, with debug_info, not stripped
```
#### Debian 10 (Buster) example:
```sh

View File

@@ -141,8 +141,8 @@ endif()
# version string, else they are combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0)
set(NVIM_VERSION_MINOR 11)
set(NVIM_VERSION_PATCH 0)
set(NVIM_VERSION_PRERELEASE "") # for package maintainers
set(NVIM_VERSION_PATCH 5)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
# API level
set(NVIM_API_LEVEL 13) # Bump this after any API/stdlib change.

View File

@@ -273,7 +273,7 @@ If you need to modify or debug the documentation flow, these are the main files:
runtime/lua/vim/* => runtime/doc/lua.txt
runtime/lua/vim/lsp/ => runtime/doc/lsp.txt
src/nvim/api/* => runtime/doc/api.txt
src/nvim/eval.lua => runtime/doc/builtin.txt
src/nvim/eval.lua => runtime/doc/vimfn.txt
src/nvim/options.lua => runtime/doc/options.txt
```

View File

@@ -66,11 +66,13 @@ Several Neovim GUIs are available from scoop (extras): [scoop.sh/#/apps?q=neovim
You can then copy your spell files over (for English, located
[here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.spl) and
[here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.sug));
- For Python plugins you need the `pynvim` module. "Virtual envs" are recommended. After activating the virtual env do `pip install pynvim` (in *both*). Edit your `init.vim` so that it contains the path to the env's Python executable:
```vim
let g:python3_host_prog='C:/Users/foo/Envs/neovim3/Scripts/python.exe'
- For Python plugins you need the `pynvim` module. Installation via uv
(https://docs.astral.sh/uv/) is recommended; the `--upgrade` switch ensures
installation of the latest version:
```
- Run `:checkhealth` and read `:help provider-python`.
uv tool install --upgrade pynvim
```
- Run `:checkhealth` and read `:help provider-python` for more details.
- **init.vim ("vimrc"):** If you already have Vim installed you can copy `%userprofile%\_vimrc` to `%userprofile%\AppData\Local\nvim\init.vim` to use your Vim config with Neovim.

View File

@@ -73,7 +73,7 @@ if(HAS_OG_FLAG)
set(DEFAULT_MAKE_CFLAGS CFLAGS+=-Og ${DEFAULT_MAKE_CFLAGS})
endif()
set(DEPS_INCLUDE_FLAGS "-I${DEPS_INSTALL_DIR}/include -I${DEPS_INSTALL_DIR}/include/luajit-2.1")
set(DEPS_INCLUDE_FLAGS "-I\"${DEPS_INSTALL_DIR}/include\" -I\"${DEPS_INSTALL_DIR}/include/luajit-2.1\"")
# If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET),
# fall back to local system version. Needs to be done here and in top-level CMakeLists.txt.
@@ -96,10 +96,10 @@ else()
find_package(Lua 5.1 EXACT)
if(LUAJIT_FOUND)
set(LUA_ENGINE LuaJit)
string(APPEND DEPS_INCLUDE_FLAGS " -I${LUAJIT_INCLUDE_DIR}")
string(APPEND DEPS_INCLUDE_FLAGS " -I\"${LUAJIT_INCLUDE_DIR}\"")
elseif(LUA_FOUND)
set(LUA_ENGINE Lua)
string(APPEND DEPS_INCLUDE_FLAGS " -I${LUA_INCLUDE_DIR}")
string(APPEND DEPS_INCLUDE_FLAGS " -I\"${LUA_INCLUDE_DIR}\"")
else()
message(FATAL_ERROR "Could not find system lua or luajit")
endif()

View File

@@ -7,5 +7,6 @@ ExternalProject_Add(wasmtime
-D WASMTIME_FASTEST_RUNTIME=ON # build with full LTO
-D WASMTIME_DISABLE_ALL_FEATURES=ON # don't need all that crap...
-D WASMTIME_FEATURE_CRANELIFT=ON # ...except this one (compiles wasm to platform code)
-D WASMTIME_FEATURE_GC_DRC=ON # ...and this one (needed by ts to create engines)
USES_TERMINAL_BUILD TRUE
${EXTERNALPROJECT_OPTIONS})

View File

@@ -34,20 +34,20 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/v2.10.0.tar.gz
UTF8PROC_SHA256 6f4f1b639daa6dca9f80bc5db1233e9cbaa31a67790887106160b33ef743f136
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.4.tar.gz
TREESITTER_C_SHA256 b66c5043e26d84e5f17a059af71b157bcf202221069ed220aa1696d7d1d28a7a
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.3.0.tar.gz
TREESITTER_LUA_SHA256 a34cc70abfd8d2d4b0fabf01403ea05f848e1a4bc37d8a4bfea7164657b35d31
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.5.0.tar.gz
TREESITTER_VIM_SHA256 90019d12d2da0751c027124f27f5335babf069a050457adaed53693b5e9cf10a
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.1.tar.gz
TREESITTER_VIMDOC_SHA256 76b65e5bee9ff78eb21256619b1995aac4d80f252c19e1c710a4839481ded09e
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.5.1.tar.gz
TREESITTER_QUERY_SHA256 fe8c712880a529d454347cd4c58336ac2db22243bae5055bdb5844fb3ea56192
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.4.1.tar.gz
TREESITTER_MARKDOWN_SHA256 e0fdb2dca1eb3063940122e1475c9c2b069062a638c95939e374c5427eddee9f
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.3.tar.gz
TREESITTER_SHA256 862fac52653bc7bc9d2cd0630483e6bdf3d02bcd23da956ca32663c4798a93e3
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.24.1.tar.gz
TREESITTER_C_SHA256 25dd4bb3dec770769a407e0fc803f424ce02c494a56ce95fedc525316dcf9b48
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.4.0.tar.gz
TREESITTER_LUA_SHA256 b0977aced4a63bb75f26725787e047b8f5f4a092712c840ea7070765d4049559
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.7.0.tar.gz
TREESITTER_VIM_SHA256 44eabc31127c4feacda19f2a05a5788272128ff561ce01093a8b7a53aadcc7b2
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v4.0.0.tar.gz
TREESITTER_VIMDOC_SHA256 8096794c0f090b2d74b7bff94548ac1be3285b929ec74f839bd9b3ff4f4c6a0b
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.6.2.tar.gz
TREESITTER_QUERY_SHA256 90682e128d048fbf2a2a17edca947db71e326fa0b3dba4136e041e096538b4eb
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.5.0.tar.gz
TREESITTER_MARKDOWN_SHA256 14c2c948ccf0e9b606eec39b09286c59dddf28307849f71b7ce2b1d1ef06937e
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.6.tar.gz
TREESITTER_SHA256 ac6ed919c6d849e8553e246d5cd3fa22661f6c7b6497299264af433f3629957c
WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v29.0.1.tar.gz
WASMTIME_SHA256 b94b6c6fd6aebaf05d4c69c1b12b5dc217b0d42c1a95f435b33af63dddfa5304

View File

@@ -1,4 +1,4 @@
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|ARM64|aarch64)$")
set(CMAKE_SYSTEM_PROCESSOR arm64)
endif()
@@ -27,9 +27,13 @@ set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md)
if(WIN32)
set(CPACK_PACKAGE_FILE_NAME "nvim-win64")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CPACK_PACKAGE_FILE_NAME "nvim-win-arm64")
else()
set(CPACK_PACKAGE_FILE_NAME "nvim-win64")
endif()
set(CPACK_GENERATOR ZIP WIX)
# WIX
# CPACK_WIX_UPGRADE_GUID should be set, but should never change.
# CPACK_WIX_PRODUCT_GUID should not be set (leave as default to auto-generate).

View File

@@ -5,11 +5,11 @@
if exists('g:loaded_clipboard_provider')
finish
endif
" Default to 1. provider#clipboard#Executable() may set 2.
" Default to 0. provider#clipboard#Executable() may set 2.
" To force a reload:
" :unlet g:loaded_clipboard_provider
" :runtime autoload/provider/clipboard.vim
let g:loaded_clipboard_provider = 1
let g:loaded_clipboard_provider = 0
let s:copy = {}
let s:paste = {}
@@ -67,6 +67,113 @@ function! s:set_osc52() abort
return 'OSC 52'
endfunction
function! s:set_pbcopy() abort
let s:copy['+'] = ['pbcopy']
let s:paste['+'] = ['pbpaste']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
let s:cache_enabled = 0
return 'pbcopy'
endfunction
function! s:set_wayland() abort
let s:copy['+'] = ['wl-copy', '--type', 'text/plain']
let s:paste['+'] = ['wl-paste', '--no-newline']
let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain']
let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
return 'wl-copy'
endfunction
function! s:set_wayclip() abort
let s:copy['+'] = ['waycopy', '-t', 'text/plain']
let s:paste['+'] = ['waypaste', '-t', 'text/plain']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'wayclip'
endfunction
function! s:set_xsel() abort
let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
let s:paste['+'] = ['xsel', '-o', '-b']
let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
let s:paste['*'] = ['xsel', '-o', '-p']
return 'xsel'
endfunction
function! s:set_xclip() abort
let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
return 'xclip'
endfunction
function! s:set_lemonade() abort
let s:copy['+'] = ['lemonade', 'copy']
let s:paste['+'] = ['lemonade', 'paste']
let s:copy['*'] = ['lemonade', 'copy']
let s:paste['*'] = ['lemonade', 'paste']
return 'lemonade'
endfunction
function! s:set_doitclient() abort
let s:copy['+'] = ['doitclient', 'wclip']
let s:paste['+'] = ['doitclient', 'wclip', '-r']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'doitclient'
endfunction
function! s:set_win32yank() abort
if has('wsl') && getftype(exepath('win32yank.exe')) == 'link'
let win32yank = resolve(exepath('win32yank.exe'))
else
let win32yank = 'win32yank.exe'
endif
let s:copy['+'] = [win32yank, '-i', '--crlf']
let s:paste['+'] = [win32yank, '-o', '--lf']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'win32yank'
endfunction
function! s:set_putclip() abort
let s:copy['+'] = ['putclip']
let s:paste['+'] = ['getclip']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'putclip'
endfunction
function! s:set_clip() abort
let s:copy['+'] = ['clip']
let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'clip'
endfunction
function! s:set_termux() abort
let s:copy['+'] = ['termux-clipboard-set']
let s:paste['+'] = ['termux-clipboard-get']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'termux-clipboard'
endfunction
function! s:set_tmux() abort
let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V']))
if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0])
let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
else
let s:copy['+'] = ['tmux', 'load-buffer', '-']
endif
let s:paste['+'] = ['tmux', 'save-buffer', '-']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'tmux'
endfunction
let s:cache_enabled = 1
let s:err = ''
@@ -78,9 +185,34 @@ function! provider#clipboard#Executable() abort
" Setting g:clipboard to v:false explicitly opts-in to using the "builtin" clipboard providers below
if exists('g:clipboard') && g:clipboard isnot# v:false
if v:t_string ==# type(g:clipboard)
" Handle string form of g:clipboard for all builtin providers
if 'osc52' == g:clipboard
" User opted-in to OSC 52 by manually setting g:clipboard.
return s:set_osc52()
elseif 'pbcopy' == g:clipboard
return s:set_pbcopy()
elseif 'wl-copy' == g:clipboard
return s:set_wayland()
elseif 'wayclip' == g:clipboard
return s:set_wayclip()
elseif 'xsel' == g:clipboard
return s:set_xsel()
elseif 'xclip' == g:clipboard
return s:set_xclip()
elseif 'lemonade' == g:clipboard
return s:set_lemonade()
elseif 'doitclient' == g:clipboard
return s:set_doitclient()
elseif 'win32yank' == g:clipboard
return s:set_win32yank()
elseif 'putclip' == g:clipboard
return s:set_putclip()
elseif 'clip' == g:clipboard
return s:set_clip()
elseif 'termux' == g:clipboard
return s:set_termux()
elseif 'tmux' == g:clipboard
return s:set_tmux()
endif
endif
@@ -102,88 +234,29 @@ function! provider#clipboard#Executable() abort
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
return get(g:clipboard, 'name', 'g:clipboard')
elseif has('mac')
let s:copy['+'] = ['pbcopy']
let s:paste['+'] = ['pbpaste']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
let s:cache_enabled = 0
return 'pbcopy'
return s:set_pbcopy()
elseif !empty($WAYLAND_DISPLAY) && executable('wl-copy') && executable('wl-paste')
let s:copy['+'] = ['wl-copy', '--type', 'text/plain']
let s:paste['+'] = ['wl-paste', '--no-newline']
let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain']
let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
return 'wl-copy'
return s:set_wayland()
elseif !empty($WAYLAND_DISPLAY) && executable('waycopy') && executable('waypaste')
let s:copy['+'] = ['waycopy', '-t', 'text/plain']
let s:paste['+'] = ['waypaste', '-t', 'text/plain']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'wayclip'
return s:set_wayclip()
elseif !empty($DISPLAY) && executable('xsel') && s:cmd_ok('xsel -o -b')
let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
let s:paste['+'] = ['xsel', '-o', '-b']
let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
let s:paste['*'] = ['xsel', '-o', '-p']
return 'xsel'
return s:set_xsel()
elseif !empty($DISPLAY) && executable('xclip')
let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
return 'xclip'
return s:set_xclip()
elseif executable('lemonade')
let s:copy['+'] = ['lemonade', 'copy']
let s:paste['+'] = ['lemonade', 'paste']
let s:copy['*'] = ['lemonade', 'copy']
let s:paste['*'] = ['lemonade', 'paste']
return 'lemonade'
return s:set_lemonade()
elseif executable('doitclient')
let s:copy['+'] = ['doitclient', 'wclip']
let s:paste['+'] = ['doitclient', 'wclip', '-r']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'doitclient'
return s:set_doitclient()
elseif executable('win32yank.exe')
if has('wsl') && getftype(exepath('win32yank.exe')) == 'link'
let win32yank = resolve(exepath('win32yank.exe'))
else
let win32yank = 'win32yank.exe'
endif
let s:copy['+'] = [win32yank, '-i', '--crlf']
let s:paste['+'] = [win32yank, '-o', '--lf']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'win32yank'
return s:set_win32yank()
elseif executable('putclip') && executable('getclip')
let s:copy['+'] = ['putclip']
let s:paste['+'] = ['getclip']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'putclip'
return s:set_putclip()
elseif executable('clip') && executable('powershell')
let s:copy['+'] = ['clip']
let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'clip'
return s:set_clip()
elseif executable('termux-clipboard-set')
let s:copy['+'] = ['termux-clipboard-set']
let s:paste['+'] = ['termux-clipboard-get']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'termux-clipboard'
return s:set_termux()
elseif executable('tmux') && (!empty($TMUX) || 0 == jobwait([jobstart(['tmux', 'list-buffers'])], 2000)[0])
let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V']))
if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0])
let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
else
let s:copy['+'] = ['tmux', 'load-buffer', '-']
endif
let s:paste['+'] = ['tmux', 'save-buffer', '-']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'tmux'
return s:set_tmux()
elseif get(get(g:, 'termfeatures', {}), 'osc52') && &clipboard ==# ''
" Don't use OSC 52 when 'clipboard' is set. It can be slow and cause a lot
" of user prompts. Users can opt-in to it by setting g:clipboard manually.
@@ -195,13 +268,11 @@ function! provider#clipboard#Executable() abort
endfunction
function! s:clipboard.get(reg) abort
if type(s:paste[a:reg]) == v:t_func
return s:paste[a:reg]()
elseif s:selections[a:reg].owner > 0
if s:selections[a:reg].owner > 0
return s:selections[a:reg].data
end
let clipboard_data = s:try_cmd(s:paste[a:reg])
let clipboard_data = type(s:paste[a:reg]) == v:t_func ? s:paste[a:reg]() : s:try_cmd(s:paste[a:reg])
if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0
\ && type(clipboard_data) == v:t_list
\ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data
@@ -221,13 +292,12 @@ function! s:clipboard.set(lines, regtype, reg) abort
return 0
end
if type(s:copy[a:reg]) == v:t_func
call s:copy[a:reg](a:lines, a:regtype)
return 0
end
if s:cache_enabled == 0
call s:try_cmd(s:copy[a:reg], a:lines)
if s:cache_enabled == 0 || type(s:copy[a:reg]) == v:t_func
if type(s:copy[a:reg]) == v:t_func
call s:copy[a:reg](a:lines, a:regtype)
else
call s:try_cmd(s:copy[a:reg], a:lines)
endif
"Cache it anyway we can compare it later to get regtype of the yank
let s:selections[a:reg] = copy(s:selection)
let s:selections[a:reg].data = [a:lines, a:regtype]
@@ -284,4 +354,4 @@ function! provider#clipboard#Call(method, args) abort
endfunction
" eval_has_provider() decides based on this variable.
let g:loaded_clipboard_provider = empty(provider#clipboard#Executable()) ? 1 : 2
let g:loaded_clipboard_provider = empty(provider#clipboard#Executable()) ? 0 : 2

View File

@@ -1,7 +1,7 @@
if exists('g:loaded_node_provider')
finish
endif
let g:loaded_node_provider = 1
let g:loaded_node_provider = 0
function! s:is_minimum_version(version, min_version) abort
if empty(a:version)
@@ -152,7 +152,7 @@ endfunction
let s:err = ''
let [s:prog, s:_] = provider#node#Detect()
let g:loaded_node_provider = empty(s:prog) ? 1 : 2
let g:loaded_node_provider = empty(s:prog) ? 0 : 2
if g:loaded_node_provider != 2
let s:err = 'Cannot find the "neovim" node package. Try :checkhealth'

View File

@@ -11,5 +11,5 @@ function! provider#perl#Require(host) abort
endfunction
let s:prog = v:lua.vim.provider.perl.detect()
let g:loaded_perl_provider = empty(s:prog) ? 1 : 2
let g:loaded_perl_provider = empty(s:prog) ? 0 : 2
call v:lua.require'vim.provider.perl'.start()

View File

@@ -11,5 +11,5 @@ function! provider#python3#Require(host) abort
endfunction
let s:prog = v:lua.vim.provider.python.detect_by_module('neovim')
let g:loaded_python3_provider = empty(s:prog) ? 1 : 2
let g:loaded_python3_provider = empty(s:prog) ? 0 : 2
call v:lua.require'vim.provider.python'.start()

View File

@@ -11,6 +11,6 @@ function! provider#ruby#Call(method, args) abort
endfunction
let s:prog = v:lua.vim.provider.ruby.detect()
let g:loaded_ruby_provider = empty(s:prog) ? 1 : 2
let g:loaded_ruby_provider = empty(s:prog) ? 0 : 2
let s:plugin_path = expand('<sfile>:p:h') . '/script_host.rb'
call v:lua.require'vim.provider.ruby'.start(s:plugin_path)

View File

@@ -77,49 +77,11 @@ function! tutor#TutorFolds()
endif
endfunction
" Marks: {{{1
function! tutor#ApplyMarks()
hi! link tutorExpect Special
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let b:tutor_sign_id = 1
for expct in keys(b:tutor_metadata['expect'])
let lnum = eval(expct)
call matchaddpos('tutorExpect', [lnum])
call tutor#CheckLine(lnum)
endfor
endif
endfunction
function! tutor#ApplyMarksOnChanged()
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let lnum = line('.')
if index(keys(b:tutor_metadata['expect']), string(lnum)) > -1
call tutor#CheckLine(lnum)
endif
endif
endfunction
function! tutor#CheckLine(line)
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let bufn = bufnr('%')
let ctext = getline(a:line)
let signs = sign_getplaced(bufn, {'lnum': a:line})[0].signs
if !empty(signs)
call sign_unplace('', {'id': signs[0].id})
endif
if b:tutor_metadata['expect'][string(a:line)] == -1 || ctext ==# b:tutor_metadata['expect'][string(a:line)]
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorok buffer=".bufn
else
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorbad buffer=".bufn
endif
let b:tutor_sign_id+=1
endif
endfunction
" Tutor Cmd: {{{1
function! s:Locale()
" Make sure l:lang exists before returning.
let l:lang = 'en_US'
if exists('v:lang') && v:lang =~ '\a\a'
let l:lang = v:lang
elseif $LC_ALL =~ '\a\a'
@@ -132,8 +94,6 @@ function! s:Locale()
endif
elseif $LANG =~ '\a\a'
let l:lang = $LANG
else
let l:lang = 'en_US'
endif
return split(l:lang, '_')
endfunction
@@ -167,15 +127,21 @@ function! s:Sort(a, b)
return retval
endfunction
function! s:GlobTutorials(name)
" returns a list of all tutor files matching the given name
function! tutor#GlobTutorials(name, locale)
let locale = a:locale
" pack/*/start/* are not reported in &rtp
let rtp = nvim_list_runtime_paths()
\ ->map({_, v -> escape(v:lua.vim.fs.normalize(v), ',')})
\ ->join(',')
" search for tutorials:
" 1. non-localized
let l:tutors = s:GlobPath(&rtp, 'tutor/'.a:name.'.tutor')
let l:tutors = s:GlobPath(rtp, 'tutor/'.a:name.'.tutor')
" 2. localized for current locale
let l:locale_tutors = s:GlobPath(&rtp, 'tutor/'.s:Locale()[0].'/'.a:name.'.tutor')
let l:locale_tutors = s:GlobPath(rtp, 'tutor/'.locale.'/'.a:name.'.tutor')
" 3. fallback to 'en'
if len(l:locale_tutors) == 0
let l:locale_tutors = s:GlobPath(&rtp, 'tutor/en/'.a:name.'.tutor')
let l:locale_tutors = s:GlobPath(rtp, 'tutor/en/'.a:name.'.tutor')
endif
call extend(l:tutors, l:locale_tutors)
return uniq(sort(l:tutors, 's:Sort'), 's:Sort')
@@ -197,7 +163,7 @@ function! tutor#TutorCmd(tutor_name)
let l:tutor_name = fnamemodify(l:tutor_name, ':r')
endif
let l:tutors = s:GlobTutorials(l:tutor_name)
let l:tutors = tutor#GlobTutorials(l:tutor_name, s:Locale()[0])
if len(l:tutors) == 0
echom "No tutorial with that name found"
@@ -220,15 +186,37 @@ function! tutor#TutorCmd(tutor_name)
call tutor#SetupVim()
exe "edit ".l:to_open
call tutor#EnableInteractive(v:true)
call tutor#ApplyTransform()
endfunction
function! tutor#TutorCmdComplete(lead,line,pos)
let l:tutors = s:GlobTutorials('*')
let l:tutors = tutor#GlobTutorials('*', s:Locale()[0])
let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort'))
return join(l:names, "\n")
endfunction
" Enables/disables interactive mode.
function! tutor#EnableInteractive(enable)
let enable = a:enable
if enable
setlocal buftype=nofile
setlocal concealcursor+=inv
setlocal conceallevel=2
lua require('nvim.tutor').apply_marks()
augroup tutor_interactive
autocmd! TextChanged,TextChangedI <buffer> lua require('nvim.tutor').apply_marks_on_changed()
augroup END
else
setlocal buftype<
setlocal concealcursor<
setlocal conceallevel<
if exists('#tutor_interactive')
autocmd! tutor_interactive * <buffer>
endif
endif
endfunction
function! tutor#ApplyTransform()
if has('win32')
sil! %s/{unix:(\(.\{-}\)),win:(\(.\{-}\))}/\2/g

View File

@@ -1183,10 +1183,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
ANSI termcodes, so you can use Nvim as a "scrollback pager" (for terminals
like kitty): *ansi-colorize* *terminal-scrollback-pager* >lua
vim.api.nvim_create_user_command('TermHl', function()
local b = vim.api.nvim_create_buf(false, true)
local chan = vim.api.nvim_open_term(b, {})
vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
vim.api.nvim_win_set_buf(0, b)
vim.api.nvim_open_term(0, {})
end, { desc = 'Highlights ANSI termcodes in curbuf' })
<
@@ -2777,8 +2774,11 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {})
<
If `end` is less than `start`, traversal works backwards. (Useful with
`limit`, to get the first marks prior to a given position.)
If `end` is less than `start`, marks are returned in reverse order.
(Useful with `limit`, to get the first marks prior to a given position.)
Note: For a reverse range, `limit` does not actually affect the traversed
range, just how many marks are returned
Note: when using extmark ranges (marks with a end_row/end_col position)
the `overlap` option might be useful. Otherwise only the start position of
@@ -3536,7 +3536,8 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
the duration of the call.
• fixed: If true when anchor is NW or SW, the float window
would be kept fixed even if the window would be truncated.
• hide: If true the floating window will be hidden.
• hide: If true the floating window will be hidden and the
cursor will be invisible when focused on it.
• vertical: Split vertically |:vertical|.
• split: Split direction: "left", "right", "above", "below".
@@ -3773,8 +3774,8 @@ nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()*
• callback (function|string) optional: Lua function (or
Vimscript function name, if string) called when the
event(s) is triggered. Lua callback can return a truthy
value (not `false` or `nil`) to delete the autocommand.
Receives one argument, a table with these keys:
value (not `false` or `nil`) to delete the autocommand, and
receives one argument, a table with these keys:
*event-args*
• id: (number) autocommand id
• event: (string) name of the triggered event

View File

@@ -311,7 +311,7 @@ Nvim's filetype detection behavior matches Vim, but is implemented as part of
|vim.filetype| (see `$VIMRUNTIME/lua/vim/filetype.lua`). The logic is encoded in
three tables, listed in order of precedence (the first match is returned):
1. `filename` for literal full path or basename lookup;
2. `pattern` for matching filenames or paths against |lua-patterns|, optimized
2. `pattern` for matching filenames or paths against |lua-pattern|s, optimized
for fast lookup;
3. `extension` for literal extension lookup.

View File

@@ -441,6 +441,7 @@ Use existing common {verb} names (actions) if possible:
- get: Gets things. Two variants (overloads):
1. `get<T>(id: int): T` returns one item.
2. `get<T>(filter: dict): T[]` returns a list.
- has: Checks for the presence of an item, feature, etc.
- inspect: Presents a high-level, often interactive, view
- is_enabled: Checks if functionality is enabled.
- open: Opens something (a buffer, window, …)
@@ -452,6 +453,7 @@ Use existing common {verb} names (actions) if possible:
- try_{verb}: Best-effort operation, failure returns null or error obj
Do NOT use these deprecated verbs:
- contains: Prefer "has".
- disable: Prefer `enable(enable: boolean)`.
- exit: Prefer "cancel" (or "stop" if appropriate).
- is_disabled: Prefer `is_enabled()`.

View File

@@ -69,6 +69,16 @@ Functions that take a severity as an optional parameter (e.g.
<
This form allows users to filter for specific severities
==============================================================================
DEFAULTS *diagnostic-defaults*
These diagnostic keymaps are created unconditionally when Nvim starts:
- `]d` jumps to the next diagnostic in the buffer. |]d-default|
- `[d` jumps to the previous diagnostic in the buffer. |[d-default|
- `]D` jumps to the last diagnostic in the buffer. |]D-default|
- `[D` jumps to the first diagnostic in the buffer. |[D-default|
- `<C-w>d` shows diagnostic at cursor in a floating window. |CTRL-W_d-default|
==============================================================================
HANDLERS *diagnostic-handlers*
@@ -269,6 +279,26 @@ DiagnosticVirtualTextHint
DiagnosticVirtualTextOk
Used for "Ok" diagnostic virtual text.
*hl-DiagnosticVirtualLinesError*
DiagnosticVirtualLinesError
Used for "Error" diagnostic virtual lines.
*hl-DiagnosticVirtualLinesWarn*
DiagnosticVirtualLinesWarn
Used for "Warn" diagnostic virtual lines.
*hl-DiagnosticVirtualLinesInfo*
DiagnosticVirtualLinesInfo
Used for "Info" diagnostic virtual lines.
*hl-DiagnosticVirtualLinesHint*
DiagnosticVirtualLinesHint
Used for "Hint" diagnostic virtual lines.
*hl-DiagnosticVirtualLinesOk*
DiagnosticVirtualLinesOk
Used for "Ok" diagnostic virtual lines.
*hl-DiagnosticUnderlineError*
DiagnosticUnderlineError
Used to underline "Error" diagnostics.
@@ -574,8 +604,8 @@ Lua module: vim.diagnostic *diagnostic-api*
*vim.diagnostic.Opts.Signs*
Fields: ~
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual text
for diagnostics matching the given severity
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show signs for
diagnostics matching the given severity
|diagnostic-severity|
• {priority}? (`integer`, default: `10`) Base priority to use for
signs. When {severity_sort} is used, the priority of a
@@ -607,6 +637,9 @@ Lua module: vim.diagnostic *diagnostic-api*
*vim.diagnostic.Opts.VirtualLines*
Fields: ~
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual
lines for diagnostics matching the given severity
|diagnostic-severity|
• {current_line}? (`boolean`, default: `false`) Only show diagnostics
for the current line.
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A

View File

@@ -714,11 +714,14 @@ list of the current window.
omitted the current entry is used.
Also see |++opt| and |+cmd|.
:[count]n[ext] [++opt] [+cmd] *:n* *:ne* *:next* *]a* *E165* *E163*
:[count]n[ext] [++opt] [+cmd] *:n* *:ne* *:next* *E165* *E163*
Edit [count] next file. This fails when changes have
been made and Vim does not want to |abandon| the
current buffer. Also see |++opt| and |+cmd|.
*]a*
]a Mapped to |:next|. |default-mappings|
:[count]n[ext]! [++opt] [+cmd]
Edit [count] next file, discard any changes to the
buffer. Also see |++opt| and |+cmd|.
@@ -740,16 +743,22 @@ list of the current window.
any changes to the buffer. Also see |++opt| and
|+cmd|.
:[count]prev[ious] [count] [++opt] [+cmd] *:prev* *:previous* *[a*
:[count]prev[ious] [count] [++opt] [+cmd] *:prev* *:previous*
Same as :Next. Also see |++opt| and |+cmd|.
*:rew* *:rewind* *[A*
*[a*
[a Mapped to |:previous|. |default-mappings|
*:rew* *:rewind*
:rew[ind] [++opt] [+cmd]
Start editing the first file in the argument list.
This fails when changes have been made and Vim does
not want to |abandon| the current buffer.
Also see |++opt| and |+cmd|.
*[A*
[A Mapped to |:rewind|. |default-mappings|
:rew[ind]! [++opt] [+cmd]
Start editing the first file in the argument list.
Discard any changes to the buffer. Also see |++opt|
@@ -759,13 +768,16 @@ list of the current window.
:fir[st][!] [++opt] [+cmd]
Other name for ":rewind".
*:la* *:last* *]A*
*:la* *:last*
:la[st] [++opt] [+cmd]
Start editing the last file in the argument list.
This fails when changes have been made and Vim does
not want to |abandon| the current buffer.
Also see |++opt| and |+cmd|.
*]A*
]A Mapped to |:last|. |default-mappings|
:la[st]! [++opt] [+cmd]
Start editing the last file in the argument list.
Discard any changes to the buffer. Also see |++opt|

View File

@@ -187,35 +187,28 @@ Run |:checkhealth| in Nvim for automatic diagnosis.
Other hints:
- The python `neovim` module was renamed to `pynvim` (long ago).
- If you're using pyenv or virtualenv for the `pynvim` module
https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to
the virtualenv's interpreter path.
- Read |provider-python|.
- Read |provider-python| to learn how to install `pynvim`.
- Be sure you have the latest version of the `pynvim` Python module: >bash
python -m pip install setuptools
python -m pip install --upgrade pynvim
python3 -m pip install --upgrade pynvim
uv tool install --upgrade pynvim
<
See |provider-python| for other installation options.
- If you're manually creating a Python virtual environment for the `pynvim` module
https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to
the virtualenv's interpreter path.
- Try with `nvim -u NORC` to make sure your config (|init.vim|) isn't causing a
problem. If you get `E117: Unknown function`, that means there's a runtime
issue: |faq-runtime|.
- The python `neovim` module was renamed to `pynvim` (long ago).
:CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME ~
This means `health#check()` couldn't load, which suggests that |$VIMRUNTIME|
or 'runtimepath' is broken.
This means |$VIMRUNTIME| or 'runtimepath' is broken.
- |$VIMRUNTIME| must point to Nvim's runtime files, not Vim's.
- The |$VIMRUNTIME| directory contents should be readable by the current user.
- Verify that `:echo &runtimepath` contains the $VIMRUNTIME path.
- Check the output of: >vim
:call health#check()
:verbose func health#check
<
NEOVIM CAN'T FIND ITS RUNTIME ~

View File

@@ -9,18 +9,18 @@
==============================================================================
Checkhealth *vim.health* *health*
vim.health is a minimal framework to help users troubleshoot configuration and
any other environment conditions that a plugin might care about. Nvim ships
with healthchecks for configuration, performance, python support, ruby
support, clipboard support, and more.
To run all healthchecks, use: >vim
:checkhealth
:checkhealth
<
Plugin authors are encouraged to write new healthchecks. |health-dev|
COMMANDS *health-commands*
*:che* *:checkhealth*
@@ -56,7 +56,6 @@ Local mappings in the healthcheck buffer:
q Closes the window.
Global configuration:
*g:health*
g:health Dictionary with the following optional keys:
- `style` (`'float'|nil`) Set to "float" to display :checkhealth in
@@ -65,16 +64,26 @@ g:health Dictionary with the following optional keys:
Example: >lua
vim.g.health = { style = 'float' }
Local configuration:
Checkhealth sets its buffer filetype to "checkhealth". You can customize the
buffer by handling the |FileType| event. For example if you don't want emojis
in the health report: >vim
autocmd FileType checkhealth :set modifiable | silent! %s/\v( ?[^\x00-\x7F])//g
<
--------------------------------------------------------------------------------
Create a healthcheck *health-dev*
Healthchecks are functions that check the user environment, configuration, or
any other prerequisites that a plugin cares about. Nvim ships with
healthchecks in:
- $VIMRUNTIME/autoload/health/
- $VIMRUNTIME/lua/vim/lsp/health.lua
- $VIMRUNTIME/lua/vim/treesitter/health.lua
- and more...
$VIMRUNTIME/autoload/health/
$VIMRUNTIME/lua/vim/lsp/health.lua
$VIMRUNTIME/lua/vim/treesitter/health.lua
and more...
To add a new healthcheck for your own plugin, simply create a "health.lua"
module on 'runtimepath' that returns a table with a "check()" function. Then
@@ -82,35 +91,35 @@ module on 'runtimepath' that returns a table with a "check()" function. Then
For example if your plugin is named "foo", define your healthcheck module at
one of these locations (on 'runtimepath'):
- lua/foo/health/init.lua
- lua/foo/health.lua
lua/foo/health/init.lua
lua/foo/health.lua
If your plugin also provides a submodule named "bar" for which you want
a separate healthcheck, define the healthcheck at one of these locations:
- lua/foo/bar/health/init.lua
- lua/foo/bar/health.lua
If your plugin also provides a submodule named "bar" for which you want a
separate healthcheck, define the healthcheck at one of these locations:
lua/foo/bar/health/init.lua
lua/foo/bar/health.lua
All such health modules must return a Lua table containing a `check()`
function.
Copy this sample code into `lua/foo/health.lua`, replacing "foo" in the path
with your plugin name: >lua
local M = {}
local M = {}
M.check = function()
vim.health.start("foo report")
-- make sure setup function parameters are ok
if check_setup() then
vim.health.ok("Setup is correct")
else
vim.health.error("Setup is incorrect")
end
-- do some more checking
-- ...
end
M.check = function()
vim.health.start("foo report")
-- make sure setup function parameters are ok
if check_setup() then
vim.health.ok("Setup is correct")
else
vim.health.error("Setup is incorrect")
end
-- do some more checking
-- ...
end
return M
return M
<
error({msg}, {...}) *vim.health.error()*

View File

@@ -373,11 +373,17 @@ To quote a block of ex-commands verbatim, place a greater than (>) character
at the end of the line before the block and a less than (<) character as the
first non-blank on a line following the block. Any line starting in column 1
also implicitly stops the block of ex-commands before it. E.g. >
function Example_Func()
echo "Example"
endfunction
function Example_Func()
echo "Example"
endfunction
<
To enable syntax highlighting for a block of code, place a language name
annotation (e.g. "vim") after a greater than (>) character. E.g. >vim
function Example_Func()
echo "Example"
endfunction
<
*help-notation*
The following are highlighted differently in a Vim help file:
- a special key name expressed either in <> notation as in <PageDown>, or
as a Ctrl character as in CTRL-X

View File

@@ -1923,7 +1923,7 @@ These commands are used to start inserting text. You can end insert mode with
<Esc>. See |mode-ins-repl| for the other special characters in Insert mode.
The effect of [count] takes place after Insert mode is exited.
The following commands insert text, but stay in normal mode:
The following |default-mappings| insert text, but stay in normal mode:
*]<Space>*
]<Space> Insert an empty line below the cursor without leaving

View File

@@ -28,38 +28,42 @@ Follow these steps to get LSP features:
upstream installation instructions. You can find language servers here:
https://microsoft.github.io/language-server-protocol/implementors/servers/
2. Use |vim.lsp.config()| to define a configuration for an LSP client.
Example: >lua
vim.lsp.config['luals'] = {
-- Command and arguments to start the server.
cmd = { 'lua-language-server' },
2. Use |vim.lsp.config()| to define a configuration for an LSP client
(see https://github.com/neovim/nvim-lspconfig for examples).
Example: >lua
vim.lsp.config['luals'] = {
-- Command and arguments to start the server.
cmd = { 'lua-language-server' },
-- Filetypes to automatically attach to.
filetypes = { 'lua' },
-- Filetypes to automatically attach to.
filetypes = { 'lua' },
-- Sets the "root directory" to the parent directory of the file in the
-- current buffer that contains either a ".luarc.json" or a
-- ".luarc.jsonc" file. Files that share a root directory will reuse
-- the connection to the same LSP server.
root_markers = { '.luarc.json', '.luarc.jsonc' },
-- Sets the "root directory" to the parent directory of the file in the
-- current buffer that contains either a ".luarc.json" or a
-- ".luarc.jsonc" file. Files that share a root directory will reuse
-- the connection to the same LSP server.
-- Nested lists indicate equal priority, see |vim.lsp.Config|.
root_markers = { { '.luarc.json', '.luarc.jsonc' }, '.git' },
-- Specific settings to send to the server. The schema for this is
-- defined by the server. For example the schema for lua-language-server
-- can be found here https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json
settings = {
Lua = {
runtime = {
version = 'LuaJIT',
}
}
}
}
-- Specific settings to send to the server. The schema for this is
-- defined by the server. For example the schema for lua-language-server
-- can be found here https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json
settings = {
Lua = {
runtime = {
version = 'LuaJIT',
}
}
}
}
<
3. Use |vim.lsp.enable()| to enable a configuration.
Example: >lua
vim.lsp.enable('luals')
<
4. Restart Nvim, or use ":edit" to reload the buffer.
4. Open a code file matching one of the `filetypes` specified in the config.
Note: Depending on the LSP server, you may need to ensure your project has
a |lsp-root_markers| file so the workspace can be recognized.
5. Check that LSP is active ("attached") for the buffer: >vim
:checkhealth vim.lsp
@@ -76,6 +80,18 @@ listed below, if (1) the language server supports the functionality and (2)
the options are empty or were set by the builtin runtime (ftplugin) files. The
options are not restored when the LSP client is stopped or detached.
GLOBAL DEFAULTS
*grr* *gra* *grn* *gri* *grt* *i_CTRL-S*
These GLOBAL keymaps are created unconditionally when Nvim starts:
- "grn" is mapped in Normal mode to |vim.lsp.buf.rename()|
- "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
- "grr" is mapped in Normal mode to |vim.lsp.buf.references()|
- "gri" is mapped in Normal mode to |vim.lsp.buf.implementation()|
- "grt" is mapped in Normal mode to |vim.lsp.buf.type_definition()|
- "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()|
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
BUFFER-LOCAL DEFAULTS
- 'omnifunc' is set to |vim.lsp.omnifunc()|, use |i_CTRL-X_CTRL-O| to trigger
completion.
- 'tagfunc' is set to |vim.lsp.tagfunc()|. This enables features like
@@ -87,21 +103,11 @@ options are not restored when the LSP client is stopped or detached.
- |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or
a custom keymap for `K` exists.
*grr* *gra* *grn* *gri* *i_CTRL-S*
Some keymaps are created unconditionally when Nvim starts:
- "grn" is mapped in Normal mode to |vim.lsp.buf.rename()|
- "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
- "grr" is mapped in Normal mode to |vim.lsp.buf.references()|
- "gri" is mapped in Normal mode to |vim.lsp.buf.implementation()|
- "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()|
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
DISABLING DEFAULTS *lsp-defaults-disable*
You can remove GLOBAL keymaps at any time using |vim.keymap.del()| or
|:unmap|. See also |gr-default|.
If not wanted, these keymaps can be removed at any time using
|vim.keymap.del()| or |:unmap| (see also |gr-default|).
*lsp-defaults-disable*
To override or delete any of the above defaults, set or unset the options on
|LspAttach|: >lua
To remove or override BUFFER-LOCAL defaults, define a |LspAttach| handler: >lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
@@ -129,7 +135,7 @@ following (in increasing priority):
1. Configuration defined for the `'*'` name.
2. Configuration from the result of merging all tables returned by
`lsp/<name>.lua` files in 'runtimepath' for a server of name `name`.
`lsp/<config>.lua` files in 'runtimepath' for the config named `<config>`.
3. Configurations defined anywhere else.
Note: The merge semantics of configurations follow the behaviour of
@@ -250,8 +256,14 @@ FAQ *lsp-faq*
" (async = false is the default for format)
autocmd BufWritePre *.rs lua vim.lsp.buf.format({ async = false })
<
- Q: How to avoid my own lsp/ folder being overridden?
- A: Place your configs under "after/lsp/". Files in "after/lsp/" are loaded
after those in "nvim/lsp/", so your settings will take precedence over
the defaults provided by nvim-lspconfig. See also: |after-directory|
*lsp-vs-treesitter*
- Q: How do LSP and Treesitter compare?
- Q: How do LSP, Treesitter and Ctags compare?
- A: LSP requires a client and language server. The language server uses
semantic analysis to understand code at a project level. This provides
language servers with the ability to rename across files, find
@@ -263,6 +275,11 @@ FAQ *lsp-faq*
like syntax highlighting, simple goto-definitions, scope analysis and
more.
A |ctags|-like program can generate a |tags| file that allows Nvim to
jump to definitions, provide simple completions via |i_CTRL-X_CTRL-]|
command. It is not as featureful and doesn't have semantic understanding,
but it is fast, lightweight and useful for navigating polyglot projects.
================================================================================
LSP API *lsp-api*
@@ -286,38 +303,33 @@ They are also listed below.
- `'callHierarchy/incomingCalls'`
- `'callHierarchy/outgoingCalls'`
- `'textDocument/codeAction'`
- `'client/registerCapability'`
- `'client/unregisterCapability'`
- `'signature_help'`
- `'textDocument/codeLens'`
- `'textDocument/completion'`
- `'textDocument/declaration'`
- `'textDocument/definition'`
- `'textDocument/diagnostic'`
- `'textDocument/documentHighlight'`
- `'textDocument/documentSymbol'`
- `'textDocument/foldingRange'`
- `'textDocument/formatting'`
- `'textDocument/hover'`
- `'textDocument/implementation'`
- `'textDocument/inlayHint'`
- `'textDocument/prepareTypeHierarchy'`
- `'textDocument/publishDiagnostics'`
- `'textDocument/rangeFormatting'`
- `'textDocument/rangesFormatting'`
- `'textDocument/references'`
- `'textDocument/rename'`
- `'textDocument/semanticTokens/full'`
- `'textDocument/semanticTokens/full/delta'`
- `'textDocument/signatureHelp'`
- `'textDocument/typeDefinition*'`
- `'typeHierarchy/subtypes'`
- `'typeHierarchy/supertypes'`
- `'window/logMessage'`
- `'window/showMessage'`
- `'window/showDocument'`
- `'window/showMessage'`
- `'window/showMessageRequest'`
- `'window/workDoneProgress/create'`
- `'workspace/applyEdit'`
- `'workspace/configuration'`
- `'workspace/executeCommand'`
- `'workspace/inlayHint/refresh'`
- `'workspace/semanticTokens/refresh'`
- `'workspace/symbol'`
- `'workspace/workspaceFolders'`
@@ -552,10 +564,19 @@ LspAttach *LspAttach*
|autocmd-pattern| is the buffer name. The client ID is passed in the
Lua handler |event-data| argument.
Example: >lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
-- ...
end
})
<
Note: If the LSP server performs dynamic registration, capabilities may be
registered any time _after_ LspAttach. In that case you may want to handle
the "registerCapability" event. Example: >lua
the "registerCapability" event.
Example: >lua
vim.lsp.handlers['client/registerCapability'] = (function(overridden)
return function(err, res, ctx)
local result = overridden(err, res, ctx)
@@ -563,8 +584,10 @@ LspAttach *LspAttach*
if not client then
return
end
-- Call your custom on_attach logic...
-- my_on_attach(client, vim.api.nvim_get_current_buf())
for bufnr, _ in pairs(client.attached_buffers) do
-- Call your custom on_attach logic...
-- my_on_attach(client, bufnr)
end
return result
end
end)(vim.lsp.handlers['client/registerCapability'])
@@ -572,8 +595,9 @@ LspAttach *LspAttach*
LspDetach *LspDetach*
Just before an LSP client detaches from a buffer. The |autocmd-pattern| is
the buffer name. The client ID is passed in the Lua handler |event-data|
argument. Example: >lua
argument.
Example: >lua
vim.api.nvim_create_autocmd('LspDetach', {
callback = function(args)
-- Get the detaching client
@@ -595,8 +619,9 @@ LspNotify *LspNotify*
LSP server.
The client_id, LSP method, and parameters are sent in the Lua handler
|event-data| table argument. Example: >lua
|event-data| table argument.
Example: >lua
vim.api.nvim_create_autocmd('LspNotify', {
callback = function(args)
local bufnr = args.buf
@@ -642,8 +667,9 @@ LspRequest *LspRequest*
The Lua handler |event-data| argument has the client ID, request ID, and
request (described at |vim.lsp.Client|, {requests} field). If the request
type is `complete`, the request will be deleted from the client's pending
requests table after processing the event handlers. Example: >lua
requests table after processing the event handlers.
Example: >lua
vim.api.nvim_create_autocmd('LspRequest', {
callback = function(args)
local bufnr = args.buf
@@ -670,8 +696,9 @@ LspTokenUpdate *LspTokenUpdate*
when an existing token becomes visible for the first time. The
|autocmd-pattern| is the buffer name. The Lua handler |event-data|
argument has the client ID and token (see
|vim.lsp.semantic_tokens.get_at_pos()|). Example: >lua
|vim.lsp.semantic_tokens.get_at_pos()|).
Example: >lua
vim.api.nvim_create_autocmd('LspTokenUpdate', {
callback = function(args)
local token = args.data.token
@@ -694,28 +721,52 @@ Lua module: vim.lsp *lsp-core*
Fields: ~
• {cmd}? (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
See `cmd` in |vim.lsp.ClientConfig|.
• {cmd}? (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient`)
See `cmd` in |vim.lsp.ClientConfig|. See also
`reuse_client` to dynamically decide (per-buffer)
when `cmd` should be re-invoked.
• {filetypes}? (`string[]`) Filetypes the client will attach to, if
activated by `vim.lsp.enable()`. If not provided,
then the client will attach to all filetypes.
• {root_markers}? (`string[]`) Directory markers (.e.g. '.git/') where
the LSP server will base its workspaceFolders,
rootUri, and rootPath on initialization. Unused if
`root_dir` is provided.
• {root_dir}? (`string|fun(bufnr: integer, cb:fun(root_dir?:string))`)
Directory where the LSP server will base its
workspaceFolders, rootUri, and rootPath on
initialization. If a function, it is passed the
buffer number and a callback argument which must be
called with the value of root_dir to use. The LSP
server will not be started until the callback is
called.
activated by `vim.lsp.enable()`. If not provided, the
client will attach to all filetypes.
• {reuse_client}? (`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
Predicate used to decide if a client should be
Predicate which decides if a client should be
re-used. Used on all running clients. The default
implementation re-uses a client if name and root_dir
matches.
• {root_dir}? (`string|fun(bufnr: integer, on_dir:fun(root_dir?:string))`)
*lsp-root_dir()* Decides the workspace root: the
directory where the LSP server will base its
workspaceFolders, rootUri, and rootPath on
initialization. The function form must call the
`on_dir` callback to provide the root dir, or LSP
will not be activated for the buffer. Thus a
`root_dir()` function can dynamically decide
per-buffer whether to activate (or skip) LSP. See
example at |vim.lsp.enable()|.
• {root_markers}? (`(string|string[])[]`) *lsp-root_markers*
Filename(s) (".git/", "package.json", …) used to
decide the workspace root. Unused if `root_dir` is
defined. The list order decides priority. To indicate
"equal priority", specify names in a nested list
`{ { 'a.txt', 'b.lua' }, ... }`.
For each item, Nvim will search upwards (from the
buffer file) for that marker, or list of markers;
search stops at the first directory containing that
marker, and the directory is used as the root dir
(workspace folder).
Example: Find the first ancestor directory containing
file or directory "stylua.toml"; if not found, find
the first ancestor containing ".git": >lua
root_markers = { 'stylua.toml', '.git' }
<
Example: Find the first ancestor directory containing
EITHER "stylua.toml" or ".luarc.json"; if not found,
find the first ancestor containing ".git": >lua
root_markers = { { 'stylua.toml', '.luarc.json' }, '.git' }
<
buf_attach_client({bufnr}, {client_id}) *vim.lsp.buf_attach_client()*
@@ -871,19 +922,36 @@ config({name}, {cfg}) *vim.lsp.config()*
• {cfg} (`vim.lsp.Config`) See |vim.lsp.Config|.
enable({name}, {enable}) *vim.lsp.enable()*
Enable an LSP server to automatically start when opening a buffer.
Uses configuration defined with `vim.lsp.config`.
Auto-starts LSP when a buffer is opened, based on the |lsp-config|
`filetypes`, `root_markers`, and `root_dir` fields.
Examples: >lua
vim.lsp.enable('clangd')
vim.lsp.enable('clangd')
vim.lsp.enable({'luals', 'pyright'})
<
vim.lsp.enable({'luals', 'pyright'})
Example: *lsp-restart* Passing `false` stops and detaches the client(s).
Thus you can "restart" LSP by disabling and re-enabling a given config: >lua
vim.lsp.enable('clangd', false)
vim.lsp.enable('clangd', true)
<
Example: To dynamically decide whether LSP is activated, define a
|lsp-root_dir()| function which calls `on_dir()` only when you want that
config to activate: >lua
vim.lsp.config('lua_ls', {
root_dir = function(bufnr, on_dir)
if not vim.fn.bufname(bufnr):match('%.txt$') then
on_dir(vim.fn.getcwd())
end
end
})
<
Parameters: ~
• {name} (`string|string[]`) Name(s) of client(s) to enable.
• {enable} (`boolean?`) `true|nil` to enable, `false` to disable.
• {enable} (`boolean?`) `true|nil` to enable, `false` to disable
(actively stops and detaches clients as needed)
foldclose({kind}, {winid}) *vim.lsp.foldclose()*
Close all {kind} of folds in the the window with {winid}.
@@ -993,6 +1061,18 @@ get_log_path() *vim.lsp.get_log_path()*
Return: ~
(`string`) path to log file
is_enabled({name}) *vim.lsp.is_enabled()*
Checks if the given LSP config is enabled (globally, not per-buffer).
Unlike `vim.lsp.config['…']`, this does not have the side-effect of
resolving the config.
Parameters: ~
• {name} (`string`) Config name
Return: ~
(`boolean`)
omnifunc({findstart}, {base}) *vim.lsp.omnifunc()*
Implements 'omnifunc' compatible LSP completion.
@@ -1128,65 +1208,17 @@ Lua module: vim.lsp.client *lsp-client*
*vim.lsp.Client*
Fields: ~
• {id} (`integer`) The id allocated to the client.
• {name} (`string`) If a name is specified on creation,
that will be used. Otherwise it is just the
client id. This is used for logs and messages.
• {rpc} (`vim.lsp.rpc.PublicClient`) RPC client
object, for low level interaction with the
client. See |vim.lsp.rpc.start()|.
• {offset_encoding} (`string`) Called "position encoding" in LSP
spec, the encoding used for communicating with
the server. You can modify this in the
`config`'s `on_init` method before text is
sent to the server.
• {handlers} (`table<string,lsp.Handler>`) The handlers
used by the client as described in
|lsp-handler|.
• {requests} (`table<integer,{ type: string, bufnr: integer, method: string}?>`)
The current pending requests in flight to the
server. Entries are key-value pairs with the
key being the request id while the value is a
table with `type`, `bufnr`, and `method`
key-value pairs. `type` is either "pending"
for an active request, or "cancel" for a
cancel request. It will be "complete"
ephemerally while executing |LspRequest|
autocmds when replies are received from the
server.
• {config} (`vim.lsp.ClientConfig`) copy of the table
that was passed by the user to
|vim.lsp.start()|. See |vim.lsp.ClientConfig|.
• {server_capabilities} (`lsp.ServerCapabilities?`) Response from the
server sent on `initialize` describing the
server's capabilities.
• {server_info} (`lsp.ServerInfo?`) Response from the server
sent on `initialize` describing information
about the server.
• {progress} (`vim.lsp.Client.Progress`) A ring buffer
(|vim.ringbuf()|) containing progress messages
sent by the server. See
|vim.lsp.Client.Progress|.
• {initialized} (`true?`)
• {workspace_folders} (`lsp.WorkspaceFolder[]?`) The workspace
folders configured in the client when the
server starts. This property is only available
if the client supports workspace folders. It
can be `null` if the client supports workspace
folders but none are configured.
• {root_dir} (`string?`)
• {attached_buffers} (`table<integer,true>`)
• {capabilities} (`lsp.ClientCapabilities`) Capabilities
provided by the client (editor or tool), at
startup.
• {commands} (`table<string,fun(command: lsp.Command, ctx: table)>`)
Table of command name to function which is
called if any LSP action (code action, code
lenses, ...) triggers the command. Client
commands take precedence over the global
command registry.
• {settings} (`lsp.LSPObject`) Map with language server
specific settings. These are returned to the
language server if requested via
`workspace/configuration`. Keys are
case-sensitive.
Client commands. See |vim.lsp.ClientConfig|.
• {config} (`vim.lsp.ClientConfig`) Copy of the config
passed to |vim.lsp.start()|. See
|vim.lsp.ClientConfig|.
• {dynamic_capabilities} (`lsp.DynamicCapabilities`) Capabilities
provided at runtime (after startup).
• {flags} (`table`) A table with flags for the client.
The current (experimental) flags are:
• {allow_incremental_sync}? (`boolean`,
@@ -1203,9 +1235,41 @@ Lua module: vim.lsp.client *lsp-client*
false, nvim exits immediately after sending
the "shutdown" request to the server.
• {get_language_id} (`fun(bufnr: integer, filetype: string): string`)
• {capabilities} (`lsp.ClientCapabilities`) The capabilities
provided by the client (editor or tool)
• {dynamic_capabilities} (`lsp.DynamicCapabilities`)
See |vim.lsp.ClientConfig|.
• {handlers} (`table<string,lsp.Handler>`) See
|vim.lsp.ClientConfig|.
• {id} (`integer`) The id allocated to the client.
• {initialized} (`true?`)
• {name} (`string`) See |vim.lsp.ClientConfig|.
• {offset_encoding} (`string`) See |vim.lsp.ClientConfig|.
• {progress} (`vim.lsp.Client.Progress`) A ring buffer
(|vim.ringbuf()|) containing progress messages
sent by the server. See
|vim.lsp.Client.Progress|.
• {requests} (`table<integer,{ type: string, bufnr: integer, method: string}?>`)
The current pending requests in flight to the
server. Entries are key-value pairs with the
key being the request id while the value is a
table with `type`, `bufnr`, and `method`
key-value pairs. `type` is either "pending"
for an active request, or "cancel" for a
cancel request. It will be "complete"
ephemerally while executing |LspRequest|
autocmds when replies are received from the
server.
• {root_dir} (`string?`) See |vim.lsp.ClientConfig|.
• {rpc} (`vim.lsp.rpc.PublicClient`) RPC client
object, for low level interaction with the
client. See |vim.lsp.rpc.start()|.
• {server_capabilities} (`lsp.ServerCapabilities?`) Response from the
server sent on `initialize` describing the
server's capabilities.
• {server_info} (`lsp.ServerInfo?`) Response from the server
sent on `initialize` describing server
information (e.g. version).
• {settings} (`lsp.LSPObject`) See |vim.lsp.ClientConfig|.
• {workspace_folders} (`lsp.WorkspaceFolder[]?`) See
|vim.lsp.ClientConfig|.
• {request} (`fun(self: vim.lsp.Client, method: string, params: table?, handler: lsp.Handler?, bufnr: integer?): boolean, integer?`)
See |Client:request()|.
• {request_sync} (`fun(self: vim.lsp.Client, method: string, params: table, timeout_ms: integer?, bufnr: integer?): {err: lsp.ResponseError?, result:any}?, string?`)
@@ -1235,125 +1299,138 @@ Lua module: vim.lsp.client *lsp-client*
*vim.lsp.ClientConfig*
Fields: ~
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
command string[] that launches the language
server (treated as in |jobstart()|, must be
absolute or on `$PATH`, shell constructs like
"~" are not expanded), or function that creates
an RPC client. Function receives a `dispatchers`
table and returns a table with member functions
`request`, `notify`, `is_closing` and
`terminate`. See |vim.lsp.rpc.request()|,
|vim.lsp.rpc.notify()|. For TCP there is a
builtin RPC client factory:
|vim.lsp.rpc.connect()|
• {cmd_cwd}? (`string`, default: cwd) Directory to launch the
`cmd` process. Not related to `root_dir`.
• {cmd_env}? (`table`) Environment flags to pass to the LSP
on spawn. Must be specified using a table.
Non-string values are coerced to string.
Example: >lua
{ PORT = 8080; HOST = "0.0.0.0"; }
• {before_init}? (`fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)`)
Callback invoked before the LSP "initialize"
phase, where `params` contains the parameters
being sent to the server and `config` is the
config that was passed to |vim.lsp.start()|.
You can use this to modify parameters before
they are sent.
• {capabilities}? (`lsp.ClientCapabilities`) Map overriding the
default capabilities defined by
|vim.lsp.protocol.make_client_capabilities()|,
passed to the language server on
initialization. Hint: use
make_client_capabilities() and modify its
result.
• Note: To send an empty dictionary use
|vim.empty_dict()|, else it will be encoded
as an array.
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient`)
Command `string[]` that launches the language
server (treated as in |jobstart()|, must be
absolute or on `$PATH`, shell constructs like
"~" are not expanded), or function that creates
an RPC client. Function receives a
`dispatchers` table and the resolved `config`,
and must return a table with member functions
`request`, `notify`, `is_closing` and
`terminate`. See |vim.lsp.rpc.request()|,
|vim.lsp.rpc.notify()|. For TCP there is a
builtin RPC client factory:
|vim.lsp.rpc.connect()|
• {cmd_cwd}? (`string`, default: cwd) Directory to launch
the `cmd` process. Not related to `root_dir`.
• {cmd_env}? (`table`) Environment variables passed to the
LSP process on spawn. Non-string values are
coerced to string. Example: >lua
{ PORT = 8080; HOST = '0.0.0.0'; }
<
• {detached}? (`boolean`, default: true) Daemonize the server
process so that it runs in a separate process
group from Nvim. Nvim will shutdown the process
on exit, but if Nvim fails to exit cleanly this
could leave behind orphaned server processes.
• {workspace_folders}? (`lsp.WorkspaceFolder[]`) List of workspace
folders passed to the language server. For
backwards compatibility rootUri and rootPath
will be derived from the first workspace folder
in this list. See `workspaceFolders` in the LSP
spec.
• {capabilities}? (`lsp.ClientCapabilities`) Map overriding the
default capabilities defined by
|vim.lsp.protocol.make_client_capabilities()|,
passed to the language server on initialization.
Hint: use make_client_capabilities() and modify
its result.
• Note: To send an empty dictionary use
|vim.empty_dict()|, else it will be encoded as
an array.
• {handlers}? (`table<string,function>`) Map of language
server method names to |lsp-handler|
• {settings}? (`lsp.LSPObject`) Map with language server
specific settings. See the {settings} in
|vim.lsp.Client|.
• {commands}? (`table<string,fun(command: lsp.Command, ctx: table)>`)
Table that maps string of clientside commands to
user-defined functions. Commands passed to
`start()` take precedence over the global
command registry. Each key must be a unique
command name, and the value is a function which
is called if any LSP action (code action, code
lenses, ...) triggers the command.
• {init_options}? (`lsp.LSPObject`) Values to pass in the
initialization request as
`initializationOptions`. See `initialize` in the
LSP spec.
• {name}? (`string`, default: client-id) Name in log
messages.
• {get_language_id}? (`fun(bufnr: integer, filetype: string): string`)
Language ID as string. Defaults to the buffer
filetype.
• {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) Called "position
encoding" in LSP spec, the encoding that the LSP
server expects. Client does not verify this is
correct.
• {on_error}? (`fun(code: integer, err: string)`) Callback
invoked when the client operation throws an
error. `code` is a number describing the error.
Other arguments may be passed depending on the
error kind. See `vim.lsp.rpc.client_errors` for
possible errors. Use
`vim.lsp.rpc.client_errors[code]` to get
human-friendly name.
• {before_init}? (`fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)`)
Callback invoked before the LSP "initialize"
phase, where `params` contains the parameters
being sent to the server and `config` is the
config that was passed to |vim.lsp.start()|. You
can use this to modify parameters before they
are sent.
• {on_init}? (`elem_or_list<fun(client: vim.lsp.Client, init_result: lsp.InitializeResult)>`)
Callback invoked after LSP "initialize", where
`result` is a table of `capabilities` and
anything else the server may send. For example,
clangd sends `init_result.offsetEncoding` if
`capabilities.offsetEncoding` was sent to it.
You can only modify the `client.offset_encoding`
here before any notifications are sent.
• {on_exit}? (`elem_or_list<fun(code: integer, signal: integer, client_id: integer)>`)
Callback invoked on client exit.
• code: exit code of the process
• signal: number describing the signal used to
terminate (if any)
• client_id: client handle
• {on_attach}? (`elem_or_list<fun(client: vim.lsp.Client, bufnr: integer)>`)
Callback invoked when client attaches to a
buffer.
• {trace}? (`'off'|'messages'|'verbose'`, default: "off")
Passed directly to the language server in the
initialize request. Invalid/empty values will
• {flags}? (`table`) A table with flags for the client. The
current (experimental) flags are:
• {allow_incremental_sync}? (`boolean`, default:
`true`) Allow using incremental sync for
buffer edits
• {debounce_text_changes} (`integer`, default:
`150`) Debounce `didChange` notifications to
the server by the given number in
milliseconds. No debounce occurs if `nil`.
• {exit_timeout} (`integer|false`, default:
`false`) Milliseconds to wait for server to
exit cleanly after sending the "shutdown"
request before sending kill -15. If set to
false, nvim exits immediately after sending
the "shutdown" request to the server.
• {root_dir}? (`string`) Directory where the LSP server will
base its workspaceFolders, rootUri, and rootPath
on initialization.
• {commands}? (`table<string,fun(command: lsp.Command, ctx: table)>`)
Client commands. Map of command names to
user-defined functions. Commands passed to
`start()` take precedence over the global
command registry. Each key must be a unique
command name, and the value is a function which
is called if any LSP action (code action, code
lenses, …) triggers the command.
• {detached}? (`boolean`, default: `true`) Daemonize the
server process so that it runs in a separate
process group from Nvim. Nvim will shutdown the
process on exit, but if Nvim fails to exit
cleanly this could leave behind orphaned server
processes.
• {flags}? (`table`) A table with flags for the client.
The current (experimental) flags are:
• {allow_incremental_sync}? (`boolean`,
default: `true`) Allow using incremental sync
for buffer edits
• {debounce_text_changes} (`integer`, default:
`150`) Debounce `didChange` notifications to
the server by the given number in
milliseconds. No debounce occurs if `nil`.
• {exit_timeout} (`integer|false`, default:
`false`) Milliseconds to wait for server to
exit cleanly after sending the "shutdown"
request before sending kill -15. If set to
false, nvim exits immediately after sending
the "shutdown" request to the server.
• {get_language_id}? (`fun(bufnr: integer, filetype: string): string`)
Language ID as string. Defaults to the buffer
filetype.
• {handlers}? (`table<string,function>`) Map of LSP method
names to |lsp-handler|s.
• {init_options}? (`lsp.LSPObject`) Values to pass in the
initialization request as
`initializationOptions`. See `initialize` in
the LSP spec.
• {name}? (`string`, default: client-id) Name in logs and
user messages.
• {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) Called "position
encoding" in LSP spec. The encoding that the
LSP server expects, used for communication. Not
validated. Can be modified in `on_init` before
text is sent to the server.
• {on_attach}? (`elem_or_list<fun(client: vim.lsp.Client, bufnr: integer)>`)
Callback invoked when client attaches to a
buffer.
• {on_error}? (`fun(code: integer, err: string)`) Callback
invoked when the client operation throws an
error. `code` is a number describing the error.
Other arguments may be passed depending on the
error kind. See `vim.lsp.rpc.client_errors` for
possible errors. Use
`vim.lsp.rpc.client_errors[code]` to get
human-friendly name.
• {on_exit}? (`elem_or_list<fun(code: integer, signal: integer, client_id: integer)>`)
Callback invoked on client exit.
• code: exit code of the process
• signal: number describing the signal used to
terminate (if any)
• client_id: client handle
• {on_init}? (`elem_or_list<fun(client: vim.lsp.Client, init_result: lsp.InitializeResult)>`)
Callback invoked after LSP "initialize", where
`result` is a table of `capabilities` and
anything else the server may send. For example,
clangd sends `init_result.offsetEncoding` if
`capabilities.offsetEncoding` was sent to it.
You can only modify the
`client.offset_encoding` here before any
notifications are sent.
• {root_dir}? (`string`) Directory where the LSP server will
base its workspaceFolders, rootUri, and
rootPath on initialization.
• {settings}? (`lsp.LSPObject`) Map of language
server-specific settings, decided by the
client. Sent to the LS if requested via
`workspace/configuration`. Keys are
case-sensitive.
• {trace}? (`'off'|'messages'|'verbose'`, default: "off")
Passed directly to the language server in the
initialize request. Invalid/empty values will
• {workspace_folders}? (`lsp.WorkspaceFolder[]`) List of workspace
folders passed to the language server. For
backwards compatibility rootUri and rootPath
are derived from the first workspace folder in
this list. Can be `null` if the client supports
workspace folders but none are configured. See
`workspaceFolders` in LSP spec.
• {workspace_required}? (`boolean`, default: `false`) Server requires a
workspace (no "single file" support). Note:
Without a workspace, cross-file features
(navigation, hover) may or may not work
depending on the language server, even if the
server doesn't require a workspace.
Client:cancel_request({id}) *Client:cancel_request()*
@@ -1539,7 +1616,8 @@ clear_references() *vim.lsp.buf.clear_references()*
Removes document highlights from current buffer.
code_action({opts}) *vim.lsp.buf.code_action()*
Selects a code action available at the current cursor position.
Selects a code action (LSP: "textDocument/codeAction" request) available
at cursor position.
Parameters: ~
• {opts} (`table?`) A table with the following fields:
@@ -2502,6 +2580,27 @@ symbols_to_items({symbols}, {bufnr}, {position_encoding})
==============================================================================
Lua module: vim.lsp.log *lsp-log*
The `vim.lsp.log` module provides logging for the Nvim LSP client.
When debugging language servers, it is helpful to enable extra-verbose logging
of the LSP client RPC events. Example: >lua
vim.lsp.set_log_level 'trace'
require('vim.lsp.log').set_format_func(vim.inspect)
<
Then try to run the language server, and open the log with: >vim
:lua vim.cmd('tabnew ' .. vim.lsp.get_log_path())
<
(Or use `:LspLog` if you have nvim-lspconfig installed.)
Note:
• Remember to DISABLE verbose logging ("debug" or "trace" level), else you may
encounter performance issues.
• "ERROR" messages containing "stderr" only indicate that the log was sent to
stderr. Many servers send harmless messages via stderr.
get_filename() *vim.lsp.log.get_filename()*
Returns the log filename.

View File

@@ -10,19 +10,18 @@
==============================================================================
Introduction *lua-guide*
This guide will go through the basics of using Lua in Nvim. It is not meant
to be a comprehensive encyclopedia of all available features, nor will it
detail all intricacies. Think of it as a survival kit -- the bare minimum
needed to know to comfortably get started on using Lua in Nvim.
An important thing to note is that this isn't a guide to the Lua language
itself. Rather, this is a guide on how to configure and modify Nvim through
the Lua language and the functions we provide to help with this. Take a look
at |luaref| and |lua-concepts| if you'd like to learn more about Lua itself.
Similarly, this guide assumes some familiarity with the basics of Nvim
This guide introduces the basics of everyday usage of Lua to configure and
operate Nvim. It assumes some familiarity with the (non-Lua) basics of Nvim
(commands, options, mappings, autocommands), which are covered in the
|user-manual|.
This is not a comprehensive encyclopedia of all available features. Think of
it as a survival kit: the bare minimum needed to comfortably get started on
using Lua in Nvim.
See |lua-plugin| for guidance on developing Lua plugins.
See |luaref| and |lua-concepts| for details on the Lua programming language.
------------------------------------------------------------------------------
Some words on the API *lua-guide-api*
@@ -93,10 +92,9 @@ Finally, you can include Lua code in a Vimscript file by putting it inside a
Using Lua files on startup *lua-guide-config*
Nvim supports using `init.vim` or `init.lua` as the configuration file, but
not both at the same time. This should be placed in your |config| directory,
which is typically `~/.config/nvim` for Linux, BSD, or macOS, and
`~/AppData/Local/nvim/` for Windows. Note that you can use Lua in `init.vim`
and Vimscript in `init.lua`, which will be covered below.
not both at the same time. This should be placed in your |config| directory
(run `:echo stdpath('config')` to see where it is). Note that you can also use
Lua in `init.vim` and Vimscript in `init.lua`, which will be covered below.
If you'd like to run any other Lua script on |startup| automatically, then you
can simply put it in `plugin/` in your |'runtimepath'|.

306
runtime/doc/lua-plugin.txt Normal file
View File

@@ -0,0 +1,306 @@
*lua-plugin.txt* Nvim
NVIM REFERENCE MANUAL
Guide to developing Lua plugins for Nvim
Type |gO| to see the table of contents.
==============================================================================
Introduction *lua-plugin*
This document provides guidance for developing Nvim (Lua) plugins:
See |lua-guide| for guidance on using Lua to configure and operate Nvim.
See |luaref| and |lua-concepts| for details on the Lua programming language.
==============================================================================
Creating your first plugin *lua-plugin-new*
Any Vimscript or Lua code file that lives in the right directory,
automatically is a "plugin". There's no maniest or "registration" required.
You can try it right now:
1. Visit your config directory: >
:exe 'edit' stdpath('config')
<
2. Create a `plugin/foo.lua` file in there.
3. Add something to it, like: >lua
vim.print('Hello World')
<
4. Start `nvim` and notice that it prints "Hello World" in the messages area.
Check `:messages` if you don't see it.
Besides `plugin/foo.lua`, which is always run at startup, you can define Lua
modules in the `lua/` directory. Those modules aren't loaded until your
`plugin/foo.lua`, the user, calls `require(…)`.
==============================================================================
Type safety *lua-plugin-type-safety*
Lua, as a dynamically typed language, is great for configuration. It provides
virtually immediate feedback.
But for larger projects, this can be a double-edged sword, leaving your plugin
susceptible to unexpected bugs at the wrong time.
You can leverage LuaCATS or "emmylua" annotations https://luals.github.io/wiki/annotations/
along with lua-language-server ("LuaLS") https://luals.github.io/ to catch
potential bugs in your CI before your plugin's users do. The Nvim codebase
uses these annotations extensively.
TOOLS
- lua-typecheck-action https://github.com/marketplace/actions/lua-typecheck-action
- lua-language-server https://luals.github.io
==============================================================================
Keymaps *lua-plugin-keymaps*
Avoid creating excessive keymaps automatically. Doing so can conflict with
user |mapping|s.
NOTE: An example for uncontroversial keymaps are buffer-local |mapping|s for
specific file types or floating windows, or <Plug> mappings.
A common approach to allow keymap configuration is to define a declarative DSL
https://en.wikipedia.org/wiki/Domain-specific_language via a `setup` function.
However, doing so means that
- You will have to implement and document it yourself.
- Users will likely face inconsistencies if another plugin has a slightly
different DSL.
- |init.lua| scripts that call such a `setup` function may throw an error if
the plugin is not installed or disabled.
As an alternative, you can provide |<Plug>| mappings to allow users to define
their own keymaps with |vim.keymap.set()|.
- This requires one line of code in user configs.
- Even if your plugin is not installed or disabled, creating the keymap won't
throw an error.
Another option is to simply expose a Lua function or |user-commands|.
Some benefits of |<Plug>| mappings are that you can
- Enforce options like `expr = true`.
- Use |vim.keymap|'s built-in mode handling to expose functionality only for
specific |map-modes|.
- Handle different |map-modes| differently with a single mapping, without
adding mode checks to the underlying implementation.
- Detect user-defined mappings through |hasmapto()| before creating defaults.
Some benefits of exposing a Lua function are:
- Extensibility, if the function takes an options table as an argument.
- A cleaner UX, if there are many options and enumerating all combinations
of options would result in a lot of |<Plug>| mappings.
NOTE: If your function takes an options table, users may still benefit
from |<Plug>| mappings for the most common combinations.
KEYMAP EXAMPLE
In your plugin:
>lua
vim.keymap.set('n', '<Plug>(SayHello)', function()
print('Hello from normal mode')
end, { noremap = true })
vim.keymap.set('v', '<Plug>(SayHello)', function()
print('Hello from visual mode')
end, { noremap = true })
<
In the user's config:
>lua
vim.keymap.set({'n', 'v'}, '<leader>h', '<Plug>(SayHello)')
<
==============================================================================
Initialization *lua-plugin-init*
Newcomers to Lua plugin development will often put all initialization logic in
a single `setup` function, which takes a table of options.
If you do this, users will be forced to call this function in order to use
your plugin, even if they are happy with the default configuration.
Strictly separated configuration and smart initialization allow your plugin to
work out of the box.
NOTE: A well designed plugin has minimal impact on startup time. See also
|lua-plugin-lazy|.
Common approaches to a strictly separated configuration are:
- A Lua function, e.g. `setup(opts)` or `configure(opts)`, which only overrides the
default configuration and does not contain any initialization logic.
- A Vimscript compatible table (e.g. in the |vim.g| or |vim.b| namespace) that your
plugin reads from and validates at initialization time.
See also |lua-vim-variables|.
Typically, automatic initialization logic is done in a |plugin| or |ftplugin|
script. See also |'runtimepath'|.
==============================================================================
Lazy loading *lua-plugin-lazy*
Some users like to micro-manage "lazy loading" of plugins by explicitly
configuring which commands and key mappings load the plugin.
Your plugin should not depend on every user micro-managing their configuration
in such a way. Nvim has a mechanism for every plugin to do its own implicit
lazy-loading (in Vimscript it's called |autoload|), via `autoload/`
(Vimscript) and `lua/` (Lua). Plugin authors can provide "lazy loading" by
providing a `plugin/<name>.lua` file which defines their commands and
keymappings. This file should be small, and should not eagerly `require()` the
rest of your plugin. Commands and mappings should do the `require()`.
Guidance:
- Plugins should arrange their "lazy" behavior once, instead of expecting every user to micromanage it.
- Keep `plugin/<name>.lua` small, avoid eagerly calling `require()` on modules
until a command or mapping is actually used.
------------------------------------------------------------------------------
Defer require() calls *lua-plugin-defer-require*
`plugin/<name>.lua` scripts (|plugin|) are eagerly run at startup; this is
intentional, so that plugins can setup the (minimal) commands and keymappings
that users will use to invoke the plugin. This also means these "plugin/"
files should NOT eagerly `require` Lua modules.
For example, instead of:
>lua
local foo = require('foo')
vim.api.nvim_create_user_command('MyCommand', function()
foo.do_something()
end, { -- ... })
<
which calls `require('foo')` as soon as the module is loaded, you can
lazy-load it by moving the `require` into the command's implementation:
>lua
vim.api.nvim_create_user_command('MyCommand', function()
local foo = require('foo')
foo.do_something()
end, {
-- ...
})
<
Likewise, if a plugin uses a Lua module as an entrypoint, it should
defer `require` calls too.
NOTE: For a Vimscript alternative to `require`, see |autoload|.
NOTE: If you are worried about eagerly creating user commands, autocommands or
keymaps at startup: Plugin managers that provide abstractions for lazy-loading
plugins on such events do the same amount of work. There is no performance
benefit for users to define lazy-loading entrypoints in their configuration
instead of plugins defining it in `plugin/<name>.lua`.
NOTE: You can use |--startuptime| to |profile| the impact a plugin has on
startup time.
------------------------------------------------------------------------------
Filetype-specific functionality *lua-plugin-filetype*
Consider making use of 'filetype' for any functionality that is specific to
a filetype, by putting the initialization logic in a `ftplugin/{filetype}.lua`
script.
FILETYPE EXAMPLE
A plugin tailored to Rust development might have initialization in
`ftplugin/rust.lua`:
>lua
if not vim.g.loaded_my_rust_plugin then
-- Initialize
end
-- NOTE: Using `vim.g.loaded_` prevents the plugin from initializing twice
-- and allows users to prevent plugins from loading
-- (in both Lua and Vimscript).
vim.g.loaded_my_rust_plugin = true
local bufnr = vim.api.nvim_get_current_buf()
-- do something specific to this buffer,
-- e.g. add a |<Plug>| mapping or create a command
vim.keymap.set('n', '<Plug>(MyPluginBufferAction)', function()
print('Hello')
end, { noremap = true, buffer = bufnr, })
<
==============================================================================
Configuration *lua-plugin-config*
Once you have merged the default configuration with the user's config, you
should validate configs.
Validations could include:
- Correct types, see |vim.validate()|
- Unknown fields in the user config (e.g. due to typos).
This can be tricky to implement, and may be better suited for a |health|
check, to reduce overhead.
==============================================================================
Troubleshooting *lua-plugin-troubleshooting*
HEALTH
Nvim's "health" framework gives plugins a simple way to report status checks
to users. See |health-dev| for an example.
Basically, this just means your plugin will have a `lua/{plugin}/health.lua`
file. |:checkhealth| will automatically find this file when it runs.
Some things to validate:
- User configuration
- Proper initialization
- Presence of Lua dependencies (e.g. other plugins)
- Presence of external dependencies
MINIMAL CONFIG TEMPLATE
It can be useful to provide a template for a minimal configuration, along with
a guide on how to use it to reproduce issues.
==============================================================================
Versioning and releases *lua-plugin-versioning*
Consider:
- Use |vim.deprecate()| or a `---@deprecate` annotation when you need to
communicate a (future) breaking change or discourged practice.
- Using SemVer https://semver.org/ tags and releases to properly communicate
bug fixes, new features, and breaking changes.
- Automating versioning and releases in CI.
- Publishing to luarocks https://luarocks.org, especially if your plugin
has dependencies or components that need to be built; or if it could be a
dependency for another plugin.
FURTHER READING
- Luarocks ❤️ Nvim https://github.com/nvim-neorocks/sample-luarocks-plugin
VERSIONING TOOLS
- luarocks-tag-release
https://github.com/marketplace/actions/luarocks-tag-release
- release-please-action
https://github.com/marketplace/actions/release-please-action
- semantic-release
https://github.com/semantic-release/semantic-release
==============================================================================
Documentation *lua-plugin-doc*
Provide vimdoc (see |help-writing|), so that users can read your plugin's
documentation in Nvim, by entering `:h {plugin}` in |command-mode|.
DOCUMENTATION TOOLS
- panvimdoc https://github.com/kdheepak/panvimdoc
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@@ -171,7 +171,7 @@ added. But visually, this small bit of sugar gets reasonably close to a
*lua-regex*
Lua intentionally does not support regular expressions, instead it has limited
|lua-patterns| which avoid the performance pitfalls of extended regex. Lua
|lua-pattern|s which avoid the performance pitfalls of extended regex. Lua
scripts can also use Vim regex via |vim.regex()|.
Examples: >lua
@@ -188,15 +188,19 @@ Examples: >lua
==============================================================================
IMPORTING LUA MODULES *lua-module-load*
Modules are searched for under the directories specified in 'runtimepath', in
the order they appear. Any "." in the module name is treated as a directory
separator when searching. For a module `foo.bar`, each directory is searched
for `lua/foo/bar.lua`, then `lua/foo/bar/init.lua`. If no files are found,
the directories are searched again for a shared library with a name matching
`lua/foo/bar.?`, where `?` is a list of suffixes (such as `so` or `dll`) derived from
the initial value of |package.cpath|. If still no files are found, Nvim falls
back to Lua's default search mechanism. The first script found is run and
`require()` returns the value returned by the script if any, else `true`.
Modules are searched for under the directories specified in 'runtimepath' and
|packages-runtimepath|, in the order they appear in the output of this command
>vim
:echo nvim_list_runtime_paths()
<
Any "." in the module name is treated as a directory separator when searching.
For a module `foo.bar`, each directory is searched for `lua/foo/bar.lua`, then
`lua/foo/bar/init.lua`. If no files are found, the directories are searched
again for a shared library with a name matching `lua/foo/bar.?`, where `?` is
a list of suffixes (such as `so` or `dll`) derived from the initial value of
|package.cpath|. If still no files are found, Nvim falls back to Lua's default
search mechanism. The first script found is run and `require()` returns the
value returned by the script if any, else `true`.
The return value is cached after the first call to `require()` for each module,
with subsequent calls returning the cached value without searching for, or
@@ -214,56 +218,9 @@ and loads the first module found ("first wins"): >
bar/lua/mod.so
bar/lua/mod.dll
<
*lua-package-path*
Nvim automatically adjusts |package.path| and |package.cpath| according to the
effective 'runtimepath' value. Adjustment happens whenever 'runtimepath' is
changed. `package.path` is adjusted by simply appending `/lua/?.lua` and
`/lua/?/init.lua` to each directory from 'runtimepath' (`/` is actually the
first character of `package.config`).
Similarly to |package.path|, modified directories from 'runtimepath' are also
added to |package.cpath|. In this case, instead of appending `/lua/?.lua` and
`/lua/?/init.lua` to each runtimepath, all unique `?`-containing suffixes of
the existing |package.cpath| are used. Example:
- 1. Given that
- 'runtimepath' contains `/foo/bar,/xxx;yyy/baz,/abc`;
- initial |package.cpath| (defined at compile-time or derived from
`$LUA_CPATH` / `$LUA_INIT`) contains `./?.so;/def/ghi/a?d/j/g.elf;/def/?.so`.
- 2. It finds `?`-containing suffixes `/?.so`, `/a?d/j/g.elf` and `/?.so`, in
order: parts of the path starting from the first path component containing
question mark and preceding path separator.
- 3. The suffix of `/def/?.so`, namely `/?.so` is not unique, as its the same
as the suffix of the first path from |package.path| (i.e. `./?.so`). Which
leaves `/?.so` and `/a?d/j/g.elf`, in this order.
- 4. 'runtimepath' has three paths: `/foo/bar`, `/xxx;yyy/baz` and `/abc`. The
second one contains a semicolon which is a paths separator so it is out,
leaving only `/foo/bar` and `/abc`, in order.
- 5. The cartesian product of paths from 4. and suffixes from 3. is taken,
giving four variants. In each variant a `/lua` path segment is inserted
between path and suffix, leaving:
- `/foo/bar/lua/?.so`
- `/foo/bar/lua/a?d/j/g.elf`
- `/abc/lua/?.so`
- `/abc/lua/a?d/j/g.elf`
- 6. New paths are prepended to the original |package.cpath|.
The result will look like this: >
/foo/bar,/xxx;yyy/baz,/abc ('runtimepath')
× ./?.so;/def/ghi/a?d/j/g.elf;/def/?.so (package.cpath)
= /foo/bar/lua/?.so;/foo/bar/lua/a?d/j/g.elf;/abc/lua/?.so;/abc/lua/a?d/j/g.elf;./?.so;/def/ghi/a?d/j/g.elf;/def/?.so
Note:
- To track 'runtimepath' updates, paths added at previous update are
remembered and removed at the next update, while all paths derived from the
new 'runtimepath' are prepended as described above. This allows removing
paths when path is removed from 'runtimepath', adding paths when they are
added and reordering |package.path|/|package.cpath| content if 'runtimepath'
was reordered.
- Although adjustments happen automatically, Nvim does not track current
- Although 'runtimepath' is tracked, Nvim does not track current
values of |package.path| or |package.cpath|. If you happen to delete some
paths from there you can set 'runtimepath' to trigger an update: >vim
let &runtimepath = &runtimepath
@@ -683,6 +640,12 @@ vim.hl.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts})
• {timeout}? (`integer`, default: -1 no timeout) Time in ms
before highlight is cleared
Return (multiple): ~
(`uv.uv_timer_t?`) range_timer A timer which manages how much time the
highlight has left
(`fun()?`) range_clear A function which allows clearing the highlight
manually. nil is returned if timeout is not specified
==============================================================================
VIM.DIFF *vim.diff*
@@ -1503,20 +1466,21 @@ Lua module: vim *lua-vim*
vim.cmd({command}) *vim.cmd()*
Executes Vimscript (|Ex-commands|).
Note that `vim.cmd` can be indexed with a command name to return a
callable function to the command.
Can be indexed with a command name to get a function, thus you can write
`vim.cmd.echo(…)` instead of `vim.cmd{cmd='echo',…}`.
Example: >lua
Examples: >lua
-- Single command:
vim.cmd('echo 42')
-- Multiline script:
vim.cmd([[
augroup My_group
augroup my.group
autocmd!
autocmd FileType c setlocal cindent
augroup END
]])
-- Ex command :echo "foo"
-- Note string literals need to be double quoted.
-- Ex command :echo "foo". Note: string literals must be double-quoted.
vim.cmd('echo "foo"')
vim.cmd { cmd = 'echo', args = { '"foo"' } }
vim.cmd.echo({ args = { '"foo"' } })
@@ -1524,22 +1488,20 @@ vim.cmd({command}) *vim.cmd()*
-- Ex command :write! myfile.txt
vim.cmd('write! myfile.txt')
vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true }
vim.cmd.write { args = { "myfile.txt" }, bang = true }
vim.cmd.write { "myfile.txt", bang = true }
vim.cmd { cmd = 'write', args = { 'myfile.txt' }, bang = true }
vim.cmd.write { args = { 'myfile.txt' }, bang = true }
vim.cmd.write { 'myfile.txt', bang = true }
-- Ex command :colorscheme blue
vim.cmd('colorscheme blue')
vim.cmd.colorscheme('blue')
-- Ex command :vertical resize +2
vim.cmd.resize({ '+2', mods = { vertical = true } })
<
Parameters: ~
• {command} (`string|table`) Command(s) to execute. If a string,
executes multiple lines of Vimscript at once. In this case,
it is an alias to |nvim_exec2()|, where `opts.output` is
set to false. Thus it works identical to |:source|. If a
table, executes a single command. In this case, it is an
alias to |nvim_cmd()| where `opts` is empty.
• {command} (`string|table`) Command(s) to execute.
• The string form supports multiline Vimscript (alias to
|nvim_exec2()|, behaves like |:source|).
• The table form executes a single command (alias to
|nvim_cmd()|).
See also: ~
• |ex-cmd-index|
@@ -1816,7 +1778,9 @@ vim.system({cmd}, {opts}, {on_exit}) *vim.system()*
the new process. Inherits the current environment with
`NVIM` set to |v:servername|.
• clear_env: (boolean) `env` defines the job environment
exactly, instead of merging current environment.
exactly, instead of merging current environment. Note: if
`env` is `nil`, the current environment is used but
without `NVIM` set.
• stdin: (string|string[]|boolean) If `true`, then a pipe
to stdin is opened and can be written to via the
`write()` method to SystemObj. If string or string[] then
@@ -2059,7 +2023,7 @@ vim.gsplit({s}, {sep}, {opts}) *vim.gsplit()*
See also: ~
• |string.gmatch()|
• |vim.split()|
• |lua-patterns|
• |lua-pattern|s
• https://www.lua.org/pil/20.2.html
• http://lua-users.org/wiki/StringLibraryTutorial
@@ -2152,7 +2116,7 @@ vim.list_slice({list}, {start}, {finish}) *vim.list_slice()*
(`any[]`) Copy of table sliced from start to finish (inclusive)
vim.pesc({s}) *vim.pesc()*
Escapes magic chars in |lua-patterns|.
Escapes magic chars in |lua-pattern|s.
Parameters: ~
• {s} (`string`) String to escape
@@ -2407,7 +2371,7 @@ vim.trim({s}) *vim.trim()*
(`string`) String with whitespace removed from its beginning and end
See also: ~
• |lua-patterns|
• |lua-pattern|s
• https://www.lua.org/pil/20.2.html
*vim.validate()*
@@ -2707,7 +2671,7 @@ vim.filetype.add({filetypes}) *vim.filetype.add()*
Filetype mappings can be added either by extension or by filename (either
the "tail" or the full file path). The full file path is checked first,
followed by the file name. If a match is not found using the filename,
then the filename is matched against the list of |lua-patterns| (sorted by
then the filename is matched against the list of |lua-pattern|s (sorted by
priority) until a match is found. Lastly, if pattern matching does not
find a filetype, then the file extension is used.
@@ -2935,7 +2899,7 @@ Use |uv.fs_stat()| to check a file's type, and whether it exists.
Example: >lua
if vim.uv.fs_stat(file) then
vim.print("file exists")
vim.print('file exists')
end
<
@@ -2977,11 +2941,13 @@ vim.fs.dir({path}, {opts}) *vim.fs.dir()*
iterate over. The path is first normalized
|vim.fs.normalize()|.
• {opts} (`table?`) Optional keyword arguments:
• depth: integer|nil How deep the traverse (default 1)
• skip: (fun(dir_name: string): boolean)|nil Predicate to
{depth}? (`integer`, default: `1`) How deep the traverse.
{skip}? (`fun(dir_name: string): boolean`) Predicate to
control traversal. Return false to stop searching the
current directory. Only useful when depth > 1
• follow: boolean|nil Follow symbolic links. (default: false)
current directory. Only useful when depth > 1 Return an
iterator over the items located in {path}
• {follow}? (`boolean`, default: `false`) Follow symbolic
links.
Return: ~
(`Iterator`) over items in {path}. Each iteration yields two values:
@@ -2990,7 +2956,8 @@ vim.fs.dir({path}, {opts}) *vim.fs.dir()*
"fifo", "socket", "char", "block", "unknown".
vim.fs.dirname({file}) *vim.fs.dirname()*
Return the parent directory of the given path
Gets the parent directory of the given path (not expanded/resolved, the
caller must do that).
Attributes: ~
Since: 0.8.0
@@ -3015,16 +2982,17 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
narrow the search to find only that type.
Examples: >lua
-- list all test directories under the runtime directory
local test_dirs = vim.fs.find(
{'test', 'tst', 'testdir'},
{limit = math.huge, type = 'directory', path = './runtime/'}
-- List all test directories under the runtime directory.
local dirs = vim.fs.find(
{ 'test', 'tst', 'testdir' },
{ limit = math.huge, type = 'directory', path = './runtime/' }
)
-- get all files ending with .cpp or .hpp inside lib/
local cpp_hpp = vim.fs.find(function(name, path)
-- Get all "lib/*.cpp" and "lib/*.hpp" files, using Lua patterns.
-- Or use `vim.glob.to_lpeg(…):match(…)` for glob/wildcard matching.
local files = vim.fs.find(function(name, path)
return name:match('.*%.[ch]pp$') and path:match('[/\\]lib$')
end, {limit = math.huge, type = 'file'})
end, { limit = math.huge, type = 'file' })
<
Attributes: ~
@@ -3041,7 +3009,7 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
The function should return `true` if the given item is
considered a match.
• {opts} (`table`) Optional keyword arguments:
• {opts} (`table?`) Optional keyword arguments:
• {path}? (`string`) Path to begin searching from. If
omitted, the |current-directory| is used.
• {upward}? (`boolean`, default: `false`) Search upward
@@ -3124,19 +3092,20 @@ vim.fs.normalize({path}, {opts}) *vim.fs.normalize()*
(`string`) Normalized path
vim.fs.parents({start}) *vim.fs.parents()*
Iterate over all the parents of the given path.
Iterate over all the parents of the given path (not expanded/resolved, the
caller must do that).
Example: >lua
local root_dir
for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
if vim.fn.isdirectory(dir .. "/.git") == 1 then
if vim.fn.isdirectory(dir .. '/.git') == 1 then
root_dir = dir
break
end
end
if root_dir then
print("Found git repository at", root_dir)
print('Found git repository at', root_dir)
end
<
@@ -3188,7 +3157,7 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
If the buffer is unnamed (has no backing file) or has a non-empty
'buftype' then the search begins from Nvim's |current-directory|.
Example: >lua
Examples: >lua
-- Find the root of a Python project, starting from file 'main.py'
vim.fs.root(vim.fs.joinpath(vim.env.PWD, 'main.py'), {'pyproject.toml', 'setup.py' })
@@ -3199,6 +3168,10 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
vim.fs.root(0, function(name, path)
return name:match('%.csproj$') ~= nil
end)
-- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
-- not found, find the first ancestor containing ".git":
vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' })
<
Attributes: ~
@@ -3208,10 +3181,13 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
• {source} (`integer|string`) Buffer number (0 for current buffer) or
file path (absolute or relative to the |current-directory|)
to begin the search from.
• {marker} (`string|string[]|fun(name: string, path: string): boolean`)
A marker, or list of markers, to search for. If a function,
the function is called for each evaluated item and should
return true if {name} and {path} are a match.
• {marker} (`(string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean`)
Filename, function, or list thereof, that decides how to
find the root. To indicate "equal priority", specify items
in a nested list `{ { 'a.txt', 'b.lua' }, … }`. A function
item must return true if `name` and `path` are a match. Each
item (which may itself be a nested list) is evaluated
in-order against all ancestors, until a match is found.
Return: ~
(`string?`) Directory path containing one of the given markers, or nil
@@ -3774,19 +3750,25 @@ vim.regex({re}) *vim.regex()*
Lua module: vim.secure *vim.secure*
vim.secure.read({path}) *vim.secure.read()*
Attempt to read the file at {path} prompting the user if the file should
be trusted. The user's choice is persisted in a trust database at
If {path} is a file: attempt to read the file, prompting the user if the
file should be trusted.
If {path} is a directory: return true if the directory is trusted
(non-recursive), prompting the user as necessary.
The user's choice is persisted in a trust database at
$XDG_STATE_HOME/nvim/trust.
Attributes: ~
Since: 0.9.0
Parameters: ~
• {path} (`string`) Path to a file to read.
• {path} (`string`) Path to a file or directory to read.
Return: ~
(`string?`) The contents of the given file if it exists and is
trusted, or nil otherwise.
(`boolean|string?`) If {path} is not trusted or does not exist,
returns `nil`. Otherwise, returns the contents of {path} if it is a
file, or true if {path} is a directory.
See also: ~
• |:trust|

View File

@@ -4150,7 +4150,7 @@ string.upper({s}) *string.upper()*
locale.
------------------------------------------------------------------------------
5.4.1 Patterns *lua-patterns*
5.4.1 Patterns *lua-pattern*
A character class is used to represent a set of characters. The following
combinations are allowed in describing a character class:
@@ -4207,6 +4207,7 @@ A pattern item may be
- a single character class followed by `+`, which matches 1 or more
repetitions of characters in the class. These repetition items will
always match the longest possible sequence;
*lua-nongreedy*
- a single character class followed by `-`, which also matches 0 or
more repetitions of characters in the class. Unlike `*`, these
repetition items will always match the shortest possible sequence;
@@ -4221,7 +4222,7 @@ A pattern item may be
`y` where the count reaches 0. For instance, the item `%b()` matches
expressions with balanced parentheses.
PATTERN *lua-pattern*
PATTERN
A pattern is a sequence of pattern items. A `^` at the beginning of a pattern
anchors the match at the beginning of the subject string. A `$` at the end of

View File

@@ -19,12 +19,7 @@ For changing the language of messages and menus see |mlang.txt|.
==============================================================================
Getting started *mbyte-first*
This is a summary of the multibyte features in Vim. If you are lucky it works
as described and you can start using Vim without much trouble. If something
doesn't work you will have to read the rest. Don't be surprised if it takes
quite a bit of work and experimenting to make Vim use all the multibyte
features. Unfortunately, every system has its own way to deal with multibyte
languages and it is quite complicated.
This is a summary of the multibyte features in Nvim.
LOCALE
@@ -54,14 +49,14 @@ See |mbyte-locale| for details.
ENCODING
Nvim always uses UTF-8 internally. Thus 'encoding' option is always set
to "utf-8" and cannot be changed.
Nvim always uses UTF-8 internally. Thus 'encoding' is always set to "utf-8"
and cannot be changed.
All the text that is used inside Vim will be in UTF-8. Not only the text in
the buffers, but also in registers, variables, etc.
You can edit files in different encodings than UTF-8. Nvim
will convert the file when you read it and convert it back when you write it.
You can edit files in different encodings than UTF-8. Nvim will convert the
file when you read it and convert it back when you write it.
See 'fileencoding', 'fileencodings' and |++enc|.
@@ -184,9 +179,9 @@ You could make a small shell script for this.
==============================================================================
Encoding *mbyte-encoding*
In Nvim UTF-8 is always used internally to encode characters.
This applies to all the places where text is used, including buffers (files
loaded into memory), registers and variables.
UTF-8 is always used internally to encode characters. This applies to all the
places where text is used, including buffers (files loaded into memory),
registers and variables.
*charset* *codeset*
Charset is another name for encoding. There are subtle differences, but these
@@ -609,25 +604,25 @@ Combining forms:
Using UTF-8 *mbyte-utf8* *UTF-8* *utf-8* *utf8*
*Unicode* *unicode*
The Unicode character set was designed to include all characters from other
character sets. Therefore it is possible to write text in any language using
Unicode (with a few rarely used languages excluded). And it's mostly possible
to mix these languages in one file, which is impossible with other encodings.
character sets. Therefore it is possible to write text in (almost) any
language using Unicode. And it's mostly possible to mix these languages in
one file, which is impossible with other encodings.
Unicode can be encoded in several ways. The most popular one is UTF-8, which
uses one or more bytes for each character and is backwards compatible with
ASCII. On MS-Windows UTF-16 is also used (previously UCS-2), which uses
16-bit words. Vim can support all of these encodings, but always uses UTF-8
ASCII. On MS-Windows UTF-16 is also used (previously UCS-2), which uses
16-bit words. Nvim supports all of these encodings, but always uses UTF-8
internally.
Vim has comprehensive UTF-8 support. It works well in:
- xterm with UTF-8 support enabled
- MS-Windows GUI
- several other platforms
Double-width characters are supported. Works best with 'guifontwide'. When
Nvim supports double-width characters; works best with 'guifontwide'. When
using only 'guifont' the wide characters are drawn in the normal width and
a space to fill the gap.
EMOJI *emoji*
You can list emoji characters using this script: >vim
:source $VIMRUNTIME/scripts/emoji_list.lua
<
*bom-bytes*
When reading a file a BOM (Byte Order Mark) can be used to recognize the
Unicode encoding:
@@ -698,7 +693,7 @@ You need to specify a font to be used. For double-wide characters another
font is required, which is exactly twice as wide. There are three ways to do
this:
1. Set 'guifont' and let Vim find a matching 'guifontwide'
1. Set 'guifont' and let Nvim find a matching 'guifontwide'
2. Set 'guifont' and 'guifontwide'
See the documentation for each option for details. Example: >
@@ -730,7 +725,7 @@ COMMAND ARGUMENTS *utf-8-char-arg*
Commands like |f|, |F|, |t| and |r| take an argument of one character. For
UTF-8 this argument may include one or two composing characters. These need
to be produced together with the base character, Vim doesn't wait for the next
to be produced together with the base character, Nvim doesn't wait for the next
character to be typed to find out if it is a composing character or not.
Using 'keymap' or |:lmap| is a nice way to type these characters.
@@ -741,7 +736,6 @@ searching for a character with a composing character, this will only find
matches with that composing character. It was implemented this way, because
not everybody is able to type a composing character.
==============================================================================
Overview of options *mbyte-options*

View File

@@ -119,10 +119,6 @@ OPTIONS
• Setting |hidden-options| now gives an error. In particular, setting
'noshellslash' is now only allowed on Windows.
PLUGINS
• TODO
TREESITTER
• |Query:iter_matches()| correctly returns all matching nodes in a match
@@ -136,12 +132,11 @@ TREESITTER
if no languages are explicitly registered.
• |vim.treesitter.language.add()| returns `true` if a parser was loaded
successfully and `nil,errmsg` otherwise instead of throwing an error.
• |vim.treesitter.get_parser()| and |vim.treesitter.start()| no longer parse
the tree before returning. Scripts must call |LanguageTree:parse()| explicitly. >lua
• |vim.treesitter.get_parser()| and |vim.treesitter.start()| no longer parse the
tree before returning. Scripts must call |LanguageTree:parse()| explicitly. >lua
local p = vim.treesitter.get_parser(0, 'c')
p:parse()
• |vim.treesitter.get_parser()| expects its buffer to be loaded.
<
TUI
@@ -176,7 +171,11 @@ API
aligned text that truncates before covering up buffer text.
• `virt_lines_overflow` field accepts value `scroll` to enable horizontal
scrolling for virtual lines with 'nowrap'.
• |vim.hl.range()| now has a optional `timeout` field which allows for a timed highlight
• |vim.secure.read()| now returns `true` for trusted directories. Previously
it would return `nil`, which made it impossible to tell if the directory was
actually trusted.
• Added |vim.lsp.is_enabled()| to check if a given LSP config has been enabled
by |vim.lsp.enable()|.
DEFAULTS
@@ -189,6 +188,7 @@ DEFAULTS
• |gri| in Normal mode maps to |vim.lsp.buf.implementation()|
• |gO| in Normal mode maps to |vim.lsp.buf.document_symbol()|
• |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|
• |grt| in Normal mode maps to |vim.lsp.buf.type_definition()|
• CTRL-S in Insert and Select mode maps to |vim.lsp.buf.signature_help()|
• Mouse |popup-menu| includes an "Open in web browser" item when you right-click
on a URL.
@@ -242,8 +242,7 @@ EDITOR
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
• |gO| now works in `help`, `checkhealth`, and `markdown` buffers.
• Jump between sections in `help` and `checkhealth` buffers with `[[` and
`]]`.
• Jump between sections in `help` and `checkhealth` buffers with `[[` and `]]`.
EVENTS
@@ -283,12 +282,16 @@ LSP
`codeAction/resolve` request.
• The `textDocument/completion` request now includes the completion context in
its parameters.
• |vim.lsp.Config| gained `workspace_required`.
• `root_markers` in |vim.lsp.Config| can now be ordered by priority.
• The function form of `cmd` in a vim.lsp.Config or vim.lsp.ClientConfig
receives the resolved config as the second arg: `cmd(dispatchers, config)`.
LUA
• Command-line completions for: `vim.g`, `vim.t`, `vim.w`, `vim.b`, `vim.v`,
`vim.o`, `vim.wo`, `vim.bo`, `vim.opt`, `vim.opt_local`, `vim.opt_global`,
and `vim.fn`.
`vim.env` and `vim.fn`.
• Documentation for |lua-bit|.
• |gf| in Lua buffers can go to module in same repo, |runtime-search-path| and
|package.path|.
@@ -302,7 +305,10 @@ LUA
• |vim.fs.relpath()| gets relative path compared to base path.
• |vim.fs.dir()| and |vim.fs.find()| can now follow symbolic links,
the behavior can be turn on using the new `follow` option.
• |vim.hl.range()| now has a optional `timeout` field which allows for multiple
timed highlights.
• |vim.text.indent()| indents/dedents text.
• |vim.fs.root()| can define "equal priority" via nested lists.
OPTIONS
@@ -312,7 +318,9 @@ OPTIONS
• 'messagesopt' configures |:messages| and |hit-enter| prompt.
• 'tabclose' controls which tab page to focus when closing a tab page.
• 'eventignorewin' to persistently ignore events in a window.
• 'winborder' sets the default border for |floating-windows|
• 'winborder' sets the default border for |floating-windows|.
• 'winborder' "bold" style.
• |g:clipboard| accepts a string name to force any builtin clipboard tool.
PERFORMANCE
@@ -345,6 +353,13 @@ PLUGINS
• 'commentstring' values can now be specified in a Treesitter capture's
`bo.commentstring` metadata field, providing finer grained support for
languages like `JSX`.
• Customize :checkhealth by handling a `FileType checkhealth` event.
|health-usage|
• Simplify Python provider setup to a single step: `uv tool install pynvim`
Nvim will detect the plugin's location without user configuration, even if
unrelated Python virtual environments are activated.
|provider-python|
STARTUP
@@ -439,6 +454,7 @@ UI
• |ui-messages| content chunks now also contain the highlight group ID.
• |:checkhealth| can display in a floating window, controlled by the
|g:health| variable.
• |:checkhealth| shows a summary in the header for every healthcheck.
VIMSCRIPT

View File

@@ -11,15 +11,43 @@ not a clone: compatibility with Vim (especially editor and Vimscript features,
except |Vim9script|) is maintained where possible. See |vim-differences| for
the complete reference.
If you already use Vim, see |nvim-from-vim| for a quickstart. If you just
installed Nvim and have never used it before, watch this 10-minute
video: https://youtu.be/TQn2hJeHQbM .
- If you already use Vim, see |nvim-from-vim| for a quickstart.
- If you have never used Vim or Nvim before, see below.
Type |gO| to see the table of contents.
==============================================================================
What now? *nvim-quickstart*
To learn how to use Vim in 30 minutes, try the tutorial: >vim
:Tutor<Enter>
<
Type |gO| to see the table of contents.
Or watch this 10-minute video: https://youtu.be/TQn2hJeHQbM .
To customize Nvim, you will need a config file. Create your |init.lua| by
copying the "example_init.lua" file: >vim
:exe 'edit' stdpath('config') .. '/init.lua'
:read $VIMRUNTIME/example_init.lua
<
See |lua-guide| for practical notes on using Lua to configure Nvim.
"IDE" features in Nvim are provided by |LSP|.
If you are just trying out Nvim for a few minutes, and want to see the
extremes of what it can do, try one of these popular "extension packs" or
"distributions" (Note: Nvim is not affiliated with these projects, and does
not support them):
- *lazyvim* https://www.lazyvim.org/
- *nvchad* https://nvchad.com/
- *kickstart* https://github.com/nvim-lua/kickstart.nvim
- Not recommended; use `$VIMRUNTIME/example_init.lua` instead.
However, we recommend (eventually) taking time to learn Nvim from its stock
configuration, and incrementally setting options and adding plugins to your
|config| as you discover a need.
==============================================================================
Transitioning from Vim *nvim-from-vim*
@@ -72,21 +100,5 @@ the same Nvim configuration on all of your machines, by creating
~/AppData/Local/nvim/init.vim containing just this line: >vim
source ~/.config/nvim/init.vim
==============================================================================
What next? *nvim-quickstart*
If you are just trying out Nvim for a few minutes, and want to see the
extremes of what it can do, try one of these popular "extension packs" or
"distributions" (Note: Nvim is not affiliated with these projects, and does
not support them):
- *kickstart* https://github.com/nvim-lua/kickstart.nvim
- *lazyvim* https://www.lazyvim.org/
- *nvchad* https://nvchad.com/
However, in general, we recommend (eventually) taking time to learn Nvim from
its stock configuration, and incrementally setting options and adding plugins
to your |config| as you find an explicit need to do so.
==============================================================================
vim:tw=78:ts=8:et:ft=help:norl:

View File

@@ -2357,10 +2357,18 @@ A jump table for the options with a short description can be found at |Q_op|.
in the |trust| list. Use |:trust| to manage trusted files. See also
|vim.secure.read()|.
To get its own location, Lua exrc files can use |debug.getinfo()|.
Compare 'exrc' to |editorconfig|:
- 'exrc' can execute any code; editorconfig only specifies settings.
- 'exrc' is Nvim-specific; editorconfig works in other editors.
To achieve project-local LSP configuration:
1. Enable 'exrc'.
2. Place LSP configs at ".nvim/lsp/*.lua" in your project root.
3. Create ".nvim.lua" in your project root directory with this line: >lua
vim.cmd[[set runtimepath+=.nvim]]
<
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
@@ -5004,9 +5012,14 @@ A jump table for the options with a short description can be found at |Q_op|.
the end of line the line break still isn't included.
When "exclusive" is used, cursor position in visual mode will be
adjusted for inclusive motions |inclusive-motion-selection-exclusive|.
Note that when "exclusive" is used and selecting from the end
backwards, you cannot include the last character of a line, when
starting in Normal mode and 'virtualedit' empty.
Note:
- When "exclusive" is used and selecting from the end backwards, you
cannot include the last character of a line, when starting in Normal
mode and 'virtualedit' empty.
- when "exclusive" is used with a single character visual selection,
Vim will behave as if the 'selection' is inclusive (in other words,
you cannot visually select an empty region).
*'selectmode'* *'slm'*
'selectmode' 'slm' string (default "")
@@ -5946,8 +5959,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'statusline'* *'stl'* *E540* *E542*
'statusline' 'stl' string (default "")
global or local to window |global-local|
When non-empty, this option determines the content of the status line.
Also see |status-line|.
Sets the |status-line|.
The option consists of printf style '%' items interspersed with
normal text. Each status line item is of the form:
@@ -7155,12 +7167,13 @@ A jump table for the options with a short description can be found at |Q_op|.
global
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "bold": Bold line box.
- "double": Double-line box.
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("╭" etc.).
- "shadow": Drop shadow effect, by blending with the background.
- "single": Single-line box.
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
*'window'* *'wi'*
'window' 'wi' number (default screen height - 1)

View File

@@ -4,6 +4,8 @@
vim-tutor-mode provides a system to follow and create interactive tutorials
for vim and third party plugins. It replaces the venerable `vimtutor` system.
Original Author: Felipe Morales <https://github.com/fmoralesc>
==============================================================================
1. Usage *vim-tutor-usage*
@@ -39,12 +41,5 @@ to be detected by the :Tutor command.
It is recommended to use a less formal style when writing tutorials than in
regular documentation (unless the content requires it).
============================================================================
3. Contributing
Development of the plugin is done over at github [1]. Feel free to report
issues and make suggestions.
[1]: https://github.com/fmoralesc/vim-tutor-mode
" vim: set ft=help :
=============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -11,7 +11,7 @@ the providers and how to install them.
*E319*
Use of a feature requiring a missing provider is an error: >
E319: No "foo" provider found. Run ":checkhealth provider"
E319: No "foo" provider found. Run ":checkhealth vim.provider"
Run the |:checkhealth| command, and review the sections below.
@@ -35,22 +35,19 @@ if you already have it (some package managers install the module with Nvim
itself).
For Python 3 plugins:
1. Make sure Python 3.4+ is available in your $PATH.
2. Install the module (try "python" if "python3" is missing): >bash
python3 -m pip install --user --upgrade pynvim
1. Make sure Python 3.9+ is available in your $PATH.
2. Install either uv (https://docs.astral.sh/uv/) or pipx
(https://pipx.pypa.io/stable/).
3. Install the module: >bash
uv tool install --upgrade pynvim
# or:
pipx install --upgrade pynvim
The pip `--upgrade` flag ensures that you get the latest version even if
The `--upgrade` flag ensures that you get the latest version even if
a previous version was already installed.
See also |python-virtualenv|.
Note: The old "neovim" module was renamed to "pynvim".
https://github.com/neovim/neovim/wiki/Following-HEAD#20181118
If you run into problems, uninstall _both_ then install "pynvim" again: >bash
python -m pip uninstall neovim pynvim
python -m pip install --user --upgrade pynvim
PYTHON PROVIDER CONFIGURATION ~
*g:python3_host_prog*
Command to start Python 3 (executable, not directory). Setting this makes
@@ -65,20 +62,18 @@ To disable Python 3 support: >vim
PYTHON VIRTUALENVS ~
*python-virtualenv*
If you plan to use per-project virtualenvs often, you should assign one
virtualenv for Nvim and hard-code the interpreter path via
|g:python3_host_prog| so that the "pynvim" package is not required
for each virtualenv.
Example using pyenv: >bash
pyenv install 3.4.4
pyenv virtualenv 3.4.4 py3nvim
pyenv activate py3nvim
python3 -m pip install pynvim
pyenv which python # Note the path
The last command reports the interpreter path, add it to your init.vim: >vim
let g:python3_host_prog = '/path/to/py3nvim/bin/python'
Using pynvim 0.6.0+ installed via uv or pipx, Nvim will automatically detect
pynvim even if other Python virtual environments are activated (technical
note: via the "pynvim-python" global python tool). For older pynvim (or older
Neovim), where detection involved finding the first Python interpreter and
checking if it could import pynvim, automatic detection would fail when
another virtual environment is active. Upgrading to the latest pynvim is the
recommended solution to this; but if that's not an option, then you can set
the variable |g:python3_host_prog| in `init.vim` to point to the full path to
the Python interpreter where `pynvim` is installed, e.g.: >vim
let g:python3_host_prog = '/path/to/pynvim-venv/bin/python'
<
See also: https://github.com/zchee/deoplete-jedi/wiki/Setting-up-Python-for-Neovim
==============================================================================
@@ -182,100 +177,112 @@ the "+" and/or "*" registers explicitly): >vim
See 'clipboard' for details and options.
*clipboard-tool*
The presence of a working clipboard tool implicitly enables the '+' and "*"
registers. Nvim looks for these clipboard tools, in order of priority:
The presence of a working clipboard tool implicitly enables the "+" and "*"
registers. Nvim supports these clipboard tools, in order of priority:
- |g:clipboard| (unless unset or `false`)
- pbcopy, pbpaste (macOS)
- wl-copy, wl-paste (if $WAYLAND_DISPLAY is set)
- waycopy, waypaste (if $WAYLAND_DISPLAY is set)
- xsel (if $DISPLAY is set)
- xclip (if $DISPLAY is set)
- lemonade (for SSH) https://github.com/pocke/lemonade
- doitclient (for SSH) https://www.chiark.greenend.org.uk/~sgtatham/doit/
- *win32yank* (Windows)
- putclip, getclip (Windows) https://cygwin.com/packages/summary/cygutils.html
- clip, powershell (Windows) https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/clip
- termux (via termux-clipboard-set, termux-clipboard-set)
- tmux (if $TMUX is set)
- |g:clipboard| : User override (if set to a dict or any string "name" below;
e.g. `g:clipboard="tmux"` forces tmux clipboard and skips auto-detection).
- "pbcopy" : pbcopy, pbpaste (macOS)
- "wl-copy" : wl-copy, wl-paste (if $WAYLAND_DISPLAY is set)
- "wayclip" : waycopy, waypaste (if $WAYLAND_DISPLAY is set)
- "xsel" : xsel (if $DISPLAY is set)
- "xclip" : xclip (if $DISPLAY is set)
- "lemonade" : lemonade (for SSH) https://github.com/pocke/lemonade
- "doitclient": doitclient (for SSH) https://www.chiark.greenend.org.uk/~sgtatham/doit/
- "win32yank" : *win32yank* (Windows)
- "putclip" : putclip, getclip (Windows) https://cygwin.com/packages/summary/cygutils.html
- "clip" : clip, powershell (Windows) https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/clip
- "termux" : termux (via termux-clipboard-set, termux-clipboard-set)
- "tmux" : tmux (if $TMUX is set)
- "osc52" : |clipboard-osc52| (if supported by your terminal)
*g:clipboard*
To configure a custom clipboard tool, set g:clipboard to a dictionary.
For example this configuration integrates the tmux clipboard: >vim
let g:clipboard = {
\ 'name': 'myClipboard',
\ 'copy': {
\ '+': ['tmux', 'load-buffer', '-'],
\ '*': ['tmux', 'load-buffer', '-'],
\ },
\ 'paste': {
\ '+': ['tmux', 'save-buffer', '-'],
\ '*': ['tmux', 'save-buffer', '-'],
\ },
\ 'cache_enabled': 1,
\ }
To configure a custom clipboard tool, set `g:clipboard` to a string name (from
the above |clipboard-tool| list), or dict (to explicitly specify the shell
commands or |lambda| functions).
If "cache_enabled" is |TRUE| then when a selection is copied Nvim will cache
the selection until the copy command process dies. When pasting, if the copy
process has not died the cached selection is applied.
g:clipboard can also use functions (see |lambda|) instead of strings.
For example this configuration uses the g:foo variable as a fake clipboard:
>vim
let g:clipboard = {
\ 'name': 'myClipboard',
\ 'copy': {
\ '+': {lines, regtype -> extend(g:, {'foo': [lines, regtype]}) },
\ '*': {lines, regtype -> extend(g:, {'foo': [lines, regtype]}) },
\ },
\ 'paste': {
\ '+': {-> get(g:, 'foo', [])},
\ '*': {-> get(g:, 'foo', [])},
\ },
\ }
The "copy" function stores a list of lines and the register type. The "paste"
function returns the clipboard as a `[lines, regtype]` list, where `lines` is
a list of lines and `regtype` is a register type conforming to |setreg()|.
Example: set to "osc52" to force OSC52, skipping auto-detection of terminal
support: >vim
let g:clipboard = 'osc52'
Example: set to "wayclip" to force waycopy/waypaste: >vim
let g:clipboard = 'wayclip'
Example: set to a dict which integrates the tmux clipboard: >vim
let g:clipboard = {
\ 'name': 'myClipboard',
\ 'copy': {
\ '+': ['tmux', 'load-buffer', '-'],
\ '*': ['tmux', 'load-buffer', '-'],
\ },
\ 'paste': {
\ '+': ['tmux', 'save-buffer', '-'],
\ '*': ['tmux', 'save-buffer', '-'],
\ },
\ 'cache_enabled': 1,
\ }
Example: set to a dict which uses g:foo as a fake clipboard: >vim
let g:clipboard = {
\ 'name': 'myClipboard',
\ 'copy': {
\ '+': {lines, regtype -> extend(g:, {'foo': [lines, regtype]}) },
\ '*': {lines, regtype -> extend(g:, {'foo': [lines, regtype]}) },
\ },
\ 'paste': {
\ '+': {-> get(g:, 'foo', [])},
\ '*': {-> get(g:, 'foo', [])},
\ },
\ }
<
*clipboard-wsl*
For Windows WSL, try this g:clipboard definition:
>vim
let g:clipboard = {
\ 'name': 'WslClipboard',
\ 'copy': {
\ '+': 'clip.exe',
\ '*': 'clip.exe',
\ },
\ 'paste': {
\ '+': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',
\ '*': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',
\ },
\ 'cache_enabled': 0,
\ }
\ 'name': 'WslClipboard',
\ 'copy': {
\ '+': 'clip.exe',
\ '*': 'clip.exe',
\ },
\ 'paste': {
\ '+': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',
\ '*': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',
\ },
\ 'cache_enabled': 0,
\ }
<
*clipboard-osc52*
Nvim bundles a clipboard provider that allows copying to the system clipboard
using OSC 52. OSC 52 is an Operating System Command control sequence that
causes the terminal emulator to write to or read from the system clipboard.
using OSC 52, an "Operating System Command" control-sequence that causes the
terminal emulator to write to or read from the system clipboard.
When Nvim is running in the |TUI|, it will automatically attempt to determine if
the host terminal emulator supports OSC 52. If it does, then Nvim will use OSC
52 for copying and pasting if no other |clipboard-tool| is found and when
'clipboard' is unset. NOTE: Using a terminal multiplexer (e.g. tmux) may
inhibit automatic OSC 52 support detection.
When Nvim is running in the |TUI|, it automatically detects host terminal
support for OSC 52. If successful, then Nvim will use OSC 52 for copying and
pasting if no other |clipboard-tool| is found and when 'clipboard' is unset.
NOTE: Using a terminal multiplexer (e.g. tmux) may inhibit automatic OSC 52
support detection.
*g:termfeatures*
To disable the automatic detection, set the "osc52" key of |g:termfeatures| to
|v:false| in the |config| file. Example: >lua
false early in your |config|. Example: >lua
local termfeatures = vim.g.termfeatures or {}
termfeatures.osc52 = false
vim.g.termfeatures = termfeatures
<
To force Nvim to always use the OSC 52 provider you can use the following
|g:clipboard| definition: >lua
To force Nvim to use the OSC 52 provider you can set |g:clipboard|: >lua
vim.g.clipboard = 'osc52'
@@ -292,7 +299,7 @@ Which is equivalent to: >lua
},
}
<
Note that not all terminal emulators support reading from the system clipboard
Note: not all terminal emulators support reading from the system clipboard
(and even for those that do, users should be aware of the security
implications), so using OSC 52 for pasting may not be possible (and not
necessary, because you can |paste| instead using your system paste function).

View File

@@ -91,28 +91,40 @@ processing a quickfix or location list command, it will be aborted.
:ll[!] [nr] Same as ":cc", except the location list for the
:[nr]ll[!] current window is used instead of the quickfix list.
*:cn* *:cne* *:cnext* *E553* *]q*
*:cn* *:cne* *:cnext* *E553*
:[count]cn[ext][!] Display the [count] next error in the list that
includes a file name. If there are no file names at
all, go to the [count] next error. See |:cc| for
[!] and 'switchbuf'.
*:lne* *:lnext* *]l*
*]q*
]q Mapped to |:cnext|. |default-mappings|
*:lne* *:lnext*
:[count]lne[xt][!] Same as ":cnext", except the location list for the
current window is used instead of the quickfix list.
:[count]cN[ext][!] *:cp* *:cprevious* *:cprev* *:cN* *:cNext* *[q*
*]l*
]l Mapped to |:lnext|. |default-mappings|
:[count]cN[ext][!] *:cp* *:cprevious* *:cprev* *:cN* *:cNext*
:[count]cp[revious][!] Display the [count] previous error in the list that
includes a file name. If there are no file names at
all, go to the [count] previous error. See |:cc| for
[!] and 'switchbuf'.
*[q*
[q Mapped to |:cprevious|. |default-mappings|
:[count]lN[ext][!] *:lp* *:lprevious* *:lprev* *:lN* *:lNext* *[l*
:[count]lN[ext][!] *:lp* *:lprevious* *:lprev* *:lN* *:lNext*
:[count]lp[revious][!] Same as ":cNext" and ":cprevious", except the location
list for the current window is used instead of the
quickfix list.
*[l*
[l Mapped to |:lprevious|. |default-mappings|
*:cabo* *:cabove*
:[count]cabo[ve] Go to the [count] error above the current line in the
current buffer. If [count] is omitted, then 1 is
@@ -171,52 +183,76 @@ processing a quickfix or location list command, it will be aborted.
:[count]laf[ter] Same as ":cafter", except the location list for the
current window is used instead of the quickfix list.
*:cnf* *:cnfile* *]CTRL-Q*
*:cnf* *:cnfile*
:[count]cnf[ile][!] Display the first error in the [count] next file in
the list that includes a file name. If there are no
file names at all or if there is no next file, go to
the [count] next error. See |:cc| for [!] and
'switchbuf'.
*:lnf* *:lnfile* *]CTRL-L*
*]CTRL-Q*
]CTRL-Q Mapped to |:cnfile|. |default-mappings|
*:lnf* *:lnfile*
:[count]lnf[ile][!] Same as ":cnfile", except the location list for the
current window is used instead of the quickfix list.
:[count]cNf[ile][!] *:cpf* *:cpfile* *:cNf* *:cNfile* *[CTRL-Q*
*]CTRL-L*
]CTRL-L Mapped to |:lnfile|. |default-mappings|
:[count]cNf[ile][!] *:cpf* *:cpfile* *:cNf* *:cNfile*
:[count]cpf[ile][!] Display the last error in the [count] previous file in
the list that includes a file name. If there are no
file names at all or if there is no next file, go to
the [count] previous error. See |:cc| for [!] and
'switchbuf'.
*[CTRL-Q*
[CTRL-Q Mapped to |:cpfile|. |default-mappings|
:[count]lNf[ile][!] *:lpf* *:lpfile* *:lNf* *:lNfile* *[CTRL-L*
:[count]lNf[ile][!] *:lpf* *:lpfile* *:lNf* *:lNfile*
:[count]lpf[ile][!] Same as ":cNfile" and ":cpfile", except the location
list for the current window is used instead of the
quickfix list.
*:crewind* *:cr* *[Q*
*[CTRL-L*
[CTRL-L Mapped to |:lpfile|. |default-mappings|
*:crewind* *:cr*
:cr[ewind][!] [nr] Display error [nr]. If [nr] is omitted, the FIRST
error is displayed. See |:cc|.
*:lrewind* *:lr* *[L*
*[Q*
[Q Mapped to |:crewind|. |default-mappings|
*:lrewind* *:lr*
:lr[ewind][!] [nr] Same as ":crewind", except the location list for the
current window is used instead of the quickfix list.
*[L*
[L Mapped to |:lrewind|. |default-mappings|
*:cfirst* *:cfir*
:cfir[st][!] [nr] Same as ":crewind".
*:lfirst* *:lfir*
:lfir[st][!] [nr] Same as ":lrewind".
*:clast* *:cla* *]Q*
*:clast* *:cla*
:cla[st][!] [nr] Display error [nr]. If [nr] is omitted, the LAST
error is displayed. See |:cc|.
*:llast* *:lla* *]L*
*]Q*
]Q Mapped to |:clast|.
*:llast* *:lla*
:lla[st][!] [nr] Same as ":clast", except the location list for the
current window is used instead of the quickfix list.
*]L*
]L Mapped to |:llast|.
*:cq* *:cquit*
:cq[uit][!]
:{N}cq[uit][!]

View File

@@ -1382,8 +1382,8 @@ The $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, $XDG_STATE_HOME,
$XDG_CACHE_HOME, $XDG_CONFIG_DIRS and $XDG_DATA_DIRS environment variables
are used if defined, else default values (listed below) are used.
Throughout the help pages these defaults are used as placeholders, e.g.
"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
Note: In the help these defaults are used as placeholders, e.g. "~/.config" is
understood as "$XDG_CONFIG_HOME or ~/.config".
CONFIG DIRECTORY (DEFAULT) ~
*$XDG_CONFIG_HOME* Nvim: stdpath("config")
@@ -1437,12 +1437,17 @@ configuration files in `$XDG_CONFIG_HOME/foo` instead of
`$XDG_CONFIG_HOME/nvim`. `$NVIM_APPNAME` must be a name, such as "foo", or a
relative path, such as "foo/bar".
Note: In the help wherever `$XDG_CONFIG_…/nvim` is mentioned it is understood
as `$XDG_CONFIG_…/$NVIM_APPNAME`.
*state-isolation*
One use-case for $NVIM_APPNAME is to "isolate" Nvim applications.
Alternatively, for true isolation, on Linux you can use cgroups namespaces: >
systemd-run --user -qt -p PrivateUsers=yes -p BindPaths=/home/user/profile_xy:/home/user/.config/nvim nvim
Note: Throughout the help pages, wherever `$XDG_CONFIG_…/nvim` is mentioned it
is understood to mean `$XDG_CONFIG_…/$NVIM_APPNAME`.
<
*stateless*
To run Nvim without creating any directories or data files: >
NVIM_LOG_FILE=/dev/null nvim -n -i NONE
LOG FILE *log* *$NVIM_LOG_FILE* *E5430*
Besides 'debug' and 'verbose', Nvim keeps a general log file for internal

View File

@@ -274,27 +274,39 @@ g CTRL-] Like CTRL-], but use ":tjump" instead of ":tag".
{Visual}g CTRL-] Same as "g CTRL-]", but use the highlighted text as
the identifier.
*:tn* *:tnext* *]t*
*:tn* *:tnext*
:[count]tn[ext][!] Jump to [count] next matching tag (default 1). See
|tag-!| for [!].
*:tp* *:tprevious* *[t*
*]t*
]t Mapped to |:tnext|. |default-mappings|
*:tp* *:tprevious*
:[count]tp[revious][!] Jump to [count] previous matching tag (default 1).
See |tag-!| for [!].
*[t*
[t Mapped to |:tprevious|. |default-mappings|
*:tN* *:tNext*
:[count]tN[ext][!] Same as ":tprevious".
*:tr* *:trewind* *[T*
*:tr* *:trewind*
:[count]tr[ewind][!] Jump to first matching tag. If [count] is given, jump
to [count]th matching tag. See |tag-!| for [!].
*[T*
[T Mapped to |:trewind|. |default-mappings|
*:tf* *:tfirst*
:[count]tf[irst][!] Same as ":trewind".
*:tl* *:tlast* *]T*
*:tl* *:tlast*
:tl[ast][!] Jump to last matching tag. See |tag-!| for [!].
*]T*
]T Mapped to |:tlast|. |default-mappings|
*:lt* *:ltag*
:lt[ag][!] [name] Jump to tag [name] and add the matching tags to a new
location list for the current window. [name] can be
@@ -335,12 +347,18 @@ the same as above, with a "p" prepended.
:ptj[ump][!] [name] Does ":tjump[!] [name]" and shows the new tag in a
"Preview" window. See |:ptag| for more info.
*:ptn* *:ptnext* *]CTRL-T*
*:ptn* *:ptnext*
:[count]ptn[ext][!] ":tnext" in the preview window. See |:ptag|.
*:ptp* *:ptprevious* *[CTRL-T*
*]CTRL-T*
]CTRL-T Mapped to |:ptnext|. |default-mappings|
*:ptp* *:ptprevious*
:[count]ptp[revious][!] ":tprevious" in the preview window. See |:ptag|.
*[CTRL-T*
[CTRL-T Mapped to |:ptprevious|. |default-mappings|
*:ptN* *:ptNext*
:[count]ptN[ext][!] Same as ":ptprevious".

View File

@@ -120,7 +120,7 @@ The following predicates are built in:
match.
`lua-match?` *treesitter-predicate-lua-match?*
Match |lua-patterns| against the text corresponding to a node,
Match |lua-pattern|s against the text corresponding to a node,
similar to `match?`
`any-lua-match?` *treesitter-predicate-any-lua-match?*
@@ -573,7 +573,10 @@ parent tree. The language injection query allows you to specify these
“injections” using the following captures:
• `@injection.content` - indicates that the captured node should have its
contents re-parsed using another language.
contents re-parsed using another language. If there are multiple
`@injection.content` captures in one pattern, all ranges will be
collected and parsed as one tree. This allows query authors to create
"scoped" injections with injection query quantifiers.
• `@injection.language` - indicates that the captured nodes text may
contain the name of a language that should be used to re-parse the
`@injection.content`.

View File

@@ -25,9 +25,9 @@ Table of contents: |usr_toc.txt|
==============================================================================
*02.1* Running Vim for the First Time
To start Vim, enter this command: >
To start Nvim, enter this command: >
gvim file.txt
nvim file.txt
On Unix you can type this at any command prompt. If you are running Microsoft
Windows, open a Command Prompt and enter the command. In either case, Vim
@@ -50,20 +50,6 @@ screen, a message line indicates the file is named file.txt and shows that you
are creating a new file. The message information is temporary and other
information overwrites it.
THE VIM COMMAND
The gvim command causes the editor to create a new window for editing. If you
use this command: >
vim file.txt
the editing occurs inside your command window. In other words, if you are
running inside an xterm, the editor uses your xterm window. If you are using
the command prompt under Microsoft Windows, the editing occurs inside this
window. The text in the window will look the same for both versions, but with
gvim you have extra features, like a menu bar. More about that later.
==============================================================================
*02.2* Inserting text
@@ -580,7 +566,7 @@ Summary: *help-summary* >
:help quote:
13) Vim Script is available at >
:help eval.txt
:help vimeval.txt
< Certain aspects of the language are available at :h expr-X where "X" is a
single letter. E.g. >
:help expr-!
@@ -660,10 +646,13 @@ Summary: *help-summary* >
command switch of Vim use: >
:help -f
24) Optional features always start with "+". To find out about the
conceal feature use: >
:help +conceal
24) Lua language and Nvim's Lua standard library are available at >vim
:help lua.txt
< Guide to using Lua in Nvim is available at >vim
:help lua-guide.txt
< Lua 5.1 reference manual is available at >vim
:help luaref.txt
<
25) Documentation for included filetype specific functionality is usually
available in the form ft-<filetype>-<functionality>. So >
:help ft-c-syntax

View File

@@ -103,11 +103,11 @@ g8 Print the hex values of the bytes used in the
*gx*
gx Opens the current filepath or URL (decided by
|<cfile>|, 'isfname') at cursor using the system
default handler, by calling |vim.ui.open()|.
default handler. Mapped to |vim.ui.open()|.
*v_gx*
{Visual}gx Opens the selected text using the system default
handler, by calling |vim.ui.open()|.
handler. Mapped to |vim.ui.open()|.
*:p* *:pr* *:print* *E749*
:[range]p[rint] [flags]
@@ -611,6 +611,8 @@ to look up the value of 'commentstring' corresponding to the cursor position.
(This can be different from the buffer's 'commentstring' in case of
|treesitter-language-injections|.)
The following |default-mappings| are defined:
*gc* *gc-default*
gc{motion} Comment or uncomment lines covered by {motion}.

View File

@@ -134,7 +134,8 @@ To remove only the "How-to disable mouse" menu item (and its separator): >vim
DEFAULT MAPPINGS
*default-mappings*
Nvim creates the following default mappings at |startup|. You can disable any
of these in your config by simply removing the mapping, e.g. ":unmap Y".
of these in your config by simply removing the mapping, e.g. ":unmap Y". If
you never want any default mappings, call |:mapclear| early in your config.
- Y |Y-default|
- <C-U> |i_CTRL-U-default|
@@ -152,6 +153,7 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
- |grr|
- |gra|
- |gri|
- |grt|
- |gO|
- <C-S> |i_CTRL-S|
- ]d |]d-default|
@@ -383,6 +385,7 @@ Options:
- 'showcmdloc' cannot be set to empty.
- 'signcolumn' can show multiple signs (dynamic or fixed columns)
- 'statuscolumn' full control of columns using 'statusline' format
- 'statusline' default is exposed as a statusline expression.
- 'splitkeep' cannot be set to empty.
- 'tabline' middle-click on tabpage label closes tabpage,
and %@Func@foo%X can call any function on mouse-click
@@ -854,9 +857,8 @@ Startup:
Test functions:
- test_alloc_fail()
- test_autochdir()
- test_disable_char_avail()
- test_feedinput()
- test_garbagecollect_soon
- test_garbagecollect_soon()
- test_getvalue()
- test_ignore_error()
- test_null_blob()
@@ -874,6 +876,8 @@ Test functions:
- test_setmouse()
- test_settime()
- test_srand_seed()
- test_unknown()
- test_void()
TUI:
*t_xx* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI*

View File

@@ -1,10 +1,10 @@
*eval.txt* Nvim
*vimeval.txt* Nvim
VIM REFERENCE MANUAL by Bram Moolenaar
Expression evaluation *vimscript* *expression* *expr* *E15* *eval*
Expression evaluation *vimscript* *expression* *expr* *E15* *eval* *eval.txt*
Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|.

View File

@@ -1,10 +1,10 @@
*builtin.txt* Nvim
*vimfn.txt* Nvim
NVIM REFERENCE MANUAL
Builtin functions *vimscript-functions* *builtin-functions*
Vimscript functions *vimscript-functions* *builtin-functions* *builtin.txt*
For functions grouped by what they are used for see |function-list|.
@@ -110,7 +110,7 @@ append({lnum}, {text}) *append()*
<
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
• {text} (`string|string[]`)
Return: ~
@@ -1047,7 +1047,7 @@ cindent({lnum}) *cindent()*
To get or set indent of lines in a string, see |vim.text.indent()|.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -1637,7 +1637,7 @@ diff_filler({lnum}) *diff_filler()*
Returns 0 if the current window is not in diff mode.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -1654,7 +1654,7 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
syntax information about the highlighting.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
• {col} (`integer`)
Return: ~
@@ -2040,7 +2040,8 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
<SID> "<SNR>123_" where "123" is the
current script ID |<SID>|
<script> sourced script file, or script file
where the current function was defined
where the current function was defined.
Use |debug.getinfo()| in Lua scripts.
<stack> call stack
<cword> word under the cursor
<cWORD> WORD under the cursor
@@ -2563,7 +2564,7 @@ foldclosed({lnum}) *foldclosed()*
line, "'m" mark m, etc.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -2576,7 +2577,7 @@ foldclosedend({lnum}) *foldclosedend()*
line, "'m" mark m, etc.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -2594,7 +2595,7 @@ foldlevel({lnum}) *foldlevel()*
line, "'m" mark m, etc.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -2629,7 +2630,7 @@ foldtextresult({lnum}) *foldtextresult()*
Useful when exporting folded text, e.g., to HTML.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`string`)
@@ -3244,7 +3245,7 @@ getcharsearch() *getcharsearch()*
Return: ~
(`table`)
getcharstr([{expr}]) *getcharstr()*
getcharstr([{expr} [, {opts}]]) *getcharstr()*
The same as |getchar()|, except that this always returns a
String, and "number" isn't allowed in {opts}.
@@ -4093,6 +4094,10 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()*
- It is evaluated in current window context, which makes a
difference if the buffer is displayed in a window with
different 'virtualedit' or 'list' values.
- When specifying an exclusive selection and {pos1} and {pos2}
are equal, the returned list contains a single character as
if selection is inclusive, to match the behavior of an empty
exclusive selection in Visual mode.
Examples: >vim
xnoremap <CR>
@@ -5706,7 +5711,7 @@ line2byte({lnum}) *line2byte()*
Also see |byte2line()|, |go| and |:goto|.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -5719,7 +5724,7 @@ lispindent({lnum}) *lispindent()*
When {lnum} is invalid, -1 is returned.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -6090,7 +6095,7 @@ mapset({dict})
<
Parameters: ~
• {dict} (`boolean`)
• {dict} (`table<string,any>`)
Return: ~
(`any`)
@@ -6990,7 +6995,7 @@ nextnonblank({lnum}) *nextnonblank()*
See also |prevnonblank()|.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -7124,7 +7129,7 @@ prevnonblank({lnum}) *prevnonblank()*
Also see |nextnonblank()|.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
Return: ~
(`integer`)
@@ -7392,7 +7397,8 @@ printf({fmt}, {expr1} ...) *printf()*
< 1.41
You will get an overflow error |E1510|, when the field-width
or precision will result in a string longer than 6400 chars.
or precision will result in a string longer than 1 MB
(1024*1024 = 1048576) chars.
*E1500*
You cannot mix positional and non-positional arguments: >vim
@@ -8937,7 +8943,7 @@ setline({lnum}, {text}) *setline()*
< Note: The '[ and '] marks are not set.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
• {text} (`any`)
Return: ~
@@ -10851,7 +10857,7 @@ synID({lnum}, {col}, {trans}) *synID()*
<
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
• {col} (`integer`)
• {trans} (`0|1`)
@@ -10956,7 +10962,7 @@ synconcealed({lnum}, {col}) *synconcealed()*
mechanisms |syntax-vs-match|.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
• {col} (`integer`)
Return: ~
@@ -10982,7 +10988,7 @@ synstack({lnum}, {col}) *synstack()*
valid positions.
Parameters: ~
• {lnum} (`integer`)
• {lnum} (`integer|string`)
• {col} (`integer`)
Return: ~
@@ -11972,14 +11978,13 @@ windowsversion() *windowsversion()*
(`string`)
winheight({nr}) *winheight()*
The result is a Number, which is the height of window {nr}.
{nr} can be the window number or the |window-ID|.
When {nr} is zero, the height of the current window is
returned. When window {nr} doesn't exist, -1 is returned.
An existing window always has a height of zero or more.
This excludes any window toolbar line.
Gets the height of |window-ID| {nr} (zero for "current
window"), excluding any 'winbar' and 'statusline'. Returns -1
if window {nr} doesn't exist. An existing window always has
a height of zero or more.
Examples: >vim
echo "The current window has " .. winheight(0) .. " lines."
echo "Current window has " .. winheight(0) .. " lines."
<
Parameters: ~
@@ -12029,7 +12034,7 @@ winlayout([{tabnr}]) *winlayout()*
• {tabnr} (`integer?`)
Return: ~
(`any[]`)
(`vim.fn.winlayout.ret`)
winline() *winline()*
The result is a Number, which is the screen line of the cursor
@@ -12146,18 +12151,21 @@ winsaveview() *winsaveview()*
(`vim.fn.winsaveview.ret`)
winwidth({nr}) *winwidth()*
The result is a Number, which is the width of window {nr}.
{nr} can be the window number or the |window-ID|.
When {nr} is zero, the width of the current window is
returned. When window {nr} doesn't exist, -1 is returned.
An existing window always has a width of zero or more.
Examples: >vim
echo "The current window has " .. winwidth(0) .. " columns."
Gets the width of |window-ID| {nr} (zero for "current
window"), including columns (|sign-column|, 'statuscolumn',
etc.). Returns -1 if window {nr} doesn't exist. An existing
window always has a width of zero or more.
Example: >vim
echo "Current window has " .. winwidth(0) .. " columns."
if winwidth(0) <= 50
50 wincmd |
endif
< For getting the terminal or screen size, see the 'columns'
option.
<
To get the buffer "viewport", use |getwininfo()|: >vim
:echo getwininfo(win_getid())[0].width - getwininfo(win_getid())[0].textoff
<
To get the Nvim screen size, see the 'columns' option.
Parameters: ~
• {nr} (`integer`)

View File

@@ -69,8 +69,9 @@ If a window is focusable, it is part of the "navigation stack", that is,
editor commands such as :windo, |CTRL-W|, etc., will consider the window as
one that can be made the "current window". A non-focusable window will be
skipped by such commands (though it can be explicitly focused by
|nvim_set_current_win()|). Non-focusable windows are not listed by |:tabs|, and
are not counted by the default 'tabline'.
|nvim_set_current_win()|). Non-focusable windows are not listed by |:tabs|,
or counted by the default 'tabline'. Their buffer content is not included
in 'complete' "w" completion.
Windows (especially floating windows) can have many other |api-win_config|
properties such as "hide" and "fixed" which also affect behavior.
@@ -438,18 +439,17 @@ CTRL-W l Move cursor to Nth window right of current one. Uses the
CTRL-W w *CTRL-W_w* *CTRL-W_CTRL-W*
CTRL-W CTRL-W Without count: move cursor to the |focusable| window
below/right of the current one. If there is no (focusable)
window below or right, go to top-left window. With count: go
to Nth window (windows are numbered from top-left to
bottom-right). To obtain the window number see |bufwinnr()|
and |winnr()|. When N is larger than the number of windows go
to the last window.
below/right of the current one. If none, go to the top-left
window. With count: go to Nth window (numbered top-left to
bottom-right), skipping unfocusable windows. To obtain the
window number see |bufwinnr()| and |winnr()|. When N is
larger than the number of windows go to the last focusable
window.
*CTRL-W_W*
CTRL-W W Without count: move cursor to the |focusable| window
above/left of current one. If there is no window above or
left, go to bottom-right window. With count: go to Nth
window, like with CTRL-W w.
above/left of current one. If none, go to the bottom-right
window. With count: go to Nth window, like CTRL-W w.
CTRL-W t *CTRL-W_t* *CTRL-W_CTRL-T*
CTRL-W CTRL-T Move cursor to top-left window.
@@ -1272,7 +1272,7 @@ list of buffers. |unlisted-buffer|
:w foobar | sp #
< Also see |+cmd|.
:[N]bn[ext][!] [+cmd] [N] *:bn* *:bnext* *]b* *E87*
:[N]bn[ext][!] [+cmd] [N] *:bn* *:bnext* *E87*
Go to [N]th next buffer in buffer list. [N] defaults to one.
Wraps around the end of the buffer list.
See |:buffer-!| for [!].
@@ -1284,13 +1284,20 @@ list of buffers. |unlisted-buffer|
the way when you're browsing code/text buffers. The next three
commands also work like this.
*]b*
]b Mapped to |:bnext|. |default-mappings|
*:sbn* *:sbnext*
:[N]sbn[ext] [+cmd] [N]
Split window and go to [N]th next buffer in buffer list.
Wraps around the end of the buffer list. Uses 'switchbuf'
Also see |+cmd|.
:[N]bN[ext][!] [+cmd] [N] *:bN* *:bNext* *:bp* *:bprevious* *[b* *E88*
:[N]bN[ext][!] [+cmd] [N] *:bN* *:bNext* *:bp* *:bprevious* *E88*
*[b*
[b Mapped to |:bprevious|. |default-mappings|
:[N]bp[revious][!] [+cmd] [N]
Go to [N]th previous buffer in buffer list. [N] defaults to
one. Wraps around the start of the buffer list.
@@ -1304,11 +1311,14 @@ list of buffers. |unlisted-buffer|
Uses 'switchbuf'.
Also see |+cmd|.
:br[ewind][!] [+cmd] *:br* *:bre* *:brewind* *[B*
:br[ewind][!] [+cmd] *:br* *:bre* *:brewind*
Go to first buffer in buffer list. If the buffer list is
empty, go to the first unlisted buffer.
See |:buffer-!| for [!].
*[B*
[B Mapped to |:brewind|. |default-mappings|
:bf[irst] [+cmd] *:bf* *:bfirst*
Same as |:brewind|.
Also see |+cmd|.
@@ -1322,11 +1332,14 @@ list of buffers. |unlisted-buffer|
:sbf[irst] [+cmd] *:sbf* *:sbfirst*
Same as ":sbrewind".
:bl[ast][!] [+cmd] *:bl* *:blast* *]B*
:bl[ast][!] [+cmd] *:bl* *:blast*
Go to last buffer in buffer list. If the buffer list is
empty, go to the last unlisted buffer.
See |:buffer-!| for [!].
*]B*
]B Mapped to |:blast|. |default-mappings|
:sbl[ast] [+cmd] *:sbl* *:sblast*
Split window and go to last buffer in buffer list. If the
buffer list is empty, go to the last unlisted buffer.

88
runtime/example_init.lua Normal file
View File

@@ -0,0 +1,88 @@
-- Set <space> as the leader key
-- See `:help mapleader`
-- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used)
vim.g.mapleader = ' '
-- [[ Setting options ]] See `:h vim.o`
-- NOTE: You can change these options as you wish!
-- For more options, you can see `:help option-list`
-- To see documentation for an option, you can use `:h 'optionname'`, for example `:h 'number'`
-- (Note the single quotes)
-- Print the line number in front of each line
vim.o.number = true
-- Use relative line numbers, so that it is easier to jump with j, k. This will affect the 'number'
-- option above, see `:h number_relativenumber`
vim.o.relativenumber = true
-- Sync clipboard between OS and Neovim. Schedule the setting after `UiEnter` because it can
-- increase startup-time. Remove this option if you want your OS clipboard to remain independent.
-- See `:help 'clipboard'`
vim.api.nvim_create_autocmd('UIEnter', {
callback = function()
vim.o.clipboard = 'unnamedplus'
end,
})
-- Case-insensitive searching UNLESS \C or one or more capital letters in the search term
vim.o.ignorecase = true
vim.o.smartcase = true
-- Highlight the line where the cursor is on
vim.o.cursorline = true
-- Minimal number of screen lines to keep above and below the cursor.
vim.o.scrolloff = 10
-- Show <tab> and trailing spaces
vim.o.list = true
-- if performing an operation that would fail due to unsaved changes in the buffer (like `:q`),
-- instead raise a dialog asking if you wish to save the current file(s) See `:help 'confirm'`
vim.o.confirm = true
-- [[ Set up keymaps ]] See `:h vim.keymap.set()`, `:h mapping`, `:h keycodes`
-- Use <Esc> to exit terminal mode
vim.keymap.set('t', '<Esc>', '<C-\\><C-n>')
-- Map <A-j>, <A-k>, <A-h>, <A-l> to navigate between windows in any modes
vim.keymap.set({ 't', 'i' }, '<A-h>', '<C-\\><C-n><C-w>h')
vim.keymap.set({ 't', 'i' }, '<A-j>', '<C-\\><C-n><C-w>j')
vim.keymap.set({ 't', 'i' }, '<A-k>', '<C-\\><C-n><C-w>k')
vim.keymap.set({ 't', 'i' }, '<A-l>', '<C-\\><C-n><C-w>l')
vim.keymap.set({ 'n' }, '<A-h>', '<C-w>h')
vim.keymap.set({ 'n' }, '<A-j>', '<C-w>j')
vim.keymap.set({ 'n' }, '<A-k>', '<C-w>k')
vim.keymap.set({ 'n' }, '<A-l>', '<C-w>l')
-- [[ Basic Autocommands ]].
-- See `:h lua-guide-autocommands`, `:h autocmd`, `:h nvim_create_autocmd()`
-- Highlight when yanking (copying) text.
-- Try it with `yap` in normal mode. See `:h vim.hl.on_yank()`
vim.api.nvim_create_autocmd('TextYankPost', {
desc = 'Highlight when yanking (copying) text',
callback = function()
vim.hl.on_yank()
end,
})
-- [[ Create user commands ]]
-- See `:h nvim_create_user_command()` and `:h user-commands`
-- Create a command `:GitBlameLine` that print the git blame for the current line
vim.api.nvim_create_user_command('GitBlameLine', function()
local line_number = vim.fn.line('.') -- Get the current line number. See `:h line()`
local filename = vim.api.nvim_buf_get_name(0)
print(vim.fn.system({ 'git', 'blame', '-L', line_number .. ',+1', filename }))
end, { desc = 'Print the git blame for the current line' })
-- [[ Add optional packages ]]
-- Nvim comes bundled with a set of packages that are not enabled by
-- default. You can enable any of them by using the `:packadd` command.
-- For example, to add the "nohlsearch" package to automatically turn off search highlighting after
-- 'updatetime' and when going to insert mode
vim.cmd('packadd! nohlsearch')

View File

@@ -3,6 +3,7 @@
" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com>
" Last Change: 2024 Apr 21
" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" 2025 Aug 29 by Vim project, add try/catch around json_decode(), #18141
if exists("b:did_ftplugin")
finish
@@ -52,13 +53,19 @@ function! s:CollectPathsFromConfig() abort
endif
endif
let paths_from_config = config_json
try
let paths_from_config = config_json
\ ->readfile()
\ ->filter({ _, val -> val =~ '^\s*[\[\]{}"0-9]' })
\ ->join()
\ ->json_decode()
\ ->get('compilerOptions', {})
\ ->get('paths', {})
catch /^Vim\%((\a\+)\)\=:E491:/ " invalid json
let paths_from_config = {}
catch /^Vim\%((\a\+)\)\=:E474:/ " invalid json in Nvim
let paths_from_config = {}
endtry
if !empty(paths_from_config)
let b:astro_paths = paths_from_config

View File

@@ -1,5 +1,5 @@
vim.keymap.set('n', 'gO', function()
require('vim.treesitter._headings').show_toc()
require('vim.treesitter._headings').show_toc(6)
end, { buffer = 0, silent = true, desc = 'Show an Outline of the current buffer' })
vim.keymap.set('n', ']]', function()

View File

@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: gpg(1) configuration file
" Maintainer: This runtime file is looking for a new maintainer.
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
" Latest Revision: 2025-07-22 (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -17,7 +18,7 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 GpgKeywordPrg
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+--' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'gpg'
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+--' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'gpg'
setlocal iskeyword+=-
setlocal keywordprg=:GpgKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer GpgKeywordPrg'

View File

@@ -5,7 +5,9 @@
" Contributor: Dorai Sitaram <ds26@gte.com>
" C.D. MacEachern <craig.daniel.maceachern@gmail.com>
" Phạm Bình An <phambinhanctb2004@gmail.com>
" Last Change: 2025 Feb 27
" @konfekt
" Last Change: 2025 Apr 04
" 2025 May 06 by Vim Project update 'path' setting #17267
if exists("b:did_ftplugin")
finish
@@ -28,6 +30,7 @@ set cpo&vim
setlocal comments=:---,:--
setlocal commentstring=--\ %s
setlocal formatoptions-=t formatoptions+=croql
setlocal path-=. " Lua doesn't support importing module in path related to current file like JS
let &l:define = '\<function\|\<local\%(\s\+function\)\='
@@ -35,7 +38,7 @@ let &l:include = '\<\%(\%(do\|load\)file\|require\)\s*('
setlocal includeexpr=s:LuaInclude(v:fname)
setlocal suffixesadd=.lua
let b:undo_ftplugin = "setl cms< com< def< fo< inc< inex< sua<"
let b:undo_ftplugin = "setl cms< com< def< fo< inc< inex< sua< pa<"
if exists("loaded_matchit") && !exists("b:match_words")
let b:match_ignorecase = 0
@@ -78,4 +81,7 @@ function s:LuaInclude(fname) abort
return fname
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8 noet:

View File

@@ -2,7 +2,7 @@
" Language: modules.conf(5) configuration file
" Maintainer: This runtime file is looking for a new maintainer.
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2024-09-20 (remove erroneous endif)
" Latest Revision: 2025-07-22 (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -19,7 +19,7 @@ setlocal formatoptions-=t formatoptions+=croql
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 ModconfKeywordPrg
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'modprobe.d'
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'modprobe.d'
setlocal iskeyword+=-
setlocal keywordprg=:ModconfKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ModconfKeywordPrg'

View File

@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: mutt RC File
" Maintainer: This runtime file is looking for a new maintainer.
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
" Latest Revision: 2025-07-22 (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -20,7 +21,7 @@ let &l:include = '^\s*source\>'
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 MuttrcKeywordPrg
\ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'muttrc'
\ silent exe 'hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'muttrc'
setlocal iskeyword+=-
setlocal keywordprg=:MuttrcKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer MuttrcKeywordPrg'

View File

@@ -5,6 +5,7 @@
" 2024 Jan 14 by Vim Project (browsefilter)
" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" 2024 Sep 19 by Konfekt (simplify keywordprg #15696)
" 2025 Jul 22 by phanium (use :hor term #17822)
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin") | finish | endif
@@ -51,7 +52,7 @@ endif
if exists('s:pwsh_cmd')
if exists(':terminal') == 2
command! -buffer -nargs=1 GetHelp silent exe 'term ' . s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full "<args>"' . (executable('less') ? ' | less' : '')
command! -buffer -nargs=1 GetHelp silent exe 'hor term ' . s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full "<args>"' . (executable('less') ? ' | less' : '')
else
command! -buffer -nargs=1 GetHelp echo system(s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full <args>')
endif

View File

@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Last Change: 2024 Sep 19 (simplify keywordprg #15696)
" 2024 Jul 22 by Vim project (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -36,7 +37,7 @@ endif
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 ReadlineKeywordPrg
\ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . '3 readline'
\ silent exe 'hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . '3 readline'
setlocal iskeyword+=-
setlocal keywordprg=:ReadlineKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ReadlineKeywordPrg'

View File

@@ -7,6 +7,7 @@
" Last Change: 2024 Sep 19 by Vim Project (compiler shellcheck)
" 2024 Dec 29 by Vim Project (improve setting shellcheck compiler)
" 2025 Mar 09 by Vim Project (set b:match_skip)
" 2025 Jul 22 by phanium (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -53,7 +54,7 @@ let s:is_kornshell = get(b:, "is_kornshell", get(g:, "is_kornshell", 0))
if s:is_bash
if exists(':terminal') == 2
command! -buffer -nargs=1 ShKeywordPrg silent exe ':term bash -c "help "<args>" 2>/dev/null || man "<args>""'
command! -buffer -nargs=1 ShKeywordPrg silent exe ':hor term bash -c "help "<args>" 2>/dev/null || man "<args>""'
else
command! -buffer -nargs=1 ShKeywordPrg echo system('bash -c "help <args>" 2>/dev/null || MANPAGER= man "<args>"')
endif

View File

@@ -2,7 +2,7 @@
" Language: OpenSSH client configuration file
" Maintainer: This runtime file is looking for a new maintainer.
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
" Latest Revision: 2025-07-22 (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -17,7 +17,7 @@ let b:undo_ftplugin = 'setlocal com< cms< fo<'
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 SshconfigKeywordPrg
\ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '$', '\') . ''' --hilite-search" man ' . 'ssh_config'
\ silent exe 'hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '$', '\') . ''' --hilite-search" man ' . 'ssh_config'
setlocal iskeyword+=-
setlocal keywordprg=:SshconfigKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SshconfigKeywordPrg'

View File

@@ -2,7 +2,7 @@
" Language: sudoers(5) configuration files
" Maintainer: This runtime file is looking for a new maintainer.
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
" Latest Revision: 2025-07-22 (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -18,7 +18,7 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 SudoersKeywordPrg
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('\b' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'sudoers'
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('\b' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'sudoers'
setlocal iskeyword+=-
setlocal keywordprg=:SudoersKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SudoersKeywordPrg'

View File

@@ -1,19 +1,18 @@
" vim: fdm=marker
" Tutor filetype plugin
" Language: Tutor (the new tutor plugin)
" Maintainer: This runtime file is looking for a new maintainer.
" Last Change: 2025 May 10
" Contributors: Phạm Bình An <phambinhanctb2004@gmail.com>
" Original Author: Felipe Morales <hel.sheep@gmail.com>
" Last Change:
" 2025 May 10 set b:undo_ftplugin
" 2025 May 12 update b:undo_ftplugin
" Base: {{{1
call tutor#SetupVim()
" Buffer Settings: {{{1
setlocal noreadonly
if !exists('g:tutor_debug') || g:tutor_debug == 0
setlocal buftype=nofile
setlocal concealcursor+=inv
setlocal conceallevel=2
else
setlocal buftype=
setlocal concealcursor&
setlocal conceallevel=0
endif
setlocal noundofile
setlocal keywordprg=:help
@@ -39,7 +38,7 @@ call tutor#SetNormalMappings()
sign define tutorok text=texthl=tutorOK
sign define tutorbad text=texthl=tutorX
if !exists('g:tutor_debug') || g:tutor_debug == 0
call tutor#ApplyMarks()
autocmd! TextChanged,TextChangedI <buffer> call tutor#ApplyMarksOnChanged()
endif
let b:undo_ftplugin = "setl foldmethod< foldexpr< foldlevel< undofile< keywordprg< iskeyword< |"
\ . "call tutor#EnableInteractive(v:false) |"
" vim: fdm=marker

View File

@@ -2,7 +2,7 @@
" Language: udev(8) rules file
" Maintainer: This runtime file is looking for a new maintainer.
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
" Latest Revision: 2025-07-22 (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -18,7 +18,7 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
if has('unix') && executable('less') && exists(':terminal') == 2
command -buffer -nargs=1 UdevrulesKeywordPrg
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'udev'
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'udev'
setlocal iskeyword+=-
setlocal keywordprg=:UdevrulesKeywordPrg
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer UdevrulesKeywordPrg'

View File

@@ -5,6 +5,8 @@
" Latest Revision: 2024 Sep 19
" License: Vim (see :h license)
" Repository: https://github.com/chrisbra/vim-zsh
" Last Change:
" 2025 Jul 23 by Vim Project (use :hor term #17822)
if exists("b:did_ftplugin")
finish
@@ -20,7 +22,7 @@ let b:undo_ftplugin = "setl com< cms< fo< "
if executable('zsh') && &shell !~# '/\%(nologin\|false\)$'
if exists(':terminal') == 2
command! -buffer -nargs=1 ZshKeywordPrg silent exe ':term zsh -c "autoload -Uz run-help; run-help <args>"'
command! -buffer -nargs=1 ZshKeywordPrg silent exe ':hor term zsh -c "autoload -Uz run-help; run-help <args>"'
else
command! -buffer -nargs=1 ZshKeywordPrg echo system('MANPAGER= zsh -c "autoload -Uz run-help; run-help <args> 2>/dev/null"')
endif

View File

@@ -3,6 +3,7 @@
" Maintainer: See https://github.com/HerringtonDarkholme/yats.vim
" Last Change: 2019 Oct 18
" 2023 Aug 28 by Vim Project (undo_indent)
" 2025 Jun 05 by Vim Project (remove Fixedgq() formatexp, #17452)
" Acknowledgement: Based off of vim-ruby maintained by Nikolai Weibull http://vim-ruby.rubyforge.org
" 0. Initialization {{{1
@@ -18,10 +19,9 @@ setlocal nosmartindent
" Now, set up our indentation expression and keys that trigger it.
setlocal indentexpr=GetTypescriptIndent()
setlocal formatexpr=Fixedgq(v:lnum,v:count)
setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e
let b:undo_indent = "setlocal formatexpr< indentexpr< indentkeys< smartindent<"
let b:undo_indent = "setlocal indentexpr< indentkeys< smartindent<"
" Only define the function once.
if exists("*GetTypescriptIndent")
@@ -443,64 +443,3 @@ endfunction
let &cpo = s:cpo_save
unlet s:cpo_save
function! Fixedgq(lnum, count)
let l:tw = &tw ? &tw : 80
let l:count = a:count
let l:first_char = indent(a:lnum) + 1
if mode() == 'i' " gq was not pressed, but tw was set
return 1
endif
" This gq is only meant to do code with strings, not comments
if s:IsLineComment(a:lnum, l:first_char) || s:IsInMultilineComment(a:lnum, l:first_char)
return 1
endif
if len(getline(a:lnum)) < l:tw && l:count == 1 " No need for gq
return 1
endif
" Put all the lines on one line and do normal splitting after that
if l:count > 1
while l:count > 1
let l:count -= 1
normal J
endwhile
endif
let l:winview = winsaveview()
call cursor(a:lnum, l:tw + 1)
let orig_breakpoint = searchpairpos(' ', '', '\.', 'bcW', '', a:lnum)
call cursor(a:lnum, l:tw + 1)
let breakpoint = searchpairpos(' ', '', '\.', 'bcW', s:skip_expr, a:lnum)
" No need for special treatment, normal gq handles edgecases better
if breakpoint[1] == orig_breakpoint[1]
call winrestview(l:winview)
return 1
endif
" Try breaking after string
if breakpoint[1] <= indent(a:lnum)
call cursor(a:lnum, l:tw + 1)
let breakpoint = searchpairpos('\.', '', ' ', 'cW', s:skip_expr, a:lnum)
endif
if breakpoint[1] != 0
call feedkeys("r\<CR>")
else
let l:count = l:count - 1
endif
" run gq on new lines
if l:count == 1
call feedkeys("gqq")
endif
return 0
endfunction

View File

@@ -245,7 +245,7 @@ local function parse_line(line)
end
--- @type string?
local glob = (line:match('%b[]') or ''):match('^%s*%[(.*)%]%s*$')
local glob = line:match('^%s*%[(.*)%]%s*$')
if glob then
return glob
end

View File

@@ -8,6 +8,10 @@ local M = {}
--- @param env? table<string,string|number>
--- @return string
local function system(cmd, silent, env)
if vim.fn.executable(cmd[1]) == 0 then
error(string.format('executable not found: "%s"', cmd[1]), 0)
end
local r = vim.system(cmd, { env = env, timeout = 10000 }):wait()
if not silent then
@@ -577,7 +581,10 @@ function M.man_complete(arg_lead, cmd_line)
return {}
end
local pages = get_paths(name, sect)
local ok, pages = pcall(get_paths, name, sect)
if not ok then
return nil
end
-- We check for duplicates in case the same manpage in different languages
-- was found.
@@ -803,6 +810,8 @@ function M.show_toc()
fn.setloclist(0, {}, 'a', { title = 'Table of contents' })
vim.cmd.lopen()
vim.w.qf_toc = bufname
-- reload syntax file after setting qf_toc variable
vim.bo.filetype = 'qf'
end
return M

View File

@@ -0,0 +1,86 @@
---@class nvim.TutorMetadata
---@field expect table<string, string|-1>
---@alias nvim.TutorExtmarks table<string, string>
---@type nvim.TutorExtmarks?
vim.b.tutor_extmarks = vim.b.tutor_extmarks
---@type nvim.TutorMetadata?
vim.b.tutor_metadata = vim.b.tutor_metadata
local sign_text_correct = ''
local sign_text_incorrect = ''
local tutor_mark_ns = vim.api.nvim_create_namespace('nvim.tutor.mark')
local tutor_hl_ns = vim.api.nvim_create_namespace('nvim.tutor.hl')
local M = {}
---@param line integer 1-based
local function check_line(line)
if vim.b.tutor_metadata and vim.b.tutor_metadata.expect and vim.b.tutor_extmarks then
local ctext = vim.fn.getline(line)
---@type vim.api.keyset.get_extmark_item[]
local extmarks = vim
.iter(vim.api.nvim_buf_get_extmarks(
0,
tutor_mark_ns,
{ line - 1, 0 },
{ line - 1, -1 }, -- the extmark can move to col > 0 if users insert text there
{ details = true }
))
:filter(function(extmark)
return not extmark[4].invalid
end)
:totable()
for _, extmark in ipairs(extmarks) do
local mark_id = extmark[1]
local expct = vim.b.tutor_extmarks[tostring(mark_id)]
local expect = vim.b.tutor_metadata.expect[expct]
local is_correct = expect == -1 or ctext == expect
vim.api.nvim_buf_set_extmark(0, tutor_mark_ns, line - 1, 0, {
id = mark_id,
sign_text = is_correct and sign_text_correct or sign_text_incorrect,
sign_hl_group = is_correct and 'tutorOK' or 'tutorX',
invalidate = true,
})
end
end
end
function M.apply_marks()
vim.cmd [[hi! link tutorExpect Special]]
if vim.b.tutor_metadata and vim.b.tutor_metadata.expect then
vim.b.tutor_extmarks = {}
for expct, _ in pairs(vim.b.tutor_metadata.expect) do
---@diagnostic disable-next-line: assign-type-mismatch
local lnum = tonumber(expct) ---@type integer
vim.api.nvim_buf_set_extmark(0, tutor_hl_ns, lnum - 1, 0, {
line_hl_group = 'tutorExpect',
invalidate = true,
})
local mark_id = vim.api.nvim_buf_set_extmark(0, tutor_mark_ns, lnum - 1, 0, {})
-- Cannot edit field of a Vimscript dictionary from Lua directly, see `:h lua-vim-variables`
---@type nvim.TutorExtmarks
local tutor_extmarks = vim.b.tutor_extmarks
tutor_extmarks[tostring(mark_id)] = expct
vim.b.tutor_extmarks = tutor_extmarks
check_line(lnum)
end
end
end
function M.apply_marks_on_changed()
if vim.b.tutor_metadata and vim.b.tutor_metadata.expect and vim.b.tutor_extmarks then
local lnum = vim.fn.line('.')
check_line(lnum)
end
end
return M

View File

@@ -191,7 +191,7 @@ do
--- client is attached. If no client is attached, or if a server does not support a capability, an
--- error message is displayed rather than exhibiting different behavior.
---
--- See |grr|, |grn|, |gra|, |gri|, |gO|, |i_CTRL-S|.
--- See |grr|, |grn|, |gra|, |gri|, |grt| |gO|, |i_CTRL-S|.
do
vim.keymap.set('n', 'grn', function()
vim.lsp.buf.rename()
@@ -209,6 +209,10 @@ do
vim.lsp.buf.implementation()
end, { desc = 'vim.lsp.buf.implementation()' })
vim.keymap.set('n', 'grt', function()
vim.lsp.buf.type_definition()
end, { desc = 'vim.lsp.buf.type_definition()' })
vim.keymap.set('n', 'gO', function()
vim.lsp.buf.document_symbol()
end, { desc = 'vim.lsp.buf.document_symbol()' })
@@ -622,10 +626,10 @@ do
end
vim.wo[0][0].winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC'
vim.keymap.set('n', '[[', function()
vim.keymap.set({ 'n', 'x', 'o' }, '[[', function()
jump_to_prompt(nvim_terminal_prompt_ns, 0, args.buf, -vim.v.count1)
end, { buffer = args.buf, desc = 'Jump [count] shell prompts backward' })
vim.keymap.set('n', ']]', function()
vim.keymap.set({ 'n', 'x', 'o' }, ']]', function()
jump_to_prompt(nvim_terminal_prompt_ns, 0, args.buf, vim.v.count1)
end, { buffer = args.buf, desc = 'Jump [count] shell prompts forward' })
end,

View File

@@ -106,7 +106,7 @@ local utfs = {
--- - env: table<string,string> Set environment variables for the new process. Inherits the
--- current environment with `NVIM` set to |v:servername|.
--- - clear_env: (boolean) `env` defines the job environment exactly, instead of merging current
--- environment.
--- environment. Note: if `env` is `nil`, the current environment is used but without `NVIM` set.
--- - stdin: (string|string[]|boolean) If `true`, then a pipe to stdin is opened and can be written
--- to via the `write()` method to SystemObj. If string or string[] then will be written to stdin
--- and closed. Defaults to `false`.
@@ -399,22 +399,23 @@ local VIM_CMD_ARG_MAX = 20
--- Executes Vimscript (|Ex-commands|).
---
--- Note that `vim.cmd` can be indexed with a command name to return a callable function to the
--- command.
--- Can be indexed with a command name to get a function, thus you can write `vim.cmd.echo(…)`
--- instead of `vim.cmd{cmd='echo',…}`.
---
--- Example:
--- Examples:
---
--- ```lua
--- -- Single command:
--- vim.cmd('echo 42')
--- -- Multiline script:
--- vim.cmd([[
--- augroup My_group
--- augroup my.group
--- autocmd!
--- autocmd FileType c setlocal cindent
--- augroup END
--- ]])
---
--- -- Ex command :echo "foo"
--- -- Note string literals need to be double quoted.
--- -- Ex command :echo "foo". Note: string literals must be double-quoted.
--- vim.cmd('echo "foo"')
--- vim.cmd { cmd = 'echo', args = { '"foo"' } }
--- vim.cmd.echo({ args = { '"foo"' } })
@@ -422,22 +423,19 @@ local VIM_CMD_ARG_MAX = 20
---
--- -- Ex command :write! myfile.txt
--- vim.cmd('write! myfile.txt')
--- vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true }
--- vim.cmd.write { args = { "myfile.txt" }, bang = true }
--- vim.cmd.write { "myfile.txt", bang = true }
--- vim.cmd { cmd = 'write', args = { 'myfile.txt' }, bang = true }
--- vim.cmd.write { args = { 'myfile.txt' }, bang = true }
--- vim.cmd.write { 'myfile.txt', bang = true }
---
--- -- Ex command :colorscheme blue
--- vim.cmd('colorscheme blue')
--- vim.cmd.colorscheme('blue')
--- -- Ex command :vertical resize +2
--- vim.cmd.resize({ '+2', mods = { vertical = true } })
--- ```
---
---@diagnostic disable-next-line: undefined-doc-param
---@param command string|table Command(s) to execute.
--- If a string, executes multiple lines of Vimscript at once. In this
--- case, it is an alias to |nvim_exec2()|, where `opts.output` is set
--- to false. Thus it works identical to |:source|.
--- If a table, executes a single command. In this case, it is an alias
--- to |nvim_cmd()| where `opts` is empty.
--- - The string form supports multiline Vimscript (alias to |nvim_exec2()|, behaves
--- like |:source|).
--- - The table form executes a single command (alias to |nvim_cmd()|).
---@see |ex-cmd-index|
vim.cmd = setmetatable({}, {
__call = function(_, command)

View File

@@ -3,13 +3,15 @@ local M = {}
--- @param module string
---@return string
function M.includeexpr(module)
local fname = module:gsub('%.', '/')
module = module:gsub('%.', '/')
local root = vim.fs.root(vim.api.nvim_buf_get_name(0), 'lua') or vim.fn.getcwd()
for _, suf in ipairs { '.lua', '/init.lua' } do
local path = vim.fs.joinpath(root, 'lua', fname .. suf)
if vim.uv.fs_stat(path) then
return path
for _, fname in ipairs { module, vim.fs.joinpath(root, 'lua', module) } do
for _, suf in ipairs { '.lua', '/init.lua' } do
local path = fname .. suf
if vim.uv.fs_stat(path) then
return path
end
end
end

View File

@@ -200,7 +200,9 @@ function vim.show_pos(bufnr, row, col, filter)
capture,
string.format(
'priority: %d language: %s',
capture.metadata.priority or vim.hl.priorities.treesitter,
capture.metadata.priority
or (capture.metadata[capture.id] and capture.metadata[capture.id].priority)
or vim.hl.priorities.treesitter,
capture.lang
)
)

View File

@@ -369,8 +369,11 @@ function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end
--- vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {})
--- ```
---
--- If `end` is less than `start`, traversal works backwards. (Useful
--- with `limit`, to get the first marks prior to a given position.)
--- If `end` is less than `start`, marks are returned in reverse order.
--- (Useful with `limit`, to get the first marks prior to a given position.)
---
--- Note: For a reverse range, `limit` does not actually affect the traversed
--- range, just how many marks are returned
---
--- Note: when using extmark ranges (marks with a end_row/end_col position)
--- the `overlap` option might be useful. Otherwise only the start position
@@ -939,8 +942,8 @@ function vim.api.nvim_create_augroup(name, opts) end
--- - desc (string) optional: description (for documentation and troubleshooting).
--- - callback (function|string) optional: Lua function (or Vimscript function name, if
--- string) called when the event(s) is triggered. Lua callback can return a truthy
--- value (not `false` or `nil`) to delete the autocommand. Receives one argument,
--- a table with these keys: [event-args]()
--- value (not `false` or `nil`) to delete the autocommand, and receives one argument, a
--- table with these keys: [event-args]()
--- - id: (number) autocommand id
--- - event: (string) name of the triggered event `autocmd-events`
--- - group: (number|nil) autocommand group id, if any
@@ -1659,10 +1662,7 @@ function vim.api.nvim_notify(msg, log_level, opts) end
---
--- ```lua
--- vim.api.nvim_create_user_command('TermHl', function()
--- local b = vim.api.nvim_create_buf(false, true)
--- local chan = vim.api.nvim_open_term(b, {})
--- vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
--- vim.api.nvim_win_set_buf(0, b)
--- vim.api.nvim_open_term(0, {})
--- end, { desc = 'Highlights ANSI termcodes in curbuf' })
--- ```
---
@@ -1840,7 +1840,8 @@ function vim.api.nvim_open_term(buffer, opts) end
--- the call.
--- - fixed: If true when anchor is NW or SW, the float window
--- would be kept fixed even if the window would be truncated.
--- - hide: If true the floating window will be hidden.
--- - hide: If true the floating window will be hidden and the cursor will be invisible when
--- focused on it.
--- - vertical: Split vertically `:vertical`.
--- - split: Split direction: "left", "right", "above", "below".
--- @return integer # |window-ID|, or 0 on error

View File

@@ -184,14 +184,14 @@
--- @field signs vim.fn.sign[]
--- @class vim.fn.sign_place.dict
--- @field lnum? integer
--- @field lnum? integer|string
--- @field priority? integer
--- @class vim.fn.sign_placelist.list.item
--- @field buffer integer|string
--- @field group? string
--- @field id? integer
--- @field lnum integer
--- @field lnum? integer|string
--- @field name string
--- @field priority? integer
@@ -297,3 +297,18 @@
--- A list of dictionaries with information about
--- undo blocks.
--- @field entries vim.fn.undotree.entry[]
--- @class vim.fn.winlayout.leaf
--- @field [1] "leaf" Node type
--- @field [2] integer winid
--- @class vim.fn.winlayout.branch
--- @field [1] "row" | "col" Node type
--- @field [2] (vim.fn.winlayout.leaf|vim.fn.winlayout.branch)[] children
--- @class vim.fn.winlayout.empty
--- @alias vim.fn.winlayout.ret
--- | vim.fn.winlayout.leaf
--- | vim.fn.winlayout.branch
--- | vim.fn.winlayout.empty

View File

@@ -655,8 +655,8 @@ vim.bo.bl = vim.bo.buflisted
--- "acwrite" implies that the buffer name is not related to a file, like
--- "nofile", but it will be written. Thus, in contrast to "nofile" and
--- "nowrite", ":w" does work and a modified buffer can't be abandoned
--- without saving. For writing there must be matching `BufWriteCmd|,
--- |FileWriteCmd` or `FileAppendCmd` autocommands.
--- without saving. For writing there must be matching `BufWriteCmd`,
--- `FileWriteCmd` or `FileAppendCmd` autocommands.
---
--- @type ''|'acwrite'|'help'|'nofile'|'nowrite'|'quickfix'|'terminal'|'prompt'
vim.o.buftype = ""
@@ -2015,10 +2015,21 @@ vim.bo.et = vim.bo.expandtab
--- in the `trust` list. Use `:trust` to manage trusted files. See also
--- `vim.secure.read()`.
---
--- To get its own location, Lua exrc files can use `debug.getinfo()`.
---
--- Compare 'exrc' to `editorconfig`:
--- - 'exrc' can execute any code; editorconfig only specifies settings.
--- - 'exrc' is Nvim-specific; editorconfig works in other editors.
---
--- To achieve project-local LSP configuration:
--- 1. Enable 'exrc'.
--- 2. Place LSP configs at ".nvim/lsp/*.lua" in your project root.
--- 3. Create ".nvim.lua" in your project root directory with this line:
---
--- ```lua
--- vim.cmd[[set runtimepath+=.nvim]]
--- ```
---
--- This option cannot be set from a `modeline` or in the `sandbox`, for
--- security reasons.
---
@@ -3151,8 +3162,8 @@ vim.o.ims = vim.o.imsearch
vim.bo.imsearch = vim.o.imsearch
vim.bo.ims = vim.bo.imsearch
--- When nonempty, shows the effects of `:substitute`, `:smagic|,
--- |:snomagic` and user commands with the `:command-preview` flag as you
--- When nonempty, shows the effects of `:substitute`, `:smagic`,
--- `:snomagic` and user commands with the `:command-preview` flag as you
--- type.
---
--- Possible values:
@@ -3491,8 +3502,8 @@ vim.go.js = vim.go.joinspaces
--- when navigating backwards in the jumplist and then
--- jumping to a location. `jumplist-stack`
---
--- view When moving through the jumplist, `changelist|,
--- |alternate-file` or using `mark-motions` try to
--- view When moving through the jumplist, `changelist`,
--- `alternate-file` or using `mark-motions` try to
--- restore the `mark-view` in which the action occurred.
---
--- clean Remove unloaded buffers from the jumplist.
@@ -5239,9 +5250,14 @@ vim.go.sect = vim.go.sections
--- the end of line the line break still isn't included.
--- When "exclusive" is used, cursor position in visual mode will be
--- adjusted for inclusive motions `inclusive-motion-selection-exclusive`.
--- Note that when "exclusive" is used and selecting from the end
--- backwards, you cannot include the last character of a line, when
--- starting in Normal mode and 'virtualedit' empty.
---
--- Note:
--- - When "exclusive" is used and selecting from the end backwards, you
--- cannot include the last character of a line, when starting in Normal
--- mode and 'virtualedit' empty.
--- - when "exclusive" is used with a single character visual selection,
--- Vim will behave as if the 'selection' is inclusive (in other words,
--- you cannot visually select an empty region).
---
--- @type 'inclusive'|'exclusive'|'old'
vim.o.selection = "inclusive"
@@ -5627,8 +5643,8 @@ vim.go.ssl = vim.go.shellslash
--- and the 'shell' command does not need to support redirection.
--- The advantage of using a temp file is that the file type and encoding
--- can be detected.
--- The `FilterReadPre`, `FilterReadPost` and `FilterWritePre|,
--- |FilterWritePost` autocommands event are not triggered when
--- The `FilterReadPre`, `FilterReadPost` and `FilterWritePre`,
--- `FilterWritePost` autocommands event are not triggered when
--- 'shelltemp' is off.
--- `system()` does not respect this option, it always uses pipes.
---
@@ -6198,8 +6214,8 @@ vim.bo.spo = vim.bo.spelloptions
---
--- expr:{expr} Evaluate expression {expr}. Use a function to avoid
--- trouble with spaces. Best is to call a function
--- without arguments, see `expr-option-function|.
--- |v:val` holds the badly spelled word. The expression
--- without arguments, see `expr-option-function`.
--- `v:val` holds the badly spelled word. The expression
--- must evaluate to a List of Lists, each with a
--- suggestion and a score.
--- Example:
@@ -6343,8 +6359,7 @@ vim.o.stc = vim.o.statuscolumn
vim.wo.statuscolumn = vim.o.statuscolumn
vim.wo.stc = vim.wo.statuscolumn
--- When non-empty, this option determines the content of the status line.
--- Also see `status-line`.
--- Sets the `status-line`.
---
--- The option consists of printf style '%' items interspersed with
--- normal text. Each status line item is of the form:
@@ -7834,14 +7849,15 @@ vim.wo.winbl = vim.wo.winblend
--- Defines the default border style of floating windows. The default value
--- is empty, which is equivalent to "none". Valid values include:
--- - "bold": Bold line box.
--- - "double": Double-line box.
--- - "none": No border.
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "shadow": Drop shadow effect, by blending with the background.
--- - "single": Single-line box.
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
---
--- @type ''|'double'|'single'|'shadow'|'rounded'|'solid'|'none'
--- @type ''|'double'|'single'|'shadow'|'rounded'|'solid'|'bold'|'none'
vim.o.winborder = ""
vim.go.winborder = vim.o.winborder

View File

@@ -85,7 +85,7 @@ function vim.fn.api_info() end
--- let failed = append(0, ["Chapter 1", "the beginning"])
--- <
---
--- @param lnum integer
--- @param lnum integer|string
--- @param text string|string[]
--- @return 0|1
function vim.fn.append(lnum, text) end
@@ -907,7 +907,7 @@ function vim.fn.chdir(dir) end
---
--- To get or set indent of lines in a string, see |vim.text.indent()|.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.cindent(lnum) end
@@ -1244,7 +1244,7 @@ function vim.fn.ctxset(context, index) end
--- @return any
function vim.fn.ctxsize() end
--- @param lnum integer
--- @param lnum integer|string
--- @param col? integer
--- @param off? integer
--- @return any
@@ -1441,7 +1441,7 @@ function vim.fn.did_filetype() end
--- line, "'m" mark m, etc.
--- Returns 0 if the current window is not in diff mode.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.diff_filler(lnum) end
@@ -1455,7 +1455,7 @@ function vim.fn.diff_filler(lnum) end
--- The highlight ID can be used with |synIDattr()| to obtain
--- syntax information about the highlighting.
---
--- @param lnum integer
--- @param lnum integer|string
--- @param col integer
--- @return any
function vim.fn.diff_hlID(lnum, col) end
@@ -1801,7 +1801,8 @@ function vim.fn.exp(expr) end
--- <SID> "<SNR>123_" where "123" is the
--- current script ID |<SID>|
--- <script> sourced script file, or script file
--- where the current function was defined
--- where the current function was defined.
--- Use |debug.getinfo()| in Lua scripts.
--- <stack> call stack
--- <cword> word under the cursor
--- <cWORD> WORD under the cursor
@@ -2282,7 +2283,7 @@ function vim.fn.fnamemodify(fname, mods) end
--- {lnum} is used like with |getline()|. Thus "." is the current
--- line, "'m" mark m, etc.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.foldclosed(lnum) end
@@ -2292,7 +2293,7 @@ function vim.fn.foldclosed(lnum) end
--- {lnum} is used like with |getline()|. Thus "." is the current
--- line, "'m" mark m, etc.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.foldclosedend(lnum) end
@@ -2307,7 +2308,7 @@ function vim.fn.foldclosedend(lnum) end
--- {lnum} is used like with |getline()|. Thus "." is the current
--- line, "'m" mark m, etc.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.foldlevel(lnum) end
@@ -2338,7 +2339,7 @@ function vim.fn.foldtext() end
--- line, "'m" mark m, etc.
--- Useful when exporting folded text, e.g., to HTML.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return string
function vim.fn.foldtextresult(lnum) end
@@ -3284,7 +3285,7 @@ function vim.fn.getjumplist(winnr, tabnr) end
--- @return string
function vim.fn.getline(lnum, end_) end
--- @param lnum integer
--- @param lnum integer|string
--- @param end_ true|number|string|table
--- @return string|string[]
function vim.fn.getline(lnum, end_) end
@@ -3692,6 +3693,10 @@ function vim.fn.getreginfo(regname) end
--- - It is evaluated in current window context, which makes a
--- difference if the buffer is displayed in a window with
--- different 'virtualedit' or 'list' values.
--- - When specifying an exclusive selection and {pos1} and {pos2}
--- are equal, the returned list contains a single character as
--- if selection is inclusive, to match the behavior of an empty
--- exclusive selection in Visual mode.
---
--- Examples: >vim
--- xnoremap <CR>
@@ -5170,7 +5175,7 @@ function vim.fn.line(expr, winid) end
--- |getline()|. When {lnum} is invalid -1 is returned.
--- Also see |byte2line()|, |go| and |:goto|.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.line2byte(lnum) end
@@ -5180,7 +5185,7 @@ function vim.fn.line2byte(lnum) end
--- relevant. {lnum} is used just like in |getline()|.
--- When {lnum} is invalid, -1 is returned.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.lispindent(lnum) end
@@ -5479,7 +5484,7 @@ function vim.fn.mapnew(expr1, expr2) end
--- @param mode string
--- @param abbr? boolean
--- @param dict? boolean
--- @param dict? table<string,any>
--- @return any
function vim.fn.mapset(mode, abbr, dict) end
@@ -5519,7 +5524,7 @@ function vim.fn.mapset(mode, abbr, dict) end
--- endfor
--- <
---
--- @param dict boolean
--- @param dict table<string,any>
--- @return any
function vim.fn.mapset(dict) end
@@ -6352,7 +6357,7 @@ function vim.fn.msgpackparse(data) end
--- {lnum} is used like with |getline()|.
--- See also |prevnonblank()|.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.nextnonblank(lnum) end
@@ -6451,7 +6456,7 @@ function vim.fn.pow(x, y) end
--- {lnum} is used like with |getline()|.
--- Also see |nextnonblank()|.
---
--- @param lnum integer
--- @param lnum integer|string
--- @return integer
function vim.fn.prevnonblank(lnum) end
@@ -6717,7 +6722,8 @@ function vim.fn.prevnonblank(lnum) end
--- < 1.41
---
--- You will get an overflow error |E1510|, when the field-width
--- or precision will result in a string longer than 6400 chars.
--- or precision will result in a string longer than 1 MB
--- (1024*1024 = 1048576) chars.
---
--- *E1500*
--- You cannot mix positional and non-positional arguments: >vim
@@ -8060,7 +8066,7 @@ function vim.fn.setcmdline(str, pos) end
--- @return any
function vim.fn.setcmdpos(pos) end
--- @param lnum integer
--- @param lnum integer|string
--- @param col? integer
--- @param off? integer
--- @return any
@@ -8139,7 +8145,7 @@ function vim.fn.setfperm(fname, mode) end
---
--- <Note: The '[ and '] marks are not set.
---
--- @param lnum integer
--- @param lnum integer|string
--- @param text any
--- @return any
function vim.fn.setline(lnum, text) end
@@ -9895,7 +9901,7 @@ function vim.fn.swapname(buf) end
--- echo synIDattr(synID(line("."), col("."), 1), "name")
--- <
---
--- @param lnum integer
--- @param lnum integer|string
--- @param col integer
--- @param trans 0|1
--- @return integer
@@ -9991,7 +9997,7 @@ function vim.fn.synIDtrans(synID) end
--- since syntax and matching highlighting are two different
--- mechanisms |syntax-vs-match|.
---
--- @param lnum integer
--- @param lnum integer|string
--- @param col integer
--- @return [integer, string, integer]
function vim.fn.synconcealed(lnum, col) end
@@ -10014,7 +10020,7 @@ function vim.fn.synconcealed(lnum, col) end
--- character in a line and the first column in an empty line are
--- valid positions.
---
--- @param lnum integer
--- @param lnum integer|string
--- @param col integer
--- @return integer[]
function vim.fn.synstack(lnum, col) end
@@ -10878,14 +10884,13 @@ function vim.fn.wincol() end
--- @return string
function vim.fn.windowsversion() end
--- The result is a Number, which is the height of window {nr}.
--- {nr} can be the window number or the |window-ID|.
--- When {nr} is zero, the height of the current window is
--- returned. When window {nr} doesn't exist, -1 is returned.
--- An existing window always has a height of zero or more.
--- This excludes any window toolbar line.
--- Gets the height of |window-ID| {nr} (zero for "current
--- window"), excluding any 'winbar' and 'statusline'. Returns -1
--- if window {nr} doesn't exist. An existing window always has
--- a height of zero or more.
---
--- Examples: >vim
--- echo "The current window has " .. winheight(0) .. " lines."
--- echo "Current window has " .. winheight(0) .. " lines."
--- <
---
--- @param nr integer
@@ -10929,7 +10934,7 @@ function vim.fn.winheight(nr) end
--- <
---
--- @param tabnr? integer
--- @return any[]
--- @return vim.fn.winlayout.ret
function vim.fn.winlayout(tabnr) end
--- The result is a Number, which is the screen line of the cursor
@@ -11037,18 +11042,21 @@ function vim.fn.winrestview(dict) end
--- @return vim.fn.winsaveview.ret
function vim.fn.winsaveview() end
--- The result is a Number, which is the width of window {nr}.
--- {nr} can be the window number or the |window-ID|.
--- When {nr} is zero, the width of the current window is
--- returned. When window {nr} doesn't exist, -1 is returned.
--- An existing window always has a width of zero or more.
--- Examples: >vim
--- echo "The current window has " .. winwidth(0) .. " columns."
--- Gets the width of |window-ID| {nr} (zero for "current
--- window"), including columns (|sign-column|, 'statuscolumn',
--- etc.). Returns -1 if window {nr} doesn't exist. An existing
--- window always has a width of zero or more.
---
--- Example: >vim
--- echo "Current window has " .. winwidth(0) .. " columns."
--- if winwidth(0) <= 50
--- 50 wincmd |
--- endif
--- <For getting the terminal or screen size, see the 'columns'
--- option.
--- <
--- To get the buffer "viewport", use |getwininfo()|: >vim
--- :echo getwininfo(win_getid())[0].width - getwininfo(win_getid())[0].textoff
--- <
--- To get the Nvim screen size, see the 'columns' option.
---
--- @param nr integer
--- @return integer

View File

@@ -210,12 +210,15 @@ end
--- @param clear_env? boolean
--- @return string[]?
local function setup_env(env, clear_env)
if clear_env then
return env
if not env and clear_env then
return
end
--- @type table<string,string|number>
env = vim.tbl_extend('force', base_env(), env or {})
env = env or {}
if not clear_env then
--- @type table<string,string|number>
env = vim.tbl_extend('force', base_env(), env)
end
local renv = {} --- @type string[]
for k, v in pairs(env) do
@@ -245,7 +248,13 @@ local function spawn(cmd, opts, on_exit, on_error)
local handle, pid_or_err = uv.spawn(cmd, opts, on_exit)
if not handle then
on_error()
error(pid_or_err)
if opts.cwd and not uv.fs_stat(opts.cwd) then
error(("%s (cwd): '%s'"):format(pid_or_err, opts.cwd))
elseif vim.fn.executable(cmd) == 0 then
error(("%s (cmd): '%s'"):format(pid_or_err, cmd))
else
error(pid_or_err)
end
end
return handle, pid_or_err --[[@as integer]]
end

View File

@@ -241,6 +241,10 @@ end
--- @class vim.diagnostic.Opts.VirtualLines
---
--- Only show virtual lines for diagnostics matching the given
--- severity |diagnostic-severity|
--- @field severity? vim.diagnostic.SeverityFilter
---
--- Only show diagnostics for the current line.
--- (default: `false`)
--- @field current_line? boolean
@@ -252,7 +256,7 @@ end
--- @class vim.diagnostic.Opts.Signs
---
--- Only show virtual text for diagnostics matching the given
--- Only show signs for diagnostics matching the given
--- severity |diagnostic-severity|
--- @field severity? vim.diagnostic.SeverityFilter
---
@@ -1438,6 +1442,7 @@ M.handlers.signs = {
vim.validate('bufnr', bufnr, 'number')
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
vim.validate('opts', opts, 'table', true)
vim.validate('opts.signs', (opts and opts or {}).signs, 'table', true)
bufnr = vim._resolve_bufnr(bufnr)
opts = opts or {}
@@ -2615,7 +2620,9 @@ function M.toqflist(diagnostics)
end_lnum = v.end_lnum and (v.end_lnum + 1) or nil,
end_col = v.end_col and (v.end_col + 1) or nil,
text = v.message,
nr = tonumber(v.code),
type = errlist_type_map[v.severity] or 'E',
valid = 1,
}
table.insert(list, item)
end
@@ -2647,7 +2654,8 @@ function M.fromqflist(list)
local col = math.max(0, item.col - 1)
local end_lnum = item.end_lnum > 0 and (item.end_lnum - 1) or lnum
local end_col = item.end_col > 0 and (item.end_col - 1) or col
local severity = item.type ~= '' and M.severity[item.type] or M.severity.ERROR
local code = item.nr > 0 and item.nr or nil
local severity = item.type ~= '' and M.severity[item.type:upper()] or M.severity.ERROR
diagnostics[#diagnostics + 1] = {
bufnr = item.bufnr,
lnum = lnum,
@@ -2656,6 +2664,7 @@ function M.fromqflist(list)
end_col = end_col,
severity = severity,
message = item.text,
code = code,
}
end
end

View File

@@ -2427,8 +2427,26 @@ local pattern = {
['^%.?gtkrc'] = starsetf('gtkrc'),
['/doc/.*%.txt$'] = function(_, bufnr)
local line = M._getline(bufnr, -1)
local ml = line:find('^vim:') or line:find('%svim:')
if ml and M._matchregex(line:sub(ml), [[\<\(ft\|filetype\)=help\>]]) then
if
M._findany(line, {
'^vim:ft=help[:%s]',
'^vim:ft=help$',
'^vim:filetype=help[:%s]',
'^vim:filetype=help$',
'^vim:.*[:%s]ft=help[:%s]',
'^vim:.*[:%s]ft=help$',
'^vim:.*[:%s]filetype=help[:%s]',
'^vim:.*[:%s]filetype=help$',
'%svim:ft=help[:%s]',
'%svim:ft=help$',
'%svim:filetype=help[:%s]',
'%svim:filetype=help$',
'%svim:.*[:%s]ft=help[:%s]',
'%svim:.*[:%s]ft=help$',
'%svim:.*[:%s]filetype=help[:%s]',
'%svim:.*[:%s]filetype=help$',
})
then
return 'help'
end
end,
@@ -2587,7 +2605,7 @@ end
--- Filetype mappings can be added either by extension or by filename (either
--- the "tail" or the full file path). The full file path is checked first,
--- followed by the file name. If a match is not found using the filename, then
--- the filename is matched against the list of |lua-patterns| (sorted by priority)
--- the filename is matched against the list of |lua-pattern|s (sorted by priority)
--- until a match is found. Lastly, if pattern matching does not find a
--- filetype, then the file extension is used.
---

View File

@@ -6,7 +6,7 @@
---
--- >lua
--- if vim.uv.fs_stat(file) then
--- vim.print("file exists")
--- vim.print('file exists')
--- end
--- <
@@ -19,21 +19,21 @@ local sysname = uv.os_uname().sysname:lower()
local iswin = not not (sysname:find('windows') or sysname:find('mingw'))
local os_sep = iswin and '\\' or '/'
--- Iterate over all the parents of the given path.
--- Iterate over all the parents of the given path (not expanded/resolved, the caller must do that).
---
--- Example:
---
--- ```lua
--- local root_dir
--- for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
--- if vim.fn.isdirectory(dir .. "/.git") == 1 then
--- if vim.fn.isdirectory(dir .. '/.git') == 1 then
--- root_dir = dir
--- break
--- end
--- end
---
--- if root_dir then
--- print("Found git repository at", root_dir)
--- print('Found git repository at', root_dir)
--- end
--- ```
---
@@ -55,7 +55,7 @@ function M.parents(start)
start
end
--- Return the parent directory of the given path
--- Gets the parent directory of the given path (not expanded/resolved, the caller must do that).
---
---@since 10
---@generic T : string|nil
@@ -124,6 +124,23 @@ function M.joinpath(...)
return (path:gsub('//+', '/'))
end
--- @class vim.fs.dir.Opts
--- @inlinedoc
---
--- How deep the traverse.
--- (default: `1`)
--- @field depth? integer
---
--- Predicate to control traversal.
--- Return false to stop searching the current directory.
--- Only useful when depth > 1
--- Return an iterator over the items located in {path}
--- @field skip? (fun(dir_name: string): boolean)
---
--- Follow symbolic links.
--- (default: `false`)
--- @field follow? boolean
---@alias Iterator fun(): string?, string?
--- Return an iterator over the items located in {path}
@@ -131,13 +148,7 @@ end
---@since 10
---@param path (string) An absolute or relative path to the directory to iterate
--- over. The path is first normalized |vim.fs.normalize()|.
--- @param opts table|nil Optional keyword arguments:
--- - depth: integer|nil How deep the traverse (default 1)
--- - skip: (fun(dir_name: string): boolean)|nil Predicate
--- to control traversal. Return false to stop searching the current directory.
--- Only useful when depth > 1
--- - follow: boolean|nil Follow symbolic links. (default: false)
---
---@param opts? vim.fs.dir.Opts Optional keyword arguments:
---@return Iterator over items in {path}. Each iteration yields two values: "name" and "type".
--- "name" is the basename of the item relative to {path}.
--- "type" is one of the following:
@@ -234,16 +245,17 @@ end
--- Examples:
---
--- ```lua
--- -- list all test directories under the runtime directory
--- local test_dirs = vim.fs.find(
--- {'test', 'tst', 'testdir'},
--- {limit = math.huge, type = 'directory', path = './runtime/'}
--- -- List all test directories under the runtime directory.
--- local dirs = vim.fs.find(
--- { 'test', 'tst', 'testdir' },
--- { limit = math.huge, type = 'directory', path = './runtime/' }
--- )
---
--- -- get all files ending with .cpp or .hpp inside lib/
--- local cpp_hpp = vim.fs.find(function(name, path)
--- -- Get all "lib/*.cpp" and "lib/*.hpp" files, using Lua patterns.
--- -- Or use `vim.glob.to_lpeg(…):match(…)` for glob/wildcard matching.
--- local files = vim.fs.find(function(name, path)
--- return name:match('.*%.[ch]pp$') and path:match('[/\\]lib$')
--- end, {limit = math.huge, type = 'file'})
--- end, { limit = math.huge, type = 'file' })
--- ```
---
---@since 10
@@ -255,7 +267,7 @@ end
---
--- The function should return `true` if the given item is considered a match.
---
---@param opts vim.fs.find.Opts Optional keyword arguments:
---@param opts? vim.fs.find.Opts Optional keyword arguments:
---@return (string[]) # Normalized paths |vim.fs.normalize()| of all matching items
function M.find(names, opts)
opts = opts or {}
@@ -374,7 +386,7 @@ end
--- If the buffer is unnamed (has no backing file) or has a non-empty 'buftype' then the search
--- begins from Nvim's |current-directory|.
---
--- Example:
--- Examples:
---
--- ```lua
--- -- Find the root of a Python project, starting from file 'main.py'
@@ -387,14 +399,21 @@ end
--- vim.fs.root(0, function(name, path)
--- return name:match('%.csproj$') ~= nil
--- end)
---
--- -- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
--- -- not found, find the first ancestor containing ".git":
--- vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' })
--- ```
---
--- @since 12
--- @param source integer|string Buffer number (0 for current buffer) or file path (absolute or
--- relative to the |current-directory|) to begin the search from.
--- @param marker (string|string[]|fun(name: string, path: string): boolean) A marker, or list
--- of markers, to search for. If a function, the function is called for each
--- evaluated item and should return true if {name} and {path} are a match.
--- @param marker (string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean
--- Filename, function, or list thereof, that decides how to find the root. To
--- indicate "equal priority", specify items in a nested list `{ { 'a.txt', 'b.lua' }, … }`.
--- A function item must return true if `name` and `path` are a match. Each item
--- (which may itself be a nested list) is evaluated in-order against all ancestors,
--- until a match is found.
--- @return string? # Directory path containing one of the given markers, or nil if no directory was
--- found.
function M.root(source, marker)
@@ -414,16 +433,19 @@ function M.root(source, marker)
error('invalid type for argument "source": expected string or buffer number')
end
local paths = M.find(marker, {
upward = true,
path = vim.fn.fnamemodify(path, ':p:h'),
})
local markers = type(marker) == 'table' and marker or { marker }
for _, mark in ipairs(markers) do
local paths = M.find(mark, {
upward = true,
path = vim.fn.fnamemodify(path, ':p:h'),
})
if #paths == 0 then
return nil
if #paths ~= 0 then
return vim.fs.dirname(paths[1])
end
end
return vim.fs.dirname(paths[1])
return nil
end
--- Split a Windows path into a prefix and a body, such that the body can be processed like a POSIX

View File

@@ -1,16 +1,16 @@
--- @brief
---<pre>help
--- vim.health is a minimal framework to help users troubleshoot configuration and
--- any other environment conditions that a plugin might care about. Nvim ships
--- with healthchecks for configuration, performance, python support, ruby
--- support, clipboard support, and more.
---
--- To run all healthchecks, use: >vim
--- vim.health is a minimal framework to help users troubleshoot configuration and any other
--- environment conditions that a plugin might care about. Nvim ships with healthchecks for
--- configuration, performance, python support, ruby support, clipboard support, and more.
---
--- :checkhealth
--- <
--- To run all healthchecks, use:
--- ```vim
--- :checkhealth
--- ```
--- Plugin authors are encouraged to write new healthchecks. |health-dev|
---
---<pre>help
--- COMMANDS *health-commands*
---
--- *:che* *:checkhealth*
@@ -46,7 +46,6 @@
--- q Closes the window.
---
--- Global configuration:
---
--- *g:health*
--- g:health Dictionary with the following optional keys:
--- - `style` (`'float'|nil`) Set to "float" to display :checkhealth in
@@ -55,57 +54,69 @@
--- Example: >lua
--- vim.g.health = { style = 'float' }
---
---</pre>
---
--- Local configuration:
---
--- Checkhealth sets its buffer filetype to "checkhealth". You can customize the buffer by handling
--- the |FileType| event. For example if you don't want emojis in the health report:
--- ```vim
--- autocmd FileType checkhealth :set modifiable | silent! %s/\v( ?[^\x00-\x7F])//g
--- ```
---
---<pre>help
--- --------------------------------------------------------------------------------
--- Create a healthcheck *health-dev*
---</pre>
---
--- Healthchecks are functions that check the user environment, configuration, or
--- any other prerequisites that a plugin cares about. Nvim ships with
--- healthchecks in:
--- - $VIMRUNTIME/autoload/health/
--- - $VIMRUNTIME/lua/vim/lsp/health.lua
--- - $VIMRUNTIME/lua/vim/treesitter/health.lua
--- - and more...
--- Healthchecks are functions that check the user environment, configuration, or any other
--- prerequisites that a plugin cares about. Nvim ships with healthchecks in:
--- - $VIMRUNTIME/autoload/health/
--- - $VIMRUNTIME/lua/vim/lsp/health.lua
--- - $VIMRUNTIME/lua/vim/treesitter/health.lua
--- - and more...
---
--- To add a new healthcheck for your own plugin, simply create a "health.lua"
--- module on 'runtimepath' that returns a table with a "check()" function. Then
--- |:checkhealth| will automatically find and invoke the function.
--- To add a new healthcheck for your own plugin, simply create a "health.lua" module on
--- 'runtimepath' that returns a table with a "check()" function. Then |:checkhealth| will
--- automatically find and invoke the function.
---
--- For example if your plugin is named "foo", define your healthcheck module at
--- one of these locations (on 'runtimepath'):
--- - lua/foo/health/init.lua
--- - lua/foo/health.lua
--- - lua/foo/health/init.lua
--- - lua/foo/health.lua
---
--- If your plugin also provides a submodule named "bar" for which you want
--- a separate healthcheck, define the healthcheck at one of these locations:
--- - lua/foo/bar/health/init.lua
--- - lua/foo/bar/health.lua
--- If your plugin also provides a submodule named "bar" for which you want a separate healthcheck,
--- define the healthcheck at one of these locations:
--- - lua/foo/bar/health/init.lua
--- - lua/foo/bar/health.lua
---
--- All such health modules must return a Lua table containing a `check()`
--- function.
--- All such health modules must return a Lua table containing a `check()` function.
---
--- Copy this sample code into `lua/foo/health.lua`, replacing "foo" in the path
--- with your plugin name: >lua
--- Copy this sample code into `lua/foo/health.lua`, replacing "foo" in the path with your plugin
--- name:
---
--- local M = {}
--- ```lua
--- local M = {}
---
--- M.check = function()
--- vim.health.start("foo report")
--- -- make sure setup function parameters are ok
--- if check_setup() then
--- vim.health.ok("Setup is correct")
--- else
--- vim.health.error("Setup is incorrect")
--- end
--- -- do some more checking
--- -- ...
--- end
--- M.check = function()
--- vim.health.start("foo report")
--- -- make sure setup function parameters are ok
--- if check_setup() then
--- vim.health.ok("Setup is correct")
--- else
--- vim.health.error("Setup is incorrect")
--- end
--- -- do some more checking
--- -- ...
--- end
---
--- return M
---</pre>
--- return M
--- ```
local M = {}
local s_output = {} ---@type string[]
local check_summary = { warn = 0, error = 0 }
-- From a path return a list [{name}, {func}, {type}] representing a healthcheck
local function filepath_to_healthcheck(path)
@@ -275,7 +286,7 @@ end
---
--- @param msg string
function M.ok(msg)
local input = format_report_message('OK', msg)
local input = format_report_message('OK', msg)
collect_output(input)
end
@@ -284,8 +295,9 @@ end
--- @param msg string
--- @param ... string|string[] Optional advice
function M.warn(msg, ...)
local input = format_report_message('WARNING', msg, ...)
local input = format_report_message('⚠️ WARNING', msg, ...)
collect_output(input)
check_summary['warn'] = check_summary['warn'] + 1
end
--- Reports an error.
@@ -293,8 +305,9 @@ end
--- @param msg string
--- @param ... string|string[] Optional advice
function M.error(msg, ...)
local input = format_report_message('ERROR', msg, ...)
local input = format_report_message('ERROR', msg, ...)
collect_output(input)
check_summary['error'] = check_summary['error'] + 1
end
local path2name = function(path)
@@ -341,6 +354,23 @@ M._complete = function()
return rv
end
--- Gets the results heading for the current report section.
---
---@return string
local function get_summary()
local s = ''
local errors = check_summary['error']
local warns = check_summary['warn']
s = s .. (warns > 0 and (' %2d ⚠️'):format(warns) or '')
s = s .. (errors > 0 and (' %2d ❌'):format(errors) or '')
if errors == 0 and warns == 0 then
s = s .. ''
end
return s
end
--- Runs the specified healthchecks.
--- Runs all discovered healthchecks if plugin_names is empty.
---
@@ -353,25 +383,29 @@ function M._check(mods, plugin_names)
local emptybuf = vim.fn.bufnr('$') == 1 and vim.fn.getline(1) == '' and 1 == vim.fn.line('$')
local bufnr = vim.api.nvim_create_buf(true, true)
local bufnr ---@type integer
if
vim.g.health
and type(vim.g.health) == 'table'
and vim.tbl_get(vim.g.health, 'style') == 'float'
then
local max_height = math.floor(vim.o.lines * 0.8)
local available_lines = vim.o.lines - 12
local max_height = math.min(math.floor(vim.o.lines * 0.8), available_lines)
local max_width = 80
local float_bufnr, float_winid = vim.lsp.util.open_floating_preview({}, '', {
local float_winid
bufnr, float_winid = vim.lsp.util.open_floating_preview({}, '', {
height = max_height,
width = max_width,
offset_x = math.floor((vim.o.columns - max_width) / 2),
offset_y = math.floor((vim.o.lines - max_height) / 2) - 1,
offset_y = math.floor((available_lines - max_height) / 2),
relative = 'editor',
close_events = {},
})
vim.api.nvim_set_current_win(float_winid)
vim.bo[float_bufnr].modifiable = true
vim.bo[bufnr].modifiable = true
vim.wo[float_winid].list = false
else
bufnr = vim.api.nvim_create_buf(true, true)
-- When no command modifiers are used:
-- - If the current buffer is empty, open healthcheck directly.
-- - If not specified otherwise open healthcheck in a tab.
@@ -383,7 +417,6 @@ function M._check(mods, plugin_names)
vim.cmd.bwipe('health://')
end
vim.cmd.file('health://')
vim.cmd.setfiletype('checkhealth')
-- This should only happen when doing `:checkhealth vim`
if next(healthchecks) == nil then
@@ -397,9 +430,9 @@ function M._check(mods, plugin_names)
local func = value[1]
local type = value[2]
s_output = {}
check_summary = { warn = 0, error = 0 }
if func == '' then
s_output = {}
M.error('No healthcheck found for "' .. name .. '" plugin.')
end
if type == 'v' then
@@ -420,10 +453,12 @@ function M._check(mods, plugin_names)
M.error('The healthcheck report for "' .. name .. '" plugin is empty.')
end
local report = get_summary()
local replen = vim.fn.strwidth(report)
local header = {
string.rep('=', 78),
-- Example: `foo.health: [ …] require("foo.health").check()`
('%s: %s%s'):format(name, (' '):rep(76 - name:len() - func:len()), func),
-- Example: `foo.health: [ …] 1 ⚠️ 5 ❌`
('%s: %s%s'):format(name, (' '):rep(76 - name:len() - replen), report),
'',
}
@@ -449,14 +484,19 @@ function M._check(mods, plugin_names)
vim.print('')
-- Quit with 'q' inside healthcheck buffers.
vim.keymap.set('n', 'q', function()
if not pcall(vim.cmd.close) then
vim.cmd.bdelete()
vim._with({ buf = bufnr }, function()
if vim.fn.maparg('q', 'n', false, false) == '' then
vim.keymap.set('n', 'q', function()
if not pcall(vim.cmd.close) then
vim.cmd.bdelete()
end
end, { buffer = bufnr, silent = true, noremap = true, nowait = true })
end
end, { buffer = bufnr, silent = true, noremap = true, nowait = true })
end)
-- Once we're done writing checks, set nomodifiable.
vim.bo[bufnr].modifiable = false
vim.cmd.setfiletype('checkhealth')
end
return M

View File

@@ -87,9 +87,9 @@ local function check_config()
health.error(
'Locale does not support UTF-8. Unicode characters may not display correctly.'
.. ('\n$LANG=%s $LC_ALL=%s $LC_CTYPE=%s'):format(
vim.env.LANG,
vim.env.LC_ALL,
vim.env.LC_CTYPE
vim.env.LANG or '',
vim.env.LC_ALL or '',
vim.env.LC_CTYPE or ''
),
{
'If using tmux, try the -u option.',
@@ -318,9 +318,11 @@ local function check_tmux()
'$TERM differs from the tmux `default-terminal` setting. Colors might look wrong.',
{ '$TERM may have been set by some rc (.bashrc, .zshrc, ...).' }
)
elseif not vim.regex([[\v(tmux-256color|screen-256color)]]):match_str(vim.env.TERM) then
elseif
not vim.regex([[\v(tmux-256color|tmux-direct|screen-256color)]]):match_str(vim.env.TERM)
then
health.error(
'$TERM should be "screen-256color" or "tmux-256color" in tmux. Colors might look wrong.',
'$TERM should be "screen-256color", "tmux-256color", or "tmux-direct" in tmux. Colors might look wrong.',
{
'Set default-terminal in ~/.tmux.conf:\nset-option -g default-terminal "screen-256color"',
suggest_faq,

View File

@@ -17,9 +17,6 @@ M.priorities = {
user = 200,
}
local range_timer --- @type uv.uv_timer_t?
local range_hl_clear --- @type fun()?
--- @class vim.hl.range.Opts
--- @inlinedoc
---
@@ -47,6 +44,10 @@ local range_hl_clear --- @type fun()?
---@param start integer[]|string Start of region as a (line, column) tuple or string accepted by |getpos()|
---@param finish integer[]|string End of region as a (line, column) tuple or string accepted by |getpos()|
---@param opts? vim.hl.range.Opts
--- @return uv.uv_timer_t? range_timer A timer which manages how much time the
--- highlight has left
--- @return fun()? range_clear A function which allows clearing the highlight manually.
--- nil is returned if timeout is not specified
function M.range(bufnr, ns, higroup, start, finish, opts)
opts = opts or {}
local regtype = opts.regtype or 'v'
@@ -108,38 +109,41 @@ function M.range(bufnr, ns, higroup, start, finish, opts)
end
end
if range_timer and not range_timer:is_closing() then
range_timer:close()
assert(range_hl_clear)
range_hl_clear()
end
range_hl_clear = function()
range_timer = nil
range_hl_clear = nil
pcall(vim.api.nvim_buf_clear_namespace, bufnr, ns, 0, -1)
pcall(vim.api.nvim__ns_set, { wins = {} })
end
local extmarks = {} --- @type integer[]
for _, res in ipairs(region) do
local start_row = res[1][2] - 1
local start_col = res[1][3] - 1
local end_row = res[2][2] - 1
local end_col = res[2][3]
api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, {
hl_group = higroup,
end_row = end_row,
end_col = end_col,
priority = priority,
strict = false,
})
table.insert(
extmarks,
api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, {
hl_group = higroup,
end_row = end_row,
end_col = end_col,
priority = priority,
strict = false,
})
)
end
local range_hl_clear = function()
if not api.nvim_buf_is_valid(bufnr) then
return
end
for _, mark in ipairs(extmarks) do
api.nvim_buf_del_extmark(bufnr, ns, mark)
end
end
if timeout ~= -1 then
range_timer = vim.defer_fn(range_hl_clear, timeout)
local range_timer = vim.defer_fn(range_hl_clear, timeout)
return range_timer, range_hl_clear
end
end
local yank_timer --- @type uv.uv_timer_t?
local yank_hl_clear --- @type fun()?
local yank_ns = api.nvim_create_namespace('nvim.hlyank')
--- Highlight the yanked text during a |TextYankPost| event.
@@ -179,8 +183,14 @@ function M.on_yank(opts)
local bufnr = vim.api.nvim_get_current_buf()
local winid = vim.api.nvim_get_current_win()
if yank_timer and not yank_timer:is_closing() then
yank_timer:close()
assert(yank_hl_clear)
yank_hl_clear()
end
vim.api.nvim__ns_set(yank_ns, { wins = { winid } })
M.range(bufnr, yank_ns, higroup, "'[", "']", {
yank_timer, yank_hl_clear = M.range(bufnr, yank_ns, higroup, "'[", "']", {
regtype = event.regtype,
inclusive = true,
priority = opts.priority or M.priorities.user,

View File

@@ -957,6 +957,9 @@ end
---@private
function ArrayIter:last()
if self._head >= self._tail then
return nil
end
local inc = self._head < self._tail and 1 or -1
local v = self._table[self._tail - inc]
self._head = self._tail

View File

@@ -147,7 +147,7 @@ end
--- @param config vim.lsp.ClientConfig
--- @return boolean
local function reuse_client_default(client, config)
if client.name ~= config.name then
if client.name ~= config.name or client:is_stopped() then
return false
end
@@ -275,26 +275,47 @@ end
--- @class vim.lsp.Config : vim.lsp.ClientConfig
---
--- See `cmd` in [vim.lsp.ClientConfig].
--- @field cmd? string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
--- See also `reuse_client` to dynamically decide (per-buffer) when `cmd` should be re-invoked.
--- @field cmd? string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient
---
--- Filetypes the client will attach to, if activated by `vim.lsp.enable()`.
--- If not provided, then the client will attach to all filetypes.
--- Filetypes the client will attach to, if activated by `vim.lsp.enable()`. If not provided, the
--- client will attach to all filetypes.
--- @field filetypes? string[]
---
--- Directory markers (.e.g. '.git/') where the LSP server will base its workspaceFolders,
--- rootUri, and rootPath on initialization. Unused if `root_dir` is provided.
--- @field root_markers? string[]
---
--- Directory where the LSP server will base its workspaceFolders, rootUri, and
--- rootPath on initialization. If a function, it is passed the buffer number
--- and a callback argument which must be called with the value of root_dir to
--- use. The LSP server will not be started until the callback is called.
--- @field root_dir? string|fun(bufnr: integer, cb:fun(root_dir?:string))
---
--- Predicate used to decide if a client should be re-used. Used on all
--- running clients. The default implementation re-uses a client if name and
--- root_dir matches.
--- Predicate which decides if a client should be re-used. Used on all running clients. The default
--- implementation re-uses a client if name and root_dir matches.
--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
---
--- [lsp-root_dir()]()
--- Decides the workspace root: the directory where the LSP server will base its workspaceFolders,
--- rootUri, and rootPath on initialization. The function form must call the `on_dir` callback to
--- provide the root dir, or LSP will not be activated for the buffer. Thus a `root_dir()` function
--- can dynamically decide per-buffer whether to activate (or skip) LSP.
--- See example at |vim.lsp.enable()|.
--- @field root_dir? string|fun(bufnr: integer, on_dir:fun(root_dir?:string))
---
--- [lsp-root_markers]()
--- Filename(s) (".git/", "package.json", …) used to decide the workspace root. Unused if `root_dir`
--- is defined. The list order decides priority. To indicate "equal priority", specify names in
--- a nested list `{ { 'a.txt', 'b.lua' }, ... }`.
---
--- For each item, Nvim will search upwards (from the buffer file) for that marker, or list of
--- markers; search stops at the first directory containing that marker, and the directory is used
--- as the root dir (workspace folder).
---
--- Example: Find the first ancestor directory containing file or directory "stylua.toml"; if not
--- found, find the first ancestor containing ".git":
--- ```lua
--- root_markers = { 'stylua.toml', '.git' }
--- ```
---
--- Example: Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
--- not found, find the first ancestor containing ".git":
--- ```lua
--- root_markers = { { 'stylua.toml', '.luarc.json' }, '.git' }
--- ```
---
--- @field root_markers? (string|string[])[]
--- Update the configuration for an LSP client.
---
@@ -362,6 +383,19 @@ local function invalidate_enabled_config(name)
end
end
--- @param name any
local function validate_config_name(name)
validate('name', name, function(value)
if type(value) ~= 'string' then
return false
end
if value ~= '*' and value:match('%*') then
return false, 'LSP config name cannot contain wildcard ("*")'
end
return true
end, 'non-wildcard string')
end
--- @nodoc
--- @class vim.lsp.config
--- @field [string] vim.lsp.Config
@@ -371,11 +405,16 @@ lsp.config = setmetatable({ _configs = {} }, {
--- @param name string
--- @return vim.lsp.Config
__index = function(self, name)
validate('name', name, 'string')
validate_config_name(name)
local rconfig = lsp._enabled_configs[name] or {}
if not rconfig.resolved_config then
if name == '*' then
rconfig.resolved_config = lsp.config._configs['*'] or {}
return rconfig.resolved_config
end
-- Resolve configs from lsp/*.lua
-- Calls to vim.lsp.config in lsp/* have a lower precedence than calls from other sites.
local rtp_config --- @type vim.lsp.Config?
@@ -385,12 +424,12 @@ lsp.config = setmetatable({ _configs = {} }, {
--- @type vim.lsp.Config?
rtp_config = vim.tbl_deep_extend('force', rtp_config or {}, config)
else
log.warn(string.format('%s does not return a table, ignoring', v))
log.warn(('%s does not return a table, ignoring'):format(v))
end
end
if not rtp_config and not self._configs[name] then
log.warn(string.format('%s does not have a configuration', name))
log.warn(('%s does not have a configuration'):format(name))
return
end
@@ -410,8 +449,9 @@ lsp.config = setmetatable({ _configs = {} }, {
--- @param name string
--- @param cfg vim.lsp.Config
__newindex = function(self, name, cfg)
validate('name', name, 'string')
validate('cfg', cfg, 'table')
validate_config_name(name)
local msg = ('table (hint: to resolve a config, use vim.lsp.config["%s"])'):format(name)
validate('cfg', cfg, 'table', msg)
invalidate_enabled_config(name)
self._configs[name] = cfg
end,
@@ -420,8 +460,9 @@ lsp.config = setmetatable({ _configs = {} }, {
--- @param name string
--- @param cfg vim.lsp.Config
__call = function(self, name, cfg)
validate('name', name, 'string')
validate('cfg', cfg, 'table')
validate_config_name(name)
local msg = ('table (hint: to resolve a config, use vim.lsp.config["%s"])'):format(name)
validate('cfg', cfg, 'table', msg)
invalidate_enabled_config(name)
self[name] = vim.tbl_deep_extend('force', self._configs[name] or {}, cfg)
end,
@@ -480,6 +521,17 @@ local function lsp_enable_callback(bufnr)
return
end
-- Stop any clients that no longer apply to this buffer.
local clients = lsp.get_clients({ bufnr = bufnr, _uninitialized = true })
for _, client in ipairs(clients) do
if
lsp.is_enabled(client.name) and not can_start(bufnr, client.name, lsp.config[client.name])
then
lsp.buf_detach_client(bufnr, client.id)
end
end
-- Start any clients that apply to this buffer.
for name in vim.spairs(lsp._enabled_configs) do
local config = lsp.config[name]
if config and can_start(bufnr, name, config) then
@@ -502,20 +554,40 @@ local function lsp_enable_callback(bufnr)
end
end
--- Enable an LSP server to automatically start when opening a buffer.
---
--- Uses configuration defined with `vim.lsp.config`.
--- Auto-starts LSP when a buffer is opened, based on the |lsp-config| `filetypes`, `root_markers`,
--- and `root_dir` fields.
---
--- Examples:
---
--- ```lua
--- vim.lsp.enable('clangd')
--- vim.lsp.enable('clangd')
--- vim.lsp.enable({'luals', 'pyright'})
--- ```
---
--- vim.lsp.enable({'luals', 'pyright'})
--- Example: [lsp-restart]() Passing `false` stops and detaches the client(s). Thus you can
--- "restart" LSP by disabling and re-enabling a given config:
---
--- ```lua
--- vim.lsp.enable('clangd', false)
--- vim.lsp.enable('clangd', true)
--- ```
---
--- Example: To _dynamically_ decide whether LSP is activated, define a |lsp-root_dir()| function
--- which calls `on_dir()` only when you want that config to activate:
---
--- ```lua
--- vim.lsp.config('lua_ls', {
--- root_dir = function(bufnr, on_dir)
--- if not vim.fn.bufname(bufnr):match('%.txt$') then
--- on_dir(vim.fn.getcwd())
--- end
--- end
--- })
--- ```
---
--- @param name string|string[] Name(s) of client(s) to enable.
--- @param enable? boolean `true|nil` to enable, `false` to disable.
--- @param enable? boolean `true|nil` to enable, `false` to disable (actively stops and detaches
--- clients as needed)
function lsp.enable(name, enable)
validate('name', name, { 'string', 'table' })
@@ -528,21 +600,44 @@ function lsp.enable(name, enable)
end
if not next(lsp._enabled_configs) then
-- If there are no remaining LSPs enabled, remove the enable autocmd.
if lsp_enable_autocmd_id then
api.nvim_del_autocmd(lsp_enable_autocmd_id)
lsp_enable_autocmd_id = nil
end
return
else
-- Only ever create autocmd once to reuse computation of config merging.
lsp_enable_autocmd_id = lsp_enable_autocmd_id
or api.nvim_create_autocmd('FileType', {
group = api.nvim_create_augroup('nvim.lsp.enable', {}),
callback = function(args)
lsp_enable_callback(args.buf)
end,
})
end
-- Only ever create autocmd once to reuse computation of config merging.
lsp_enable_autocmd_id = lsp_enable_autocmd_id
or api.nvim_create_autocmd('FileType', {
group = api.nvim_create_augroup('nvim.lsp.enable', {}),
callback = function(args)
lsp_enable_callback(args.buf)
end,
})
-- Ensure any pre-existing buffers start/stop their LSP clients.
if enable ~= false then
if vim.v.vim_did_enter == 1 then
vim.cmd.doautoall('nvim.lsp.enable FileType')
end
else
for _, nm in ipairs(names) do
for _, client in ipairs(lsp.get_clients({ name = nm })) do
client:stop()
end
end
end
end
--- Checks if the given LSP config is enabled (globally, not per-buffer).
---
--- Unlike `vim.lsp.config['…']`, this does not have the side-effect of resolving the config.
---
--- @param name string Config name
--- @return boolean
function lsp.is_enabled(name)
return lsp._enabled_configs[name] ~= nil
end
--- @class vim.lsp.start.Opts
@@ -564,7 +659,7 @@ end
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent? boolean
---
--- @field package _root_markers? string[]
--- @field package _root_markers? (string|string[])[]
--- Create a new LSP client and start a language server or reuses an already
--- running client if one is found matching `name` and `root_dir`.
@@ -611,10 +706,23 @@ function lsp.start(config, opts)
local bufnr = vim._resolve_bufnr(opts.bufnr)
if not config.root_dir and opts._root_markers then
validate('root_markers', opts._root_markers, 'table')
config = vim.deepcopy(config)
config.root_dir = vim.fs.root(bufnr, opts._root_markers)
end
if
not config.root_dir
and (not config.workspace_folders or #config.workspace_folders == 0)
and config.workspace_required
then
log.info(
('skipping config "%s": workspace_required=true, no workspace found'):format(config.name)
)
return
end
for _, client in pairs(all_clients) do
if reuse_client(client, config) then
if opts.attach == false then
@@ -1181,7 +1289,9 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
local function _cancel_all_requests()
for client_id, request_id in pairs(client_request_ids) do
local client = all_clients[client_id]
client:cancel_request(request_id)
if client.requests[request_id] then
client:cancel_request(request_id)
end
end
end

View File

@@ -3,6 +3,13 @@ local log = require('vim.lsp.log')
local ms = require('vim.lsp.protocol').Methods
local api = vim.api
---@type table<lsp.FoldingRangeKind, true>
local supported_fold_kinds = {
['comment'] = true,
['imports'] = true,
['region'] = true,
}
local M = {}
---@class (private) vim.lsp.folding_range.BufState
@@ -39,7 +46,7 @@ local function renew(bufnr)
---@type table<integer, string?>
local row_text = {}
for _, ranges in pairs(bufstate.client_ranges) do
for client_id, ranges in pairs(bufstate.client_ranges) do
for _, range in ipairs(ranges) do
local start_row = range.startLine
local end_row = range.endLine
@@ -49,9 +56,14 @@ local function renew(bufnr)
local kind = range.kind
if kind then
local kinds = row_kinds[start_row] or {}
kinds[kind] = true
row_kinds[start_row] = kinds
-- Ignore unsupported fold kinds.
if supported_fold_kinds[kind] then
local kinds = row_kinds[start_row] or {}
kinds[kind] = true
row_kinds[start_row] = kinds
else
log.info(('Unknown fold kind "%s" from client %d'):format(kind, client_id))
end
end
for row = start_row, end_row do

View File

@@ -71,7 +71,7 @@ function M.hover(config)
if vim.tbl_isempty(results1) then
if config.silent ~= true then
vim.notify('No information available')
vim.notify('No information available', vim.log.levels.INFO)
end
return
end
@@ -215,7 +215,13 @@ local function get_locations(method, opts)
vim.fn.settagstack(vim.fn.win_getid(win), { items = tagstack }, 't')
vim.bo[b].buflisted = true
local w = opts.reuse_win and vim.fn.win_findbuf(b)[1] or win
local w = win
if opts.reuse_win then
w = vim.fn.win_findbuf(b)[1] or w
if w ~= win then
api.nvim_set_current_win(w)
end
end
api.nvim_win_set_buf(w, b)
api.nvim_win_set_cursor(w, { item.lnum, item.col - 1 })
vim._with({ win = w }, function()
@@ -303,6 +309,7 @@ end
--- @param results table<integer,{err: lsp.ResponseError?, result: lsp.SignatureHelp?}>
local function process_signature_help_results(results)
local signatures = {} --- @type [vim.lsp.Client,lsp.SignatureInformation][]
local active_signature = 1
-- Pre-process results
for client_id, r in pairs(results) do
@@ -317,15 +324,19 @@ local function process_signature_help_results(results)
else
local result = r.result --- @type lsp.SignatureHelp
if result and result.signatures and result.signatures[1] then
for _, sig in ipairs(result.signatures) do
for i, sig in ipairs(result.signatures) do
sig.activeParameter = sig.activeParameter or result.activeParameter
signatures[#signatures + 1] = { client, sig }
local idx = #signatures + 1
if (result.activeSignature or 0) + 1 == i then
active_signature = idx
end
signatures[idx] = { client, sig }
end
end
end
end
return signatures
return signatures, active_signature
end
local sig_help_ns = api.nvim_create_namespace('nvim.lsp.signature_help')
@@ -341,6 +352,7 @@ function M.signature_help(config)
config = config and vim.deepcopy(config) or {}
config.focus_id = method
local user_title = config.title
lsp.buf_request_all(0, method, client_positional_params(), function(results, ctx)
if api.nvim_get_current_buf() ~= ctx.bufnr then
@@ -348,19 +360,19 @@ function M.signature_help(config)
return
end
local signatures = process_signature_help_results(results)
local signatures, active_signature = process_signature_help_results(results)
if not next(signatures) then
if config.silent ~= true then
print('No signature help available')
vim.notify('No signature help available', vim.log.levels.INFO)
end
return
end
local ft = vim.bo[ctx.bufnr].filetype
local total = #signatures
local can_cycle = total > 1 and config.focusable
local idx = 0
local can_cycle = total > 1 and config.focusable ~= false
local idx = active_signature - 1
--- @param update_win? integer
local function show_signature(update_win)
@@ -375,15 +387,19 @@ function M.signature_help(config)
return
end
local sfx = can_cycle and string.format(' (%d/%d) (<C-s> to cycle)', idx, total) or ''
local title = string.format('Signature Help: %s%s', client.name, sfx)
if config.border then
config.title = title
else
table.insert(lines, 1, '# ' .. title)
if hl then
hl[1] = hl[1] + 1
hl[3] = hl[3] + 1
-- Show title only if there are multiple clients or multiple signatures.
if total > 1 then
local sfx = total > 1
and string.format(' (%d/%d)%s', idx, total, can_cycle and ' (<C-s> to cycle)' or '')
or ''
config.title = user_title or string.format('Signature Help: %s%s', client.name, sfx)
-- If no border is set, render title inside the window.
if not (config.border or vim.o.winborder ~= '') then
table.insert(lines, 1, '# ' .. config.title)
if hl then
hl[1] = hl[1] + 1
hl[3] = hl[3] + 1
end
end
end
@@ -427,7 +443,7 @@ end
---
---@see vim.lsp.protocol.CompletionTriggerKind
function M.completion(context)
vim.depends('vim.lsp.buf.completion', 'vim.lsp.completion.trigger', '0.12')
vim.deprecate('vim.lsp.buf.completion', 'vim.lsp.completion.trigger', '0.12')
return lsp.buf_request(
0,
ms.textDocument_completion,
@@ -957,7 +973,7 @@ function M.add_workspace_folder(workspace_folder)
return
end
if vim.fn.isdirectory(workspace_folder) == 0 then
print(workspace_folder, ' is not a valid directory')
vim.notify(workspace_folder .. ' is not a valid directory')
return
end
local bufnr = api.nvim_get_current_buf()
@@ -981,7 +997,7 @@ function M.remove_workspace_folder(workspace_folder)
for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do
client:_remove_workspace_folder(workspace_folder)
end
print(workspace_folder, 'is not currently part of the workspace')
vim.notify(workspace_folder .. 'is not currently part of the workspace')
end
--- Lists all symbols in the current workspace in the quickfix window.
@@ -1198,8 +1214,7 @@ local function on_code_action_results(results, opts)
vim.ui.select(actions, select_opts, on_user_choice)
end
--- Selects a code action available at the current
--- cursor position.
--- Selects a code action (LSP: "textDocument/codeAction" request) available at cursor position.
---
---@param opts? vim.lsp.buf.code_action.Opts
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction

View File

@@ -30,38 +30,11 @@ local validate = vim.validate
--- @field exit_timeout integer|false
--- @class vim.lsp.ClientConfig
--- command string[] that launches the language
--- server (treated as in |jobstart()|, must be absolute or on `$PATH`, shell constructs like
--- "~" are not expanded), or function that creates an RPC client. Function receives
--- a `dispatchers` table and returns a table with member functions `request`, `notify`,
--- `is_closing` and `terminate`.
--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
---
--- Directory to launch the `cmd` process. Not related to `root_dir`.
--- (default: cwd)
--- @field cmd_cwd? string
---
--- Environment flags to pass to the LSP on spawn.
--- Must be specified using a table.
--- Non-string values are coerced to string.
--- Example:
--- ```lua
--- { PORT = 8080; HOST = "0.0.0.0"; }
--- ```
--- @field cmd_env? table
---
--- Daemonize the server process so that it runs in a separate process group from Nvim.
--- Nvim will shutdown the process on exit, but if Nvim fails to exit cleanly this could leave
--- behind orphaned server processes.
--- (default: true)
--- @field detached? boolean
---
--- List of workspace folders passed to the language server.
--- For backwards compatibility rootUri and rootPath will be derived from the first workspace
--- folder in this list. See `workspaceFolders` in the LSP spec.
--- @field workspace_folders? lsp.WorkspaceFolder[]
--- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters
--- being sent to the server and `config` is the config that was passed to |vim.lsp.start()|.
--- You can use this to modify parameters before they are sent.
--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)
---
--- Map overriding the default capabilities defined by |vim.lsp.protocol.make_client_capabilities()|,
--- passed to the language server on initialization. Hint: use make_client_capabilities() and modify
@@ -70,93 +43,143 @@ local validate = vim.validate
--- array.
--- @field capabilities? lsp.ClientCapabilities
---
--- Map of language server method names to |lsp-handler|
--- @field handlers? table<string,function>
--- Command `string[]` that launches the language server (treated as in |jobstart()|, must be
--- absolute or on `$PATH`, shell constructs like "~" are not expanded), or function that creates an
--- RPC client. Function receives a `dispatchers` table and the resolved `config`, and must return
--- a table with member functions `request`, `notify`, `is_closing` and `terminate`.
--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient
---
--- Map with language server specific settings.
--- See the {settings} in |vim.lsp.Client|.
--- @field settings? lsp.LSPObject
--- Directory to launch the `cmd` process. Not related to `root_dir`.
--- (default: cwd)
--- @field cmd_cwd? string
---
--- Table that maps string of clientside commands to user-defined functions.
--- Commands passed to `start()` take precedence over the global command registry. Each key
--- must be a unique command name, and the value is a function which is called if any LSP action
--- (code action, code lenses, ...) triggers the command.
--- Environment variables passed to the LSP process on spawn. Non-string values are coerced to
--- string.
--- Example:
--- ```lua
--- { PORT = 8080; HOST = '0.0.0.0'; }
--- ```
--- @field cmd_env? table
---
--- Client commands. Map of command names to user-defined functions. Commands passed to `start()`
--- take precedence over the global command registry. Each key must be a unique command name, and
--- the value is a function which is called if any LSP action (code action, code lenses, …) triggers
--- the command.
--- @field commands? table<string,fun(command: lsp.Command, ctx: table)>
---
--- Daemonize the server process so that it runs in a separate process group from Nvim.
--- Nvim will shutdown the process on exit, but if Nvim fails to exit cleanly this could leave
--- behind orphaned server processes.
--- (default: `true`)
--- @field detached? boolean
---
--- A table with flags for the client. The current (experimental) flags are:
--- @field flags? vim.lsp.Client.Flags
---
--- Language ID as string. Defaults to the buffer filetype.
--- @field get_language_id? fun(bufnr: integer, filetype: string): string
---
--- Map of LSP method names to |lsp-handler|s.
--- @field handlers? table<string,function>
---
--- Values to pass in the initialization request as `initializationOptions`. See `initialize` in
--- the LSP spec.
--- @field init_options? lsp.LSPObject
---
--- Name in log messages.
--- Name in logs and user messages.
--- (default: client-id)
--- @field name? string
---
--- Language ID as string. Defaults to the buffer filetype.
--- @field get_language_id? fun(bufnr: integer, filetype: string): string
---
--- Called "position encoding" in LSP spec, the encoding that the LSP server expects.
--- Client does not verify this is correct.
--- Called "position encoding" in LSP spec. The encoding that the LSP server expects, used for
--- communication. Not validated. Can be modified in `on_init` before text is sent to the server.
--- @field offset_encoding? 'utf-8'|'utf-16'|'utf-32'
---
--- Callback invoked when client attaches to a buffer.
--- @field on_attach? elem_or_list<fun(client: vim.lsp.Client, bufnr: integer)>
---
--- Callback invoked when the client operation throws an error. `code` is a number describing the error.
--- Other arguments may be passed depending on the error kind. See `vim.lsp.rpc.client_errors`
--- for possible errors. Use `vim.lsp.rpc.client_errors[code]` to get human-friendly name.
--- @field on_error? fun(code: integer, err: string)
---
--- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters
--- being sent to the server and `config` is the config that was passed to |vim.lsp.start()|.
--- You can use this to modify parameters before they are sent.
--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)
---
--- Callback invoked after LSP "initialize", where `result` is a table of `capabilities` and
--- anything else the server may send. For example, clangd sends `init_result.offsetEncoding` if
--- `capabilities.offsetEncoding` was sent to it. You can only modify the `client.offset_encoding`
--- here before any notifications are sent.
--- @field on_init? elem_or_list<fun(client: vim.lsp.Client, init_result: lsp.InitializeResult)>
---
--- Callback invoked on client exit.
--- - code: exit code of the process
--- - signal: number describing the signal used to terminate (if any)
--- - client_id: client handle
--- @field on_exit? elem_or_list<fun(code: integer, signal: integer, client_id: integer)>
---
--- Callback invoked when client attaches to a buffer.
--- @field on_attach? elem_or_list<fun(client: vim.lsp.Client, bufnr: integer)>
--- Callback invoked after LSP "initialize", where `result` is a table of `capabilities` and
--- anything else the server may send. For example, clangd sends `init_result.offsetEncoding` if
--- `capabilities.offsetEncoding` was sent to it. You can only modify the `client.offset_encoding`
--- here before any notifications are sent.
--- @field on_init? elem_or_list<fun(client: vim.lsp.Client, init_result: lsp.InitializeResult)>
---
--- Directory where the LSP server will base its workspaceFolders, rootUri, and rootPath on initialization.
--- @field root_dir? string
---
--- Map of language server-specific settings, decided by the client. Sent to the LS if requested via
--- `workspace/configuration`. Keys are case-sensitive.
--- @field settings? lsp.LSPObject
---
--- Passed directly to the language server in the initialize request. Invalid/empty values will
--- (default: "off")
--- @field trace? 'off'|'messages'|'verbose'
---
--- A table with flags for the client. The current (experimental) flags are:
--- @field flags? vim.lsp.Client.Flags
--- List of workspace folders passed to the language server. For backwards compatibility rootUri and
--- rootPath are derived from the first workspace folder in this list. Can be `null` if the client
--- supports workspace folders but none are configured. See `workspaceFolders` in LSP spec.
--- @field workspace_folders? lsp.WorkspaceFolder[]
---
--- Directory where the LSP server will base its workspaceFolders, rootUri, and rootPath on initialization.
--- @field root_dir? string
--- Server requires a workspace (no "single file" support). Note: Without
--- a workspace, cross-file features (navigation, hover) may or may not work depending on the
--- language server, even if the server doesn't require a workspace.
--- (default: `false`)
--- @field workspace_required? boolean
--- @class vim.lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}>
--- @field pending table<lsp.ProgressToken,lsp.LSPAny>
--- @class vim.lsp.Client
---
--- @field attached_buffers table<integer,true>
---
--- Capabilities provided by the client (editor or tool), at startup.
--- @field capabilities lsp.ClientCapabilities
---
--- Client commands. See [vim.lsp.ClientConfig].
--- @field commands table<string,fun(command: lsp.Command, ctx: table)>
---
--- Copy of the config passed to |vim.lsp.start()|.
--- @field config vim.lsp.ClientConfig
---
--- Capabilities provided at runtime (after startup).
--- @field dynamic_capabilities lsp.DynamicCapabilities
---
--- A table with flags for the client. The current (experimental) flags are:
--- @field flags vim.lsp.Client.Flags
---
--- See [vim.lsp.ClientConfig].
--- @field get_language_id fun(bufnr: integer, filetype: string): string
---
--- See [vim.lsp.ClientConfig].
--- @field handlers table<string,lsp.Handler>
---
--- The id allocated to the client.
--- @field id integer
---
--- If a name is specified on creation, that will be used. Otherwise it is just
--- the client id. This is used for logs and messages.
--- @field initialized true?
---
--- See [vim.lsp.ClientConfig].
--- @field name string
---
--- RPC client object, for low level interaction with the client.
--- See |vim.lsp.rpc.start()|.
--- @field rpc vim.lsp.rpc.PublicClient
---
--- Called "position encoding" in LSP spec,
--- the encoding used for communicating with the server.
--- You can modify this in the `config`'s `on_init` method
--- before text is sent to the server.
--- See [vim.lsp.ClientConfig].
--- @field offset_encoding string
---
--- The handlers used by the client as described in |lsp-handler|.
--- @field handlers table<string,lsp.Handler>
--- A ring buffer (|vim.ringbuf()|) containing progress messages
--- sent by the server.
--- @field progress vim.lsp.Client.Progress
---
--- The current pending requests in flight to the server. Entries are key-value
--- pairs with the key being the request id while the value is a table with
@@ -166,34 +189,25 @@ local validate = vim.validate
--- are received from the server.
--- @field requests table<integer,{ type: string, bufnr: integer, method: string}?>
---
--- copy of the table that was passed by the user
--- to |vim.lsp.start()|.
--- @field config vim.lsp.ClientConfig
---
--- Response from the server sent on `initialize` describing the server's
--- capabilities.
--- @field server_capabilities lsp.ServerCapabilities?
---
--- Response from the server sent on `initialize` describing information about
--- the server.
--- @field server_info lsp.ServerInfo?
---
--- A ring buffer (|vim.ringbuf()|) containing progress messages
--- sent by the server.
--- @field progress vim.lsp.Client.Progress
---
--- @field initialized true?
---
--- The workspace folders configured in the client when the server starts.
--- This property is only available if the client supports workspace folders.
--- It can be `null` if the client supports workspace folders but none are
--- configured.
--- @field workspace_folders lsp.WorkspaceFolder[]?
--- See [vim.lsp.ClientConfig].
--- @field root_dir string?
---
--- @field attached_buffers table<integer,true>
--- RPC client object, for low level interaction with the client.
--- See |vim.lsp.rpc.start()|.
--- @field rpc vim.lsp.rpc.PublicClient
---
--- Response from the server sent on `initialize` describing the server's capabilities.
--- @field server_capabilities lsp.ServerCapabilities?
---
--- Response from the server sent on `initialize` describing server information (e.g. version).
--- @field server_info lsp.ServerInfo?
---
--- See [vim.lsp.ClientConfig].
--- @field settings lsp.LSPObject
---
--- See [vim.lsp.ClientConfig].
--- @field workspace_folders lsp.WorkspaceFolder[]?
---
--- @field private _log_prefix string
---
--- Track this so that we can escalate automatically if we've already tried a
--- graceful shutdown
@@ -203,26 +217,8 @@ local validate = vim.validate
--- trace = "off" | "messages" | "verbose";
--- @field private _trace 'off'|'messages'|'verbose'
---
--- Table of command name to function which is called if any LSP action
--- (code action, code lenses, ...) triggers the command.
--- Client commands take precedence over the global command registry.
--- @field commands table<string,fun(command: lsp.Command, ctx: table)>
---
--- Map with language server specific settings. These are returned to the
--- language server if requested via `workspace/configuration`. Keys are
--- case-sensitive.
--- @field settings lsp.LSPObject
---
--- A table with flags for the client. The current (experimental) flags are:
--- @field flags vim.lsp.Client.Flags
---
--- @field get_language_id fun(bufnr: integer, filetype: string): string
---
--- The capabilities provided by the client (editor or tool)
--- @field capabilities lsp.ClientCapabilities
--- @field private registrations table<string,lsp.Registration[]>
--- @field dynamic_capabilities lsp.DynamicCapabilities
---
--- @field private _log_prefix string
--- @field private _before_init_cb? vim.lsp.client.before_init_cb
--- @field private _on_attach_cbs vim.lsp.client.on_attach_cb[]
--- @field private _on_init_cbs vim.lsp.client.on_init_cb[]
@@ -392,6 +388,7 @@ function Client.create(config)
capabilities = config.capabilities,
workspace_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir),
root_dir = config.root_dir,
_is_stopping = false,
_before_init_cb = config.before_init,
_on_init_cbs = vim._ensure_list(config.on_init),
_on_exit_cbs = vim._ensure_list(config.on_exit),
@@ -458,7 +455,7 @@ function Client.create(config)
-- Start the RPC client.
local config_cmd = config.cmd
if type(config_cmd) == 'function' then
self.rpc = config_cmd(dispatchers)
self.rpc = config_cmd(dispatchers, config)
else
self.rpc = lsp.rpc.start(config_cmd, dispatchers, {
cwd = config.cmd_cwd,
@@ -675,6 +672,12 @@ function Client:request(method, params, handler, bufnr)
bufnr = vim._resolve_bufnr(bufnr)
local version = lsp.util.buf_versions[bufnr]
log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr)
-- Detect if request resolved synchronously (only possible with in-process servers).
local already_responded = false
local request_registered = false
-- NOTE: rpc.request might call an in-process (Lua) server, thus may be synchronous.
local success, request_id = self.rpc.request(method, params, function(err, result)
handler(err, result, {
method = method,
@@ -685,11 +688,15 @@ function Client:request(method, params, handler, bufnr)
})
end, function(request_id)
-- Called when the server sends a response to the request (including cancelled acknowledgment).
self:_process_request(request_id, 'complete')
if request_registered then
self:_process_request(request_id, 'complete')
end
already_responded = true
end)
if success and request_id then
if success and request_id and not already_responded then
self:_process_request(request_id, 'pending', bufnr, method)
request_registered = true
end
return success, request_id
@@ -799,12 +806,13 @@ end
---
--- @param force? boolean
function Client:stop(force)
local rpc = self.rpc
if rpc.is_closing() then
if self:is_stopped() then
return
end
self._is_stopping = true
local rpc = self.rpc
vim.lsp._watchfiles.cancel(self.id)
if force or not self.initialized or self._graceful_shutdown_failed then
@@ -930,7 +938,7 @@ end
--- @return boolean # true if client is stopped or in the process of being
--- stopped; false otherwise
function Client:is_stopped()
return self.rpc.is_closing()
return self.rpc.is_closing() or self._is_stopping
end
--- Execute a lsp command, either via client command function (if available)

View File

@@ -370,7 +370,7 @@ end
local function adjust_start_col(lnum, line, items, encoding)
local min_start_char = nil
for _, item in pairs(items) do
if item.textEdit and item.textEdit.range.start.line == lnum then
if item.textEdit and item.textEdit.range and item.textEdit.range.start.line == lnum then
if min_start_char and min_start_char ~= item.textEdit.range.start.character then
return nil
end
@@ -506,14 +506,19 @@ local function trigger(bufnr, clients, ctx)
local matches = {}
local server_start_boundary --- @type integer?
for client_id, response in pairs(responses) do
local client = lsp.get_client_by_id(client_id)
if response.err then
vim.notify_once(response.err.message, vim.log.levels.WARN)
local msg = ('%s: %s %s'):format(
client and client.name or 'UNKNOWN',
response.err.code or 'NO_CODE',
response.err.message
)
vim.notify_once(msg, vim.log.levels.WARN)
end
local result = response.result
if result then
Context.isIncomplete = Context.isIncomplete or result.isIncomplete
local client = lsp.get_client_by_id(client_id)
local encoding = client and client.offset_encoding or 'utf-16'
local client_matches
client_matches, server_start_boundary = M._convert_results(

View File

@@ -93,12 +93,16 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
message = diagnostic.message.value
end
local line = buf_lines and buf_lines[start.line + 1] or ''
local end_line = line
if _end.line > start.line then
end_line = buf_lines and buf_lines[_end.line + 1] or ''
end
--- @type vim.Diagnostic
return {
lnum = start.line,
col = vim.str_byteindex(line, position_encoding, start.character, false),
end_lnum = _end.line,
end_col = vim.str_byteindex(line, position_encoding, _end.character, false),
end_col = vim.str_byteindex(end_line, position_encoding, _end.character, false),
severity = severity_lsp_to_vim(diagnostic.severity),
message = message,
source = diagnostic.source,

View File

@@ -111,8 +111,8 @@ local function check_watcher()
watchfunc_name = 'libuv-watch'
elseif watchfunc == vim._watch.watchdirs then
watchfunc_name = 'libuv-watchdirs'
elseif watchfunc == vim._watch.inotifywait then
watchfunc_name = 'inotifywait'
elseif watchfunc == vim._watch.inotify then
watchfunc_name = 'inotify'
else
local nm = debug.getinfo(watchfunc, 'S').source
watchfunc_name = string.format('Custom (%s)', nm)
@@ -187,26 +187,32 @@ local function check_enabled_configs()
local config = vim.lsp.config[name]
local text = {} --- @type string[]
text[#text + 1] = ('%s:'):format(name)
for k, v in
vim.spairs(config --[[@as table<string,any>]])
do
local v_str --- @type string?
if k == 'name' then
v_str = nil
elseif k == 'filetypes' or k == 'root_markers' then
v_str = table.concat(v, ', ')
elseif type(v) == 'function' then
v_str = func_tostring(v)
else
v_str = vim.inspect(v, { newline = '\n ' })
end
if not config then
report_warn(
("'%s' config not found. Ensure that vim.lsp.config('%s') was called."):format(name, name)
)
else
for k, v in
vim.spairs(config --[[@as table<string,any>]])
do
local v_str --- @type string?
if k == 'name' then
v_str = nil
elseif k == 'filetypes' then
v_str = table.concat(v, ', ')
elseif type(v) == 'function' then
v_str = func_tostring(v)
else
v_str = vim.inspect(v, { newline = '\n ' })
end
if k == 'cmd' and type(v) == 'table' and vim.fn.executable(v[1]) == 0 then
report_warn(("'%s' is not executable. Configuration will not be used."):format(v[1]))
end
if k == 'cmd' and type(v) == 'table' and vim.fn.executable(v[1]) == 0 then
report_warn(("'%s' is not executable. Configuration will not be used."):format(v[1]))
end
if v_str then
text[#text + 1] = ('- %s: %s'):format(k, v_str)
if v_str then
text[#text + 1] = ('- %s: %s'):format(k, v_str)
end
end
end
text[#text + 1] = ''

View File

@@ -94,10 +94,10 @@ function M.on_refresh(err, _, ctx)
for _, bufnr in ipairs(vim.lsp.get_buffers_by_client_id(ctx.client_id)) do
for _, winid in ipairs(api.nvim_list_wins()) do
if api.nvim_win_get_buf(winid) == bufnr then
if bufstates[bufnr] then
if bufstates[bufnr] and bufstates[bufnr].enabled then
bufstates[bufnr].applied = {}
util._refresh(ms.textDocument_inlayHint, { bufnr = bufnr })
end
util._refresh(ms.textDocument_inlayHint, { bufnr = bufnr })
end
end
end

View File

@@ -1,4 +1,25 @@
-- Logger for language client plugin.
--- @brief
--- The `vim.lsp.log` module provides logging for the Nvim LSP client.
---
--- When debugging language servers, it is helpful to enable extra-verbose logging of the LSP client
--- RPC events. Example:
--- ```lua
--- vim.lsp.set_log_level 'trace'
--- require('vim.lsp.log').set_format_func(vim.inspect)
--- ```
---
--- Then try to run the language server, and open the log with:
--- ```vim
--- :lua vim.cmd('tabnew ' .. vim.lsp.get_log_path())
--- ```
---
--- (Or use `:LspLog` if you have nvim-lspconfig installed.)
---
--- Note:
--- - Remember to DISABLE verbose logging ("debug" or "trace" level), else you may encounter
--- performance issues.
--- - "ERROR" messages containing "stderr" only indicate that the log was sent to stderr. Many
--- servers send harmless messages via stderr.
local log = {}

View File

@@ -162,14 +162,13 @@ local constants = {
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
-- Defined by the protocol.
RequestCancelled = -32800,
ContentModified = -32801,
ServerCancelled = -32802,
RequestFailed = -32803,
},
-- Describes the content type that a client supports in various
@@ -329,6 +328,7 @@ end
--- capabilities.
--- @return lsp.ClientCapabilities
function protocol.make_client_capabilities()
---@type lsp.ClientCapabilities
return {
general = {
positionEncodings = {
@@ -340,6 +340,9 @@ function protocol.make_client_capabilities()
textDocument = {
diagnostic = {
dynamicRegistration = false,
tagSupport = {
valueSet = get_value_set(constants.DiagnosticTag),
},
},
inlayHint = {
dynamicRegistration = true,
@@ -436,6 +439,9 @@ function protocol.make_client_capabilities()
foldingRange = {
dynamicRegistration = false,
lineFoldingOnly = true,
foldingRangeKind = {
valueSet = { 'comment', 'imports', 'region' },
},
foldingRange = {
collapsedText = true,
},

View File

@@ -24,6 +24,7 @@ local border_size = {
rounded = { 2, 2 },
solid = { 2, 2 },
shadow = { 1, 1 },
bold = { 2, 2 },
}
--- Check the border given by opts or the default border for the additional
@@ -744,6 +745,10 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers
if type(doc) == 'string' then
signature.documentation = { kind = 'plaintext', value = doc }
end
-- Add delimiter if there is documentation to display
if signature.documentation.value ~= '' then
contents[#contents + 1] = '---'
end
M.convert_input_to_markdown_lines(signature.documentation, contents)
end
if signature.parameters and #signature.parameters > 0 then
@@ -860,7 +865,7 @@ function M.make_floating_popup_options(width, height, opts)
col = 1
end
local title = (opts.border and opts.title) and opts.title or nil
local title = ((opts.border or vim.o.winborder ~= '') and opts.title) and opts.title or nil
local title_pos --- @type 'left'|'center'|'right'?
if title then
@@ -1138,10 +1143,8 @@ function M.stylize_markdown(bufnr, contents, opts)
-- Clean up
contents = vim.split(table.concat(contents, '\n'), '\n', { trimempty = true })
local stripped = {}
local stripped = {} --- @type string[]
local highlights = {} --- @type {ft:string,start:integer,finish:integer}[]
-- keep track of lnums that contain markdown
local markdown_lines = {} --- @type table<integer,boolean>
local i = 1
while i <= #contents do
@@ -1156,7 +1159,7 @@ function M.stylize_markdown(bufnr, contents, opts)
i = i + 1
break
end
table.insert(stripped, line)
stripped[#stripped + 1] = line
i = i + 1
end
table.insert(highlights, {
@@ -1166,30 +1169,23 @@ function M.stylize_markdown(bufnr, contents, opts)
})
-- add a separator, but not on the last line
if opts.separator and i < #contents then
table.insert(stripped, '---')
markdown_lines[#stripped] = true
stripped[#stripped + 1] = '---'
end
else
-- strip any empty lines or separators prior to this separator in actual markdown
if line:match('^---+$') then
while
markdown_lines[#stripped]
stripped[#stripped]
and (stripped[#stripped]:match('^%s*$') or stripped[#stripped]:match('^---+$'))
do
markdown_lines[#stripped] = false
table.remove(stripped, #stripped)
stripped[#stripped] = nil
end
end
-- add the line if its not an empty line following a separator
if
not (
line:match('^%s*$')
and markdown_lines[#stripped]
and stripped[#stripped]:match('^---+$')
)
not (line:match('^%s*$') and stripped[#stripped] and stripped[#stripped]:match('^---+$'))
then
table.insert(stripped, line)
markdown_lines[#stripped] = true
stripped[#stripped + 1] = line
end
i = i + 1
end
@@ -1220,7 +1216,7 @@ function M.stylize_markdown(bufnr, contents, opts)
local sep_line = string.rep('', math.min(width, opts.wrap_at or width))
for l in pairs(markdown_lines) do
for l in ipairs(stripped) do
if stripped[l]:match('^---+$') then
stripped[l] = sep_line
end
@@ -1348,26 +1344,34 @@ end
---
---@param events table list of events
---@param winnr integer window id of preview window
---@param bufnrs table list of buffers where the preview window will remain visible
---@param floating_bufnr integer floating preview buffer
---@param bufnr integer buffer that opened the floating preview buffer
---@see autocmd-events
local function close_preview_autocmd(events, winnr, bufnrs)
local function close_preview_autocmd(events, winnr, floating_bufnr, bufnr)
local augroup = api.nvim_create_augroup('nvim.preview_window_' .. winnr, {
clear = true,
})
-- close the preview window when entered a buffer that is not
-- the floating window buffer or the buffer that spawned it
api.nvim_create_autocmd('BufEnter', {
api.nvim_create_autocmd('BufLeave', {
group = augroup,
buffer = bufnr,
callback = function()
close_preview_window(winnr, bufnrs)
vim.schedule(function()
-- When jumping to the quickfix window from the preview window,
-- do not close the preview window.
if api.nvim_get_option_value('filetype', { buf = 0 }) ~= 'qf' then
close_preview_window(winnr, { floating_bufnr, bufnr })
end
end)
end,
})
if #events > 0 then
api.nvim_create_autocmd(events, {
group = augroup,
buffer = bufnrs[2],
buffer = bufnr,
callback = function()
close_preview_window(winnr)
end,
@@ -1614,7 +1618,7 @@ function M.open_floating_preview(contents, syntax, opts)
'<cmd>bdelete<cr>',
{ silent = true, noremap = true, nowait = true }
)
close_preview_autocmd(opts.close_events, floating_winnr, { floating_bufnr, bufnr })
close_preview_autocmd(opts.close_events, floating_winnr, floating_bufnr, bufnr)
-- save focus_id
if opts.focus_id then
@@ -1801,7 +1805,7 @@ function M.symbols_to_items(symbols, bufnr, position_encoding)
'symbols_to_items must be called with valid position encoding',
vim.log.levels.WARN
)
position_encoding = vim.lsp.get_clients({ bufnr = 0 })[1].offset_encoding
position_encoding = vim.lsp.get_clients({ bufnr = bufnr })[1].offset_encoding
end
local items = {} --- @type vim.quickfix.entry[]

View File

@@ -107,9 +107,22 @@ local function provider_disabled(provider)
return false
end
--- Checks the hygiene of a `g:loaded_xx_provider` variable.
local function check_loaded_var(var)
if vim.g[var] == 1 then
health.error(('`g:%s=1` may have been set by mistake.'):format(var), {
('Remove `vim.g.%s=1` from your config.'):format(var),
'To disable the provider, set this to 0, not 1.',
'If you want to enable the provider but skip automatic detection, set the respective `g:…_host_prog` var. See :help provider',
})
end
end
local function clipboard()
health.start('Clipboard (optional)')
check_loaded_var('loaded_clipboard_provider')
if
os.getenv('TMUX')
and vim.fn.executable('tmux') == 1
@@ -144,6 +157,8 @@ end
local function node()
health.start('Node.js provider (optional)')
check_loaded_var('loaded_node_provider')
if provider_disabled('node') then
return
end
@@ -247,6 +262,8 @@ end
local function perl()
health.start('Perl provider (optional)')
check_loaded_var('loaded_perl_provider')
if provider_disabled('perl') then
return
end
@@ -256,7 +273,7 @@ local function perl()
if not perl_exec then
health.warn(assert(perl_warnings), {
'See :help provider-perl for more information.',
'You may disable this provider (and warning) by adding `let g:loaded_perl_provider = 0` to your init.vim',
'You can disable this provider (and warning) by adding `let g:loaded_perl_provider = 0` to your init.vim',
})
health.warn('No usable perl executable found')
return
@@ -547,7 +564,7 @@ local function version_info(python)
local nvim_path_base = vim.fn.fnamemodify(nvim_path, [[:~:h]])
local version_status = 'unknown; ' .. nvim_path_base
if is_bad_response(nvim_version) and is_bad_response(pypi_version) then
if not is_bad_response(nvim_version) and not is_bad_response(pypi_version) then
if vim.version.lt(nvim_version, pypi_version) then
version_status = 'outdated; from ' .. nvim_path_base
else
@@ -561,6 +578,8 @@ end
local function python()
health.start('Python 3 provider (optional)')
check_loaded_var('loaded_python3_provider')
local python_exe = ''
local virtual_env = os.getenv('VIRTUAL_ENV')
local venv = virtual_env and vim.fn.resolve(virtual_env) or ''
@@ -595,7 +614,7 @@ local function python()
if pythonx_warnings then
health.warn(pythonx_warnings, {
'See :help provider-python for more information.',
'You may disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim',
'You can disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim',
})
elseif pyname and pyname ~= '' and python_exe == '' then
if not vim.g[host_prog_var] then
@@ -705,10 +724,9 @@ local function python()
local message = 'Detected pip upgrade failure: Python executable can import "pynvim" but not "neovim": '
.. pynvim_exe
local advice = {
'Use that Python version to reinstall "pynvim" and optionally "neovim".',
'Use that Python version to uninstall any "pynvim" or "neovim", e.g.:',
pynvim_exe .. ' -m pip uninstall pynvim neovim',
pynvim_exe .. ' -m pip install pynvim',
pynvim_exe .. ' -m pip install neovim # only if needed by third-party software',
'Then see :help provider-python for "pynvim" installation steps.',
}
health.error(message, advice)
end
@@ -734,7 +752,7 @@ local function python()
if is_bad_response(current) then
health.error(
'pynvim is not installed.\nError: ' .. current,
'Run in shell: ' .. python_exe .. ' -m pip install pynvim'
'See :help provider-python for "pynvim" installation steps.'
)
end
@@ -840,6 +858,8 @@ end
local function ruby()
health.start('Ruby provider (optional)')
check_loaded_var('loaded_ruby_provider')
if provider_disabled('ruby') then
return
end
@@ -860,7 +880,7 @@ local function ruby()
'Run `gem environment` to ensure the gem bin directory is in $PATH.',
'If you are using rvm/rbenv/chruby, try "rehashing".',
'See :help g:ruby_host_prog for non-standard gem installations.',
'You may disable this provider (and warning) by adding `let g:loaded_ruby_provider = 0` to your init.vim',
'You can disable this provider (and warning) by adding `let g:loaded_ruby_provider = 0` to your init.vim',
})
return
end

View File

@@ -1,5 +1,5 @@
local M = {}
local min_version = '3.7'
local min_version = '3.9'
local s_err ---@type string?
local s_host ---@type string?
@@ -83,6 +83,10 @@ function M.detect_by_module(module)
return vim.fn.exepath(vim.fn.expand(python_exe, true)), nil
end
if vim.fn.executable('pynvim-python') == 1 then
return 'pynvim-python'
end
local errors = {}
for _, exe in ipairs(python_candidates) do
local error = check_for_module(exe, module)

View File

@@ -21,6 +21,50 @@ local function read_trust()
return trust
end
--- If {fullpath} is a file, read the contents of {fullpath} (or the contents of {bufnr}
--- if given) and returns the contents and a hash of the contents.
---
--- If {fullpath} is a directory, then nothing is read from the filesystem, and
--- `contents = true` and `hash = "directory"` is returned instead.
---
---@param fullpath (string) Path to a file or directory to read.
---@param bufnr (number?) The number of the buffer.
---@return string|boolean? contents the contents of the file, or true if it's a directory
---@return string? hash the hash of the contents, or "directory" if it's a directory
local function compute_hash(fullpath, bufnr)
local contents ---@type string|boolean?
local hash ---@type string
if vim.fn.isdirectory(fullpath) == 1 then
return true, 'directory'
end
if bufnr then
local newline = vim.bo[bufnr].fileformat == 'unix' and '\n' or '\r\n'
contents =
table.concat(vim.api.nvim_buf_get_lines(bufnr --[[@as integer]], 0, -1, false), newline)
if vim.bo[bufnr].endofline then
contents = contents .. newline
end
else
do
local f = io.open(fullpath, 'r')
if not f then
return nil, nil
end
contents = f:read('*a')
f:close()
end
if not contents then
return nil, nil
end
end
hash = vim.fn.sha256(contents)
return contents, hash
end
--- Writes provided {trust} table to trust database at
--- $XDG_STATE_HOME/nvim/trust.
---
@@ -37,17 +81,22 @@ local function write_trust(trust)
f:close()
end
--- Attempt to read the file at {path} prompting the user if the file should be
--- trusted. The user's choice is persisted in a trust database at
--- If {path} is a file: attempt to read the file, prompting the user if the file should be
--- trusted.
---
--- If {path} is a directory: return true if the directory is trusted (non-recursive), prompting
--- the user as necessary.
---
--- The user's choice is persisted in a trust database at
--- $XDG_STATE_HOME/nvim/trust.
---
---@since 11
---@see |:trust|
---
---@param path (string) Path to a file to read.
---@param path (string) Path to a file or directory to read.
---
---@return (string|nil) The contents of the given file if it exists and is
--- trusted, or nil otherwise.
---@return (boolean|string|nil) If {path} is not trusted or does not exist, returns `nil`. Otherwise,
--- returns the contents of {path} if it is a file, or true if {path} is a directory.
function M.read(path)
vim.validate('path', path, 'string')
local fullpath = vim.uv.fs_realpath(vim.fs.normalize(path))
@@ -62,26 +111,25 @@ function M.read(path)
return nil
end
local contents ---@type string?
do
local f = io.open(fullpath, 'r')
if not f then
return nil
end
contents = f:read('*a')
f:close()
local contents, hash = compute_hash(fullpath, nil)
if not contents then
return nil
end
local hash = vim.fn.sha256(contents)
if trust[fullpath] == hash then
-- File already exists in trust database
return contents
end
local dir_msg = ''
if hash == 'directory' then
dir_msg = ' DIRECTORY trust is decided only by its name, not its contents.'
end
-- File either does not exist in trust database or the hash does not match
local ok, result = pcall(
vim.fn.confirm,
string.format('%s is not trusted.', fullpath),
string.format('%s is not trusted.%s', fullpath, dir_msg),
'&ignore\n&view\n&deny\n&allow',
1
)
@@ -169,13 +217,10 @@ function M.trust(opts)
local trust = read_trust()
if action == 'allow' then
local newline = vim.bo[bufnr].fileformat == 'unix' and '\n' or '\r\n'
local contents =
table.concat(vim.api.nvim_buf_get_lines(bufnr --[[@as integer]], 0, -1, false), newline)
if vim.bo[bufnr].endofline then
contents = contents .. newline
local contents, hash = compute_hash(fullpath, bufnr)
if not contents then
return false, string.format('could not read path: %s', fullpath)
end
local hash = vim.fn.sha256(contents)
trust[fullpath] = hash
elseif action == 'deny' then

View File

@@ -95,7 +95,7 @@ end
---
--- @see |string.gmatch()|
--- @see |vim.split()|
--- @see |lua-patterns|
--- @see |lua-pattern|s
--- @see https://www.lua.org/pil/20.2.html
--- @see http://lua-users.org/wiki/StringLibraryTutorial
---
@@ -784,7 +784,7 @@ end
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
---
---@see |lua-patterns|
---@see |lua-pattern|s
---@see https://www.lua.org/pil/20.2.html
---@param s string String to trim
---@return string String with whitespace removed from its beginning and end
@@ -793,7 +793,7 @@ function vim.trim(s)
return s:match('^%s*(.*%S)') or ''
end
--- Escapes magic chars in |lua-patterns|.
--- Escapes magic chars in |lua-pattern|s.
---
---@see https://github.com/rxi/lume
---@param s string String to escape
@@ -854,7 +854,7 @@ do
--- @param param_name string
--- @param val any
--- @param validator vim.validate.Validator
--- @param message? string
--- @param message? string "Expected" message
--- @param allow_alias? boolean Allow short type names: 'n', 's', 't', 'b', 'f', 'c'
--- @return string?
local function is_valid(param_name, val, validator, message, allow_alias)
@@ -866,18 +866,18 @@ do
end
if not is_type(val, expected) then
return string.format('%s: expected %s, got %s', param_name, expected, type(val))
return ('%s: expected %s, got %s'):format(param_name, message or expected, type(val))
end
elseif vim.is_callable(validator) then
-- Check user-provided validation function
local valid, opt_msg = validator(val)
if not valid then
local err_msg =
string.format('%s: expected %s, got %s', param_name, message or '?', tostring(val))
if opt_msg then
err_msg = string.format('%s. Info: %s', err_msg, opt_msg)
end
local err_msg = ('%s: expected %s, got %s'):format(
param_name,
message or '?',
tostring(val)
)
err_msg = opt_msg and ('%s. Info: %s'):format(err_msg, opt_msg) or err_msg
return err_msg
end

View File

@@ -119,7 +119,7 @@ local Tabstop = {}
function Tabstop.new(index, bufnr, range, choices)
local extmark_id = vim.api.nvim_buf_set_extmark(bufnr, snippet_ns, range[1], range[2], {
right_gravity = true,
end_right_gravity = true,
end_right_gravity = false,
end_line = range[3],
end_col = range[4],
hl_group = hl_group,
@@ -170,7 +170,7 @@ function Tabstop:set_right_gravity(right_gravity)
local range = self:get_range()
self.extmark_id = vim.api.nvim_buf_set_extmark(self.bufnr, snippet_ns, range[1], range[2], {
right_gravity = right_gravity,
end_right_gravity = true,
end_right_gravity = not right_gravity,
end_line = range[3],
end_col = range[4],
hl_group = hl_group,
@@ -257,10 +257,21 @@ local M = { session = nil }
local function display_choices(tabstop)
assert(tabstop.choices, 'Tabstop has no choices')
local text = tabstop:get_text()
local found_text = false
local start_col = tabstop:get_range()[2] + 1
local matches = {} --- @type table[]
for _, choice in ipairs(tabstop.choices) do
matches[#matches + 1] = { word = choice }
if choice ~= text then
matches[#matches + 1] = { word = choice }
else
found_text = true
end
end
if found_text then
table.insert(matches, 1, text)
end
vim.defer_fn(function()
@@ -278,17 +289,6 @@ local function select_tabstop(tabstop)
vim.api.nvim_feedkeys(keys, 'n', true)
end
--- NOTE: We don't use `vim.api.nvim_win_set_cursor` here because it causes the cursor to end
--- at the end of the selection instead of the start.
---
--- @param row integer
--- @param col integer
local function move_cursor_to(row, col)
local line = vim.fn.getline(row) --[[ @as string ]]
col = math.max(vim.fn.strchars(line:sub(1, col)) - 1, 0)
feedkeys(string.format('%sG0%s', row, string.rep('<Right>', col)))
end
local range = tabstop:get_range()
local mode = vim.fn.mode()
@@ -309,17 +309,21 @@ local function select_tabstop(tabstop)
vim.cmd.startinsert({ bang = range[4] >= #vim.api.nvim_get_current_line() })
end
if tabstop.choices then
vim.fn.cursor(range[3] + 1, range[4] + 1)
display_choices(tabstop)
end
else
-- Else, select the tabstop's text.
if mode ~= 'n' then
feedkeys('<Esc>')
end
move_cursor_to(range[1] + 1, range[2] + 1)
feedkeys('v')
move_cursor_to(range[3] + 1, range[4])
feedkeys('o<c-g><c-r>_')
-- Need this exact order so cannot mix regular API calls with feedkeys, which
-- are not executed immediately. Use <Cmd> to set the cursor position.
local keys = {
mode ~= 'n' and '<Esc>' or '',
('<Cmd>call cursor(%s,%s)<CR>'):format(range[1] + 1, range[2] + 1),
'v',
('<Cmd>call cursor(%s,%s)<CR>'):format(range[3] + 1, range[4]),
'o<c-g><c-r>_',
}
feedkeys(table.concat(keys))
end
end

View File

@@ -40,10 +40,6 @@ local heading_queries = {
]],
}
local function hash_tick(bufnr)
return tostring(vim.b[bufnr].changedtick)
end
---@class TS.Heading
---@field bufnr integer
---@field lnum integer
@@ -53,7 +49,7 @@ end
--- Extract headings from buffer
--- @param bufnr integer buffer to extract headings from
--- @return TS.Heading[]
local get_headings = vim.func._memoize(hash_tick, function(bufnr)
local get_headings = function(bufnr)
local lang = ts.language.get_lang(vim.bo[bufnr].filetype)
if not lang then
return {}
@@ -85,11 +81,13 @@ local get_headings = vim.func._memoize(hash_tick, function(bufnr)
end
end
return headings
end)
end
--- @param qf_height? integer height of loclist window
--- Shows an Outline (table of contents) of the current buffer, in the loclist.
function M.show_toc()
function M.show_toc(qf_height)
local bufnr = api.nvim_get_current_buf()
local bufname = api.nvim_buf_get_name(bufnr)
local headings = get_headings(bufnr)
if #headings == 0 then
return
@@ -105,7 +103,10 @@ function M.show_toc()
end
vim.fn.setloclist(0, headings, ' ')
vim.fn.setloclist(0, {}, 'a', { title = 'Table of contents' })
vim.cmd.lopen()
vim.cmd.lopen({ count = qf_height })
vim.w.qf_toc = bufname
-- reload syntax file after setting qf_toc variable
vim.bo.filetype = 'qf'
end
--- Jump to section

View File

@@ -18,11 +18,14 @@ error('Cannot require a meta file')
---@field captures string[]
---@field patterns table<integer, (integer|string)[][]>
---
---@class TSLangMetadata
---@field major_version integer
---@field minor_version integer
---@field patch_version integer
---
---@class TSLangInfo
---@field abi_version integer
---@field major_version? integer
---@field minor_version? integer
---@field patch_version? integer
---@field metadata? TSLangMetadata -- ABI 15 only
---@field state_count integer
---@field fields string[]
---@field symbols table<string,boolean>

Some files were not shown because too many files have changed in this diff Show More