Compare commits

..

175 Commits

Author SHA1 Message Date
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
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
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
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
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
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
6f8efea940 fix(tui): check for title support correctly (#34866)
(cherry picked from commit e65c0a0810)
2025-07-10 07:06:22 +00:00
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
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
2ddb5d21bb test(api): nvim_get_keymap returns correct lhsraw and lhsrawalt
(cherry picked from commit 0c973bf442)
2025-07-08 00:29:05 +00:00
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
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
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
0ab089add4 refactor(lsp): consistent usage of vim.notify #34802
(cherry picked from commit 580b8cfac7)
2025-07-06 14:40:39 +00:00
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
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
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
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
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
f0f163b267 test(editor/defaults_spec): fix flakiness (#34752)
(cherry picked from commit 17ecb2b988)
2025-07-04 03:21:14 +00:00
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
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
0f81af53b0 build: support static build #34728
(cherry picked from commit e91224bfaa)
2025-07-02 22:47:42 +00:00
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
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
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
2d3517012a Merge #34722 from justinmk/release 2025-07-01 04:34:05 -07:00
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
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
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
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
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
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
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
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
e6eb910496 Merge pull request #34668 from brianhuster/release-0.11 2025-06-26 11:32:41 -07:00
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
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
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
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
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
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
68d204462c fix(health): highlight group conflicts with help #34616
(cherry picked from commit 6942dec9b2)
2025-06-23 17:04:55 +00:00
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
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
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
4303337c77 fix(diagnostics): validate opts.signs #34565
(cherry picked from commit 3594c213a7)
2025-06-18 17:53:10 +00:00
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
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
ea8db9003b fix(lsp): use correct deprecation function (#34518)
(cherry picked from commit 00ad477419)
2025-06-17 03:14:09 +00:00
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
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
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
3d5be364bc fix(treesitter): enable a gc for wasmtime
(cherry picked from commit 5fe582448c)
2025-06-16 08:48:29 +00:00
ce292026ea docs(meta): fix incorrect bar -> backtick replacement (#34520)
(cherry picked from commit 4b2c2eb120)
2025-06-16 01:43:41 +00:00
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
a34b8e42df docs: vim.fs., diagnostics, lsp #34488
backport of #34402

(cherry picked from commit 8001276bd0)
2025-06-13 16:22:10 +00:00
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
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
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
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
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
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
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
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
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
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
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
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
718b3ffe74 docs(diagnostics): default keymaps #34400
(cherry picked from commit 2d980e37c8)
2025-06-09 16:10:53 +00:00
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
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
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
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
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
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
a03057560a test(treesitter): test node access after tree edit
(cherry picked from commit 4c333fdbb7)
2025-06-06 15:04:39 +00:00
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
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
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
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
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
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
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
25a869a097 Merge pull request #34305
backport: fix(windows): don't set window icon on SIGHUP
2025-06-04 10:20:05 -07:00
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
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
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
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
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
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
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
d519b77d2b docs: news, intro, lsp, api #34264 2025-06-01 23:16:54 +00:00
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
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
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
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
f4a79230c8 version bump 2025-05-30 11:41:44 +02:00
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
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
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
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
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
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
cefc91a82e fix(system): don't treat NUL at start as no input (#34167) 2025-05-25 09:32:45 +08:00
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
e5e69f758d docs: add missing change to getcharstr() signature (#33797)
(cherry picked from commit 862e676efc)
2025-05-03 00:51:46 +00:00
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
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
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
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
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
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
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
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
0fbc78caa1 Merge #33734 from justinmk/release
backport: LSP root_markers, docs
2025-04-30 07:21:21 -07:00
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
9dfb429e93 test: drop redundant clear() #33654
followup to #33647 after overlapping merge
2025-04-30 15:58:03 +02:00
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
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
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
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
fa292e6f61 docs: lsp, emoji, startup #33683
Co-authored-by: Maria José Solano <majosolano99@gmail.com>
2025-04-27 23:00:36 +00:00
bc66a5ff6f Merge pull request #33680 from justinmk/release 2025-04-27 15:32:22 -07:00
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
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
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
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
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
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
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
32842b0ee3 fix(health): checkhealth float opens extra empty buffer #33648
(cherry picked from commit d927a87ed6)
2025-04-26 16:37:46 +00:00
4f0e828190 version bump 2025-04-26 16:31:02 +02:00
243 changed files with 5282 additions and 2095 deletions

View File

@ -75,5 +75,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,7 +132,7 @@ jobs:
windows:
needs: setup
runs-on: windows-2019
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
@ -193,25 +193,13 @@ 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 }}
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-win64/*
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-win64/*

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,7 +141,7 @@ 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 1)
set(NVIM_VERSION_PATCH 3)
set(NVIM_VERSION_PRERELEASE "") # for package maintainers
# API level

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

@ -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

@ -268,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
@ -294,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]

View File

@ -120,6 +120,8 @@ 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 +134,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 +167,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 +203,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 +226,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
call tutor#ApplyMarks()
augroup tutor_interactive
autocmd! TextChanged,TextChangedI <buffer> call tutor#ApplyMarksOnChanged()
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' })
<

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.

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

@ -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

@ -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)
@ -251,7 +257,7 @@ FAQ *lsp-faq*
autocmd BufWritePre *.rs lua vim.lsp.buf.format({ async = false })
<
*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 +269,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 +297,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 +558,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 +578,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 +589,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 +613,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 +661,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 +690,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 +715,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 +916,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 +1055,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 +1202,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 +1229,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,40 +1293,13 @@ 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"; }
<
• {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.
• {workspace_required}? (`boolean`) (default false) Server requires a
workspace (no "single file" support).
• {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()|,
@ -1279,68 +1310,40 @@ Lua module: vim.lsp.client *lsp-client*
• 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|.
• {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'; }
<
• {commands}? (`table<string,fun(command: lsp.Command, ctx: table)>`)
Table that maps string of clientside commands
to user-defined functions. Commands passed to
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.
• {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
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`,
@ -1356,9 +1359,72 @@ Lua module: vim.lsp.client *lsp-client*
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()*
@ -1544,7 +1610,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:
@ -2507,6 +2574,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

@ -93,10 +93,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'|.

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
@ -1466,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"' } })
@ -1487,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|
@ -1779,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
@ -2022,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
@ -2115,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
@ -2370,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()*
@ -2670,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.
@ -2898,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
<
@ -2940,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:
@ -2953,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
@ -2978,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: ~
@ -3004,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
@ -3087,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
<
@ -3151,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' })
@ -3162,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: ~
@ -3171,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
@ -3737,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

@ -171,6 +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.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
@ -183,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.
@ -277,6 +283,9 @@ LSP
• 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
@ -299,6 +308,7 @@ LUA
• |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
@ -343,6 +353,8 @@ 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|
STARTUP
@ -437,6 +449,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:

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

@ -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

@ -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|.
@ -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
@ -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>
@ -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

View File

@ -439,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.
@ -1273,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 [!].
@ -1285,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.
@ -1305,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|.
@ -1323,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

@ -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

@ -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

@ -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

@ -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

@ -810,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

@ -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()' })

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

@ -1662,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' })
--- ```
---

View File

@ -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:

View File

@ -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
@ -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>
@ -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

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(('%s: "%s"'):format(pid_or_err, cmd))
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

@ -1442,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 {}

View File

@ -2605,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)
@ -286,6 +297,7 @@ end
function M.warn(msg, ...)
local input = format_report_message('⚠️ WARNING', msg, ...)
collect_output(input)
check_summary['warn'] = check_summary['warn'] + 1
end
--- Reports an error.
@ -295,6 +307,7 @@ end
function M.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),
'',
}
@ -461,6 +496,7 @@ function M._check(mods, plugin_names)
-- 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.',

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.
---
@ -429,7 +450,8 @@ lsp.config = setmetatable({ _configs = {} }, {
--- @param cfg vim.lsp.Config
__newindex = function(self, name, cfg)
validate_config_name(name)
validate('cfg', cfg, 'table')
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,
@ -439,7 +461,8 @@ lsp.config = setmetatable({ _configs = {} }, {
--- @param cfg vim.lsp.Config
__call = function(self, name, cfg)
validate_config_name(name)
validate('cfg', cfg, 'table')
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,
@ -498,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
@ -520,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' })
@ -546,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
@ -582,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`.
@ -629,7 +706,9 @@ 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
@ -1210,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
@ -363,7 +363,7 @@ function M.signature_help(config)
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
@ -440,7 +440,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,
@ -970,7 +970,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()
@ -994,7 +994,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.
@ -1211,8 +1211,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,41 +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[]
---
--- (default false) Server requires a workspace (no "single file" support).
--- @field workspace_required? boolean
--- 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
@ -73,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
@ -169,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
@ -206,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[]
@ -395,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),
@ -461,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,
@ -678,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,
@ -688,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
@ -802,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
@ -933,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

@ -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

@ -1349,10 +1349,17 @@ local function close_preview_autocmd(events, winnr, bufnrs)
-- 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 = bufnrs[1],
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, bufnrs)
end
end)
end,
})
@ -1793,7 +1800,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

@ -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

@ -83,9 +83,11 @@ local get_headings = function(bufnr)
return headings
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
@ -101,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>

View File

@ -26,6 +26,7 @@ function TSTree:root() end
---@param end_col_old integer
---@param end_row_new integer
---@param end_col_new integer
---@return TSTree
---@nodoc
function TSTree:edit(start_byte, end_byte_old, end_byte_new, start_row, start_col, end_row_old, end_col_old, end_row_new, end_col_new) end

View File

@ -451,6 +451,8 @@ function M.inspect_tree(opts)
end,
})
api.nvim_buf_set_keymap(b, 'n', 'q', '<C-w>c', { desc = 'Close language tree window' })
local group = api.nvim_create_augroup('nvim.treesitter.dev', {})
api.nvim_create_autocmd('CursorMoved', {

View File

@ -63,15 +63,16 @@ end
---@field active table<integer,vim.treesitter.highlighter>
---@field bufnr integer
---@field private orig_spelloptions string
--- A map of highlight states.
--- A map from window ID to highlight states.
--- This state is kept during rendering across each line update.
---@field private _highlight_states vim.treesitter.highlighter.State[]
---@field private _highlight_states table<integer, vim.treesitter.highlighter.State[]>
---@field private _queries table<string,vim.treesitter.highlighter.Query>
---@field _conceal_line boolean?
---@field _conceal_checked table<integer, boolean>
---@field tree vim.treesitter.LanguageTree
---@field private redraw_count integer
---@field parsing boolean true if we are parsing asynchronously
--- A map from window ID to whether we are currently parsing that window asynchronously
---@field parsing table<integer, boolean>
local TSHighlighter = {
active = {},
}
@ -131,6 +132,8 @@ function TSHighlighter.new(tree, opts)
self.redraw_count = 0
self._conceal_checked = {}
self._queries = {}
self._highlight_states = {}
self.parsing = {}
-- Queries for a specific language can be overridden by a custom
-- string query... if one is not provided it will be looked up by file.
@ -184,11 +187,12 @@ function TSHighlighter:destroy()
end
end
---@param win integer
---@param srow integer
---@param erow integer exclusive
---@private
function TSHighlighter:prepare_highlight_states(srow, erow)
self._highlight_states = {}
function TSHighlighter:prepare_highlight_states(win, srow, erow)
self._highlight_states[win] = {}
self.tree:for_each_tree(function(tstree, tree)
if not tstree then
@ -211,7 +215,7 @@ function TSHighlighter:prepare_highlight_states(srow, erow)
-- _highlight_states should be a list so that the highlights are added in the same order as
-- for_each_tree traversal. This ensures that parents' highlight don't override children's.
table.insert(self._highlight_states, {
table.insert(self._highlight_states[win], {
tstree = tstree,
next_row = 0,
iter = nil,
@ -220,10 +224,11 @@ function TSHighlighter:prepare_highlight_states(srow, erow)
end)
end
---@param win integer
---@param fn fun(state: vim.treesitter.highlighter.State)
---@package
function TSHighlighter:for_each_highlight_state(fn)
for _, state in ipairs(self._highlight_states) do
function TSHighlighter:for_each_highlight_state(win, fn)
for _, state in ipairs(self._highlight_states[win] or {}) do
fn(state)
end
end
@ -307,13 +312,14 @@ local function get_spell(capture_name)
end
---@param self vim.treesitter.highlighter
---@param win integer
---@param buf integer
---@param line integer
---@param on_spell boolean
---@param on_conceal boolean
local function on_line_impl(self, buf, line, on_spell, on_conceal)
local function on_line_impl(self, win, buf, line, on_spell, on_conceal)
self._conceal_checked[line] = true
self:for_each_highlight_state(function(state)
self:for_each_highlight_state(win, function(state)
local root_node = state.tstree:root()
local root_start_row, _, root_end_row, _ = root_node:range()
@ -380,6 +386,7 @@ local function on_line_impl(self, buf, line, on_spell, on_conceal)
api.nvim_buf_set_extmark(buf, ns, start_row, 0, {
end_line = end_row,
conceal_lines = '',
invalidate = true,
})
end
end
@ -392,23 +399,24 @@ local function on_line_impl(self, buf, line, on_spell, on_conceal)
end
---@private
---@param _win integer
---@param win integer
---@param buf integer
---@param line integer
function TSHighlighter._on_line(_, _win, buf, line, _)
function TSHighlighter._on_line(_, win, buf, line, _)
local self = TSHighlighter.active[buf]
if not self then
return
end
on_line_impl(self, buf, line, false, false)
on_line_impl(self, win, buf, line, false, false)
end
---@private
---@param win integer
---@param buf integer
---@param srow integer
---@param erow integer
function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
function TSHighlighter._on_spell_nav(_, win, buf, srow, _, erow, _)
local self = TSHighlighter.active[buf]
if not self then
return
@ -416,30 +424,31 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
-- Do not affect potentially populated highlight state. Here we just want a temporary
-- empty state so the C code can detect whether the region should be spell checked.
local highlight_states = self._highlight_states
self:prepare_highlight_states(srow, erow)
local highlight_states = self._highlight_states[win]
self:prepare_highlight_states(win, srow, erow)
for row = srow, erow do
on_line_impl(self, buf, row, true, false)
on_line_impl(self, win, buf, row, true, false)
end
self._highlight_states = highlight_states
self._highlight_states[win] = highlight_states
end
---@private
---@param win integer
---@param buf integer
---@param row integer
function TSHighlighter._on_conceal_line(_, _, buf, row)
function TSHighlighter._on_conceal_line(_, win, buf, row)
local self = TSHighlighter.active[buf]
if not self or not self._conceal_line or self._conceal_checked[row] then
return
end
-- Do not affect potentially populated highlight state.
local highlight_states = self._highlight_states
local highlight_states = self._highlight_states[win]
self.tree:parse({ row, row })
self:prepare_highlight_states(row, row)
on_line_impl(self, buf, row, false, true)
self._highlight_states = highlight_states
self:prepare_highlight_states(win, row, row)
on_line_impl(self, win, buf, row, false, true)
self._highlight_states[win] = highlight_states
end
---@private
@ -459,20 +468,38 @@ end
---@param buf integer
---@param topline integer
---@param botline integer
function TSHighlighter._on_win(_, _, buf, topline, botline)
function TSHighlighter._on_win(_, win, buf, topline, botline)
local self = TSHighlighter.active[buf]
if not self or self.parsing then
if not self then
return false
end
self.parsing = self.tree:parse({ topline, botline + 1 }, function(_, trees)
if trees and self.parsing then
self.parsing = false
api.nvim__redraw({ buf = buf, valid = false, flush = false })
end
end) == nil
self.redraw_count = self.redraw_count + 1
self:prepare_highlight_states(topline, botline)
return #self._highlight_states > 0
self.parsing[win] = self.parsing[win]
or nil
== self.tree:parse({ topline, botline + 1 }, function(_, trees)
if trees and self.parsing[win] then
self.parsing[win] = false
if api.nvim_win_is_valid(win) then
api.nvim__redraw({ win = win, valid = false, flush = false })
end
end
end)
if not self.parsing[win] then
self.redraw_count = self.redraw_count + 1
self:prepare_highlight_states(win, topline, botline)
else
self:for_each_highlight_state(win, function(state)
-- TODO(ribru17): Inefficient. Eventually all marks should be applied in on_buf, and all
-- non-folded ranges of each open window should be merged, and iterators should only be
-- created over those regions. This would also fix #31777.
--
-- Currently this is not possible because the parser discards previously parsed injection
-- trees upon parsing a different region.
state.iter = nil
state.next_row = 0
end)
end
local hl_states = self._highlight_states[win] or {}
return #hl_states > 0
end
api.nvim_set_decoration_provider(ns, {

View File

@ -956,7 +956,9 @@ function LanguageTree:_get_injection(match, metadata)
local ft = vim.filetype.match({ filename = text })
lang = ft and resolve_lang(ft)
elseif name == 'injection.content' then
ranges = get_node_ranges(node, self._source, metadata[id], include_children)
for _, range in ipairs(get_node_ranges(node, self._source, metadata[id], include_children)) do
ranges[#ranges + 1] = range
end
end
end
end
@ -1080,8 +1082,8 @@ function LanguageTree:_edit(
end_row_new,
end_col_new
)
for _, tree in pairs(self._trees) do
tree:edit(
for i, tree in pairs(self._trees) do
self._trees[i] = tree:edit(
start_byte,
end_byte_old,
end_byte_new,
@ -1268,12 +1270,13 @@ end
local function tree_contains(tree, range)
local tree_ranges = tree:included_ranges(false)
return Range.contains({
tree_ranges[1][1],
tree_ranges[1][2],
tree_ranges[#tree_ranges][3],
tree_ranges[#tree_ranges][4],
}, range)
for _, tree_range in ipairs(tree_ranges) do
if Range.contains(tree_range, range) then
return true
end
end
return false
end
--- Determines whether {range} is contained in the |LanguageTree|.

View File

@ -979,8 +979,7 @@ function Query:iter_captures(node, source, start, stop, opts)
start, stop = value_or_node_range(start, stop, node)
-- Copy the tree to ensure it is valid during the entire lifetime of the iterator
local tree = node:tree():copy()
local tree = node:tree()
local cursor = vim._create_ts_querycursor(node, self.query, start, stop, opts)
-- For faster checks that a match is not in the cache.
@ -1079,8 +1078,7 @@ function Query:iter_matches(node, source, start, stop, opts)
start, stop = value_or_node_range(start, stop, node)
-- Copy the tree to ensure it is valid during the entire lifetime of the iterator
local tree = node:tree():copy()
local tree = node:tree()
local cursor = vim._create_ts_querycursor(node, self.query, start, stop, opts)
local function iter()

View File

@ -238,8 +238,8 @@ function VersionRange:has(version)
version = setmetatable(vim.deepcopy(version, true), Version)
end
if version then
if version.prerelease ~= self.from.prerelease then
return false
if self.from == self.to then
return version == self.from
end
return version >= self.from and (self.to == nil or version < self.to)
end
@ -310,9 +310,7 @@ function M.range(spec) -- Adapted from https://github.com/folke/lazy.nvim
local from = semver --- @type vim.Version?
local to = vim.deepcopy(semver, true) --- @type vim.Version?
---@diagnostic disable: need-check-nil
if mods == '' or mods == '=' then
to.patch = to.patch + 1
elseif mods == '<' then
if mods == '<' then
from = M._version({})
elseif mods == '<=' then
from = M._version({})

View File

@ -26,6 +26,8 @@
</screenshots>
<releases>
<release date="2025-07-12" version="0.11.3"/>
<release date="2025-05-30" version="0.11.2"/>
<release date="2025-04-26" version="0.11.1"/>
<release date="2025-03-26" version="0.11.0"/>
<release date="2025-01-29" version="0.10.4"/>

View File

@ -78,7 +78,7 @@ Comment[wa]=Asspougnî des fitchîs tecses
Comment[zh_CN]=编辑文本文件
Comment[zh_TW]=編輯文字檔
TryExec=nvim
Exec=nvim "%F"
Exec=nvim %F
Terminal=true
Type=Application
Keywords=Text;editor;

View File

@ -1,3 +1,9 @@
" Tutor: New Style Tutor Plugin :h vim-tutor-mode
" Maintainer: This runtime file is looking for a new maintainer.
" Contributors: Phạm Bình An <phambinhanctb2004@gmail.com>
" Original Author: Felipe Morales <hel.sheep@gmail.com>
" Date: 2025 May 12
if exists('g:loaded_tutor_mode_plugin') || &compatible
finish
endif

View File

@ -127,6 +127,7 @@
"eval"
"sign"
"abort"
"substitute"
] @keyword
(map_statement
@ -252,6 +253,9 @@
(heredoc
(parameter) @keyword)
(script
(parameter) @keyword)
[
(marker_definition)
(endmarker)
@ -313,6 +317,9 @@
(binary_operation
"." @operator)
(lua_statement
"=" @keyword)
; Punctuation
[
"("

View File

@ -14,8 +14,8 @@ syn keyword DiagnosticError ERROR[:]
syn keyword DiagnosticWarn WARNING[:]
syn keyword DiagnosticOk OK[:]
" Note: hs=e starts higlighting on the title line (instead of the "===" line).
syn match helpSectionDelim /^======*\n.*$/hs=e
highlight helpSectionDelim gui=reverse cterm=reverse
syn match healthHeadingChar "=" conceal cchar= contained containedin=helpSectionDelim
syn match healthSectionDelim /^======*\n.*$/hs=e
highlight default healthSectionDelim gui=reverse cterm=reverse
syn match healthHeadingChar "=" conceal cchar= contained containedin=healthSectionDelim
let b:current_syntax = "checkhealth"

View File

@ -19,7 +19,7 @@ syn match qfError "error" contained
syn cluster qfType contains=qfError
" Hide file name and line number for help outline (TOC).
if has_key(w:, 'qf_toc') || get(w:, 'quickfix_title') =~# '\<TOC$'
if has_key(w:, 'qf_toc') || get(w:, 'quickfix_title') =~# '\<TOC$\|\<Table of contents\>'
setlocal conceallevel=3 concealcursor=nc
syn match Ignore "^[^|]*|[^|]*| " conceal
endif

View File

@ -1,5 +1,7 @@
# Welcome to the Neovim Tutorial
# Chapter 1
Neovim is a very powerful editor that has many commands, too many to explain in
a tutorial such as this. This tutorial is designed to describe enough of the
commands that you will be able to easily use Neovim as an all-purpose editor.
@ -464,7 +466,7 @@ Now go on to the next lesson.
# Lesson 4.1: CURSOR LOCATION AND FILE STATUS
** Type `<C-g>`{normal} to show your location in a file and the file status.
Type `G`{normal} to move to a line in the file. **
Type `{count}G`{normal} to move to line {count} in the file. **
NOTE: Read the entire lesson before executing any of these steps!!
@ -905,26 +907,7 @@ You can find help on just about any subject, by giving an argument to the
:help insert-index
:help user-manual
~~~
# Lesson 7.2: CREATE A STARTUP SCRIPT
** Enable Neovim features. **
Neovim is a very configurable editor. You can customise it any way you like.
To start using more features create an "init.vim" file.
1. Start editing the "init.vim" file.
`:call mkdir(stdpath('config'),'p')`{vim}
`:exe 'edit' stdpath('config').'/init.vim'`{vim}
2. Write the file with:
`:w`{vim}
You can add all your preferred settings to this "init.vim" file.
For more information type `:help init.vim`{vim}.
# Lesson 7.3: COMPLETION
# Lesson 7.2: COMPLETION
** Command line completion with `<C-d>`{normal} and `<Tab>`{normal}. **
@ -934,14 +917,46 @@ For more information type `:help init.vim`{vim}.
3. Press `<C-d>`{normal} and Neovim will show a list of commands beginning with "e".
4. Press `<Tab>`{normal} and Neovim will complete the command name to ":edit".
4. Press `<Tab>`{normal} and Neovim will show a menu with possible completions
(or complete the match, if the entered command is unique, e.g.
":ed`<Tab>`{normal}" will be completed to ":edit").
5. Now add a space and the start of an existing file name: `:edit FIL`{vim}
5. Use `<Tab>`{normal} or `<C-n>`{normal} to go to the next match. Or use
`<S-Tab>`{normal} or `<C-p>`{normal} to go to the previous match.
6. Press `<Tab>`{normal}. Neovim will complete the name ("FIL" -> "FILE", if it is unique).
6. Choose the entry `edit`{vim}. Now you can see that the word `edit`{vim}
have been automatically inserted to the command line.
7. Now add a space and the start of an existing file name: `:edit FIL`{vim}
8. Press `<Tab>`{normal}. Vim will show a completion menu with list of file
names that start with `FIL`
NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
# Lesson 7.3: CONFIGURING NVIM
Neovim is a very configurable editor. You can customise it any way you like. To
start using more features, create a vimrc file, which can be "init.lua" if you
want to use Lua, or "init.vim" if you want to use Vimscript. We'll use
"init.lua" in this lesson.
1. Start editing the "init.lua" file.
`:exe 'edit' stdpath('config')..'/init.lua'`{vim}
2. Copy the example configuration in Lua to your "init.lua" file.
`:read $VIMRUNTIME/example_init.lua`{vim}
3. Write the file (also creates any missing parent directories):
`:w ++p`{vim}
4. Next time you start Neovim, you can quickly open this vimrc file with:
`:e $MYVIMRC`{vim}
# Lesson 7 SUMMARY
1. Type `:help`{vim}
@ -953,13 +968,21 @@ NOTE: Completion works for many commands. It is especially useful for `:help`{vi
4. Type `:q`{vim} to close the help window
5. Create an init.vim startup script to keep your preferred settings.
5. While in command mode, press `<C-d>`{normal} to see possible completions.
Press `<Tab>`{normal} to use the completion menu and select a match.
6. While in command mode, press `<C-d>`{normal} to see possible completions.
Press `<Tab>`{normal} to use one completion.
6. Create your configuration file to save your preferred settings. You can
revisit it with `:e $MYVIMRC`{vim}.
# What's next?
Run `:help nvim-quickstart`{vim} for more information on extending Nvim.
# CONCLUSION
This concludes Chapter 1 of the Vim Tutor. Consider continuing with
[Chapter 2](@tutor:vim-02-beginner).
This was intended to give a brief overview of the Neovim editor, just enough to
allow you to use it fairly easily. It is far from complete as Neovim has
many many more commands. Consult the help often.

View File

@ -1,44 +1,44 @@
{
"expect": {
"103": "The cow jumped over the moon.",
"125": "There is some text missing from this line.",
"126": "There is some text missing from this line.",
"145": "There is some text missing from this line.",
"146": "There is some text missing from this line.",
"147": "There is also some text missing here.",
"148": "There is also some text missing here.",
"216": "There are some words that don't belong in this sentence.",
"232": "Somebody typed the end of this line twice.",
"271": -1,
"290": "This line of words is cleaned up.",
"307": "1) Roses are red,",
"308": "3) Violets are blue,",
"309": "6) Sugar is sweet",
"310": "7) And so are you.",
"311": "7) And so are you.",
"105": "The cow jumped over the moon.",
"127": "There is some text missing from this line.",
"128": "There is some text missing from this line.",
"147": "There is some text missing from this line.",
"148": "There is some text missing from this line.",
"149": "There is also some text missing here.",
"150": "There is also some text missing here.",
"218": "There are some words that don't belong in this sentence.",
"234": "Somebody typed the end of this line twice.",
"273": -1,
"292": "This line of words is cleaned up.",
"309": "1) Roses are red,",
"310": "3) Violets are blue,",
"311": "6) Sugar is sweet",
"312": "7) And so are you.",
"313": "7) And so are you.",
"333": "Fix the errors on this line and replace them with undo.",
"379": -1,
"380": -1,
"314": "7) And so are you.",
"315": "7) And so are you.",
"335": "Fix the errors on this line and replace them with undo.",
"381": -1,
"382": -1,
"398": "When this line was typed in, someone pressed some wrong keys!",
"399": "When this line was typed in, someone pressed some wrong keys!",
"419": "This line has a few words that need changing using the change operator.",
"420": "This line has a few words that need changing using the change operator.",
"440": "The end of this line needs to be corrected using the c$ command.",
"441": "The end of this line needs to be corrected using the c$ command.",
"504": -1,
"523": -1,
"546": "Usually the best time to see the flowers is in the spring.",
"741": -1,
"746": -1,
"762": "This line will allow you to practice appending text to a line.",
"763": "This line will allow you to practice appending text to a line.",
"783": "Adding 123 to 456 gives you 579.",
"784": "Adding 123 to 456 gives you 579.",
"810": "a) This is the first item.",
"811": "b) This is the second item."
"383": -1,
"384": -1,
"400": "When this line was typed in, someone pressed some wrong keys!",
"401": "When this line was typed in, someone pressed some wrong keys!",
"421": "This line has a few words that need changing using the change operator.",
"422": "This line has a few words that need changing using the change operator.",
"442": "The end of this line needs to be corrected using the c$ command.",
"443": "The end of this line needs to be corrected using the c$ command.",
"506": -1,
"525": -1,
"548": "Usually the best time to see the flowers is in the spring.",
"743": -1,
"748": -1,
"764": "This line will allow you to practice appending text to a line.",
"765": "This line will allow you to practice appending text to a line.",
"785": "Adding 123 to 456 gives you 579.",
"786": "Adding 123 to 456 gives you 579.",
"812": "a) This is the first item.",
"813": "b) This is the second item."
}
}

View File

@ -0,0 +1,194 @@
# Welcome to the Neovim Tutorial
# Chapter 2
Hic Sunt Dracones: if this is your first exposure to vim and you
intended to avail yourself of the introductory chapter, kindly type
on the command line of the Vim editor
~~~ cmd
:Tutor vim-01-beginner
~~~
Or just open the [first chapter](@tutor:vim-01-beginner) of the tutor at the link.
The approximate time required to complete this chapter is 8-10 minutes,
depending upon how much time is spent with experimentation.
# Lesson 2.1.1: THE NAMED REGISTERS
** Store two yanked words concurrently and then paste them **
1. Move the cursor to the line below marked ✓
2. Navigate to any point on the word 'Edward' and type `"ayiw`{normal}
**MNEMONIC**: *into register(") named (a) (y)ank (i)nner (w)ord*
3. Navigate forward to the word 'cookie' (`fk`{normal} or `2fc`{normal}
or `$2b`{normal} or `/co`{normal} `<ENTER>`{normal}) and type `"byiw`{normal}
4. Navigate to any point on the word 'Vince' and type `ciw<CTRL-r>a<ESC>`{normal}
**MNEMONIC**: *(c)hange (i)nner (w)ord with <contents of (r)egister> named (a)*
5. Navigate to any point on the word 'cake' and type `ciw<CTRL-r>b<ESC>`{normal}
a) Edward will henceforth be in charge of the cookie rations
b) In this capacity, Vince will have sole cake discretionary powers
NOTE: Delete also works into registers, i.e. `"sdiw`{normal} will delete
the word under the cursor into register s.
REFERENCE: [Registers](registers)
[Named Registers](quotea)
[Motion](text-objects)
[CTRL-R](i_CTRL-R)
# Lesson 2.1.2: THE EXPRESSION REGISTER
** Insert the results of calculations on the fly **
1. Move the cursor to the line below marked ✗
2. Navigate to any point on the supplied number
3. Type `ciw<CTRL-r>=`{normal}60\*60\*24 `<ENTER>`{normal}
4. On the next line, enter insert mode and add today's date with
`<CTRL-r>=`{normal}`system('date')`{vim} `<ENTER>`{normal}
NOTE: All calls to system are OS dependent, e.g. on Windows use
`system('date /t')`{vim} or `:r!date /t`{vim}
I have forgotten the exact number of seconds in a day, is it 84600?
Today's date is:
NOTE: the same can be achieved with `:pu=`{normal}`system('date')`{vim}
or, with fewer keystrokes `:r!date`{vim}
REFERENCE: [Expression Register](quote=)
# Lesson 2.1.3: THE NUMBERED REGISTERS
** Press `yy`{normal} and `dd`{normal} to witness their effect on the registers **
1. Move the cursor to the line below marked ✓
2. yank the zeroth line, then inspect registers with `:reg`{vim} `<ENTER>`{normal}
3. delete line 0. with `"cdd`{normal}, then inspect registers
(Where do you expect line 0 to be?)
4. continue deleting each successive line, inspecting `:reg`{vim} as you go
NOTE: You should notice that old full-line deletions move down the list
as new full-line deletions are added
5. Now (p)aste the following registers in order; c, 7, 4, 8, 2. i.e. `"7p`{normal}
0. This
9. wobble
8. secret
7. is
6. on
5. axis
4. a
3. war
2. message
1. tribute
NOTE: Whole line deletions (`dd`{normal}) are much longer lived in the
numbered registers than whole line yanks, or deletions involving
smaller movements
REFERENCE: [Numbered Registers](quote0)
# Lesson 2.1.4: THE BEAUTY OF MARKS
** Code monkey arithmetic avoidance **
NOTE: a common conundrum when coding is moving around large chunks of code.
The following technique helps avoid number line calculations associated
with operations like `"a147d`{normal} or `:945,1091d a`{vim} or even worse
using `i<CTRL-r>=`{normal}1091-945 `<ENTER>`{normal} first
1. Move the cursor to the line below marked ✓
2. Go to the first line of the function and mark it with `ma`{normal}
NOTE: exact position on line is NOT important!
3. Navigate to the end of the line and then the end of the code block
with `$%`{normal}
4. Delete the block into register a with `"ad'a`{normal}
**MNEMONIC**: *into register(") named (a) put the (d)eletion from the cursor to
the LINE containing mark(') (a)*
5. Paste the block between BBB and CCC `"ap`{normal}
NOTE: practice this operation multiple times to become fluent `ma$%"ad'a`{normal}
~~~ cmd
AAA
function itGotRealBigRealFast() {
if ( somethingIsTrue ) {
doIt()
}
// the taxonomy of our function has changed and it
// no longer makes alphabetical sense in its current position
// imagine hundreds of lines of code
// naively you could navigate to the start and end and record or
// remember each line number
}
BBB
CCC
~~~
NOTE: marks and registers do not share a namespace, therefore register a is
completely independent of mark a. This is not true of registers and
macros.
REFERENCE: [Marks](marks)
[Mark Motions](mark-motions) (difference between ' and \`)
# Lesson 2.1 SUMMARY
1. To store (yank, delete) text into, and retrieve (paste) from, a total of
26 registers (a-z)
2. Yank a whole word from anywhere within a word: `yiw`{normal}
3. Change a whole word from anywhere within a word: `ciw`{normal}
4. Insert text directly from registers in insert mode: `<CTRL-r>a`{normal}
5. Insert the results of simple arithmetic operations:
`<CTRL-r>=`{normal}60\*60 `<ENTER>`{normal} in insert mode
6. Insert the results of system calls:
`<CTRL-r>=`{normal}`system('ls -1')`{vim} in insert mode
7. Inspect registers with `:reg`{vim}
8. Learn the final destination of whole line deletions: `dd`{normal} in
the numbered registers, i.e. descending from register 1 - 9. Appreciate
that whole line deletions are preserved in the numbered registers longer
than any other operation
9. Learn the final destination of all yanks in the numbered registers and
how ephemeral they are
10. Place marks from command mode `m[a-zA-Z0-9]`{normal}
11. Move line-wise to a mark with `'`{normal}
# CONCLUSION
This concludes chapter two of the Vim Tutor. It is a work in progress.
This chapter was written by Paul D. Parker.
Modified for vim-tutor-mode by Restorer.

View File

@ -0,0 +1,10 @@
{
"expect": {
"36": -1,
"37": "b) In this capacity, Edward will have sole cookie discretionary powers",
"64": "I have forgotten the exact number of seconds in a day, is it 86400",
"65": -1,
"91": -1,
"138": -1
}
}

View File

@ -31,7 +31,7 @@ NOTE: 以下の練習用コマンドにはこの文章を変更するものも
また、次のようにコマンドを実行するよう求められることや、(後で詳しく説明します。)
`:help`{vim} `<Enter>`{normal}
キーシークエンスを押すこともあります。
~~~ normal
<Esc>0f<Space>d3wP$P
@ -465,8 +465,8 @@ NOTE: タイプ中の間違いはバックスペースキーを使って直す
# レッスン 4.1: 位置とファイルの情報
** ファイル内での位置とファイルの状態を表示するには `<C-g>`{normal} をタイプします。ファイ
ル内のある行に移動するには `G`{normal} をタイプします。 **
** ファイル内での位置とファイルの状態を表示するには `<C-g>`{normal} をタイプします。
ファイル内の{count}行に移動するには `{count}G`{normal} をタイプします。 **
NOTE: ステップを実行する前に、このレッスン全てに目を通しましょう!!
@ -875,7 +875,7 @@ NOTE: 1つの検索コマンドだけ大文字小文字の区別をやめたい
~~~
# レッスン 7.1: ヘルプコマンド
** Use the online help system. **
** オンラインヘルプシステムを使用する **
Neovim には広範にわたるオンラインヘルプシステムがあります。
@ -895,27 +895,7 @@ Neovim には広範にわたるオンラインヘルプシステムがありま
:help insert-index
:help user-manual
~~~
# レッスン 7.2: 起動スクリプトの作成
** Neovim の特徴を発揮する **
Neovim はとても自由度の高いエディタです。あなたの好きなようにカスタマイズするこ
とができます。より多くの機能を使いはじめるには "init.vim" ファイルを作成します。
1. "init.vim" ファイルの編集を開始します。
`:call mkdir(stdpath('config'),'p')`{vim}
`:exe 'edit' stdpath('config').'/init.vim'`{vim}
2. 以下のようにしてファイルを保存します。
`:w`{vim}
この "init.vim" ファイルへ、お好みの設定を追加することができます。
より多くの情報を得るには `:help init.vim`{vim} とタイプします。
# レッスン 7.3: 補完
# レッスン 7.2: 補完
** `<C-d>`{normal} と `<Tab>`{normal} でコマンドラインを補完する **
@ -925,14 +905,45 @@ Neovim はとても自由度の高いエディタです。あなたの好きな
3. `<C-d>`{normal} を押すと Neovim は "e" から始まるコマンドの一覧を表示します。
4. `<Tab>`{normal} とタイプすると Neoim は ":edit" というコマンド名を補完します
4. `<Tab>`{normal} を押すと、Neovim は可能な補完候補のメニューを表示します
(または、ただの一つのマッチがあるときは、補完します。
例: ":ed`<Tab>`{normal}" は":edit"に補完されます)。
5. さらに空白と、既存のファイル名の始まりを加えます: `:edit FIL`{vim}
5. 次のマッチに移動するには `<Tab>`{normal} または `<C-n>`{normal}を使用し、
前のマッチに移動するには `<S-Tab>`{normal} または `<C-p>`{normal}を使用します。
6. `<Tab>`{normal} を押すと Neovim は名前を補完します。("FIL" -> "FILE"、重複しない場合)
6. `edit`{vim} を選択すると、コマンドラインに`edit` が挿入されます。
7. さらに空白と、既存のファイル名の始まりを加えます: `:edit FIL`{vim}
8. `<Tab>`{normal}を押すと、Vim は `FIL` で始まるファイル名の候補リストを含む補完メニューを
表示します。
NOTE: 補完は多くのコマンドで動作します。特に `:help`{vim} の際に役立ちます。
# レッスン 7.3: 設定ファイルの作成
Neovim はとても自由度の高いエディタです。あなたの好きなようにカスタマイズするこ
とができます。より多くの機能を使い始めるには設定ファイルを作成します。 Lua を使
いたい場合は "init.lua" にし、Vimscript を使いたい場合は "init.vim" にします。
このレッスンでは "init.lua" を使います。
1. `"init.lua"` ファイルを編集します。
`:exe 'edit' stdpath('config')..'/init.lua'`{vim}
2. Lua の例の設定を "init.lua" にコピーします。
`:read $VIMRUNTIME/example_init.lua`{vim}
3. ファイルを書き込みます(必要に応じて親ディレクトリも作成されます):
`:w ++p`{vim}
4. 次回 Neovim を起動したときに、以下のコマンドでこの設定ファイルを開けます:
`:e $MYVIMRC`{vim}
# レッスン 7 要約
1. ヘルプウィンドウを開くには `:help`{vim} とするか `<F1>`{normal} を押す。
@ -943,11 +954,12 @@ NOTE: 補完は多くのコマンドで動作します。特に `:help`{vim} の
4. ヘルプウィンドウを閉じるには `:q`{vim} とタイプする。
5. お好みの設定を保つには init.vim 起動スクリプトを作成する。
6. : command で可能な補完を見るには `<C-d>`{normal} をタイプする。
5. コマンドラインモードで可能な補完を見るには `<C-d>`{normal} をタイプする。
補完を使用するには `<Tab>`{normal} を押す。
6. お好みの設定を保つには設定ファイルを作成する。作成した設定ファイルは
`:e $MYVIMRC`{vim} でいつでも開き直せます。
# おわりに
これにて Neovim のチュートリアルを終わります。エディタを簡単に、しかも充分に使う

View File

@ -17,15 +17,8 @@ Table of contents:
## SETTING UP *setting-up*
First, you'll need to enable "debug" mode
~~~ cmd
:let g:tutor_debug = 1
~~~
This will allow saving changes to the tutor files and will disable conceals, so
you can more easily check your changes.
After this, create a new .tutor file (we will be practicing on this very file, so you
don't need to do this now):
Create a new .tutor file (we will be practicing on this very file, so you don't
need to do this now):
~~~ cmd
:e new-tutorial.tutor
~~~

View File

@ -1,35 +1,35 @@
{
"expect": {
"63": "This is text with **important information**",
"64": "This is text with **important information**",
"71": "TODO: Document '&variable'",
"72": "TODO: Document '&variable'",
"78": "# This is a level 1 header",
"79": "# This is a level 1 header",
"80": "### This is a level 3 header",
"81": "### This is a level 3 header",
"82": "# This is a header with a label {*label*}",
"83": "# This is a header with a label {*label*}",
"108": "A link to help for the ['breakindent']('breakindent') option",
"109": "A link to help for the ['breakindent']('breakindent') option",
"123": "A link to the [Links](*links*) section",
"124": "A link to the [Links](*links*) section",
"139": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
"140": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
"157": "~~~ viml",
"158": "echom 'the value of &number is'.string(&number)",
"159": "~~~",
"161": "~~~ viml",
"162": "echom 'the value of &number is'.string(&number)",
"163": "~~~",
"188": "~~~ normal",
"189": "d2w",
"190": "~~~",
"192": "~~~ normal",
"193": "d2w",
"194": "~~~",
"206": "`d2w`{normal}",
"207": "`d2w`{normal}",
"244": -1
"56": "This is text with **important information**",
"57": "This is text with **important information**",
"64": "TODO: Document '&variable'",
"65": "TODO: Document '&variable'",
"71": "# This is a level 1 header",
"72": "# This is a level 1 header",
"73": "### This is a level 3 header",
"74": "### This is a level 3 header",
"75": "# This is a header with a label {*label*}",
"76": "# This is a header with a label {*label*}",
"101": "A link to help for the ['breakindent']('breakindent') option",
"102": "A link to help for the ['breakindent']('breakindent') option",
"116": "A link to the [Links](*links*) section",
"117": "A link to the [Links](*links*) section",
"132": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
"133": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
"150": "~~~ viml",
"151": "echom 'the value of &number is'.string(&number)",
"152": "~~~",
"154": "~~~ viml",
"155": "echom 'the value of &number is'.string(&number)",
"156": "~~~",
"181": "~~~ normal",
"182": "d2w",
"183": "~~~",
"185": "~~~ normal",
"186": "d2w",
"187": "~~~",
"199": "`d2w`{normal}",
"200": "`d2w`{normal}",
"237": -1
}
}

View File

@ -293,6 +293,10 @@ preprocess_patch() {
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/option\.h/\1\/option_vars.h/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
# Rename runtime/doc/eval.txt to runtime/doc/vimeval.txt
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/eval\.txt/\1\/vimeval.txt/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
# Rename version*.txt to news.txt
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/version[0-9]+\.txt/\1\/news.txt/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"

View File

@ -82,7 +82,7 @@
#define DEFAULT_ENCODE_INVALID_NUMBERS 0
#define DEFAULT_DECODE_INVALID_NUMBERS 1
#define DEFAULT_ENCODE_KEEP_BUFFER 1
#define DEFAULT_ENCODE_NUMBER_PRECISION 14
#define DEFAULT_ENCODE_NUMBER_PRECISION 16
#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 0
#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1

View File

@ -359,11 +359,11 @@ local function norm_text(x, special)
x = x:gsub([=[%|?(nvim_[^.()| ]+)%(?%)?%|?]=], 'vim.api.%1')
-- TODO: Remove backticks when LuaLS resolves: https://github.com/LuaLS/lua-language-server/issues/2889
-- "|foo|" => "`:help foo`"
x = x:gsub([=[|([^ ]+)|]=], '`:help %1`')
x = x:gsub([=[|([^%s|]+)|]=], '`:help %1`')
end
return (
x:gsub('|([^ ]+)|', '`%1`')
x:gsub('|([^%s|]+)|', '`%1`')
:gsub('\n*>lua', '\n\n```lua')
:gsub('\n*>vim', '\n\n```vim')
:gsub('\n+<$', '\n```')
@ -949,17 +949,17 @@ local CONFIG = {
render = render_api_keyset_meta,
},
{
path = 'runtime/doc/builtin.txt',
path = 'runtime/doc/vimfn.txt',
funcs = get_eval_meta,
render = render_eval_doc,
header = {
'*builtin.txt* Nvim',
'*vimfn.txt* Nvim',
'',
'',
'\t\t NVIM REFERENCE MANUAL',
'',
'',
'Builtin functions\t\t*vimscript-functions* *builtin-functions*',
'Vimscript functions\t*vimscript-functions* *builtin-functions* *builtin.txt*',
'',
'For functions grouped by what they are used for see |function-list|.',
'',

View File

@ -92,7 +92,7 @@ local redirects = {
-- TODO: These known invalid |links| require an update to the relevant docs.
local exclude_invalid = {
["'string'"] = 'eval.txt',
["'string'"] = 'vimeval.txt',
Query = 'treesitter.txt',
matchit = 'vim_diff.txt',
['set!'] = 'treesitter.txt',

View File

@ -742,7 +742,11 @@ endif()
target_sources(nlua0 PUBLIC ${NLUA0_SOURCES})
if(STATIC_BUILD)
target_link_options(nvim_bin PRIVATE -static-libgcc -static-libstdc++ -static)
endif()
target_link_libraries(nvim_bin PRIVATE main_lib PUBLIC libuv)
install_helper(TARGETS nvim_bin)
if(MSVC)
install(FILES $<TARGET_PDB_FILE:nvim_bin> DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
@ -975,7 +979,7 @@ add_target(doc-eval
${PROJECT_SOURCE_DIR}/src/nvim/eval.lua
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua
${NVIM_RUNTIME_DIR}/doc/builtin.txt
${NVIM_RUNTIME_DIR}/doc/vimfn.txt
)
add_custom_target(doc)

View File

@ -62,7 +62,7 @@ Object nvim_execute_lua(String code, Array args, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(7)
FUNC_API_REMOTE_ONLY
{
return nlua_exec(code, args, kRetObject, arena, err);
return nlua_exec(code, NULL, args, kRetObject, arena, err);
}
/// Gets the buffer number

View File

@ -45,6 +45,7 @@
# include "ui_events_remote.generated.h" // IWYU pragma: export
#endif
// TODO(bfredl): just make UI:s owned by their channels instead
static PMap(uint64_t) connected_uis = MAP_INIT;
static char *mpack_array_dyn16(char **buf)
@ -71,14 +72,33 @@ static void remote_ui_destroy(RemoteUI *ui)
xfree(ui);
}
void remote_ui_disconnect(uint64_t channel_id)
/// Removes the client on the given channel from the list of UIs.
///
/// @param err if non-NULL and there is no UI on the channel, set an error
/// @param send_error_exit send an "error_exit" event with 0 status first
void remote_ui_disconnect(uint64_t channel_id, Error *err, bool send_error_exit)
{
RemoteUI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui) {
if (err != NULL) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
}
return;
}
if (send_error_exit) {
MAXSIZE_TEMP_ARRAY(args, 1);
ADD_C(args, INTEGER_OBJ(0));
push_call(ui, "error_exit", args);
ui_flush_buf(ui, false);
}
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
ui_detach_impl(ui, channel_id);
Channel *chan = find_channel(channel_id);
if (chan && chan->rpc.ui == ui) {
chan->rpc.ui = NULL;
}
remote_ui_destroy(ui);
}
@ -176,6 +196,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt
ui->nevents_pos = NULL;
ui->nevents = 0;
ui->flushed_events = false;
ui->incomplete_event = false;
ui->ncalls_pos = NULL;
ui->ncalls = 0;
ui->ncells_pending = 0;
@ -192,6 +213,11 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt
current_ui = channel_id;
ui_attach_impl(ui, channel_id);
Channel *chan = find_channel(channel_id);
if (chan) {
chan->rpc.ui = ui;
}
may_trigger_vim_suspend_resume(false);
}
@ -231,12 +257,7 @@ void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error)
void nvim_ui_detach(uint64_t channel_id, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!map_has(uint64_t, &connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
}
remote_ui_disconnect(channel_id);
remote_ui_disconnect(channel_id, err, false);
}
// TODO(bfredl): use me to detach a specific ui from the server
@ -536,7 +557,7 @@ static void prepare_call(RemoteUI *ui, const char *name)
{
if (ui->packer.startptr
&& (BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE || ui->ncells_pending >= 500)) {
ui_flush_buf(ui);
ui_flush_buf(ui, false);
}
if (ui->packer.startptr == NULL) {
@ -578,7 +599,7 @@ static void push_call(RemoteUI *ui, const char *name, Array args)
static void ui_flush_callback(PackerBuffer *packer)
{
RemoteUI *ui = packer->anydata;
ui_flush_buf(ui);
ui_flush_buf(ui, true);
ui_alloc_buf(ui);
}
@ -804,7 +825,7 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
mpack_w2(&lenpos, nelem);
// We only ever set the wrap field on the final "grid_line" event for the line.
mpack_bool(buf, false);
ui_flush_buf(ui);
ui_flush_buf(ui, false);
prepare_call(ui, "grid_line");
mpack_array(buf, 5);
@ -877,11 +898,12 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
///
/// This might happen multiple times before the actual ui_flush, if the
/// total redraw size is large!
static void ui_flush_buf(RemoteUI *ui)
static void ui_flush_buf(RemoteUI *ui, bool incomplete_event)
{
if (!ui->packer.startptr || !BUF_POS(ui)) {
return;
}
ui->incomplete_event = incomplete_event;
flush_event(ui);
if (ui->nevents_pos != NULL) {
@ -912,11 +934,16 @@ void remote_ui_flush(RemoteUI *ui)
remote_ui_cursor_goto(ui, ui->cursor_row, ui->cursor_col);
}
push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
ui_flush_buf(ui);
ui_flush_buf(ui, false);
ui->flushed_events = false;
}
}
void remote_ui_flush_pending_data(RemoteUI *ui)
{
ui_flush_buf(ui, false);
}
static Array translate_contents(RemoteUI *ui, Array contents, Arena *arena)
{
Array new_contents = arena_array(arena, contents.size);

View File

@ -173,5 +173,13 @@ void msg_history_show(Array entries)
void msg_history_clear(void)
FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY;
// This UI event is currently undocumented.
// - When the server needs to intentionally exit with an exit code, and there is no
// message in server stderr for the user, this event is sent with positive `status`
// argument, to indicate that the UI should exit normally with `status`.
// - When the server has crashed or there is a message in server stderr for the user,
// this event is not sent, and the UI should make server stderr visible.
// - When :detach is used on the server, this event is sent with a zero `status`
// argument, to indicate that the UI shouldn't wait for server exit.
void error_exit(Integer status)
FUNC_API_SINCE(12);
FUNC_API_SINCE(12) FUNC_API_CLIENT_IMPL;

View File

@ -514,7 +514,7 @@ Object nvim_exec_lua(String code, Array args, Arena *arena, Error *err)
FUNC_API_REMOTE_ONLY
{
// TODO(bfredl): convert directly from msgpack to lua and then back again
return nlua_exec(code, args, kRetObject, arena, err);
return nlua_exec(code, NULL, args, kRetObject, arena, err);
}
/// Calculates the number of display cells occupied by `text`.
@ -989,10 +989,7 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
///
/// ```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' })
/// ```
///
@ -2360,6 +2357,8 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
// Redraw pending screen updates when explicitly requested or when determined
// that it is necessary to properly draw other requested components.
if (opts->flush && !cmdpreview) {
validate_cursor(curwin);
update_topline(curwin);
update_screen();
}

View File

@ -235,8 +235,9 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
win_T *wp = NULL;
tabpage_T *tp = curtab;
win_T *parent = NULL;
if (config->win != -1) {
assert(curwin != NULL);
win_T *parent = config->win == 0 ? curwin : NULL;
if (config->win > 0) {
parent = find_window_by_handle(fconfig.window, err);
if (!parent) {
// find_window_by_handle has already set the error
@ -408,8 +409,8 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
if (!parse_win_config(win, config, &fconfig, !was_split || to_split, err)) {
return;
}
win_T *parent = NULL;
if (config->win != -1) {
win_T *parent = config->win == 0 ? curwin : NULL;
if (config->win > 0) {
parent = find_window_by_handle(fconfig.window, err);
if (!parent) {
return;

View File

@ -525,7 +525,7 @@ void check_arg_idx(win_T *win)
}
}
/// ":args", ":argslocal" and ":argsglobal".
/// ":args", ":arglocal" and ":argglobal".
void ex_args(exarg_T *eap)
{
if (eap->cmdidx != CMD_args) {

View File

@ -1268,9 +1268,10 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
{
win_T *win;
bool need_append = true; // Append `aucmd_win` to the window list.
const bool same_buffer = buf == curbuf;
// Find a window that is for the new buffer
if (buf == curbuf) { // be quick when buf is curbuf
if (same_buffer) { // be quick when buf is curbuf
win = curwin;
} else {
win = NULL;
@ -1360,9 +1361,11 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
aco->new_curwin_handle = curwin->handle;
set_bufref(&aco->new_curbuf, curbuf);
// disable the Visual area, the position may be invalid in another buffer
aco->save_VIsual_active = VIsual_active;
VIsual_active = false;
if (!same_buffer) {
// disable the Visual area, position may be invalid in another buffer
VIsual_active = false;
}
}
/// Cleanup after executing autocommands for a (hidden) buffer.
@ -1635,11 +1638,12 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
// into "buf" are ignoring the event.
if (buf == curbuf && event_names[event].event <= 0) {
win_ignore = event_ignored(event, curwin->w_p_eiw);
} else if (buf != NULL && event_names[event].event <= 0) {
for (size_t i = 0; i < kv_size(buf->b_wininfo); i++) {
WinInfo *wip = kv_A(buf->b_wininfo, i);
if (wip->wi_win != NULL && wip->wi_win->w_buffer == buf) {
win_ignore = event_ignored(event, wip->wi_win->w_p_eiw);
} else if (buf != NULL && event_names[event].event <= 0 && buf->b_nwindows > 0) {
win_ignore = true;
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf && !event_ignored(event, wp->w_p_eiw)) {
win_ignore = false;
break;
}
}
}

View File

@ -480,11 +480,6 @@ static bool can_unload_buffer(buf_T *buf)
return can_unload;
}
bool buf_locked(buf_T *buf)
{
return buf->b_locked || buf->b_locked_split;
}
/// Close the link to a buffer.
///
/// @param win If not NULL, set b_last_cursor.
@ -1300,11 +1295,17 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags)
return FAIL;
}
if (action == DOBUF_GOTO
&& buf != curbuf
&& !check_can_set_curbuf_forceit((flags & DOBUF_FORCEIT) ? true : false)) {
// disallow navigating to another buffer when 'winfixbuf' is applied
return FAIL;
if (action == DOBUF_GOTO && buf != curbuf) {
if (!check_can_set_curbuf_forceit((flags & DOBUF_FORCEIT) != 0)) {
// disallow navigating to another buffer when 'winfixbuf' is applied
return FAIL;
}
if (buf->b_locked_split) {
// disallow navigating to a closing buffer, which like splitting,
// can result in more windows displaying it
emsg(_(e_cannot_switch_to_a_closing_buffer));
return FAIL;
}
}
if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) && (buf->b_flags & BF_DUMMY)) {
@ -1772,6 +1773,10 @@ void enter_buffer(buf_T *buf)
}
curbuf->b_last_used = time(NULL);
if (curbuf->terminal != NULL) {
terminal_check_size(curbuf->terminal);
}
redraw_later(curwin, UPD_NOT_VALID);
}
@ -1899,18 +1904,21 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags)
// buffer.)
buf = NULL;
if ((flags & BLN_CURBUF) && curbuf_reusable()) {
bufref_T bufref;
assert(curbuf != NULL);
buf = curbuf;
set_bufref(&bufref, buf);
// It's like this buffer is deleted. Watch out for autocommands that
// change curbuf! If that happens, allocate a new buffer anyway.
buf_freeall(buf, BFA_WIPE | BFA_DEL);
if (buf != curbuf) { // autocommands deleted the buffer!
return NULL;
}
if (aborting()) { // autocmds may abort script processing
xfree(ffname);
return NULL;
}
if (!bufref_valid(&bufref)) {
buf = NULL; // buf was deleted; allocate a new buffer
}
}
if (buf != curbuf || curbuf == NULL) {
buf = xcalloc(1, sizeof(buf_T));

View File

@ -366,7 +366,7 @@ struct file_buffer {
int b_locked; // Buffer is being closed or referenced, don't
// let autocommands wipe it out.
int b_locked_split; // Buffer is being closed, don't allow opening
// a new window with it.
// it in more windows.
int b_ro_locked; // Non-zero when the buffer can't be changed.
// Used for FileChangedRO

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