Compare commits

..

168 Commits

Author SHA1 Message Date
bfredl
a73904168a NVIM 0.11.2
This is a maintenance release, focusing on bug fixes. Some enhancements related
to vim.lsp.enable are also included.

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

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

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

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

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

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

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

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

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

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

closes: vim/vim#17373

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

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

closes: vim/vim#17360

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

closes: vim/vim#17355

5b07aff2f6

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

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

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

This was previously reported in at least two issues:

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

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

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

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

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

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

Solution:

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

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

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

closes: vim/vim#17341

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

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

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

670d0c1468

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

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

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

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

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

closes: vim/vim#17319

0077282c82

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

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

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

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

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

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

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

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

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

Therefore, I remove `g:tutor_debug`

closes: vim/vim#17299

13bea589a2

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

closes: vim/vim#17274

3704b5b58a

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

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

closes: vim/vim#17294

d4110e0695

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

closes: vim/vim#17283

270124f46a

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

related: vim/vim#17283

b4074ead5c

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

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

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

closes: vim/vim#17246

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

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

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

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

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

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

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

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

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

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

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

Fixes #24356

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

Solution:
Add the missing logic.

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

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

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

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

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

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

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

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

Solution:
Update docs for all "default mappings".

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes #33733

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

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

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

Related #33791

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

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

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

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

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

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

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

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

Also fix other bugs:

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

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

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

Solution:
Support nesting:

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

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

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

Fix #33708

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

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

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

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

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

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

Problem: Some parts of the tutor are outdated.

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

closes: vim/vim#17107

829eda7d38

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

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

* docs: provide example_init.lua #33524

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

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

(cherry picked from commit 86b34ad073)

---------

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

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

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

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

closes: vim/vim#17107

829eda7d38

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

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

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

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

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

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

Following is a list of fixes/features commits.

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

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

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

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

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

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

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

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

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

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

cf7f01252f

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

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

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

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

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

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

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

closes: vim/vim#17144

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

closes: vim/vim#17138

06fdfa11c5

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

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

cca5dea76e

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

closes: vim/vim#15639

5b9237c2e7

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

813b7a85f2

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

b8b1c8ebd4

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

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

closes: vim/vim#17129

1c2b258250

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

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

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

Solution:
Call nvim_set_current_win if necessary.

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

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

BEFORE:

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

AFTER:

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

fix #33445

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

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

Fixes #33493

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

closes: vim/vim#17118

2137710b43

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

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

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

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

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

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

(cherry picked from commit a8dd5c7e41)

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

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

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

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

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

Steps to reproduce:

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

Solution:
Handle +cmd in ex_drop().

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

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

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

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

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

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

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

Solution:
Fix the healthcheck.

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

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

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

Solution:
check nvim_buf_is_valid.

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

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

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

closes: vim/vim#17043

3e50a28a03

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

closes: vim/vim#17033

e4e4d1c381

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

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

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

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

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

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

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

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

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

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

Solution:

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

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

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

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

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

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

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

Solution:
Also define them for in visual mode.

(cherry picked from commit cb247e06f0)

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

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

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

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

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

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

Solution:
Use emoji next to each status.

(cherry picked from commit 75fe540500)

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

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

(cherry picked from commit b4906577c9)

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

Solution:
Quote the filename in the .desktop config.

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

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

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

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

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

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

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

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

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

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

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

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

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

closes: vim/vim#16987

7d8e7df551

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

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

View File

@@ -18,7 +18,6 @@ Checks: >
-bugprone-not-null-terminated-result, -bugprone-not-null-terminated-result,
-bugprone-suspicious-memory-comparison, -bugprone-suspicious-memory-comparison,
-bugprone-switch-missing-default-case, -bugprone-switch-missing-default-case,
-bugprone-tagged-union-member-count,
-cert-env33-c, -cert-env33-c,
-cert-err33-c, -cert-err33-c,
-cert-err34-c, -cert-err34-c,
@@ -64,7 +63,6 @@ Checks: >
Aliases. These are just duplicates of other warnings and should always be ignored, Aliases. These are just duplicates of other warnings and should always be ignored,
-bugprone-narrowing-conversions, -bugprone-narrowing-conversions,
-cert-arr39-c,
-cert-dcl37-c, -cert-dcl37-c,
-cert-dcl51-cpp, -cert-dcl51-cpp,
-cert-exp42-c, -cert-exp42-c,

View File

@@ -1,25 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
"format": {
"externalTool": {
"program": "stylua",
"args": [
"-",
"--stdin-filepath",
"${file}"
]
}
},
"diagnostics": {
"disable": [
"unnecessary-if"
]
},
"codeAction": {
"insertSpace": true
},
"strict": {
"typeCall": true,
"arrayIndex": true
}
}

0
.gitattributes vendored Normal file → Executable file
View File

View File

@@ -1,5 +0,0 @@
<!--
Thank you for contributing to Neovim!
If this is your first time, check out https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#pull-requests-prs
for our PR guidelines.
-->

View File

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

View File

@@ -57,7 +57,6 @@ module.exports = async ({ github, context }) => {
if (labels.includes("lsp")) { if (labels.includes("lsp")) {
reviewers.add("MariaSolOs"); reviewers.add("MariaSolOs");
reviewers.add("ribru17");
} }
if (labels.includes("netrw")) { if (labels.includes("netrw")) {
@@ -90,7 +89,6 @@ module.exports = async ({ github, context }) => {
reviewers.add("clason"); reviewers.add("clason");
reviewers.add("lewis6991"); reviewers.add("lewis6991");
reviewers.add("wookayin"); reviewers.add("wookayin");
reviewers.add("ribru17");
} }
if (labels.includes("tui")) { if (labels.includes("tui")) {

View File

@@ -11,9 +11,9 @@ jobs:
if: github.event.pull_request.merged if: github.event.pull_request.merged
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/create-github-app-token@v2 - uses: actions/create-github-app-token@v1
id: app-token id: app-token
with: with:
app-id: ${{ vars.BACKPORT_APP }} app-id: ${{ vars.BACKPORT_APP }}

View File

@@ -28,7 +28,7 @@ jobs:
test: [ubuntu-latest, macos-latest, windows-latest] test: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.test }} runs-on: ${{ matrix.test }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- run: | - run: |
cmake -S cmake.deps --preset ci -D ENABLE_WASMTIME=ON cmake -S cmake.deps --preset ci -D ENABLE_WASMTIME=ON
@@ -44,7 +44,7 @@ jobs:
CMAKE_URL: 'https://cmake.org/files/v3.16/cmake-3.16.0-Linux-x86_64.sh' CMAKE_URL: 'https://cmake.org/files/v3.16/cmake-3.16.0-Linux-x86_64.sh'
CMAKE_VERSION: '3.16.0' CMAKE_VERSION: '3.16.0'
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Install minimum required version of cmake - name: Install minimum required version of cmake
@@ -73,7 +73,7 @@ jobs:
name: Test USE_EXISTING_SRC_DIR=ON builds with no network access name: Test USE_EXISTING_SRC_DIR=ON builds with no network access
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Build bundled dependencies - name: Build bundled dependencies

View File

@@ -22,7 +22,7 @@ jobs:
security-events: write security-events: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Initialize CodeQL - name: Initialize CodeQL

View File

@@ -8,7 +8,7 @@ jobs:
scan: scan:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Download Coverity - name: Download Coverity

View File

@@ -10,7 +10,7 @@ jobs:
contents: write contents: write
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Generate docs - name: Generate docs

View File

@@ -9,7 +9,7 @@ jobs:
contents: read contents: read
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/labeler@v5 - uses: actions/labeler@v5
with: with:
configuration-path: .github/scripts/labeler_configuration.yml configuration-path: .github/scripts/labeler_configuration.yml

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event.pull_request.draft == false && !contains(github.event.pull_request.labels.*.name, 'ci:skip-news') if: github.event.pull_request.draft == false && !contains(github.event.pull_request.labels.*.name, 'ci:skip-news')
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}

View File

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

View File

@@ -55,7 +55,7 @@ jobs:
outputs: outputs:
version: ${{ steps.build.outputs.version }} version: ${{ steps.build.outputs.version }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
# Perform a full checkout #13471 # Perform a full checkout #13471
fetch-depth: 0 fetch-depth: 0
@@ -101,7 +101,7 @@ jobs:
env: env:
MACOSX_DEPLOYMENT_TARGET: 11.0 MACOSX_DEPLOYMENT_TARGET: 11.0
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
# Perform a full checkout #13471 # Perform a full checkout #13471
fetch-depth: 0 fetch-depth: 0
@@ -132,44 +132,27 @@ jobs:
windows: windows:
needs: setup needs: setup
strategy: runs-on: windows-2019
matrix:
include:
- runner: windows-2022
arch: x86_64
archive_name: nvim-win64
- runner: windows-11-arm
arch: arm64
archive_name: nvim-win-arm64
runs-on: ${{ matrix.runner }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
# Perform a full checkout #13471 # Perform a full checkout #13471
fetch-depth: 0 fetch-depth: 0
- run: .github/scripts/env.ps1 - run: .github/scripts/env.ps1
env:
BUILD_ARCH: ${{ matrix.arch }}
- name: Install Wix
run: |
Invoke-WebRequest -Uri "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip" -OutFile "wix314-binaries.zip"
Expand-Archive -Path "wix314-binaries.zip" -DestinationPath "C:/wix"
echo "C:\wix" >> $env:GITHUB_PATH
- name: Build deps - name: Build deps
run: | run: |
cmake -S cmake.deps -B .deps -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }} cmake -S cmake.deps -B .deps -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}
cmake --build .deps cmake --build .deps
- name: Build package - name: build package
run: | run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }} cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}
cmake --build build --target package cmake --build build --target package
- name: Upload artifact - uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v4
with: with:
name: nvim-win-${{ matrix.arch }} name: nvim-win64
path: | path: |
build/${{ matrix.archive_name }}.zip build/nvim-win64.msi
build/${{ matrix.archive_name }}.msi build/nvim-win64.zip
retention-days: 1 retention-days: 1
publish: publish:
@@ -183,9 +166,9 @@ jobs:
steps: steps:
# Must perform checkout first, since it deletes the target directory # Must perform checkout first, since it deletes the target directory
# before running, and would therefore delete the downloaded artifacts # before running, and would therefore delete the downloaded artifacts
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/download-artifact@v5 - uses: actions/download-artifact@v4
- name: Install dependencies - name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y gettext-base run: sudo apt-get update && sudo apt-get install -y gettext-base
@@ -210,14 +193,25 @@ jobs:
echo 'PRERELEASE=') >> $GITHUB_ENV echo 'PRERELEASE=') >> $GITHUB_ENV
gh release delete stable --yes || true gh release delete stable --yes || true
git push origin :stable || 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 - name: Publish release
env: env:
NVIM_VERSION: ${{ needs.linux.outputs.version }} NVIM_VERSION: ${{ needs.linux.outputs.version }}
NVIM_COMMIT: ${{ github.sha }}
DEBUG: api DEBUG: api
run: | run: |
envsubst < "$GITHUB_WORKSPACE/.github/workflows/notes.md" > "$RUNNER_TEMP/notes.md" 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 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-win-x86_64/* nvim-win-arm64/* 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
fi 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-win-x86_64/* nvim-win-arm64/* 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

View File

@@ -13,7 +13,7 @@ jobs:
issues: write issues: write
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/github-script@v7 - uses: actions/github-script@v7
with: with:
script: | script: |
@@ -27,7 +27,7 @@ jobs:
issues: write issues: write
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/github-script@v7 - uses: actions/github-script@v7
with: with:
script: | script: |

View File

@@ -10,7 +10,7 @@ jobs:
permissions: permissions:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: 'Request reviewers' - name: 'Request reviewers'
uses: actions/github-script@v7 uses: actions/github-script@v7
with: with:

View File

@@ -8,7 +8,7 @@ jobs:
permissions: permissions:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: 'Remove reviewers' - name: 'Remove reviewers'
uses: actions/github-script@v7 uses: actions/github-script@v7
with: with:

View File

@@ -28,17 +28,17 @@ env:
jobs: jobs:
lint: lint:
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04
timeout-minutes: 10 timeout-minutes: 10
env: env:
CC: clang CC: clang
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Install stylua - name: Install stylua
run: | run: |
wget --directory-prefix="$BIN_DIR" https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-aarch64.zip wget --directory-prefix="$BIN_DIR" https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-x86_64.zip
(cd "$BIN_DIR"; unzip stylua*.zip) (cd "$BIN_DIR"; unzip stylua*.zip)
- name: Build third-party deps - name: Build third-party deps
@@ -82,12 +82,12 @@ jobs:
run: cmake --build build --target lintc-uncrustify run: cmake --build build --target lintc-uncrustify
clang-analyzer: clang-analyzer:
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04
timeout-minutes: 20 timeout-minutes: 20
env: env:
CC: clang CC: clang
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Build third-party deps - name: Build third-party deps
run: | run: |
@@ -111,7 +111,7 @@ jobs:
{ runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON }, { runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON },
{ runner: ubuntu-24.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON }, { runner: ubuntu-24.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON },
{ runner: ubuntu-24.04, os: ubuntu, flavor: release, cc: gcc, flags: -D CMAKE_BUILD_TYPE=Release -D ENABLE_TRANSLATIONS=ON }, { runner: ubuntu-24.04, os: ubuntu, flavor: release, cc: gcc, flags: -D CMAKE_BUILD_TYPE=Release -D ENABLE_TRANSLATIONS=ON },
{ runner: ubuntu-24.04-arm, os: ubuntu, flavor: arm, cc: clang, flags: -D CMAKE_BUILD_TYPE=RelWithDebInfo }, # { runner: ubuntu-24.04-arm, os: ubuntu, flavor: arm, cc: gcc, flags: -D CMAKE_BUILD_TYPE=RelWithDebInfo },
{ runner: macos-13, os: macos, flavor: intel, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER }, { runner: macos-13, os: macos, flavor: intel, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: macos-15, os: macos, flavor: arm, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER }, { runner: macos-15, os: macos, flavor: arm, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: ubuntu-24.04, os: ubuntu, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON }, { runner: ubuntu-24.04, os: ubuntu, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON },
@@ -124,17 +124,12 @@ jobs:
build: { flavor: puc-lua } build: { flavor: puc-lua }
- test: oldtest - test: oldtest
build: { flavor: tsan } build: { flavor: tsan }
- test: unittest
build: { runner: ubuntu-24.04-arm }
- test: oldtest
build: { runner: ubuntu-24.04-arm }
runs-on: ${{ matrix.build.runner }} runs-on: ${{ matrix.build.runner }}
timeout-minutes: 45 timeout-minutes: 45
env: env:
CC: ${{ matrix.build.cc }} CC: ${{ matrix.build.cc }}
NVIM_TEST_INTEG: ${{ matrix.build.flavor == 'release' && '1' || '0' }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
with: with:
install_flags: "--test" install_flags: "--test"
@@ -206,35 +201,16 @@ jobs:
name: Show logs name: Show logs
run: cat $(find "$LOG_DIR" -type f) run: cat $(find "$LOG_DIR" -type f)
zig-build:
runs-on: ubuntu-24.04
timeout-minutes: 45
name: build using zig build (linux)
steps:
- uses: actions/checkout@v5
- uses: mlugg/setup-zig@v2
with:
version: 0.14.1
- run: sudo apt-get install -y inotify-tools
- run: zig build test_nlua0
- run: zig build nvim && ./zig-out/bin/nvim --version
- run: zig build unittest
- run: zig build functionaltest
# `zig build nvim` uses a lua script for doctags in order to support cross-compiling
# compare with the builtin generator that they match
- run: cd runtime; ../zig-out/bin/nvim -u NONE -i NONE -e --headless -c "helptags ++t doc" -c quit
- run: diff -u runtime/doc/tags zig-out/runtime/doc/tags
windows: windows:
uses: ./.github/workflows/test_windows.yml uses: ./.github/workflows/test_windows.yml
with-external-deps: with-external-deps:
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04
timeout-minutes: 10 timeout-minutes: 10
env: env:
CC: gcc CC: gcc
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Install dependencies - name: Install dependencies

View File

@@ -18,7 +18,7 @@ jobs:
matrix: matrix:
test: [functional, old] test: [functional, old]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: ./.github/actions/setup - uses: ./.github/actions/setup
- name: Build deps - name: Build deps

View File

@@ -15,11 +15,11 @@ jobs:
VERSION_BRANCH: marvim/ci-version-update VERSION_BRANCH: marvim/ci-version-update
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
repository: vim/vim repository: vim/vim
path: ${{ env.VIM_SOURCE_DIR }} path: ${{ env.VIM_SOURCE_DIR }}

3
.gitignore vendored
View File

@@ -10,8 +10,7 @@ compile_commands.json
/.idea/ /.idea/
# Build/deps dir # Build/deps dir
/.zig-cache/ /build/
/zig-out/
/.deps/ /.deps/
/tmp/ /tmp/
/.clangd/ /.clangd/

View File

@@ -49,7 +49,6 @@ exclude_files = {
'runtime/lua/vim/_meta/vimfn.lua', 'runtime/lua/vim/_meta/vimfn.lua',
'runtime/lua/vim/_meta/api.lua', 'runtime/lua/vim/_meta/api.lua',
'runtime/lua/vim/re.lua', 'runtime/lua/vim/re.lua',
'runtime/lua/uv/_meta.lua',
'runtime/lua/coxpcall.lua', 'runtime/lua/coxpcall.lua',
'src/nvim/eval.lua', 'src/nvim/eval.lua',
} }

View File

@@ -5,12 +5,13 @@
}, },
"workspace": { "workspace": {
"library": [ "library": [
"${3rd}/busted/library" "runtime/lua",
"${3rd}/busted/library",
"${3rd}/luv/library"
], ],
"ignoreDir": [ "ignoreDir": [
".deps", "test",
"build", "_vim9script.lua"
"test"
], ],
"checkThirdParty": "Disable" "checkThirdParty": "Disable"
}, },

View File

@@ -1,8 +0,0 @@
# Alternative settings for special snowflakes like: decorations_spec.lua, multigrid_spec.lua, etc.
column_width = 140
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferSingle"
call_parentheses = "Input"

View File

@@ -1,15 +1,14 @@
build/ /build/
.deps/ /.deps/
runtime/lua/coxpcall.lua /runtime/lua/coxpcall.lua
runtime/lua/uv/_meta.lua /runtime/lua/vim/_meta
runtime/lua/vim/_meta /runtime/lua/vim/re.lua
runtime/lua/vim/re.lua
# These are formatted explicitly by the "formatlua2" build task.
test/functional/ui/decorations_spec.lua test/functional/ui/decorations_spec.lua
test/functional/ui/float_spec.lua test/functional/ui/float_spec.lua
test/functional/ui/multigrid_spec.lua test/functional/ui/multigrid_spec.lua
test/functional/fixtures/lua/syntax_error.lua /test/functional/fixtures/lua/syntax_error.lua
test/functional/legacy/030_fileformats_spec.lua /test/functional/legacy/030_fileformats_spec.lua
test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua /test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua
test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua /test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
/test/functional/lua/luaeval_spec.lua

View File

@@ -165,40 +165,11 @@ https://github.com/cascent/neovim-cygwin was built on Cygwin 2.9.0. Newer `libuv
mingw32-make install mingw32-make install
``` ```
### Windows WSL
Build Ubuntu/Debian linux binary on [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) (Windows Subsystem for Linux).
```bash
# Install build prerequisites
sudo apt-get install ninja-build gettext cmake build-essential
# Build the linux binary in WSL
make CMAKE_BUILD_TYPE=RelWithDebInfo
# Install the linux binary in WSL (with `<arch>` either `x86_64` or `arm64`)
cd build && cpack -G DEB && sudo dpkg -i nvim-linux-<arch>.deb
# Verify the installation
nvim --version && which nvim # should be debug build in /usr/bin/nvim
```
**Note**: If you encounter linker errors or segfaults during the build, Windows libraries in your PATH may be interfering. Use a clean PATH to avoid conflicts:
```bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" make CMAKE_BUILD_TYPE=RelWithDebInfo
```
## Localization ## Localization
### Localization build ### Localization build
Translations are turned off by default. Enable by building Nvim with the CMake flag `ENABLE_TRANSLATIONS=ON`. A normal build will create `.mo` files in `build/src/nvim/po`.
Doing this will create `.mo` files in `build/src/nvim/po`. Example:
```
make CMAKE_EXTRA_FLAGS="-DENABLE_TRANSLATIONS=ON"
```
* If you see `msgfmt: command not found`, you need to install [`gettext`](http://en.wikipedia.org/wiki/Gettext). On most systems, the package is just called `gettext`. * If you see `msgfmt: command not found`, you need to install [`gettext`](http://en.wikipedia.org/wiki/Gettext). On most systems, the package is just called `gettext`.
@@ -252,7 +223,7 @@ rebuild:
## Third-party dependencies ## Third-party dependencies
Reference the [Debian package](https://packages.debian.org/sid/source/neovim) (or alternatively, the [Homebrew formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/n/neovim.rb)) for the precise list of dependencies/versions. Reference the [Debian package](https://packages.debian.org/sid/source/neovim) (or alternatively, the [Homebrew formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/neovim.rb)) for the precise list of dependencies/versions.
To build the bundled dependencies using CMake: To build the bundled dependencies using CMake:
@@ -288,29 +259,6 @@ cmake --build build
- Using `ninja` is strongly recommended. - 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/`). 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 git && 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: #### Debian 10 (Buster) example:
```sh ```sh
@@ -346,31 +294,31 @@ Platform-specific requirements are listed below.
### Ubuntu / Debian ### Ubuntu / Debian
```sh ```sh
sudo apt-get install ninja-build gettext cmake curl build-essential git sudo apt-get install ninja-build gettext cmake curl build-essential
``` ```
### RHEL / Fedora ### RHEL / Fedora
``` ```
sudo dnf -y install ninja-build cmake gcc make gettext curl glibc-gconv-extra git sudo dnf -y install ninja-build cmake gcc make gettext curl glibc-gconv-extra
``` ```
### openSUSE ### openSUSE
``` ```
sudo zypper install ninja cmake gcc-c++ gettext-tools curl git sudo zypper install ninja cmake gcc-c++ gettext-tools curl
``` ```
### Arch Linux ### Arch Linux
``` ```
sudo pacman -S base-devel cmake ninja curl git sudo pacman -S base-devel cmake ninja curl
``` ```
### Alpine Linux ### Alpine Linux
``` ```
apk add build-base cmake coreutils curl gettext-tiny-dev git apk add build-base cmake coreutils curl gettext-tiny-dev
``` ```
### Void Linux ### Void Linux
@@ -434,7 +382,7 @@ or a specific SHA1 like `--override-input neovim-src github:neovim/neovim/89dc8f
### FreeBSD ### FreeBSD
``` ```
sudo pkg install cmake gmake sha wget gettext curl git sudo pkg install cmake gmake sha wget gettext curl
``` ```
If you get an error regarding a `sha256sum` mismatch, where the actual SHA-256 hash is `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, then this is your issue (that's the `sha256sum` of an empty file). If you get an error regarding a `sha256sum` mismatch, where the actual SHA-256 hash is `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, then this is your issue (that's the `sha256sum` of an empty file).
@@ -442,7 +390,7 @@ If you get an error regarding a `sha256sum` mismatch, where the actual SHA-256 h
### OpenBSD ### OpenBSD
```sh ```sh
doas pkg_add gmake cmake curl gettext-tools git doas pkg_add gmake cmake curl gettext-tools
``` ```
Build can sometimes fail when using the top level `Makefile`, apparently due to some third-party component (see [#2445-comment](https://github.com/neovim/neovim/issues/2445#issuecomment-108124236)). The following instructions use CMake: Build can sometimes fail when using the top level `Makefile`, apparently due to some third-party component (see [#2445-comment](https://github.com/neovim/neovim/issues/2445#issuecomment-108124236)). The following instructions use CMake:
@@ -467,7 +415,7 @@ gmake
2. Install [Homebrew](http://brew.sh) 2. Install [Homebrew](http://brew.sh)
3. Install Neovim build dependencies: 3. Install Neovim build dependencies:
``` ```
brew install ninja cmake gettext curl git brew install ninja cmake gettext curl
``` ```
- **Note**: If you see Wget certificate errors (for older macOS versions less than 10.10): - **Note**: If you see Wget certificate errors (for older macOS versions less than 10.10):
```sh ```sh
@@ -485,7 +433,7 @@ gmake
2. Install [MacPorts](http://www.macports.org) 2. Install [MacPorts](http://www.macports.org)
3. Install Neovim build dependencies: 3. Install Neovim build dependencies:
``` ```
sudo port install ninja cmake gettext git sudo port install ninja cmake gettext
``` ```
- **Note**: If you see Wget certificate errors (for older macOS versions less than 10.10): - **Note**: If you see Wget certificate errors (for older macOS versions less than 10.10):
```sh ```sh

View File

@@ -35,11 +35,6 @@ include(InstallHelpers)
include(PreventInTreeBuilds) include(PreventInTreeBuilds)
include(Util) include(Util)
if(NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
# Auto-create a .gitignore in the specified "build" directory.
file(GENERATE OUTPUT .gitignore CONTENT "*")
endif()
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# User settings # User settings
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@@ -145,19 +140,19 @@ endif()
# If not in a git repo (e.g., a tarball) these tokens define the complete # If not in a git repo (e.g., a tarball) these tokens define the complete
# version string, else they are combined with the result of `git describe`. # version string, else they are combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0) set(NVIM_VERSION_MAJOR 0)
set(NVIM_VERSION_MINOR 12) set(NVIM_VERSION_MINOR 11)
set(NVIM_VERSION_PATCH 0) set(NVIM_VERSION_PATCH 2)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers set(NVIM_VERSION_PRERELEASE "") # for package maintainers
# API level # API level
set(NVIM_API_LEVEL 14) # Bump this after any API/stdlib change. set(NVIM_API_LEVEL 13) # Bump this after any API/stdlib change.
set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change. set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
set(NVIM_API_PRERELEASE true) set(NVIM_API_PRERELEASE false)
# We _want_ assertions in RelWithDebInfo build-type. # We _want_ assertions in RelWithDebInfo build-type.
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG) if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
string(REPLACE "-DNDEBUG" "-DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/DNDEBUG" "/DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace
endif() endif()
@@ -241,7 +236,7 @@ set(STYLUA_DIRS runtime scripts src test contrib)
add_glob_target( add_glob_target(
TARGET lintlua-luacheck TARGET lintlua-luacheck
COMMAND $<TARGET_FILE:nvim_bin> COMMAND $<TARGET_FILE:nvim_bin>
FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr/share/lua/5.1 luacheck -q FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr luacheck -q
GLOB_DIRS runtime scripts src test GLOB_DIRS runtime scripts src test
GLOB_PAT *.lua GLOB_PAT *.lua
TOUCH_STRATEGY PER_DIR) TOUCH_STRATEGY PER_DIR)
@@ -254,16 +249,6 @@ add_glob_target(
GLOB_DIRS ${STYLUA_DIRS} GLOB_DIRS ${STYLUA_DIRS}
GLOB_PAT *.lua GLOB_PAT *.lua
TOUCH_STRATEGY PER_DIR) TOUCH_STRATEGY PER_DIR)
# Special handling of some files (which are ignored in .styluaignore).
# Workaround because stylua doesn't(?) support file-specific settings.
add_custom_target(lintlua-stylua2
COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml"
--color=always --check
"${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua"
"${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua"
"${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua"
)
add_dependencies(lintlua-stylua lintlua-stylua2)
add_custom_target(lintlua) add_custom_target(lintlua)
add_dependencies(lintlua lintlua-luacheck lintlua-stylua) add_dependencies(lintlua lintlua-luacheck lintlua-stylua)
@@ -277,7 +262,7 @@ add_glob_target(
TOUCH_STRATEGY PER_DIR) TOUCH_STRATEGY PER_DIR)
add_custom_target(lintcommit add_custom_target(lintcommit
COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main) COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
add_dependencies(lintcommit nvim_bin) add_dependencies(lintcommit nvim_bin)
add_custom_target(lint) add_custom_target(lint)
@@ -291,15 +276,7 @@ add_glob_target(
GLOB_DIRS ${STYLUA_DIRS} GLOB_DIRS ${STYLUA_DIRS}
GLOB_PAT *.lua GLOB_PAT *.lua
TOUCH_STRATEGY PER_DIR) TOUCH_STRATEGY PER_DIR)
# Special handling of some files (which are ignored in .styluaignore).
# Workaround because stylua doesn't(?) support file-specific settings.
add_custom_target(formatlua2
COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml"
"${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua"
"${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua"
"${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua"
)
add_dependencies(formatlua formatlua2)
add_custom_target(format) add_custom_target(format)
add_dependencies(format formatc formatlua) add_dependencies(format formatc formatlua)
@@ -346,13 +323,13 @@ else()
add_custom_target(lua_dev_deps) add_custom_target(lua_dev_deps)
endif() endif()
if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch") if (CMAKE_SYSTEM_PROCESSOR MATCHES arm64)
set(LUALS_ARCH arm64) set(LUALS_ARCH arm64)
else() else()
set(LUALS_ARCH x64) set(LUALS_ARCH x64)
endif() endif()
set(LUALS_VERSION 3.15.0) set(LUALS_VERSION 3.13.9)
set(LUALS "lua-language-server-${LUALS_VERSION}-${CMAKE_SYSTEM_NAME}-${LUALS_ARCH}") set(LUALS "lua-language-server-${LUALS_VERSION}-${CMAKE_SYSTEM_NAME}-${LUALS_ARCH}")
set(LUALS_TARBALL ${LUALS}.tar.gz) set(LUALS_TARBALL ${LUALS}.tar.gz)
set(LUALS_URL https://github.com/LuaLS/lua-language-server/releases/download/${LUALS_VERSION}/${LUALS_TARBALL}) set(LUALS_URL https://github.com/LuaLS/lua-language-server/releases/download/${LUALS_VERSION}/${LUALS_TARBALL})

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/* => runtime/doc/lua.txt
runtime/lua/vim/lsp/ => runtime/doc/lsp.txt runtime/lua/vim/lsp/ => runtime/doc/lsp.txt
src/nvim/api/* => runtime/doc/api.txt src/nvim/api/* => runtime/doc/api.txt
src/nvim/eval.lua => runtime/doc/vimfn.txt src/nvim/eval.lua => runtime/doc/builtin.txt
src/nvim/options.lua => runtime/doc/options.txt src/nvim/options.lua => runtime/doc/options.txt
``` ```
@@ -299,7 +299,7 @@ types, etc. See [:help dev-lua-doc][dev-lua-doc].
- If possible, add type information (`table`, `string`, `number`, ...). Multiple valid types are separated by a bar (`string|table`). Indicate optional parameters via `type|nil`. - If possible, add type information (`table`, `string`, `number`, ...). Multiple valid types are separated by a bar (`string|table`). Indicate optional parameters via `type|nil`.
- If a function in your Lua module should _not_ be documented, add `@nodoc`. - If a function in your Lua module should _not_ be documented, add `@nodoc`.
- If the function is internal or otherwise non-public add `@private`. - If the function is internal or otherwise non-public add `@private`.
- Private functions usually should be underscore-prefixed (named "_foo", not "foo"). Prefixing with an underscore implies `@nodoc`. - Private functions usually should be underscore-prefixed (named "_foo", not "foo").
- Mark deprecated functions with `@deprecated`. - Mark deprecated functions with `@deprecated`.
Third-party dependencies Third-party dependencies

View File

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

View File

@@ -289,8 +289,3 @@ IV) It is not allowed to remove this license from the distribution of the Vim
license for previous Vim releases instead of the license that they came license for previous Vim releases instead of the license that they came
with, at your option. with, at your option.
====
In addition, different license conditions may apply to some runtime files
included with Vim; these will be specified in the header of each respective
file.

View File

@@ -81,7 +81,7 @@ When a (non-experimental) feature is slated to be removed it should:
as described for Lua features. as described for Lua features.
- `vim.deprecate(…, 'x.y.z')` where major version `x` is greater than the - `vim.deprecate(…, 'x.y.z')` where major version `x` is greater than the
current Nvim major version, is always treated as _soft_ deprecation. current Nvim major version, is always treated as _soft_ deprecation.
2. Be _hard_ deprecated in a release following the release in which it was soft deprecated. 2. Be _hard_ deprecated in a following a release in which it was soft deprecated.
- Use of the deprecated feature will still work but should issue a warning. - Use of the deprecated feature will still work but should issue a warning.
- Features implemented in C will need bespoke implementations to communicate - Features implemented in C will need bespoke implementations to communicate
to users that the feature is deprecated. to users that the feature is deprecated.
@@ -127,9 +127,7 @@ Some can be auto-bumped by `scripts/bump_deps.lua`.
* [LuaJIT](https://github.com/LuaJIT/LuaJIT) * [LuaJIT](https://github.com/LuaJIT/LuaJIT)
* [Lua](https://www.lua.org/download.html) * [Lua](https://www.lua.org/download.html)
* [Luv](https://github.com/luvit/luv) * [Luv](https://github.com/luvit/luv)
* When bumping, also sync * When bumping, also sync [our bundled documentation](https://github.com/neovim/neovim/blob/master/runtime/doc/luvref.txt) with [the upstream documentation](https://github.com/luvit/luv/blob/master/docs.md).
- [our bundled meta file](https://github.com/neovim/neovim/blob/master/runtime/lua/uv/_meta.lua) with [the upstream meta file](https://github.com/luvit/luv/blob/master/docs/meta.lua);
- [our bundled documentation](https://github.com/neovim/neovim/blob/master/runtime/doc/luvref.txt) with [the upstream documentation](https://github.com/luvit/luv/blob/master/docs/docs.md).
* [gettext](https://ftp.gnu.org/pub/gnu/gettext/) * [gettext](https://ftp.gnu.org/pub/gnu/gettext/)
* [libiconv](https://ftp.gnu.org/pub/gnu/libiconv) * [libiconv](https://ftp.gnu.org/pub/gnu/libiconv)
* [libuv](https://github.com/libuv/libuv) * [libuv](https://github.com/libuv/libuv)
@@ -154,7 +152,7 @@ These dependencies are "vendored" (inlined), we must update the sources manually
* `src/nvim/tui/terminfo_defs.h`: terminfo definitions * `src/nvim/tui/terminfo_defs.h`: terminfo definitions
* Run `scripts/update_terminfo.sh` to update these definitions. * Run `scripts/update_terminfo.sh` to update these definitions.
* `runtime/lua/vim/lsp/_meta/protocol.lua`: LSP specification * `runtime/lua/vim/lsp/_meta/protocol.lua`: LSP specification
* Run `src/gen/gen_lsp.lua` to update. * Run `scripts/gen_lsp.lua` to update.
* `runtime/lua/vim/_meta/lpeg.lua`: LPeg definitions. * `runtime/lua/vim/_meta/lpeg.lua`: LPeg definitions.
* Refer to [`LuaCATS/lpeg`](https://github.com/LuaCATS/lpeg) for updates. * Refer to [`LuaCATS/lpeg`](https://github.com/LuaCATS/lpeg) for updates.
* Update the git SHA revision from which the documentation was taken. * Update the git SHA revision from which the documentation was taken.

View File

@@ -182,9 +182,3 @@ appimage-%:
bash scripts/genappimage.sh $* bash scripts/genappimage.sh $*
.PHONY: test clean distclean nvim libnvim cmake deps install appimage checkprefix benchmark $(FORMAT) $(LINT) $(TEST) .PHONY: test clean distclean nvim libnvim cmake deps install appimage checkprefix benchmark $(FORMAT) $(LINT) $(TEST)
.PHONY: emmylua-check
emmylua-check:
-emmylua_check runtime/lua \
--config .luarc.json \
--config .emmyrc.json

462
build.zig
View File

@@ -1,462 +0,0 @@
const std = @import("std");
const LazyPath = std.Build.LazyPath;
const build_lua = @import("src/build_lua.zig");
const gen = @import("src/gen/gen_steps.zig");
const runtime = @import("runtime/gen_runtime.zig");
const tests = @import("test/run_tests.zig");
const version = struct {
const major = 0;
const minor = 12;
const patch = 0;
const prerelease = "-dev";
const api_level = 14;
const api_level_compat = 0;
const api_prerelease = true;
};
// TODO(bfredl): this is for an upstream issue
pub fn lazyArtifact(d: *std.Build.Dependency, name: []const u8) ?*std.Build.Step.Compile {
var found: ?*std.Build.Step.Compile = null;
for (d.builder.install_tls.step.dependencies.items) |dep_step| {
const inst = dep_step.cast(std.Build.Step.InstallArtifact) orelse continue;
if (std.mem.eql(u8, inst.artifact.name, name)) {
if (found != null) std.debug.panic("artifact name '{s}' is ambiguous", .{name});
found = inst.artifact;
}
}
return found;
}
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const t = target.result;
const os_tag = t.os.tag;
const is_windows = (os_tag == .windows);
const is_linux = (os_tag == .linux);
const is_darwin = os_tag.isDarwin();
const modern_unix = is_darwin or os_tag.isBSD() or is_linux;
const cross_compiling = b.option(bool, "cross", "cross compile") orelse false;
// TODO(bfredl): option to set nlua0 target explicitly when cross compiling?
const target_host = if (cross_compiling) b.graph.host else target;
const optimize_host = .ReleaseSafe;
// puc lua 5.1 is not ReleaseSafe "safe"
const optimize_lua = if (optimize == .Debug or optimize == .ReleaseSafe) .ReleaseSmall else optimize;
const arch = t.cpu.arch;
const default_luajit = (is_linux and arch == .x86_64) or (is_darwin and arch == .aarch64);
const use_luajit = b.option(bool, "luajit", "use luajit") orelse default_luajit;
const host_use_luajit = if (cross_compiling) false else use_luajit;
const E = enum { luajit, lua51 };
const ziglua = b.dependency("zlua", .{
.target = target,
.optimize = optimize_lua,
.lang = if (use_luajit) E.luajit else E.lua51,
.shared = false,
});
const ziglua_host = if (cross_compiling) b.dependency("zlua", .{
.target = target_host,
.optimize = optimize_lua,
.lang = if (host_use_luajit) E.luajit else E.lua51,
.shared = false,
}) else ziglua;
const lpeg = b.dependency("lpeg", .{});
const iconv = if (is_windows or is_darwin) b.lazyDependency("libiconv", .{ .target = target, .optimize = optimize }) else null;
// this is currently not necessary, as ziglua currently doesn't use lazy dependencies
// to circumvent ziglua.artifact() failing in a bad way.
const lua = lazyArtifact(ziglua, "lua") orelse return;
if (cross_compiling) {
_ = lazyArtifact(ziglua_host, "lua") orelse return;
}
// const lua = ziglua.artifact("lua");
const libuv_dep = b.dependency("libuv", .{ .target = target, .optimize = optimize });
const libuv = libuv_dep.artifact("uv");
const libluv = try build_lua.build_libluv(b, target, optimize, lua, libuv);
const libluv_host = if (cross_compiling) libluv_host: {
const libuv_dep_host = b.dependency("libuv", .{ .target = target_host, .optimize = optimize_host });
const libuv_host = libuv_dep_host.artifact("uv");
break :libluv_host try build_lua.build_libluv(b, target_host, optimize_host, ziglua_host.artifact("lua"), libuv_host);
} else libluv;
const utf8proc = b.dependency("utf8proc", .{ .target = target, .optimize = optimize });
const unibilium = b.dependency("unibilium", .{ .target = target, .optimize = optimize });
// TODO(bfredl): fix upstream bugs with UBSAN
const treesitter = b.dependency("treesitter", .{ .target = target, .optimize = .ReleaseFast });
const nlua0 = build_lua.build_nlua0(b, target_host, optimize_host, host_use_luajit, ziglua_host, lpeg, libluv_host);
// usual caveat emptor: might need to force a rebuild if the only change is
// addition of new .c files, as those are not seen by any hash
const subdirs = [_][]const u8{
"", // src/nvim itself
"os/",
"api/",
"api/private/",
"msgpack_rpc/",
"tui/",
"tui/termkey/",
"event/",
"eval/",
"lib/",
"lua/",
"viml/",
"viml/parser/",
"vterm/",
};
// source names _relative_ src/nvim/, not including other src/ subdircs
var nvim_sources = try std.ArrayList(gen.SourceItem).initCapacity(b.allocator, 100);
var nvim_headers = try std.ArrayList([]u8).initCapacity(b.allocator, 100);
// both source headers and the {module}.h.generated.h files
var api_headers = try std.ArrayList(std.Build.LazyPath).initCapacity(b.allocator, 10);
// TODO(bfredl): these should just become subdirs..
const windows_only = [_][]const u8{ "pty_proc_win.c", "pty_proc_win.h", "pty_conpty_win.c", "pty_conpty_win.h", "os_win_console.c", "win_defs.h" };
const unix_only = [_][]const u8{ "unix_defs.h", "pty_proc_unix.c", "pty_proc_unix.h" };
const exclude_list = if (is_windows) &unix_only else &windows_only;
const src_dir = b.build_root.handle;
for (subdirs) |s| {
var dir = try src_dir.openDir(b.fmt("src/nvim/{s}", .{s}), .{ .iterate = true });
defer dir.close();
var it = dir.iterateAssumeFirstIteration();
const api_export = std.mem.eql(u8, s, "api/");
const os_check = std.mem.eql(u8, s, "os/");
entries: while (try it.next()) |entry| {
if (entry.name.len < 3) continue;
if (entry.name[0] < 'a' or entry.name[0] > 'z') continue;
if (os_check) {
for (exclude_list) |name| {
if (std.mem.eql(u8, name, entry.name)) {
continue :entries;
}
}
}
if (std.mem.eql(u8, ".c", entry.name[entry.name.len - 2 ..])) {
try nvim_sources.append(.{ .name = b.fmt("{s}{s}", .{ s, entry.name }), .api_export = api_export });
}
if (std.mem.eql(u8, ".h", entry.name[entry.name.len - 2 ..])) {
try nvim_headers.append(b.fmt("{s}{s}", .{ s, entry.name }));
if (api_export and !std.mem.eql(u8, "ui_events.in.h", entry.name)) {
try api_headers.append(b.path(b.fmt("src/nvim/{s}{s}", .{ s, entry.name })));
}
}
}
}
const support_unittests = use_luajit;
const gen_config = b.addWriteFiles();
const version_lua = gen_config.add("nvim_version.lua", lua_version_info(b));
var config_str = b.fmt("zig build -Doptimize={s}", .{@tagName(optimize)});
if (cross_compiling) {
config_str = b.fmt("{s} -Dcross -Dtarget={s} (host: {s})", .{ config_str, try t.linuxTriple(b.allocator), try b.graph.host.result.linuxTriple(b.allocator) });
}
const versiondef_step = b.addConfigHeader(.{ .style = .{ .cmake = b.path("cmake.config/versiondef.h.in") } }, .{
.NVIM_VERSION_MAJOR = version.major,
.NVIM_VERSION_MINOR = version.minor,
.NVIM_VERSION_PATCH = version.patch,
.NVIM_VERSION_PRERELEASE = version.prerelease,
.NVIM_VERSION_MEDIUM = "",
.VERSION_STRING = "TODO", // TODO(bfredl): not sure what to put here. summary already in "config_str"
.CONFIG = config_str,
});
_ = gen_config.addCopyFile(versiondef_step.getOutput(), "auto/versiondef.h"); // run_preprocessor() workaronnd
const ptrwidth = t.ptrBitWidth() / 8;
const sysconfig_step = b.addConfigHeader(.{ .style = .{ .cmake = b.path("cmake.config/config.h.in") } }, .{
.SIZEOF_INT = t.cTypeByteSize(.int),
.SIZEOF_INTMAX_T = t.cTypeByteSize(.longlong), // TODO
.SIZEOF_LONG = t.cTypeByteSize(.long),
.SIZEOF_SIZE_T = ptrwidth,
.SIZEOF_VOID_PTR = ptrwidth,
.PROJECT_NAME = "nvim",
.HAVE__NSGETENVIRON = is_darwin,
.HAVE_FD_CLOEXEC = modern_unix,
.HAVE_FSEEKO = modern_unix,
.HAVE_LANGINFO_H = modern_unix,
.HAVE_NL_LANGINFO_CODESET = modern_unix,
.HAVE_NL_MSG_CAT_CNTR = t.isGnuLibC(),
.HAVE_PWD_FUNCS = modern_unix,
.HAVE_READLINK = modern_unix,
.HAVE_STRNLEN = modern_unix,
.HAVE_STRCASECMP = modern_unix,
.HAVE_STRINGS_H = modern_unix,
.HAVE_STRNCASECMP = modern_unix,
.HAVE_STRPTIME = modern_unix,
.HAVE_XATTR = is_linux,
.HAVE_SYS_SDT_H = false,
.HAVE_SYS_UTSNAME_H = modern_unix,
.HAVE_SYS_WAIT_H = false, // unused
.HAVE_TERMIOS_H = modern_unix,
.HAVE_WORKING_LIBINTL = t.isGnuLibC(),
.UNIX = modern_unix,
.CASE_INSENSITIVE_FILENAME = is_darwin or is_windows,
.HAVE_SYS_UIO_H = modern_unix,
.HAVE_READV = modern_unix,
.HAVE_DIRFD_AND_FLOCK = modern_unix,
.HAVE_FORKPTY = modern_unix and !is_darwin, // also on Darwin but we lack the headers :(
.HAVE_BE64TOH = modern_unix and !is_darwin,
.ORDER_BIG_ENDIAN = t.cpu.arch.endian() == .big,
.ENDIAN_INCLUDE_FILE = "endian.h",
.HAVE_EXECINFO_BACKTRACE = modern_unix and !t.isMuslLibC(),
.HAVE_BUILTIN_ADD_OVERFLOW = true,
.HAVE_WIMPLICIT_FALLTHROUGH_FLAG = true,
.HAVE_BITSCANFORWARD64 = null,
.VTERM_TEST_FILE = "test/vterm_test_output", // TODO(bfredl): revisit when porting libvterm tests
});
_ = gen_config.addCopyFile(sysconfig_step.getOutput(), "auto/config.h"); // run_preprocessor() workaronnd
_ = gen_config.add("auto/pathdef.h", b.fmt(
\\char *default_vim_dir = "/usr/local/share/nvim";
\\char *default_vimruntime_dir = "";
\\char *default_lib_dir = "/usr/local/lib/nvim";
, .{}));
// TODO(bfredl): include git version when available
const medium = b.fmt("v{}.{}.{}{s}+zig", .{ version.major, version.minor, version.patch, version.prerelease });
const versiondef_git = gen_config.add("auto/versiondef_git.h", b.fmt(
\\#define NVIM_VERSION_MEDIUM "{s}"
\\#define NVIM_VERSION_BUILD "???"
\\
, .{medium}));
// TODO(zig): using getEmittedIncludeTree() is ugly af. we want unittests
// to reuse the std.build.Module include_path thing
const unittest_include_path = [_]LazyPath{
b.path("src/"),
gen_config.getDirectory(),
lua.getEmittedIncludeTree(),
libuv.getEmittedIncludeTree(),
libluv.getEmittedIncludeTree(),
utf8proc.artifact("utf8proc").getEmittedIncludeTree(),
unibilium.artifact("unibilium").getEmittedIncludeTree(),
treesitter.artifact("tree-sitter").getEmittedIncludeTree(),
if (iconv) |dep| dep.artifact("iconv").getEmittedIncludeTree() else b.path("UNUSED_PATH/"),
};
const gen_headers, const funcs_data = try gen.nvim_gen_sources(b, nlua0, &nvim_sources, &nvim_headers, &api_headers, versiondef_git, version_lua);
const test_config_step = b.addWriteFiles();
_ = test_config_step.add("test/cmakeconfig/paths.lua", try test_config(b));
const test_gen_step = b.step("gen_headers", "debug: output generated headers");
const config_install = b.addInstallDirectory(.{ .source_dir = gen_config.getDirectory(), .install_dir = .prefix, .install_subdir = "config/" });
test_gen_step.dependOn(&config_install.step);
test_gen_step.dependOn(&b.addInstallDirectory(.{ .source_dir = gen_headers.getDirectory(), .install_dir = .prefix, .install_subdir = "headers/" }).step);
const nvim_exe = b.addExecutable(.{
.name = "nvim",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
nvim_exe.rdynamic = true; // -E
nvim_exe.linkLibrary(lua);
nvim_exe.linkLibrary(libuv);
nvim_exe.linkLibrary(libluv);
if (iconv) |dep| nvim_exe.linkLibrary(dep.artifact("iconv"));
nvim_exe.linkLibrary(utf8proc.artifact("utf8proc"));
nvim_exe.linkLibrary(unibilium.artifact("unibilium"));
nvim_exe.linkLibrary(treesitter.artifact("tree-sitter"));
if (is_windows) {
nvim_exe.linkSystemLibrary("netapi32");
}
nvim_exe.addIncludePath(b.path("src"));
nvim_exe.addIncludePath(gen_config.getDirectory());
nvim_exe.addIncludePath(gen_headers.getDirectory());
build_lua.add_lua_modules(nvim_exe.root_module, lpeg, use_luajit, false);
var unit_test_sources = try std.ArrayList([]u8).initCapacity(b.allocator, 10);
if (support_unittests) {
var unit_test_fixtures = try src_dir.openDir("test/unit/fixtures/", .{ .iterate = true });
defer unit_test_fixtures.close();
var it = unit_test_fixtures.iterateAssumeFirstIteration();
while (try it.next()) |entry| {
if (entry.name.len < 3) continue;
if (std.mem.eql(u8, ".c", entry.name[entry.name.len - 2 ..])) {
try unit_test_sources.append(b.fmt("test/unit/fixtures/{s}", .{entry.name}));
}
}
}
const src_paths = try b.allocator.alloc([]u8, nvim_sources.items.len + unit_test_sources.items.len);
for (nvim_sources.items, 0..) |s, i| {
src_paths[i] = b.fmt("src/nvim/{s}", .{s.name});
}
@memcpy(src_paths[nvim_sources.items.len..], unit_test_sources.items);
const flags = [_][]const u8{
"-std=gnu99",
"-DZIG_BUILD",
"-D_GNU_SOURCE",
if (support_unittests) "-DUNIT_TESTING" else "",
if (use_luajit) "" else "-DNVIM_VENDOR_BIT",
if (is_windows) "-DMSWIN" else "",
if (is_windows) "-DWIN32_LEAN_AND_MEAN" else "",
if (is_windows) "-DUTF8PROC_STATIC" else "",
};
nvim_exe.addCSourceFiles(.{ .files = src_paths, .flags = &flags });
nvim_exe.addCSourceFiles(.{ .files = &.{
"src/xdiff/xdiffi.c",
"src/xdiff/xemit.c",
"src/xdiff/xhistogram.c",
"src/xdiff/xpatience.c",
"src/xdiff/xprepare.c",
"src/xdiff/xutils.c",
"src/cjson/lua_cjson.c",
"src/cjson/fpconv.c",
"src/cjson/strbuf.c",
}, .flags = &flags });
const nvim_exe_step = b.step("nvim_bin", "only the binary (not a fully working install!)");
const nvim_exe_install = b.addInstallArtifact(nvim_exe, .{});
nvim_exe_step.dependOn(&nvim_exe_install.step);
const gen_runtime = try runtime.nvim_gen_runtime(b, nlua0, funcs_data);
const runtime_install = b.addInstallDirectory(.{ .source_dir = gen_runtime.getDirectory(), .install_dir = .prefix, .install_subdir = "runtime/" });
const nvim = b.step("nvim", "build the editor");
nvim.dependOn(&nvim_exe_install.step);
nvim.dependOn(&runtime_install.step);
const lua_dev_deps = b.dependency("lua_dev_deps", .{});
const test_deps = b.step("test_deps", "test prerequisites");
test_deps.dependOn(&nvim_exe_install.step);
test_deps.dependOn(&runtime_install.step);
test_deps.dependOn(test_fixture(b, "shell-test", null, target, optimize));
test_deps.dependOn(test_fixture(b, "tty-test", libuv, target, optimize));
test_deps.dependOn(test_fixture(b, "pwsh-test", null, target, optimize));
test_deps.dependOn(test_fixture(b, "printargs-test", null, target, optimize));
test_deps.dependOn(test_fixture(b, "printenv-test", null, target, optimize));
test_deps.dependOn(test_fixture(b, "streams-test", libuv, target, optimize));
const parser_c = b.dependency("treesitter_c", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize));
const parser_markdown = b.dependency("treesitter_markdown", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize));
test_deps.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize));
const parser_vim = b.dependency("treesitter_vim", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize));
const parser_vimdoc = b.dependency("treesitter_vimdoc", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize));
const parser_lua = b.dependency("treesitter_lua", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize));
const parser_query = b.dependency("treesitter_query", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize));
const unit_headers: ?[]const LazyPath = if (support_unittests) &(unittest_include_path ++ .{gen_headers.getDirectory()}) else null;
try tests.test_steps(b, nvim_exe, test_deps, lua_dev_deps.path("."), test_config_step.getDirectory(), unit_headers);
}
pub fn test_fixture(
b: *std.Build,
name: []const u8,
libuv: ?*std.Build.Step.Compile,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
) *std.Build.Step {
const fixture = b.addExecutable(.{
.name = name,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
const source = if (std.mem.eql(u8, name, "pwsh-test")) "shell-test" else name;
fixture.addCSourceFile(.{ .file = b.path(b.fmt("./test/functional/fixtures/{s}.c", .{source})) });
fixture.linkLibC();
if (libuv) |uv| fixture.linkLibrary(uv);
return &b.addInstallArtifact(fixture, .{}).step;
}
pub fn add_ts_parser(
b: *std.Build,
name: []const u8,
parser_dir: LazyPath,
scanner: bool,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
) *std.Build.Step {
const parser = b.addLibrary(.{
.name = name,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
.linkage = .dynamic,
});
parser.addCSourceFile(.{ .file = parser_dir.path(b, "src/parser.c") });
if (scanner) parser.addCSourceFile(.{ .file = parser_dir.path(b, "src/scanner.c") });
parser.addIncludePath(parser_dir.path(b, "src"));
parser.linkLibC();
const parser_install = b.addInstallArtifact(parser, .{ .dest_sub_path = b.fmt("parser/{s}.so", .{name}) });
return &parser_install.step;
}
pub fn lua_version_info(b: *std.Build) []u8 {
const v = version;
return b.fmt(
\\return {{
\\ {{"major", {}}},
\\ {{"minor", {}}},
\\ {{"patch", {}}},
\\ {{"prerelease", {}}},
\\ {{"api_level", {}}},
\\ {{"api_compatible", {}}},
\\ {{"api_prerelease", {}}},
\\}}
, .{ v.major, v.minor, v.patch, v.prerelease.len > 0, v.api_level, v.api_level_compat, v.api_prerelease });
}
pub fn test_config(b: *std.Build) ![]u8 {
var buf: [std.fs.max_path_bytes]u8 = undefined;
const src_path = try b.build_root.handle.realpath(".", &buf);
// we don't use test/cmakeconfig/paths.lua.in because it contains cmake specific logic
return b.fmt(
\\local M = {{}}
\\
\\M.apple_sysroot = ""
\\M.translations_enabled = "$ENABLE_TRANSLATIONS" == "ON"
\\M.is_asan = "$ENABLE_ASAN_UBSAN" == "ON"
\\M.is_zig_build = true
\\M.vterm_test_file = "test/vterm_test_output"
\\M.test_build_dir = "{[bin_dir]s}" -- bull
\\M.test_source_path = "{[src_path]s}"
\\M.test_lua_prg = ""
\\M.test_luajit_prg = ""
\\ -- include path passed on the cmdline, see test/lua_runner.lua
\\M.include_paths = _G.c_include_path or {{}}
\\
\\return M
, .{ .bin_dir = b.install_path, .src_path = src_path });
}

View File

@@ -1,72 +0,0 @@
.{
.name = .neovim,
.fingerprint = 0x66eb090879307a38,
.version = "0.12.0",
.minimum_zig_version = "0.14.0",
.dependencies = .{
.zlua = .{
.url = "git+https://github.com/natecraddock/ziglua#6889b2d90ee6ae96810a9f04ec7c62d9aa91d088",
.hash = "zlua-0.1.0-hGRpCxctBQDEQgDArJ0Kc4RDIsD-Hw3pw9pPPw_kGmmY",
},
.lpeg = .{
.url = "https://github.com/neovim/deps/raw/d495ee6f79e7962a53ad79670cb92488abe0b9b4/opt/lpeg-1.1.0.tar.gz",
.hash = "N-V-__8AAMnaAwCEutreuREG3QayBVEZqUTDQFY1Nsrv2OIt",
},
.luv = .{
.url = "git+https://github.com/luvit/luv?ref=1.51.0-1#4c9fbc6cf6f3338bb0e0426710cf885ee557b540",
.hash = "N-V-__8AAMlNDwCY07jUoMiq3iORXdZy0uFWKiHsy8MaDBJA",
},
.lua_compat53 = .{
.url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13.tar.gz",
.hash = "N-V-__8AADi-AwDnVoXwDCQvv2wcYOmN0bJLqZ44J3lwoQY2",
},
.treesitter = .{
.url = "git+https://github.com/tree-sitter/tree-sitter#d87921bb9c39b0b06c811f2082f9a9991cdca027",
.hash = "tree_sitter-0.26.0-Tw2sRxO7CwC0NyDrSygSi7UXRHMNUFEF8GRq6dK81lRF",
},
.libuv = .{
.url = "git+https://github.com/allyourcodebase/libuv#a2dfd385bd2a00d6d290fda85a40a55a9d6cffc5",
.hash = "libuv-1.51.0-htqqv6liAADxBLIBCZT-qUh_3nRRwtNYsOFQOUmrd_sx",
},
.utf8proc = .{ .path = "./deps/utf8proc/" },
.unibilium = .{ .path = "./deps/unibilium/" },
.libiconv = .{
.url = "git+https://github.com/allyourcodebase/libiconv#9def4c8a1743380e85bcedb80f2c15b455e236f3",
.hash = "libiconv-1.18.0-p9sJwWnqAACzVYeWgXB5r5lOQ74XwTPlptixV0JPRO28",
.lazy = true,
},
.lua_dev_deps = .{
.url = "https://github.com/neovim/deps/raw/06ef2b58b0876f8de1a3f5a710473dcd7afff251/opt/lua-dev-deps.tar.gz",
.hash = "N-V-__8AAGevEQCHAkCozca5AIdN9DFc3Luf3g3r2AcbyOrm",
},
.treesitter_c = .{
.url = "git+https://github.com/tree-sitter/tree-sitter-c?ref=v0.24.1#7fa1be1b694b6e763686793d97da01f36a0e5c12",
.hash = "N-V-__8AANxPSABzw3WBTSH_YkwaGAfrK6PBqAMqQedkDDim",
},
.treesitter_markdown = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-markdown?ref=v0.5.0#afaa4138517363362f54c89330c9d79391e81168",
.hash = "N-V-__8AAIIZUwD3CGdyI2DiHu7Suj2jIF_EAVlM6REFGwju",
},
.treesitter_lua = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-lua?ref=v0.4.0#4569d1c361129e71a205b94a05e158bd71b1709f",
.hash = "N-V-__8AAEF5CABqSL9zqc03aQsT6Nni54ZCcL98pnuDL2D3",
},
.treesitter_vim = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-vim?ref=v0.7.0#3dd4747082d1b717b8978211c06ef7b6cd16125b",
.hash = "N-V-__8AAMArVAB4uo2wg2XRs8HBviQ4Pq366cC_iRolX4Vc",
},
.treesitter_vimdoc = .{
.url = "git+https://github.com/neovim/tree-sitter-vimdoc?ref=v4.0.0#9f6191a98702edc1084245abd5523279d4b681fb",
.hash = "N-V-__8AAI4YCgD7OqxCEAmz2RqT_ohl6eA4F0fGMtLIe7nb",
},
.treesitter_query = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-query?ref=v0.6.2#8a43889f89fd0667289936341bff3a77bafade17",
.hash = "N-V-__8AAARLBACBLGiXGFTijEzLv8AwiqT_kJpmVjir1BgX",
},
},
.paths = .{
// TODO(bfredl): explicitly list the subdirs which actually are used
"",
},
}

View File

@@ -12,10 +12,6 @@
#endif #endif
#define NVIM_VERSION_CFLAGS "${VERSION_STRING}" #define NVIM_VERSION_CFLAGS "${VERSION_STRING}"
#ifdef ZIG_BUILD #define NVIM_VERSION_BUILD_TYPE "$<CONFIG>"
# define NVIM_VERSION_BUILD_TYPE "${CONFIG}"
#else
# define NVIM_VERSION_BUILD_TYPE "$<CONFIG>"
#endif
#endif // AUTO_VERSIONDEF_H #endif // AUTO_VERSIONDEF_H

View File

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

View File

@@ -42,7 +42,7 @@ if(APPLE)
endif() endif()
if(UNIX) if(UNIX)
BuildLuajit(INSTALL_COMMAND ${BUILDCMD_UNIX} BuildLuaJit(INSTALL_COMMAND ${BUILDCMD_UNIX}
CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR} CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR}
${DEPLOYMENT_TARGET} install) ${DEPLOYMENT_TARGET} install)
@@ -53,7 +53,7 @@ elseif(MINGW)
else() else()
set(LUAJIT_MAKE_PRG ${CMAKE_MAKE_PROGRAM}) set(LUAJIT_MAKE_PRG ${CMAKE_MAKE_PROGRAM})
endif() endif()
BuildLuajit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER} BuildLuaJit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER}
PREFIX=${DEPS_INSTALL_DIR} PREFIX=${DEPS_INSTALL_DIR}
CFLAGS+=-DLUA_USE_APICHECK CFLAGS+=-DLUA_USE_APICHECK
CFLAGS+=-funwind-tables CFLAGS+=-funwind-tables
@@ -75,7 +75,7 @@ elseif(MINGW)
) )
elseif(MSVC) elseif(MSVC)
BuildLuajit( BuildLuaJit(
BUILD_COMMAND ${CMAKE_COMMAND} -E chdir ${DEPS_BUILD_DIR}/src/luajit/src ${DEPS_BUILD_DIR}/src/luajit/src/msvcbuild.bat BUILD_COMMAND ${CMAKE_COMMAND} -E chdir ${DEPS_BUILD_DIR}/src/luajit/src ${DEPS_BUILD_DIR}/src/luajit/src/msvcbuild.bat
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_BIN_DIR} INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_BIN_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/luajit.exe ${DEPS_BIN_DIR} COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/luajit.exe ${DEPS_BIN_DIR}

View File

@@ -7,6 +7,5 @@ ExternalProject_Add(wasmtime
-D WASMTIME_FASTEST_RUNTIME=ON # build with full LTO -D WASMTIME_FASTEST_RUNTIME=ON # build with full LTO
-D WASMTIME_DISABLE_ALL_FEATURES=ON # don't need all that crap... -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_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 USES_TERMINAL_BUILD TRUE
${EXTERNALPROJECT_OPTIONS}) ${EXTERNALPROJECT_OPTIONS})

View File

@@ -1,8 +1,8 @@
LIBUV_URL https://github.com/libuv/libuv/archive/v1.51.0.tar.gz LIBUV_URL https://github.com/libuv/libuv/archive/v1.50.0.tar.gz
LIBUV_SHA256 27e55cf7083913bfb6826ca78cde9de7647cded648d35f24163f2d31bb9f51cd LIBUV_SHA256 b1ec56444ee3f1e10c8bd3eed16ba47016ed0b94fe42137435aaf2e0bd574579
LUAJIT_URL https://github.com/luajit/luajit/archive/871db2c84ecefd70a850e03a6c340214a81739f0.tar.gz LUAJIT_URL https://github.com/luajit/luajit/archive/538a82133ad6fddfd0ca64de167c4aca3bc1a2da.tar.gz
LUAJIT_SHA256 ab3f16d82df6946543565cfb0d2810d387d79a3a43e0431695b03466188e2680 LUAJIT_SHA256 7acbc36be8f21072422eb9a5e5fc468d0eaa55bec1b70260d651e845684621e2
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333 LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
@@ -10,8 +10,8 @@ LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz
UNIBILIUM_SHA256 370ecb07fbbc20d91d1b350c55f1c806b06bf86797e164081ccc977fc9b3af7a UNIBILIUM_SHA256 370ecb07fbbc20d91d1b350c55f1c806b06bf86797e164081ccc977fc9b3af7a
LUV_URL https://github.com/luvit/luv/archive/1.51.0-1.tar.gz LUV_URL https://github.com/luvit/luv/archive/1.50.0-1.tar.gz
LUV_SHA256 d4a11178ae8e16ba5886799ea91905dd9b0b479c75aebd67866d37373e41526f LUV_SHA256 bb4f0570571e40c1d2a7644f6f9c1309a6ccdb19bf4d397e8d7bfd0c6b88e613
LPEG_URL https://github.com/neovim/deps/raw/d495ee6f79e7962a53ad79670cb92488abe0b9b4/opt/lpeg-1.1.0.tar.gz LPEG_URL https://github.com/neovim/deps/raw/d495ee6f79e7962a53ad79670cb92488abe0b9b4/opt/lpeg-1.1.0.tar.gz
LPEG_SHA256 4b155d67d2246c1ffa7ad7bc466c1ea899bbc40fef0257cc9c03cecbaed4352a LPEG_SHA256 4b155d67d2246c1ffa7ad7bc466c1ea899bbc40fef0257cc9c03cecbaed4352a
@@ -34,25 +34,25 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/v2.10.0.tar.gz UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/v2.10.0.tar.gz
UTF8PROC_SHA256 6f4f1b639daa6dca9f80bc5db1233e9cbaa31a67790887106160b33ef743f136 UTF8PROC_SHA256 6f4f1b639daa6dca9f80bc5db1233e9cbaa31a67790887106160b33ef743f136
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.24.1.tar.gz TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.4.tar.gz
TREESITTER_C_SHA256 25dd4bb3dec770769a407e0fc803f424ce02c494a56ce95fedc525316dcf9b48 TREESITTER_C_SHA256 b66c5043e26d84e5f17a059af71b157bcf202221069ed220aa1696d7d1d28a7a
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.4.0.tar.gz TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.3.0.tar.gz
TREESITTER_LUA_SHA256 b0977aced4a63bb75f26725787e047b8f5f4a092712c840ea7070765d4049559 TREESITTER_LUA_SHA256 a34cc70abfd8d2d4b0fabf01403ea05f848e1a4bc37d8a4bfea7164657b35d31
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.7.0.tar.gz TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.5.0.tar.gz
TREESITTER_VIM_SHA256 44eabc31127c4feacda19f2a05a5788272128ff561ce01093a8b7a53aadcc7b2 TREESITTER_VIM_SHA256 90019d12d2da0751c027124f27f5335babf069a050457adaed53693b5e9cf10a
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v4.0.0.tar.gz TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.1.tar.gz
TREESITTER_VIMDOC_SHA256 8096794c0f090b2d74b7bff94548ac1be3285b929ec74f839bd9b3ff4f4c6a0b TREESITTER_VIMDOC_SHA256 76b65e5bee9ff78eb21256619b1995aac4d80f252c19e1c710a4839481ded09e
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.6.2.tar.gz TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.5.1.tar.gz
TREESITTER_QUERY_SHA256 90682e128d048fbf2a2a17edca947db71e326fa0b3dba4136e041e096538b4eb TREESITTER_QUERY_SHA256 fe8c712880a529d454347cd4c58336ac2db22243bae5055bdb5844fb3ea56192
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.5.0.tar.gz TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.4.1.tar.gz
TREESITTER_MARKDOWN_SHA256 14c2c948ccf0e9b606eec39b09286c59dddf28307849f71b7ce2b1d1ef06937e TREESITTER_MARKDOWN_SHA256 e0fdb2dca1eb3063940122e1475c9c2b069062a638c95939e374c5427eddee9f
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.8.tar.gz TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.3.tar.gz
TREESITTER_SHA256 178b575244d967f4920a4642408dc4edf6de96948d37d7f06e5b78acee9c0b4e TREESITTER_SHA256 862fac52653bc7bc9d2cd0630483e6bdf3d02bcd23da956ca32663c4798a93e3
WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v29.0.1.tar.gz WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v29.0.1.tar.gz
WASMTIME_SHA256 b94b6c6fd6aebaf05d4c69c1b12b5dc217b0d42c1a95f435b33af63dddfa5304 WASMTIME_SHA256 b94b6c6fd6aebaf05d4c69c1b12b5dc217b0d42c1a95f435b33af63dddfa5304
UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.81.0.tar.gz UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.80.1.tar.gz
UNCRUSTIFY_SHA256 484623dc16b92206adc6ac0770077c6c67c6e441102148c2a121a19549330ff9 UNCRUSTIFY_SHA256 0e2616ec2f78e12816388c513f7060072ff7942b42f1175eb28b24cb75aaec48
LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/06ef2b58b0876f8de1a3f5a710473dcd7afff251/opt/lua-dev-deps.tar.gz LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/06ef2b58b0876f8de1a3f5a710473dcd7afff251/opt/lua-dev-deps.tar.gz
LUA_DEV_DEPS_SHA256 49f8399e453103064a23c65534f266f3067cda716b6502f016bfafeed5799354 LUA_DEV_DEPS_SHA256 49f8399e453103064a23c65534f266f3067cda716b6502f016bfafeed5799354

View File

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

View File

@@ -7,7 +7,6 @@ set(ENV{XDG_DATA_HOME} ${BUILD_DIR}/Xtest_xdg/share)
set(ENV{XDG_STATE_HOME} ${BUILD_DIR}/Xtest_xdg/state) set(ENV{XDG_STATE_HOME} ${BUILD_DIR}/Xtest_xdg/state)
unset(ENV{XDG_DATA_DIRS}) unset(ENV{XDG_DATA_DIRS})
unset(ENV{NVIM}) # Clear $NVIM in case tests are running from Nvim. #11009 unset(ENV{NVIM}) # Clear $NVIM in case tests are running from Nvim. #11009
unset(ENV{TMUX}) # Nvim TUI shouldn't think it's running in tmux. #34173
# TODO(dundargoc): The CIRRUS_CI environment variable isn't passed to here from # TODO(dundargoc): The CIRRUS_CI environment variable isn't passed to here from
# the main CMakeLists.txt, so we have to manually pass it to this script and # the main CMakeLists.txt, so we have to manually pass it to this script and
@@ -69,7 +68,7 @@ endif()
execute_process( execute_process(
# Note: because of "-ll" (low-level interpreter mode), some modules like # Note: because of "-ll" (low-level interpreter mode), some modules like
# _editor.lua are not loaded. # _editor.lua are not loaded.
COMMAND ${NVIM_PRG} -ll ${WORKING_DIR}/test/lua_runner.lua ${DEPS_INSTALL_DIR}/share/lua/5.1/ busted -v -o test.busted.outputHandlers.nvim COMMAND ${NVIM_PRG} -ll ${WORKING_DIR}/test/lua_runner.lua ${DEPS_INSTALL_DIR} busted -v -o test.busted.outputHandlers.nvim
--lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
--lpath=${BUILD_DIR}/?.lua --lpath=${BUILD_DIR}/?.lua
--lpath=${WORKING_DIR}/src/?.lua --lpath=${WORKING_DIR}/src/?.lua
@@ -79,6 +78,7 @@ execute_process(
${TEST_PATH} ${TEST_PATH}
TIMEOUT $ENV{TEST_TIMEOUT} TIMEOUT $ENV{TEST_TIMEOUT}
WORKING_DIRECTORY ${WORKING_DIR} WORKING_DIRECTORY ${WORKING_DIR}
ERROR_VARIABLE err
RESULT_VARIABLE res RESULT_VARIABLE res
${EXTRA_ARGS}) ${EXTRA_ARGS})
@@ -87,6 +87,11 @@ file(REMOVE_RECURSE ${RM_FILES})
if(res) if(res)
message(STATUS "Tests exited non-zero: ${res}") message(STATUS "Tests exited non-zero: ${res}")
if("${err}" STREQUAL "")
message(STATUS "No output to stderr.")
else()
message(STATUS "Output to stderr:\n${err}")
endif()
# Dump the logfile on CI (if not displayed and moved already). # Dump the logfile on CI (if not displayed and moved already).
if(CI_BUILD) if(CI_BUILD)

View File

@@ -1,30 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("unibilium", .{});
const lib = b.addLibrary(.{
.name = "unibilium",
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
lib.addIncludePath(upstream.path(""));
lib.installHeader(upstream.path("unibilium.h"), "unibilium.h");
lib.linkLibC();
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"unibilium.c",
"uninames.c",
"uniutil.c",
}, .flags = &.{"-DTERMINFO_DIRS=\"/etc/terminfo:/usr/share/terminfo\""} });
b.installArtifact(lib);
}

View File

@@ -1,12 +0,0 @@
.{
.name = "unibilium",
.version = "2.1.2",
.paths = .{""},
.dependencies = .{
.unibilium = .{
.url = "git+https://github.com/neovim/unibilium?ref=v2.1.2#bfcb0350129dd76893bc90399cf37c45812268a2",
.hash = "N-V-__8AADO1CgCggvx73yptnBlXbEm7TjOSO6VGIqc0CvYR",
},
},
}

View File

@@ -1,27 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("utf8proc", .{});
const lib = b.addLibrary(.{
.name = "utf8proc",
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
lib.addIncludePath(upstream.path(""));
lib.installHeader(upstream.path("utf8proc.h"), "utf8proc.h");
lib.linkLibC();
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"utf8proc.c",
}, .flags = &.{"-DUTF8PROC_STATIC"} });
b.installArtifact(lib);
}

View File

@@ -1,12 +0,0 @@
.{
.name = "utf8proc",
.version = "2.10.0",
.paths = .{""},
.dependencies = .{
.utf8proc = .{
.url = "git+https://github.com/JuliaStrings/utf8proc?ref=v2.10.0#a1b99daa2a3393884220264c927a48ba1251a9c6",
.hash = "N-V-__8AAPJfKADYDOC95xuKyudrlob6eFqgzfFl8NbpOoU9",
},
},
}

View File

@@ -12,17 +12,12 @@ get_directory_property(LUA_GEN_DEPS DIRECTORY ${PROJECT_SOURCE_DIR}/src/nvim DEF
add_custom_command(OUTPUT ${GENERATED_SYN_VIM} add_custom_command(OUTPUT ${GENERATED_SYN_VIM}
COMMAND ${LUA_GEN} ${SYN_VIM_GENERATOR} ${GENERATED_SYN_VIM} ${FUNCS_DATA} COMMAND ${LUA_GEN} ${SYN_VIM_GENERATOR} ${GENERATED_SYN_VIM} ${FUNCS_DATA}
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua
DEPENDS DEPENDS
${LUA_GEN_DEPS} ${LUA_GEN_DEPS}
${SYN_VIM_GENERATOR} ${SYN_VIM_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua ${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua ${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
${PROJECT_SOURCE_DIR}/src/nvim/options.lua ${PROJECT_SOURCE_DIR}/src/nvim/options.lua
${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua
${PROJECT_SOURCE_DIR}/src/nvim/eval.c ${PROJECT_SOURCE_DIR}/src/nvim/eval.c
${FUNCS_DATA} ${FUNCS_DATA}
) )

View File

@@ -0,0 +1,859 @@
----------------------------------------
-- This file is generated via github.com/tjdevries/vim9jit
-- For any bugs, please first consider reporting there.
----------------------------------------
-- Ignore "value assigned to a local variable is unused" because
-- we can't guarantee that local variables will be used by plugins
-- luacheck: ignore
--- @diagnostic disable
local vim9 = require('_vim9script')
local M = {}
local prepended = nil
local grepCache = nil
local Complete = nil
local GetAddition = nil
local Tag2item = nil
local Dict2info = nil
local ParseTagline = nil
local Tagline2item = nil
local Tagcmd2extra = nil
local Nextitem = nil
local StructMembers = nil
local SearchMembers = nil
-- vim9script
-- # Vim completion script
-- # Language: C
-- # Maintainer: The Vim Project <https://github.com/vim/vim>
-- # Last Change: 2023 Aug 10
-- # Rewritten in Vim9 script by github user lacygoill
-- # Former Maintainer: Bram Moolenaar <Bram@vim.org>
prepended = ''
grepCache = vim.empty_dict()
-- # This function is used for the 'omnifunc' option.
Complete = function(findstart, abase)
findstart = vim9.bool(findstart)
if vim9.bool(findstart) then
-- # Locate the start of the item, including ".", "->" and "[...]".
local line = vim9.fn.getline('.')
local start = vim9.fn.charcol('.') - 1
local lastword = -1
while start > 0 do
if vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\w') then
start = start - 1
elseif
vim9.bool(vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\.'))
then
if lastword == -1 then
lastword = start
end
start = start - 1
elseif
vim9.bool(
start > 1
and vim9.index(line, vim9.ops.Minus(start, 2)) == '-'
and vim9.index(line, vim9.ops.Minus(start, 1)) == '>'
)
then
if lastword == -1 then
lastword = start
end
start = vim9.ops.Minus(start, 2)
elseif vim9.bool(vim9.index(line, vim9.ops.Minus(start, 1)) == ']') then
-- # Skip over [...].
local n = 0
start = start - 1
while start > 0 do
start = start - 1
if vim9.index(line, start) == '[' then
if n == 0 then
break
end
n = n - 1
elseif vim9.bool(vim9.index(line, start) == ']') then
n = n + 1
end
end
else
break
end
end
-- # Return the column of the last word, which is going to be changed.
-- # Remember the text that comes before it in prepended.
if lastword == -1 then
prepended = ''
return vim9.fn.byteidx(line, start)
end
prepended = vim9.slice(line, start, vim9.ops.Minus(lastword, 1))
return vim9.fn.byteidx(line, lastword)
end
-- # Return list of matches.
local base = prepended .. abase
-- # Don't do anything for an empty base, would result in all the tags in the
-- # tags file.
if base == '' then
return {}
end
-- # init cache for vimgrep to empty
grepCache = {}
-- # Split item in words, keep empty word after "." or "->".
-- # "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
-- # We can't use split, because we need to skip nested [...].
-- # "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc.
local items = {}
local s = 0
local arrays = 0
while 1 do
local e = vim9.fn.charidx(base, vim9.fn.match(base, '\\.\\|->\\|\\[', s))
if e < 0 then
if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then
vim9.fn.add(items, vim9.slice(base, s, nil))
end
break
end
if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then
vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1)))
end
if vim9.index(base, e) == '.' then
-- # skip over '.'
s = vim9.ops.Plus(e, 1)
elseif vim9.bool(vim9.index(base, e) == '-') then
-- # skip over '->'
s = vim9.ops.Plus(e, 2)
else
-- # Skip over [...].
local n = 0
s = e
e = e + 1
while e < vim9.fn.strcharlen(base) do
if vim9.index(base, e) == ']' then
if n == 0 then
break
end
n = n - 1
elseif vim9.bool(vim9.index(base, e) == '[') then
n = n + 1
end
e = e + 1
end
e = e + 1
vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1)))
arrays = arrays + 1
s = e
end
end
-- # Find the variable items[0].
-- # 1. in current function (like with "gd")
-- # 2. in tags file(s) (like with ":tag")
-- # 3. in current file (like with "gD")
local res = {}
if vim9.fn.searchdecl(vim9.index(items, 0), false, true) == 0 then
-- # Found, now figure out the type.
-- # TODO: join previous line if it makes sense
local line = vim9.fn.getline('.')
local col = vim9.fn.charcol('.')
if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ';') >= 0 then
-- # Handle multiple declarations on the same line.
local col2 = vim9.ops.Minus(col, 1)
while vim9.index(line, col2) ~= ';' do
col2 = col2 - 1
end
line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil)
col = vim9.ops.Minus(col, col2)
end
if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ',') >= 0 then
-- # Handle multiple declarations on the same line in a function
-- # declaration.
local col2 = vim9.ops.Minus(col, 1)
while vim9.index(line, col2) ~= ',' do
col2 = col2 - 1
end
if
vim9.ops.RegexpMatches(
vim9.slice(line, vim9.ops.Plus(col2, 1), vim9.ops.Minus(col, 1)),
' *[^ ][^ ]* *[^ ]'
)
then
line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil)
col = vim9.ops.Minus(col, col2)
end
end
if vim9.fn.len(items) == 1 then
-- # Completing one word and it's a local variable: May add '[', '.' or
-- # '->'.
local match = vim9.index(items, 0)
local kind = 'v'
if vim9.fn.match(line, '\\<' .. match .. '\\s*\\[') > 0 then
match = match .. '['
else
res = Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), { '' }, 0, true)
if vim9.fn.len(res) > 0 then
-- # There are members, thus add "." or "->".
if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then
match = match .. '->'
else
match = match .. '.'
end
end
end
res = { { ['match'] = match, ['tagline'] = '', ['kind'] = kind, ['info'] = line } }
elseif vim9.bool(vim9.fn.len(items) == vim9.ops.Plus(arrays, 1)) then
-- # Completing one word and it's a local array variable: build tagline
-- # from declaration line
local match = vim9.index(items, 0)
local kind = 'v'
local tagline = '\t/^' .. line .. '$/'
res = { { ['match'] = match, ['tagline'] = tagline, ['kind'] = kind, ['info'] = line } }
else
-- # Completing "var.", "var.something", etc.
res =
Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true)
end
end
if vim9.fn.len(items) == 1 or vim9.fn.len(items) == vim9.ops.Plus(arrays, 1) then
-- # Only one part, no "." or "->": complete from tags file.
local tags = {}
if vim9.fn.len(items) == 1 then
tags = vim9.fn.taglist('^' .. base)
else
tags = vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$')
end
vim9.fn_mut('filter', {
vim9.fn_mut('filter', {
tags,
function(_, v)
return vim9.ternary(vim9.fn.has_key(v, 'kind'), function()
return v.kind ~= 'm'
end, true)
end,
}, { replace = 0 }),
function(_, v)
return vim9.ops.Or(
vim9.ops.Or(
vim9.prefix['Bang'](vim9.fn.has_key(v, 'static')),
vim9.prefix['Bang'](vim9.index(v, 'static'))
),
vim9.fn.bufnr('%') == vim9.fn.bufnr(vim9.index(v, 'filename'))
)
end,
}, { replace = 0 })
res = vim9.fn.extend(
res,
vim9.fn.map(tags, function(_, v)
return Tag2item(v)
end)
)
end
if vim9.fn.len(res) == 0 then
-- # Find the variable in the tags file(s)
local diclist = vim9.fn.filter(
vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$'),
function(_, v)
return vim9.ternary(vim9.fn.has_key(v, 'kind'), function()
return v.kind ~= 'm'
end, true)
end
)
res = {}
for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do
-- # New ctags has the "typeref" field. Patched version has "typename".
if vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typename')) then
res = vim9.fn.extend(
res,
StructMembers(
vim9.index(vim9.index(diclist, i), 'typename'),
vim9.slice(items, 1, nil),
true
)
)
elseif vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typeref')) then
res = vim9.fn.extend(
res,
StructMembers(
vim9.index(vim9.index(diclist, i), 'typeref'),
vim9.slice(items, 1, nil),
true
)
)
end
-- # For a variable use the command, which must be a search pattern that
-- # shows the declaration of the variable.
if vim9.index(vim9.index(diclist, i), 'kind') == 'v' then
local line = vim9.index(vim9.index(diclist, i), 'cmd')
if vim9.slice(line, nil, 1) == '/^' then
local col =
vim9.fn.charidx(line, vim9.fn.match(line, '\\<' .. vim9.index(items, 0) .. '\\>'))
res = vim9.fn.extend(
res,
Nextitem(
vim9.slice(line, 2, vim9.ops.Minus(col, 1)),
vim9.slice(items, 1, nil),
0,
true
)
)
end
end
end
end
if vim9.fn.len(res) == 0 and vim9.fn.searchdecl(vim9.index(items, 0), true) == 0 then
-- # Found, now figure out the type.
-- # TODO: join previous line if it makes sense
local line = vim9.fn.getline('.')
local col = vim9.fn.charcol('.')
res =
Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true)
end
-- # If the last item(s) are [...] they need to be added to the matches.
local last = vim9.fn.len(items) - 1
local brackets = ''
while last >= 0 do
if vim9.index(vim9.index(items, last), 0) ~= '[' then
break
end
brackets = vim9.index(items, last) .. brackets
last = last - 1
end
return vim9.fn.map(res, function(_, v)
return Tagline2item(v, brackets)
end)
end
M['Complete'] = Complete
GetAddition = function(line, match, memarg, bracket)
bracket = vim9.bool(bracket)
-- # Guess if the item is an array.
if vim9.bool(vim9.ops.And(bracket, vim9.fn.match(line, match .. '\\s*\\[') > 0)) then
return '['
end
-- # Check if the item has members.
if vim9.fn.len(SearchMembers(memarg, { '' }, false)) > 0 then
-- # If there is a '*' before the name use "->".
if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then
return '->'
else
return '.'
end
end
return ''
end
Tag2item = function(val)
-- # Turn the tag info "val" into an item for completion.
-- # "val" is is an item in the list returned by taglist().
-- # If it is a variable we may add "." or "->". Don't do it for other types,
-- # such as a typedef, by not including the info that GetAddition() uses.
local res = vim9.convert.decl_dict({ ['match'] = vim9.index(val, 'name') })
res[vim9.index_expr('extra')] =
Tagcmd2extra(vim9.index(val, 'cmd'), vim9.index(val, 'name'), vim9.index(val, 'filename'))
local s = Dict2info(val)
if s ~= '' then
res[vim9.index_expr('info')] = s
end
res[vim9.index_expr('tagline')] = ''
if vim9.bool(vim9.fn.has_key(val, 'kind')) then
local kind = vim9.index(val, 'kind')
res[vim9.index_expr('kind')] = kind
if kind == 'v' then
res[vim9.index_expr('tagline')] = '\t' .. vim9.index(val, 'cmd')
res[vim9.index_expr('dict')] = val
elseif vim9.bool(kind == 'f') then
res[vim9.index_expr('match')] = vim9.index(val, 'name') .. '('
end
end
return res
end
Dict2info = function(dict)
-- # Use all the items in dictionary for the "info" entry.
local info = ''
for _, k in vim9.iter(vim9.fn_mut('sort', { vim9.fn.keys(dict) }, { replace = 0 })) do
info = info .. k .. vim9.fn['repeat'](' ', 10 - vim9.fn.strlen(k))
if k == 'cmd' then
info = info
.. vim9.fn.substitute(
vim9.fn.matchstr(vim9.index(dict, 'cmd'), '/^\\s*\\zs.*\\ze$/'),
'\\\\\\(.\\)',
'\\1',
'g'
)
else
local dictk = vim9.index(dict, k)
if vim9.fn.typename(dictk) ~= 'string' then
info = info .. vim9.fn.string(dictk)
else
info = info .. dictk
end
end
info = info .. '\n'
end
return info
end
ParseTagline = function(line)
-- # Parse a tag line and return a dictionary with items like taglist()
local l = vim9.fn.split(line, '\t')
local d = vim.empty_dict()
if vim9.fn.len(l) >= 3 then
d[vim9.index_expr('name')] = vim9.index(l, 0)
d[vim9.index_expr('filename')] = vim9.index(l, 1)
d[vim9.index_expr('cmd')] = vim9.index(l, 2)
local n = 2
if vim9.ops.RegexpMatches(vim9.index(l, 2), '^/') then
-- # Find end of cmd, it may contain Tabs.
while n < vim9.fn.len(l) and vim9.ops.NotRegexpMatches(vim9.index(l, n), '/;"$') do
n = n + 1
d[vim9.index_expr('cmd')] = vim9.index(d, 'cmd') .. ' ' .. vim9.index(l, n)
end
end
for _, i in vim9.iter(vim9.fn.range(vim9.ops.Plus(n, 1), vim9.fn.len(l) - 1)) do
if vim9.index(l, i) == 'file:' then
d[vim9.index_expr('static')] = 1
elseif vim9.bool(vim9.ops.NotRegexpMatches(vim9.index(l, i), ':')) then
d[vim9.index_expr('kind')] = vim9.index(l, i)
else
d[vim9.index_expr(vim9.fn.matchstr(vim9.index(l, i), '[^:]*'))] =
vim9.fn.matchstr(vim9.index(l, i), ':\\zs.*')
end
end
end
return d
end
Tagline2item = function(val, brackets)
-- # Turn a match item "val" into an item for completion.
-- # "val['match']" is the matching item.
-- # "val['tagline']" is the tagline in which the last part was found.
local line = vim9.index(val, 'tagline')
local add = GetAddition(line, vim9.index(val, 'match'), { val }, brackets == '')
local res = vim9.convert.decl_dict({ ['word'] = vim9.index(val, 'match') .. brackets .. add })
if vim9.bool(vim9.fn.has_key(val, 'info')) then
-- # Use info from Tag2item().
res[vim9.index_expr('info')] = vim9.index(val, 'info')
else
-- # Parse the tag line and add each part to the "info" entry.
local s = Dict2info(ParseTagline(line))
if s ~= '' then
res[vim9.index_expr('info')] = s
end
end
if vim9.bool(vim9.fn.has_key(val, 'kind')) then
res[vim9.index_expr('kind')] = vim9.index(val, 'kind')
elseif vim9.bool(add == '(') then
res[vim9.index_expr('kind')] = 'f'
else
local s = vim9.fn.matchstr(line, '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)')
if s ~= '' then
res[vim9.index_expr('kind')] = s
end
end
if vim9.bool(vim9.fn.has_key(val, 'extra')) then
res[vim9.index_expr('menu')] = vim9.index(val, 'extra')
return res
end
-- # Isolate the command after the tag and filename.
local s = vim9.fn.matchstr(
line,
'[^\\t]*\\t[^\\t]*\\t\\zs\\(/^.*$/\\|[^\\t]*\\)\\ze\\(;"\\t\\|\\t\\|$\\)'
)
if s ~= '' then
res[vim9.index_expr('menu')] = Tagcmd2extra(
s,
vim9.index(val, 'match'),
vim9.fn.matchstr(line, '[^\\t]*\\t\\zs[^\\t]*\\ze\\t')
)
end
return res
end
Tagcmd2extra = function(cmd, name, fname)
-- # Turn a command from a tag line to something that is useful in the menu
local x = ''
if vim9.ops.RegexpMatches(cmd, '^/^') then
-- # The command is a search command, useful to see what it is.
x = vim9.fn.substitute(
vim9.fn.substitute(
vim9.fn.matchstr(cmd, '^/^\\s*\\zs.*\\ze$/'),
'\\<' .. name .. '\\>',
'@@',
''
),
'\\\\\\(.\\)',
'\\1',
'g'
) .. ' - ' .. fname
elseif vim9.bool(vim9.ops.RegexpMatches(cmd, '^\\d*$')) then
-- # The command is a line number, the file name is more useful.
x = fname .. ' - ' .. cmd
else
-- # Not recognized, use command and file name.
x = cmd .. ' - ' .. fname
end
return x
end
Nextitem = function(lead, items, depth, all)
all = vim9.bool(all)
-- # Find composing type in "lead" and match items[0] with it.
-- # Repeat this recursively for items[1], if it's there.
-- # When resolving typedefs "depth" is used to avoid infinite recursion.
-- # Return the list of matches.
-- # Use the text up to the variable name and split it in tokens.
local tokens = vim9.fn.split(lead, '\\s\\+\\|\\<')
-- # Try to recognize the type of the variable. This is rough guessing...
local res = {}
local body = function(_, tidx)
-- # Skip tokens starting with a non-ID character.
if vim9.ops.NotRegexpMatches(vim9.index(tokens, tidx), '^\\h') then
return vim9.ITER_CONTINUE
end
-- # Recognize "struct foobar" and "union foobar".
-- # Also do "class foobar" when it's C++ after all (doesn't work very well
-- # though).
if
(
vim9.index(tokens, tidx) == 'struct'
or vim9.index(tokens, tidx) == 'union'
or vim9.index(tokens, tidx) == 'class'
) and vim9.ops.Plus(tidx, 1) < vim9.fn.len(tokens)
then
res = StructMembers(
vim9.index(tokens, tidx) .. ':' .. vim9.index(tokens, vim9.ops.Plus(tidx, 1)),
items,
all
)
return vim9.ITER_BREAK
end
-- # TODO: add more reserved words
if
vim9.fn.index(
{ 'int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern' },
vim9.index(tokens, tidx)
) >= 0
then
return vim9.ITER_CONTINUE
end
-- # Use the tags file to find out if this is a typedef.
local diclist = vim9.fn.taglist('^' .. vim9.index(tokens, tidx) .. '$')
local body = function(_, tagidx)
local item = vim9.convert.decl_dict(vim9.index(diclist, tagidx))
-- # New ctags has the "typeref" field. Patched version has "typename".
if vim9.bool(vim9.fn.has_key(item, 'typeref')) then
res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typeref'), items, all))
return vim9.ITER_CONTINUE
end
if vim9.bool(vim9.fn.has_key(item, 'typename')) then
res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typename'), items, all))
return vim9.ITER_CONTINUE
end
-- # Only handle typedefs here.
if vim9.index(item, 'kind') ~= 't' then
return vim9.ITER_CONTINUE
end
-- # Skip matches local to another file.
if
vim9.bool(
vim9.ops.And(
vim9.ops.And(vim9.fn.has_key(item, 'static'), vim9.index(item, 'static')),
vim9.fn.bufnr('%') ~= vim9.fn.bufnr(vim9.index(item, 'filename'))
)
)
then
return vim9.ITER_CONTINUE
end
-- # For old ctags we recognize "typedef struct aaa" and
-- # "typedef union bbb" in the tags file command.
local cmd = vim9.index(item, 'cmd')
local ei = vim9.fn.charidx(cmd, vim9.fn.matchend(cmd, 'typedef\\s\\+'))
if ei > 1 then
local cmdtokens = vim9.fn.split(vim9.slice(cmd, ei, nil), '\\s\\+\\|\\<')
if vim9.fn.len(cmdtokens) > 1 then
if
vim9.index(cmdtokens, 0) == 'struct'
or vim9.index(cmdtokens, 0) == 'union'
or vim9.index(cmdtokens, 0) == 'class'
then
local name = ''
-- # Use the first identifier after the "struct" or "union"
for _, ti in vim9.iter(vim9.fn.range((vim9.fn.len(cmdtokens) - 1))) do
if vim9.ops.RegexpMatches(vim9.index(cmdtokens, ti), '^\\w') then
name = vim9.index(cmdtokens, ti)
break
end
end
if name ~= '' then
res = vim9.fn.extend(
res,
StructMembers(vim9.index(cmdtokens, 0) .. ':' .. name, items, all)
)
end
elseif vim9.bool(depth < 10) then
-- # Could be "typedef other_T some_T".
res = vim9.fn.extend(
res,
Nextitem(vim9.index(cmdtokens, 0), items, vim9.ops.Plus(depth, 1), all)
)
end
end
end
return vim9.ITER_DEFAULT
end
for _, tagidx in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do
local nvim9_status, nvim9_ret = body(_, tagidx)
if nvim9_status == vim9.ITER_BREAK then
break
elseif nvim9_status == vim9.ITER_RETURN then
return nvim9_ret
end
end
if vim9.fn.len(res) > 0 then
return vim9.ITER_BREAK
end
return vim9.ITER_DEFAULT
end
for _, tidx in vim9.iter(vim9.fn.range(vim9.fn.len(tokens))) do
local nvim9_status, nvim9_ret = body(_, tidx)
if nvim9_status == vim9.ITER_BREAK then
break
elseif nvim9_status == vim9.ITER_RETURN then
return nvim9_ret
end
end
return res
end
StructMembers = function(atypename, items, all)
all = vim9.bool(all)
-- # Search for members of structure "typename" in tags files.
-- # Return a list with resulting matches.
-- # Each match is a dictionary with "match" and "tagline" entries.
-- # When "all" is true find all, otherwise just return 1 if there is any member.
-- # Todo: What about local structures?
local fnames = vim9.fn.join(vim9.fn.map(vim9.fn.tagfiles(), function(_, v)
return vim9.fn.escape(v, ' \\#%')
end))
if fnames == '' then
return {}
end
local typename = atypename
local qflist = {}
local cached = 0
local n = ''
if vim9.bool(vim9.prefix['Bang'](all)) then
n = '1'
if vim9.bool(vim9.fn.has_key(grepCache, typename)) then
qflist = vim9.index(grepCache, typename)
cached = 1
end
else
n = ''
end
if vim9.bool(vim9.prefix['Bang'](cached)) then
while 1 do
vim.api.nvim_command(
'silent! keepjumps noautocmd '
.. n
.. 'vimgrep '
.. '/\\t'
.. typename
.. '\\(\\t\\|$\\)/j '
.. fnames
)
qflist = vim9.fn.getqflist()
if vim9.fn.len(qflist) > 0 or vim9.fn.match(typename, '::') < 0 then
break
end
-- # No match for "struct:context::name", remove "context::" and try again.
typename = vim9.fn.substitute(typename, ':[^:]*::', ':', '')
end
if vim9.bool(vim9.prefix['Bang'](all)) then
-- # Store the result to be able to use it again later.
grepCache[vim9.index_expr(typename)] = qflist
end
end
-- # Skip over [...] items
local idx = 0
local target = ''
while 1 do
if idx >= vim9.fn.len(items) then
target = ''
break
end
if vim9.index(vim9.index(items, idx), 0) ~= '[' then
target = vim9.index(items, idx)
break
end
idx = idx + 1
end
-- # Put matching members in matches[].
local matches = {}
for _, l in vim9.iter(qflist) do
local memb = vim9.fn.matchstr(vim9.index(l, 'text'), '[^\\t]*')
if vim9.ops.RegexpMatches(memb, '^' .. target) then
-- # Skip matches local to another file.
if
vim9.fn.match(vim9.index(l, 'text'), '\tfile:') < 0
or vim9.fn.bufnr('%')
== vim9.fn.bufnr(vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\zs[^\\t]*'))
then
local item =
vim9.convert.decl_dict({ ['match'] = memb, ['tagline'] = vim9.index(l, 'text') })
-- # Add the kind of item.
local s =
vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)')
if s ~= '' then
item[vim9.index_expr('kind')] = s
if s == 'f' then
item[vim9.index_expr('match')] = memb .. '('
end
end
vim9.fn.add(matches, item)
end
end
end
if vim9.fn.len(matches) > 0 then
-- # Skip over next [...] items
idx = idx + 1
while 1 do
if idx >= vim9.fn.len(items) then
return matches
end
if vim9.index(vim9.index(items, idx), 0) ~= '[' then
break
end
idx = idx + 1
end
-- # More items following. For each of the possible members find the
-- # matching following members.
return SearchMembers(matches, vim9.slice(items, idx, nil), all)
end
-- # Failed to find anything.
return {}
end
SearchMembers = function(matches, items, all)
all = vim9.bool(all)
-- # For matching members, find matches for following items.
-- # When "all" is true find all, otherwise just return 1 if there is any member.
local res = {}
for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(matches))) do
local typename = ''
local line = ''
if vim9.bool(vim9.fn.has_key(vim9.index(matches, i), 'dict')) then
if vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typename')) then
typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typename')
elseif vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')) then
typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')
end
line = '\t' .. vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'cmd')
else
line = vim9.index(vim9.index(matches, i), 'tagline')
local eb = vim9.fn.matchend(line, '\\ttypename:')
local e = vim9.fn.charidx(line, eb)
if e < 0 then
eb = vim9.fn.matchend(line, '\\ttyperef:')
e = vim9.fn.charidx(line, eb)
end
if e > 0 then
-- # Use typename field
typename = vim9.fn.matchstr(line, '[^\\t]*', eb)
end
end
if typename ~= '' then
res = vim9.fn.extend(res, StructMembers(typename, items, all))
else
-- # Use the search command (the declaration itself).
local sb = vim9.fn.match(line, '\\t\\zs/^')
local s = vim9.fn.charidx(line, sb)
if s > 0 then
local e = vim9.fn.charidx(
line,
vim9.fn.match(line, '\\<' .. vim9.index(vim9.index(matches, i), 'match') .. '\\>', sb)
)
if e > 0 then
res =
vim9.fn.extend(res, Nextitem(vim9.slice(line, s, vim9.ops.Minus(e, 1)), items, 0, all))
end
end
end
if vim9.bool(vim9.ops.And(vim9.prefix['Bang'](all), vim9.fn.len(res) > 0)) then
break
end
end
return res
end
-- #}}}1
-- # vim: noet sw=2 sts=2
return M

View File

@@ -1,682 +1,8 @@
" Vim completion script " Generated vim file by vim9jit. Please do not edit
" Language: C let s:path = expand("<script>")
" Maintainer: Bram Moolenaar <Bram@vim.org> let s:lua_path = fnamemodify(s:path, ":r") . ".lua"
" Last Change: 2020 Nov 14 let s:nvim_module = luaeval('require("_vim9script").autoload(_A)', s:lua_path)
let s:cpo_save = &cpo function! ccomplete#Complete(findstart, abase) abort
set cpo&vim return s:nvim_module.Complete(a:findstart, a:abase)
endfunction
" This function is used for the 'omnifunc' option.
func ccomplete#Complete(findstart, base)
if a:findstart
" Locate the start of the item, including ".", "->" and "[...]".
let line = getline('.')
let start = col('.') - 1
let lastword = -1
while start > 0
if line[start - 1] =~ '\w'
let start -= 1
elseif line[start - 1] =~ '\.'
if lastword == -1
let lastword = start
endif
let start -= 1
elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
if lastword == -1
let lastword = start
endif
let start -= 2
elseif line[start - 1] == ']'
" Skip over [...].
let n = 0
let start -= 1
while start > 0
let start -= 1
if line[start] == '['
if n == 0
break
endif
let n -= 1
elseif line[start] == ']' " nested []
let n += 1
endif
endwhile
else
break
endif
endwhile
" Return the column of the last word, which is going to be changed.
" Remember the text that comes before it in s:prepended.
if lastword == -1
let s:prepended = ''
return start
endif
let s:prepended = strpart(line, start, lastword - start)
return lastword
endif
" Return list of matches.
let base = s:prepended . a:base
" Don't do anything for an empty base, would result in all the tags in the
" tags file.
if base == ''
return []
endif
" init cache for vimgrep to empty
let s:grepCache = {}
" Split item in words, keep empty word after "." or "->".
" "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
" We can't use split, because we need to skip nested [...].
" "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc.
let items = []
let s = 0
let arrays = 0
while 1
let e = match(base, '\.\|->\|\[', s)
if e < 0
if s == 0 || base[s - 1] != ']'
call add(items, strpart(base, s))
endif
break
endif
if s == 0 || base[s - 1] != ']'
call add(items, strpart(base, s, e - s))
endif
if base[e] == '.'
let s = e + 1 " skip over '.'
elseif base[e] == '-'
let s = e + 2 " skip over '->'
else
" Skip over [...].
let n = 0
let s = e
let e += 1
while e < len(base)
if base[e] == ']'
if n == 0
break
endif
let n -= 1
elseif base[e] == '[' " nested [...]
let n += 1
endif
let e += 1
endwhile
let e += 1
call add(items, strpart(base, s, e - s))
let arrays += 1
let s = e
endif
endwhile
if complete_check()
" return v:none
return []
endif
" Find the variable items[0].
" 1. in current function (like with "gd")
" 2. in tags file(s) (like with ":tag")
" 3. in current file (like with "gD")
let res = []
if searchdecl(items[0], 0, 1) == 0
" Found, now figure out the type.
" TODO: join previous line if it makes sense
let line = getline('.')
let col = col('.')
if stridx(strpart(line, 0, col), ';') != -1
" Handle multiple declarations on the same line.
let col2 = col - 1
while line[col2] != ';'
if complete_check()
return res
endif
let col2 -= 1
endwhile
let line = strpart(line, col2 + 1)
let col -= col2
endif
if stridx(strpart(line, 0, col), ',') != -1
" Handle multiple declarations on the same line in a function
" declaration.
let col2 = col - 1
while line[col2] != ','
if complete_check()
return res
endif
let col2 -= 1
endwhile
if strpart(line, col2 + 1, col - col2 - 1) =~ ' *[^ ][^ ]* *[^ ]'
let line = strpart(line, col2 + 1)
let col -= col2
endif
endif
if len(items) == 1
" Completing one word and it's a local variable: May add '[', '.' or
" '->'.
let match = items[0]
let kind = 'v'
if match(line, '\<' . match . '\s*\[') > 0
let match .= '['
else
let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1)
if len(res) > 0
" There are members, thus add "." or "->".
if match(line, '\*[ \t(]*' . match . '\>') > 0
let match .= '->'
else
let match .= '.'
endif
endif
endif
let res = [{'match': match, 'tagline' : '', 'kind' : kind, 'info' : line}]
elseif len(items) == arrays + 1
" Completing one word and it's a local array variable: build tagline
" from declaration line
let match = items[0]
let kind = 'v'
let tagline = "\t/^" . line . '$/'
let res = [{'match': match, 'tagline' : tagline, 'kind' : kind, 'info' : line}]
else
" Completing "var.", "var.something", etc.
let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
endif
endif
if len(items) == 1 || len(items) == arrays + 1
" Only one part, no "." or "->": complete from tags file.
if len(items) == 1
let tags = taglist('^' . base)
else
let tags = taglist('^' . items[0] . '$')
endif
" Remove members, these can't appear without something in front.
call filter(tags, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
" Remove static matches in other files.
call filter(tags, '!has_key(v:val, "static") || !v:val["static"] || bufnr("%") == bufnr(v:val["filename"])')
call extend(res, map(tags, 's:Tag2item(v:val)'))
endif
if len(res) == 0
" Find the variable in the tags file(s)
let diclist = taglist('^' . items[0] . '$')
" Remove members, these can't appear without something in front.
call filter(diclist, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
let res = []
for i in range(len(diclist))
if complete_check()
return res
endif
" New ctags has the "typeref" field. Patched version has "typename".
if has_key(diclist[i], 'typename')
call extend(res, s:StructMembers(diclist[i]['typename'], items[1:], 1))
elseif has_key(diclist[i], 'typeref')
call extend(res, s:StructMembers(diclist[i]['typeref'], items[1:], 1))
endif
" For a variable use the command, which must be a search pattern that
" shows the declaration of the variable.
if diclist[i]['kind'] == 'v'
let line = diclist[i]['cmd']
if line[0] == '/' && line[1] == '^'
let col = match(line, '\<' . items[0] . '\>')
call extend(res, s:Nextitem(strpart(line, 2, col - 2), items[1:], 0, 1))
endif
endif
endfor
endif
if len(res) == 0 && searchdecl(items[0], 1) == 0
" Found, now figure out the type.
" TODO: join previous line if it makes sense
let line = getline('.')
let col = col('.')
let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
endif
" If the last item(s) are [...] they need to be added to the matches.
let last = len(items) - 1
let brackets = ''
while last >= 0
if complete_check()
return res
endif
if items[last][0] != '['
break
endif
let brackets = items[last] . brackets
let last -= 1
endwhile
return map(res, 's:Tagline2item(v:val, brackets)')
endfunc
func s:GetAddition(line, match, memarg, bracket)
" Guess if the item is an array.
if a:bracket && match(a:line, a:match . '\s*\[') > 0
return '['
endif
" Check if the item has members.
if len(s:SearchMembers(a:memarg, [''], 0)) > 0
" If there is a '*' before the name use "->".
if match(a:line, '\*[ \t(]*' . a:match . '\>') > 0
return '->'
else
return '.'
endif
endif
return ''
endfunc
" Turn the tag info "val" into an item for completion.
" "val" is is an item in the list returned by taglist().
" If it is a variable we may add "." or "->". Don't do it for other types,
" such as a typedef, by not including the info that s:GetAddition() uses.
func s:Tag2item(val)
let res = {'match': a:val['name']}
let res['extra'] = s:Tagcmd2extra(a:val['cmd'], a:val['name'], a:val['filename'])
let s = s:Dict2info(a:val)
if s != ''
let res['info'] = s
endif
let res['tagline'] = ''
if has_key(a:val, "kind")
let kind = a:val['kind']
let res['kind'] = kind
if kind == 'v'
let res['tagline'] = "\t" . a:val['cmd']
let res['dict'] = a:val
elseif kind == 'f'
let res['match'] = a:val['name'] . '('
endif
endif
return res
endfunc
" Use all the items in dictionary for the "info" entry.
func s:Dict2info(dict)
let info = ''
for k in sort(keys(a:dict))
if complete_check()
return info
endif
let info .= k . repeat(' ', 10 - len(k))
if k == 'cmd'
let info .= substitute(matchstr(a:dict['cmd'], '/^\s*\zs.*\ze$/'), '\\\(.\)', '\1', 'g')
else
let info .= a:dict[k]
endif
let info .= "\n"
endfor
return info
endfunc
" Parse a tag line and return a dictionary with items like taglist()
func s:ParseTagline(line)
let l = split(a:line, "\t")
let d = {}
if len(l) >= 3
let d['name'] = l[0]
let d['filename'] = l[1]
let d['cmd'] = l[2]
let n = 2
if l[2] =~ '^/'
" Find end of cmd, it may contain Tabs.
while n < len(l) && l[n] !~ '/;"$'
let n += 1
let d['cmd'] .= " " . l[n]
endwhile
endif
for i in range(n + 1, len(l) - 1)
if complete_check()
return d
endif
if l[i] == 'file:'
let d['static'] = 1
elseif l[i] !~ ':'
let d['kind'] = l[i]
else
let d[matchstr(l[i], '[^:]*')] = matchstr(l[i], ':\zs.*')
endif
endfor
endif
return d
endfunc
" Turn a match item "val" into an item for completion.
" "val['match']" is the matching item.
" "val['tagline']" is the tagline in which the last part was found.
func s:Tagline2item(val, brackets)
let line = a:val['tagline']
let add = s:GetAddition(line, a:val['match'], [a:val], a:brackets == '')
let res = {'word': a:val['match'] . a:brackets . add }
if has_key(a:val, 'info')
" Use info from Tag2item().
let res['info'] = a:val['info']
else
" Parse the tag line and add each part to the "info" entry.
let s = s:Dict2info(s:ParseTagline(line))
if s != ''
let res['info'] = s
endif
endif
if has_key(a:val, 'kind')
let res['kind'] = a:val['kind']
elseif add == '('
let res['kind'] = 'f'
else
let s = matchstr(line, '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
if s != ''
let res['kind'] = s
endif
endif
if has_key(a:val, 'extra')
let res['menu'] = a:val['extra']
return res
endif
" Isolate the command after the tag and filename.
let s = matchstr(line, '[^\t]*\t[^\t]*\t\zs\(/^.*$/\|[^\t]*\)\ze\(;"\t\|\t\|$\)')
if s != ''
let res['menu'] = s:Tagcmd2extra(s, a:val['match'], matchstr(line, '[^\t]*\t\zs[^\t]*\ze\t'))
endif
return res
endfunc
" Turn a command from a tag line to something that is useful in the menu
func s:Tagcmd2extra(cmd, name, fname)
if a:cmd =~ '^/^'
" The command is a search command, useful to see what it is.
let x = matchstr(a:cmd, '^/^\s*\zs.*\ze$/')
let x = substitute(x, '\<' . a:name . '\>', '@@', '')
let x = substitute(x, '\\\(.\)', '\1', 'g')
let x = x . ' - ' . a:fname
elseif a:cmd =~ '^\d*$'
" The command is a line number, the file name is more useful.
let x = a:fname . ' - ' . a:cmd
else
" Not recognized, use command and file name.
let x = a:cmd . ' - ' . a:fname
endif
return x
endfunc
" Find composing type in "lead" and match items[0] with it.
" Repeat this recursively for items[1], if it's there.
" When resolving typedefs "depth" is used to avoid infinite recursion.
" Return the list of matches.
func s:Nextitem(lead, items, depth, all)
" Use the text up to the variable name and split it in tokens.
let tokens = split(a:lead, '\s\+\|\<')
" Try to recognize the type of the variable. This is rough guessing...
let res = []
for tidx in range(len(tokens))
if complete_check()
return res
endif
" Skip tokens starting with a non-ID character.
if tokens[tidx] !~ '^\h'
continue
endif
" Recognize "struct foobar" and "union foobar".
" Also do "class foobar" when it's C++ after all (doesn't work very well
" though).
if (tokens[tidx] == 'struct' || tokens[tidx] == 'union' || tokens[tidx] == 'class') && tidx + 1 < len(tokens)
let res = s:StructMembers(tokens[tidx] . ':' . tokens[tidx + 1], a:items, a:all)
break
endif
" TODO: add more reserved words
if index(['int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern'], tokens[tidx]) >= 0
continue
endif
" Use the tags file to find out if this is a typedef.
let diclist = taglist('^' . tokens[tidx] . '$')
for tagidx in range(len(diclist))
if complete_check()
return res
endif
let item = diclist[tagidx]
" New ctags has the "typeref" field. Patched version has "typename".
if has_key(item, 'typeref')
call extend(res, s:StructMembers(item['typeref'], a:items, a:all))
continue
endif
if has_key(item, 'typename')
call extend(res, s:StructMembers(item['typename'], a:items, a:all))
continue
endif
" Only handle typedefs here.
if item['kind'] != 't'
continue
endif
" Skip matches local to another file.
if has_key(item, 'static') && item['static'] && bufnr('%') != bufnr(item['filename'])
continue
endif
" For old ctags we recognize "typedef struct aaa" and
" "typedef union bbb" in the tags file command.
let cmd = item['cmd']
let ei = matchend(cmd, 'typedef\s\+')
if ei > 1
let cmdtokens = split(strpart(cmd, ei), '\s\+\|\<')
if len(cmdtokens) > 1
if cmdtokens[0] == 'struct' || cmdtokens[0] == 'union' || cmdtokens[0] == 'class'
let name = ''
" Use the first identifier after the "struct" or "union"
for ti in range(len(cmdtokens) - 1)
if cmdtokens[ti] =~ '^\w'
let name = cmdtokens[ti]
break
endif
endfor
if name != ''
call extend(res, s:StructMembers(cmdtokens[0] . ':' . name, a:items, a:all))
endif
elseif a:depth < 10
" Could be "typedef other_T some_T".
call extend(res, s:Nextitem(cmdtokens[0], a:items, a:depth + 1, a:all))
endif
endif
endif
endfor
if len(res) > 0
break
endif
endfor
return res
endfunc
" Search for members of structure "typename" in tags files.
" Return a list with resulting matches.
" Each match is a dictionary with "match" and "tagline" entries.
" When "all" is non-zero find all, otherwise just return 1 if there is any
" member.
func s:StructMembers(typename, items, all)
" Todo: What about local structures?
let fnames = join(map(tagfiles(), 'escape(v:val, " \\#%")'))
if fnames == ''
return []
endif
let typename = a:typename
let qflist = []
let cached = 0
if a:all == 0
let n = '1' " stop at first found match
if has_key(s:grepCache, a:typename)
let qflist = s:grepCache[a:typename]
let cached = 1
endif
else
let n = ''
endif
if !cached
while 1
if complete_check()
return []
endif
exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames
let qflist = getqflist()
if len(qflist) > 0 || match(typename, "::") < 0
break
endif
" No match for "struct:context::name", remove "context::" and try again.
let typename = substitute(typename, ':[^:]*::', ':', '')
endwhile
if a:all == 0
" Store the result to be able to use it again later.
let s:grepCache[a:typename] = qflist
endif
endif
" Skip over [...] items
let idx = 0
while 1
if complete_check()
return []
endif
if idx >= len(a:items)
let target = '' " No further items, matching all members
break
endif
if a:items[idx][0] != '['
let target = a:items[idx]
break
endif
let idx += 1
endwhile
" Put matching members in matches[].
let matches = []
for l in qflist
let memb = matchstr(l['text'], '[^\t]*')
if memb =~ '^' . target
" Skip matches local to another file.
if match(l['text'], "\tfile:") < 0 || bufnr('%') == bufnr(matchstr(l['text'], '\t\zs[^\t]*'))
let item = {'match': memb, 'tagline': l['text']}
" Add the kind of item.
let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
if s != ''
let item['kind'] = s
if s == 'f'
let item['match'] = memb . '('
endif
endif
call add(matches, item)
endif
endif
endfor
if len(matches) > 0
" Skip over next [...] items
let idx += 1
while 1
if complete_check()
return matches
endif
if idx >= len(a:items)
return matches " No further items, return the result.
endif
if a:items[idx][0] != '['
break
endif
let idx += 1
endwhile
" More items following. For each of the possible members find the
" matching following members.
return s:SearchMembers(matches, a:items[idx :], a:all)
endif
" Failed to find anything.
return []
endfunc
" For matching members, find matches for following items.
" When "all" is non-zero find all, otherwise just return 1 if there is any
" member.
func s:SearchMembers(matches, items, all)
let res = []
for i in range(len(a:matches))
if complete_check()
return res
endif
let typename = ''
if has_key(a:matches[i], 'dict')
if has_key(a:matches[i].dict, 'typename')
let typename = a:matches[i].dict['typename']
elseif has_key(a:matches[i].dict, 'typeref')
let typename = a:matches[i].dict['typeref']
endif
let line = "\t" . a:matches[i].dict['cmd']
else
let line = a:matches[i]['tagline']
let e = matchend(line, '\ttypename:')
if e < 0
let e = matchend(line, '\ttyperef:')
endif
if e > 0
" Use typename field
let typename = matchstr(line, '[^\t]*', e)
endif
endif
if typename != ''
call extend(res, s:StructMembers(typename, a:items, a:all))
else
" Use the search command (the declaration itself).
let s = match(line, '\t\zs/^')
if s > 0
let e = match(line, '\<' . a:matches[i]['match'] . '\>', s)
if e > 0
call extend(res, s:Nextitem(strpart(line, s, e - s), a:items, 0, a:all))
endif
endif
endif
if a:all == 0 && len(res) > 0
break
endif
endfor
return res
endfunc
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: noet sw=2 sts=2

View File

@@ -2,21 +2,6 @@
" Maintainer: Gregory Anders " Maintainer: Gregory Anders
" Last Change: 2024-09-03 " Last Change: 2024-09-03
" Based on: https://github.com/hashivim/vim-terraform " Based on: https://github.com/hashivim/vim-terraform
" License: ISC
"
" Copyright (c) 2014-2016 Mark Cornick <mark@markcornick.com>
"
" Permission to use, copy, modify, and/or distribute this software for any purpose
" with or without fee is hereby granted, provided that the above copyright notice
" and this permission notice appear in all copies.
"
" THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
" FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
" OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
" THIS SOFTWARE.
function! hcl#indentexpr(lnum) function! hcl#indentexpr(lnum)
" Beginning of the file should have no indent " Beginning of the file should have no indent

View File

@@ -1,192 +0,0 @@
" HTML folding script, :h ft-html-plugin
" Latest Change: 2025 May 10
" Original Author: Aliaksei Budavei <0x000c70@gmail.com>
function! htmlfold#MapBalancedTags() abort
" Describe only _a capturable-name prefix_ for start and end patterns of
" a tag so that start tags with attributes spanning across lines can also be
" matched with a single call of "getline()".
let tag = '\m\c</\=\([0-9A-Za-z-]\+\)'
let names = []
let pairs = []
let ends = []
let pos = getpos('.')
try
call cursor(1, 1)
let [lnum, cnum] = searchpos(tag, 'cnW')
" Pair up nearest non-inlined tags in scope.
while lnum > 0
let name_attr = synIDattr(synID(lnum, cnum, 0), 'name')
if name_attr ==# 'htmlTag' || name_attr ==# 'htmlScriptTag'
let name = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
if !empty(name)
call insert(names, tolower(name), 0)
call insert(pairs, [lnum, -1], 0)
endif
elseif name_attr ==# 'htmlEndTag'
let name = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
if !empty(name)
let idx = index(names, tolower(name))
if idx >= 0
" Dismiss inlined balanced tags and opened-only tags.
if pairs[idx][0] != lnum
let pairs[idx][1] = lnum
call add(ends, lnum)
endif
" Claim a pair.
let names[: idx] = repeat([''], (idx + 1))
endif
endif
endif
" Advance the cursor, at "<", past "</a", "<a>", etc.
call cursor(lnum, (cnum + 3))
let [lnum, cnum] = searchpos(tag, 'cnW')
endwhile
finally
call setpos('.', pos)
endtry
if empty(ends)
return {}
endif
let folds = {}
let pending_end = ends[0]
let level = 0
while !empty(pairs)
let [start, end] = remove(pairs, -1)
if end < 0
continue
endif
if start >= pending_end
" Mark a sibling tag.
call remove(ends, 0)
while start >= ends[0]
" Mark a parent tag.
call remove(ends, 0)
let level -= 1
endwhile
let pending_end = ends[0]
else
" Mark a child tag.
let level += 1
endif
" Flatten the innermost inlined folds.
let folds[start] = get(folds, start, ('>' . level))
let folds[end] = get(folds, end, ('<' . level))
endwhile
return folds
endfunction
" See ":help vim9-mix".
if !has("vim9script")
finish
endif
def! g:htmlfold#MapBalancedTags(): dict<string>
# Describe only _a capturable-name prefix_ for start and end patterns of
# a tag so that start tags with attributes spanning across lines can also be
# matched with a single call of "getline()".
const tag: string = '\m\c</\=\([0-9A-Za-z-]\+\)'
var names: list<string> = []
var pairs: list<list<number>> = []
var ends: list<number> = []
const pos: list<number> = getpos('.')
try
cursor(1, 1)
var [lnum: number, cnum: number] = searchpos(tag, 'cnW')
# Pair up nearest non-inlined tags in scope.
while lnum > 0
const name_attr: string = synIDattr(synID(lnum, cnum, 0), 'name')
if name_attr ==# 'htmlTag' || name_attr ==# 'htmlScriptTag'
const name: string = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
if !empty(name)
insert(names, tolower(name), 0)
insert(pairs, [lnum, -1], 0)
endif
elseif name_attr ==# 'htmlEndTag'
const name: string = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
if !empty(name)
const idx: number = index(names, tolower(name))
if idx >= 0
# Dismiss inlined balanced tags and opened-only tags.
if pairs[idx][0] != lnum
pairs[idx][1] = lnum
add(ends, lnum)
endif
# Claim a pair.
names[: idx] = repeat([''], (idx + 1))
endif
endif
endif
# Advance the cursor, at "<", past "</a", "<a>", etc.
cursor(lnum, (cnum + 3))
[lnum, cnum] = searchpos(tag, 'cnW')
endwhile
finally
setpos('.', pos)
endtry
if empty(ends)
return {}
endif
var folds: dict<string> = {}
var pending_end: number = ends[0]
var level: number = 0
while !empty(pairs)
const [start: number, end: number] = remove(pairs, -1)
if end < 0
continue
endif
if start >= pending_end
# Mark a sibling tag.
remove(ends, 0)
while start >= ends[0]
# Mark a parent tag.
remove(ends, 0)
level -= 1
endwhile
pending_end = ends[0]
else
# Mark a child tag.
level += 1
endif
# Flatten the innermost inlined folds.
folds[start] = get(folds, start, ('>' .. level))
folds[end] = get(folds, end, ('<' .. level))
endwhile
return folds
enddef
" vim: fdm=syntax sw=2 ts=8 noet

View File

@@ -85,10 +85,10 @@ function! s:set_wayland() abort
endfunction endfunction
function! s:set_wayclip() abort function! s:set_wayclip() abort
let s:copy['+'] = ['waycopy'] let s:copy['+'] = ['waycopy', '-t', 'text/plain']
let s:paste['+'] = ['waypaste'] let s:paste['+'] = ['waypaste', '-t', 'text/plain']
let s:copy['*'] = ['waycopy', '-p'] let s:copy['*'] = s:copy['+']
let s:paste['*'] = ['waypaste', '-p'] let s:paste['*'] = s:paste['+']
return 'wayclip' return 'wayclip'
endfunction endfunction
@@ -268,11 +268,13 @@ function! provider#clipboard#Executable() abort
endfunction endfunction
function! s:clipboard.get(reg) abort function! s:clipboard.get(reg) abort
if s:selections[a:reg].owner > 0 if type(s:paste[a:reg]) == v:t_func
return s:paste[a:reg]()
elseif s:selections[a:reg].owner > 0
return s:selections[a:reg].data return s:selections[a:reg].data
end end
let clipboard_data = type(s:paste[a:reg]) == v:t_func ? s:paste[a:reg]() : s:try_cmd(s:paste[a:reg]) let clipboard_data = s:try_cmd(s:paste[a:reg])
if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0 if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0
\ && type(clipboard_data) == v:t_list \ && type(clipboard_data) == v:t_list
\ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data \ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data
@@ -292,12 +294,13 @@ function! s:clipboard.set(lines, regtype, reg) abort
return 0 return 0
end end
if s:cache_enabled == 0 || type(s:copy[a:reg]) == v:t_func if 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)
call s:copy[a:reg](a:lines, a:regtype) return 0
else end
call s:try_cmd(s:copy[a:reg], a:lines)
endif if s:cache_enabled == 0
call s:try_cmd(s:copy[a:reg], a:lines)
"Cache it anyway we can compare it later to get regtype of the yank "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] = copy(s:selection)
let s:selections[a:reg].data = [a:lines, a:regtype] let s:selections[a:reg].data = [a:lines, a:regtype]

View File

@@ -1,8 +1,5 @@
" Author: Stephen Sugden <stephen@stephensugden.com> " Author: Stephen Sugden <stephen@stephensugden.com>
" Last Modified: 2023-09-11 " Last Modified: 2023-09-11
" Last Change:
" 2025 Mar 31 by Vim project (rename s:RustfmtConfigOptions())
" 2025 Jul 14 by Vim project (don't parse rustfmt version automatically #17745)
" "
" Adapted from https://github.com/fatih/vim-go " Adapted from https://github.com/fatih/vim-go
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
@@ -24,12 +21,6 @@ if !exists("g:rustfmt_fail_silently")
endif endif
function! rustfmt#DetectVersion() function! rustfmt#DetectVersion()
let s:rustfmt_version = "0"
let s:rustfmt_help = ""
let s:rustfmt_unstable_features = ""
if !get(g:, 'rustfmt_detect_version', 0)
return s:rustfmt_version
endif
" Save rustfmt '--help' for feature inspection " Save rustfmt '--help' for feature inspection
silent let s:rustfmt_help = system(g:rustfmt_command . " --help") silent let s:rustfmt_help = system(g:rustfmt_command . " --help")
let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features" let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features"
@@ -38,7 +29,9 @@ function! rustfmt#DetectVersion()
silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version") silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version")
let l:rustfmt_version_list = matchlist(l:rustfmt_version_full, let l:rustfmt_version_list = matchlist(l:rustfmt_version_full,
\ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)') \ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)')
if len(l:rustfmt_version_list) >= 3 if len(l:rustfmt_version_list) < 3
let s:rustfmt_version = "0"
else
let s:rustfmt_version = l:rustfmt_version_list[1] let s:rustfmt_version = l:rustfmt_version_list[1]
endif endif
return s:rustfmt_version return s:rustfmt_version
@@ -68,13 +61,7 @@ function! s:RustfmtWriteMode()
endif endif
endfunction endfunction
function! rustfmt#RustfmtConfigOptions() function! s:RustfmtConfigOptions()
let default = '--edition 2018'
if !get(g:, 'rustfmt_find_toml', 0)
return default
endif
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';') let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
if l:rustfmt_toml !=# '' if l:rustfmt_toml !=# ''
return '--config-path '.shellescape(fnamemodify(l:rustfmt_toml, ":p")) return '--config-path '.shellescape(fnamemodify(l:rustfmt_toml, ":p"))
@@ -86,7 +73,7 @@ function! rustfmt#RustfmtConfigOptions()
endif endif
" Default to edition 2018 in case no rustfmt.toml was found. " Default to edition 2018 in case no rustfmt.toml was found.
return default return '--edition 2018'
endfunction endfunction
function! s:RustfmtCommandRange(filename, line1, line2) function! s:RustfmtCommandRange(filename, line1, line2)
@@ -97,7 +84,7 @@ function! s:RustfmtCommandRange(filename, line1, line2)
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
let l:write_mode = s:RustfmtWriteMode() let l:write_mode = s:RustfmtWriteMode()
let l:rustfmt_config = rustfmt#RustfmtConfigOptions() let l:rustfmt_config = s:RustfmtConfigOptions()
" FIXME: When --file-lines gets to be stable, add version range checking " FIXME: When --file-lines gets to be stable, add version range checking
" accordingly. " accordingly.
@@ -112,7 +99,7 @@ endfunction
function! s:RustfmtCommand() function! s:RustfmtCommand()
let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display' let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display'
let config = rustfmt#RustfmtConfigOptions() let config = s:RustfmtConfigOptions()
return join([g:rustfmt_command, write_mode, config, g:rustfmt_options]) return join([g:rustfmt_command, write_mode, config, g:rustfmt_options])
endfunction endfunction

View File

@@ -12,11 +12,6 @@
" 2025 Feb 28 by Vim Project: add support for bzip3 (#16755) " 2025 Feb 28 by Vim Project: add support for bzip3 (#16755)
" 2025 Mar 01 by Vim Project: fix syntax error in tar#Read() " 2025 Mar 01 by Vim Project: fix syntax error in tar#Read()
" 2025 Mar 02 by Vim Project: escape the filename before using :read " 2025 Mar 02 by Vim Project: escape the filename before using :read
" 2025 Mar 02 by Vim Project: determine the compression using readblob()
" instead of shelling out to file(1)
" 2025 Apr 16 by Vim Project: decouple from netrw by adding s:WinPath()
" 2025 May 19 by Vim Project: restore working directory after read/write
" 2025 Jul 13 by Vim Project: warn with path traversal attacks
" "
" Contains many ideas from Michael Toren's <tar.vim> " Contains many ideas from Michael Toren's <tar.vim>
" "
@@ -35,9 +30,9 @@ if &cp || exists("g:loaded_tar")
finish finish
endif endif
let g:loaded_tar= "v32b" let g:loaded_tar= "v32b"
if !has('nvim-0.12') && v:version < 900 if v:version < 702
echohl WarningMsg echohl WarningMsg
echo "***warning*** this version of tar needs vim 9.0" echo "***warning*** this version of tar needs vim 7.2"
echohl Normal echohl Normal
finish finish
endif endif
@@ -47,10 +42,10 @@ set cpo&vim
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
" Default Settings: {{{1 " Default Settings: {{{1
if !exists("g:tar_browseoptions") if !exists("g:tar_browseoptions")
let g:tar_browseoptions= "tf" let g:tar_browseoptions= "Ptf"
endif endif
if !exists("g:tar_readoptions") if !exists("g:tar_readoptions")
let g:tar_readoptions= "pxf" let g:tar_readoptions= "pPxf"
endif endif
if !exists("g:tar_cmd") if !exists("g:tar_cmd")
let g:tar_cmd= "tar" let g:tar_cmd= "tar"
@@ -59,7 +54,6 @@ if !exists("g:tar_writeoptions")
let g:tar_writeoptions= "uf" let g:tar_writeoptions= "uf"
endif endif
if !exists("g:tar_delfile") if !exists("g:tar_delfile")
" Note: not supported on BSD
let g:tar_delfile="--delete -f" let g:tar_delfile="--delete -f"
endif endif
if !exists("g:netrw_cygwin") if !exists("g:netrw_cygwin")
@@ -108,26 +102,10 @@ if !exists("g:tar_shq")
endif endif
endif endif
let g:tar_secure=' -- '
let g:tar_leading_pat='^\%([.]\{,2\}/\)\+'
" ---------------- " ----------------
" Functions: {{{1 " Functions: {{{1
" ---------------- " ----------------
" ---------------------------------------------------------------------
" s:Msg: {{{2
fun! s:Msg(func, severity, msg)
redraw!
if a:severity =~? 'error'
echohl Error
else
echohl WarningMsg
endif
echo $"***{a:severity}*** ({a:func}) {a:msg}"
echohl None
endfunc
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
" tar#Browse: {{{2 " tar#Browse: {{{2
fun! tar#Browse(tarfile) fun! tar#Browse(tarfile)
@@ -136,14 +114,16 @@ fun! tar#Browse(tarfile)
" sanity checks " sanity checks
if !executable(g:tar_cmd) if !executable(g:tar_cmd)
call s:Msg('tar#Browse', 'error', $"{g:tar_cmd} not available on your system") redraw!
echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
let &report= repkeep let &report= repkeep
return return
endif endif
if !filereadable(a:tarfile) if !filereadable(a:tarfile)
if a:tarfile !~# '^\a\+://' if a:tarfile !~# '^\a\+://'
" if it's an url, don't complain, let url-handlers such as vim do its thing " if it's an url, don't complain, let url-handlers such as vim do its thing
call s:Msg('tar#Browse', 'error', $"File not readable<{a:tarfile}>") redraw!
echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None
endif endif
let &report= repkeep let &report= repkeep
return return
@@ -164,7 +144,7 @@ fun! tar#Browse(tarfile)
let lastline= line("$") let lastline= line("$")
call setline(lastline+1,'" tar.vim version '.g:loaded_tar) call setline(lastline+1,'" tar.vim version '.g:loaded_tar)
call setline(lastline+2,'" Browsing tarfile '.a:tarfile) call setline(lastline+2,'" Browsing tarfile '.a:tarfile)
call setline(lastline+3,'" Select a file with cursor and press ENTER, "x" to extract a file') call setline(lastline+3,'" Select a file with cursor and press ENTER')
keepj $put ='' keepj $put =''
keepj sil! 0d keepj sil! 0d
keepj $ keepj $
@@ -181,19 +161,23 @@ fun! tar#Browse(tarfile)
elseif tarfile =~# '\.\(tgz\)$' || tarfile =~# '\.\(tbz\)$' || tarfile =~# '\.\(txz\)$' || elseif tarfile =~# '\.\(tgz\)$' || tarfile =~# '\.\(tbz\)$' || tarfile =~# '\.\(txz\)$' ||
\ tarfile =~# '\.\(tzst\)$' || tarfile =~# '\.\(tlz4\)$' \ tarfile =~# '\.\(tzst\)$' || tarfile =~# '\.\(tlz4\)$'
let header= s:Header(tarfile) if has("unix") && executable("file")
let filekind= system("file ".shellescape(tarfile,1))
else
let filekind= ""
endif
if header =~? 'bzip2' if filekind =~ "bzip2"
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - " exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
elseif header =~? 'bzip3' elseif filekind =~ "bzip3"
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - " exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
elseif header =~? 'xz' elseif filekind =~ "XZ"
exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - " exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
elseif header =~? 'zstd' elseif filekind =~ "Zstandard"
exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - " exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
elseif header =~? 'lz4' elseif filekind =~ "LZ4"
exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - " exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
elseif header =~? 'gzip' else
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - " exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
endif endif
@@ -219,18 +203,28 @@ fun! tar#Browse(tarfile)
exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1) exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1)
endif endif
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Browse', 'warning', $"please check your g:tar_browseoptions '<{g:tar_browseoptions}>'") redraw!
echohl WarningMsg | echo "***warning*** (tar#Browse) please check your g:tar_browseoptions<".g:tar_browseoptions.">"
return return
endif endif
"
" remove tar: Removing leading '/' from member names " The following should not be neccessary, since in case of errors the
" Note: the message could be localized " previous if statement should have caught the problem (because tar exited
if search('^tar: ') > 0 || search(g:tar_leading_pat) > 0 " with a non-zero exit code).
call append(3,'" Note: Path Traversal Attack detected!') " if line("$") == curlast || ( line("$") == (curlast + 1) &&
let b:leading_slash = 1 " \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' &&
" remove the message output " \ getline("$") =~ '\s' )
sil g/^tar: /d " redraw!
endif " echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None
" keepj sil! %d
" let eikeep= &ei
" set ei=BufReadCmd,FileReadCmd
" exe "r ".fnameescape(a:tarfile)
" let &ei= eikeep
" keepj sil! 1d
" call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
" return
" endif
" set up maps supported for tar " set up maps supported for tar
setlocal noma nomod ro setlocal noma nomod ro
@@ -249,7 +243,12 @@ fun! s:TarBrowseSelect()
let repkeep= &report let repkeep= &report
set report=10 set report=10
let fname= getline(".") let fname= getline(".")
let ls= get(b:, 'leading_slash', 0)
if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-'
redraw!
echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"'
return
endif
" sanity check " sanity check
if fname =~ '^"' if fname =~ '^"'
@@ -271,8 +270,7 @@ fun! s:TarBrowseSelect()
wincmd _ wincmd _
endif endif
let s:tblfile_{winnr()}= curfile let s:tblfile_{winnr()}= curfile
let b:leading_slash= ls call tar#Read("tarfile:".tarfile.'::'.fname,1)
call tar#Read("tarfile:".tarfile.'::'.fname)
filetype detect filetype detect
set nomod set nomod
exe 'com! -buffer -nargs=? -complete=file TarDiff :call tar#Diff(<q-args>,"'.fnameescape(fname).'")' exe 'com! -buffer -nargs=? -complete=file TarDiff :call tar#Diff(<q-args>,"'.fnameescape(fname).'")'
@@ -282,18 +280,26 @@ endfun
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
" tar#Read: {{{2 " tar#Read: {{{2
fun! tar#Read(fname) fun! tar#Read(fname,mode)
let repkeep= &report let repkeep= &report
set report=10 set report=10
let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','') let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','')
let fname = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','') let fname = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','')
" be careful not to execute special crafted files " be careful not to execute special crafted files
let escape_file = fname->substitute(g:tar_leading_pat, '', '')->fnameescape() let escape_file = fname->fnameescape()
" changing the directory to the temporary earlier to allow tar to extract the file with permissions intact
if !exists("*mkdir")
redraw!
echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
let &report= repkeep
return
endif
let curdir= getcwd() let curdir= getcwd()
let b:curdir= curdir
let tmpdir= tempname() let tmpdir= tempname()
let b:tmpdir= tmpdir let b:curdir= tmpdir
let b:tmpdir= curdir
if tmpdir =~ '\.' if tmpdir =~ '\.'
let tmpdir= substitute(tmpdir,'\.[^.]*$','','e') let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
endif endif
@@ -301,9 +307,10 @@ fun! tar#Read(fname)
" attempt to change to the indicated directory " attempt to change to the indicated directory
try try
exe "lcd ".fnameescape(tmpdir) exe "cd ".fnameescape(tmpdir)
catch /^Vim\%((\a\+)\)\=:E344/ catch /^Vim\%((\a\+)\)\=:E344/
call s:Msg('tar#Read', 'error', "cannot lcd to temporary directory") redraw!
echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
let &report= repkeep let &report= repkeep
return return
endtry endtry
@@ -313,7 +320,7 @@ fun! tar#Read(fname)
call s:Rmdir("_ZIPVIM_") call s:Rmdir("_ZIPVIM_")
endif endif
call mkdir("_ZIPVIM_") call mkdir("_ZIPVIM_")
lcd _ZIPVIM_ cd _ZIPVIM_
if has("win32unix") && executable("cygpath") if has("win32unix") && executable("cygpath")
" assuming cygwin " assuming cygwin
@@ -326,7 +333,7 @@ fun! tar#Read(fname)
elseif fname =~ '\.bz3$' && executable("bz3cat") elseif fname =~ '\.bz3$' && executable("bz3cat")
let decmp= "|bz3cat" let decmp= "|bz3cat"
let doro = 1 let doro = 1
elseif fname =~ '\.t\=gz$' && executable("zcat") elseif fname =~ '\.t\=gz$' && executable("zcat")
let decmp= "|zcat" let decmp= "|zcat"
let doro = 1 let doro = 1
elseif fname =~ '\.lzma$' && executable("lzcat") elseif fname =~ '\.lzma$' && executable("lzcat")
@@ -349,66 +356,72 @@ fun! tar#Read(fname)
endif endif
endif endif
if exists("g:tar_secure")
let tar_secure= " -- "
else
let tar_secure= " "
endif
if tarfile =~# '\.bz2$' if tarfile =~# '\.bz2$'
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif tarfile =~# '\.bz3$' elseif tarfile =~# '\.bz3$'
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif tarfile =~# '\.\(gz\)$' elseif tarfile =~# '\.\(gz\)$'
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)' elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)'
let filekind= s:Header(tarfile) if has("unix") && executable("file")
if filekind =~? "bzip2" let filekind= system("file ".shellescape(tarfile,1))
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp else
let filekind= ""
endif
if filekind =~ "bzip2"
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif filekind =~ "bzip3" elseif filekind =~ "bzip3"
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif filekind =~? "xz" elseif filekind =~ "XZ"
exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif filekind =~? "zstd" elseif filekind =~ "Zstandard"
exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif filekind =~? "gzip" else
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
endif endif
elseif tarfile =~# '\.lrp$' elseif tarfile =~# '\.lrp$'
exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif tarfile =~# '\.lzma$' elseif tarfile =~# '\.lzma$'
exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif tarfile =~# '\.\(xz\|txz\)$' elseif tarfile =~# '\.\(xz\|txz\)$'
exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
elseif tarfile =~# '\.\(lz4\|tlz4\)$' elseif tarfile =~# '\.\(lz4\|tlz4\)$'
exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
else else
if tarfile =~ '^\s*-' if tarfile =~ '^\s*-'
" A file name starting with a dash is taken as an option. Prepend ./ to avoid that. " A file name starting with a dash is taken as an option. Prepend ./ to avoid that.
let tarfile = substitute(tarfile, '-', './-', '') let tarfile = substitute(tarfile, '-', './-', '')
endif endif
exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".g:tar_secure.shellescape(fname,1).decmp exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".tar_secure.shellescape(fname,1).decmp
exe "read ".escape_file exe "read ".escape_file
endif endif
if get(b:, 'leading_slash', 0)
sil g/^tar: /d
endif
redraw! redraw!
if v:shell_error != 0 if v:shell_error != 0
lcd .. cd ..
call s:Rmdir("_ZIPVIM_") call s:Rmdir("_ZIPVIM_")
exe "lcd ".fnameescape(curdir) exe "cd ".fnameescape(curdir)
call s:Msg('tar#Read', 'error', $"sorry, unable to open or extract {tarfile} with {fname}") echohl Error | echo "***error*** (tar#Read) sorry, unable to open or extract ".tarfile." with ".fname | echohl None
endif endif
if doro if doro
@@ -417,54 +430,40 @@ fun! tar#Read(fname)
endif endif
let b:tarfile= a:fname let b:tarfile= a:fname
exe "file tarfile::".fnameescape(fname)
" cleanup " cleanup
keepj sil! 0d keepj sil! 0d
set nomod set nomod
let &report= repkeep let &report= repkeep
exe "lcd ".fnameescape(curdir)
silent exe "file tarfile::". fname->fnameescape()
endfun endfun
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
" tar#Write: {{{2 " tar#Write: {{{2
fun! tar#Write(fname) fun! tar#Write(fname)
let pwdkeep= getcwd()
let repkeep= &report let repkeep= &report
set report=10 set report=10
" temporary buffer variable workaround because too fucking tired. but it works now
let curdir= b:curdir let curdir= b:curdir
let tmpdir= b:tmpdir let tmpdir= b:tmpdir
if !exists("g:tar_secure") && a:fname =~ '^\s*-\|\s\+-'
redraw!
echohl WarningMsg | echo '***warning*** (tar#Write) rejecting tarfile member<'.a:fname.'> because of embedded "-"'
return
endif
" sanity checks " sanity checks
if !executable(g:tar_cmd) if !executable(g:tar_cmd)
redraw! redraw!
let &report= repkeep let &report= repkeep
return return
endif endif
let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','') let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','')
let fname = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','') let fname = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','')
if get(b:, 'leading_slash', 0)
call s:Msg('tar#Write', 'error', $"sorry, not attempting to update {tarfile} with {fname}")
let &report= repkeep
return
endif
if !isdirectory(fnameescape(tmpdir))
call mkdir(fnameescape(tmpdir), 'p')
endif
exe $"lcd {fnameescape(tmpdir)}"
if isdirectory("_ZIPVIM_")
call s:Rmdir("_ZIPVIM_")
endif
call mkdir("_ZIPVIM_")
lcd _ZIPVIM_
let dir = fnamemodify(fname, ':p:h')
if dir !~# '_ZIPVIM_$'
call mkdir(dir)
endif
" handle compressed archives " handle compressed archives
if tarfile =~# '\.bz2' if tarfile =~# '\.bz2'
call system("bzip2 -d -- ".shellescape(tarfile,0)) call system("bzip2 -d -- ".shellescape(tarfile,0))
@@ -500,10 +499,10 @@ fun! tar#Write(fname)
let tarfile = substitute(tarfile,'\.lzma','','e') let tarfile = substitute(tarfile,'\.lzma','','e')
let compress= "lzma -- ".shellescape(tarfile,0) let compress= "lzma -- ".shellescape(tarfile,0)
endif endif
" Note: no support for name.tar.tbz/.txz/.tgz/.tlz4/.tzst
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Write', 'error', $"sorry, unable to update {tarfile} with {fname}") redraw!
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None
else else
if fname =~ '/' if fname =~ '/'
@@ -521,22 +520,28 @@ fun! tar#Write(fname)
let tarfile = substitute(tarfile, '-', './-', '') let tarfile = substitute(tarfile, '-', './-', '')
endif endif
" don't overwrite a file forcefully if exists("g:tar_secure")
exe "w ".fnameescape(fname) let tar_secure= " -- "
else
let tar_secure= " "
endif
exe "w! ".fnameescape(fname)
if has("win32unix") && executable("cygpath") if has("win32unix") && executable("cygpath")
let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e') let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e')
endif endif
" delete old file from tarfile " delete old file from tarfile
" Note: BSD tar does not support --delete flag call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).g:tar_secure.shellescape(fname,0))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)} --delete not supported?") redraw!
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
else else
" update tarfile with new file " update tarfile with new file
call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).g:tar_secure.shellescape(fname,0)) call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)}") redraw!
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
elseif exists("compress") elseif exists("compress")
call system(compress) call system(compress)
if exists("tgz") if exists("tgz")
@@ -562,9 +567,9 @@ fun! tar#Write(fname)
endif endif
" cleanup and restore current directory " cleanup and restore current directory
lcd .. cd ..
call s:Rmdir("_ZIPVIM_") call s:Rmdir("_ZIPVIM_")
exe "lcd ".fnameescape(pwdkeep) exe "cd ".fnameescape(curdir)
setlocal nomod setlocal nomod
let &report= repkeep let &report= repkeep
@@ -577,7 +582,6 @@ fun! tar#Diff(userfname,fname)
if a:userfname != "" if a:userfname != ""
let fname= a:userfname let fname= a:userfname
endif endif
exe "lcd ".fnameescape(b:tmpdir). '/_ZIPVIM_'
if filereadable(fname) if filereadable(fname)
" sets current file (from tarball) for diff'ing " sets current file (from tarball) for diff'ing
" splits window vertically " splits window vertically
@@ -601,6 +605,12 @@ fun! tar#Extract()
set report=10 set report=10
let fname= getline(".") let fname= getline(".")
if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-'
redraw!
echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"'
return
endif
" sanity check " sanity check
if fname =~ '^"' if fname =~ '^"'
let &report= repkeep let &report= repkeep
@@ -610,20 +620,20 @@ fun! tar#Extract()
let tarball = expand("%") let tarball = expand("%")
let tarbase = substitute(tarball,'\..*$','','') let tarbase = substitute(tarball,'\..*$','','')
let extractcmd= s:WinPath(g:tar_extractcmd) let extractcmd= netrw#WinPath(g:tar_extractcmd)
if filereadable(tarbase.".tar") if filereadable(tarbase.".tar")
call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ". fname echo "***note*** successfully extracted ".fname
endif endif
elseif filereadable(tarbase.".tgz") elseif filereadable(tarbase.".tgz")
let extractcmd= substitute(extractcmd,"-","-z","") let extractcmd= substitute(extractcmd,"-","-z","")
call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tgz {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tgz ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -632,7 +642,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-z","") let extractcmd= substitute(extractcmd,"-","-z","")
call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.gz {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.gz ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -641,7 +651,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-j","") let extractcmd= substitute(extractcmd,"-","-j","")
call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tbz {fname}: failed!") echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tbz ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -650,7 +660,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-j","") let extractcmd= substitute(extractcmd,"-","-j","")
call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz2 {fname}: failed!") echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz2 ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -659,7 +669,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-j","") let extractcmd= substitute(extractcmd,"-","-j","")
call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz3 {fname}: failed!") echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz3 ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -668,7 +678,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-J","") let extractcmd= substitute(extractcmd,"-","-J","")
call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.txz {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".txz ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -677,7 +687,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-J","") let extractcmd= substitute(extractcmd,"-","-J","")
call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.xz {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.xz ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -686,7 +696,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","--zstd","") let extractcmd= substitute(extractcmd,"-","--zstd","")
call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tzst {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tzst ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -695,7 +705,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","--zstd","") let extractcmd= substitute(extractcmd,"-","--zstd","")
call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.zst {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.zst ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -704,7 +714,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-I lz4","") let extractcmd= substitute(extractcmd,"-","-I lz4","")
call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tlz4 {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tlz4 ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -713,7 +723,7 @@ fun! tar#Extract()
let extractcmd= substitute(extractcmd,"-","-I lz4","") let extractcmd= substitute(extractcmd,"-","-I lz4","")
call system(extractcmd." ".shellescape(tarbase).".tar.lz4".shellescape(fname)) call system(extractcmd." ".shellescape(tarbase).".tar.lz4".shellescape(fname))
if v:shell_error != 0 if v:shell_error != 0
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.lz4 {fname}: failed!") echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.lz4 ".fname.": failed!" | echohl NONE
else else
echo "***note*** successfully extracted ".fname echo "***note*** successfully extracted ".fname
endif endif
@@ -726,50 +736,15 @@ endfun
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
" s:Rmdir: {{{2 " s:Rmdir: {{{2
fun! s:Rmdir(fname) fun! s:Rmdir(fname)
call delete(a:fname, 'rf') if has("unix")
endfun call system("/bin/rm -rf -- ".shellescape(a:fname,0))
elseif has("win32") || has("win95") || has("win64") || has("win16")
" s:FileHeader: {{{2 if &shell =~? "sh$"
fun! s:Header(fname) call system("/bin/rm -rf -- ".shellescape(a:fname,0))
let header= readblob(a:fname, 0, 6) else
" Nvim: see https://github.com/neovim/neovim/pull/34968 call system("del /S ".shellescape(a:fname,0))
if header[0:2] == 0z425A68 " bzip2 header endif
return "bzip2"
elseif header[0:2] == 0z425A33 " bzip3 header
return "bzip3"
elseif header == 0zFD377A58.5A00 " xz header
return "xz"
elseif header[0:3] == 0z28B52FFD " zstd header
return "zstd"
elseif header[0:3] == 0z04224D18 " lz4 header
return "lz4"
elseif (header[0:1] == 0z1F9D ||
\ header[0:1] == 0z1F8B ||
\ header[0:1] == 0z1F9E ||
\ header[0:1] == 0z1FA0 ||
\ header[0:1] == 0z1F1E)
return "gzip"
endif endif
return "unknown"
endfun
" ---------------------------------------------------------------------
" s:WinPath: {{{2
fun! s:WinPath(path)
if (!g:netrw_cygwin || &shell !~ '\%(\<bash\>\|\<zsh\>\)\%(\.exe\)\=$') && has("win32")
" remove cygdrive prefix, if present
let path = substitute(a:path, '/cygdrive/\(.\)', '\1:', '')
" remove trailing slash (Win95)
let path = substitute(path, '\(\\\|/\)$', '', 'g')
" remove escaped spaces
let path = substitute(path, '\ ', ' ', 'g')
" convert slashes to backslashes
let path = substitute(path, '/', '\', 'g')
else
let path = a:path
endif
return path
endfun endfun
" ===================================================================== " =====================================================================

View File

@@ -77,6 +77,46 @@ function! tutor#TutorFolds()
endif endif
endfunction endfunction
" Marks: {{{1
function! tutor#ApplyMarks()
hi! link tutorExpect Special
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let b:tutor_sign_id = 1
for expct in keys(b:tutor_metadata['expect'])
let lnum = eval(expct)
call matchaddpos('tutorExpect', [lnum])
call tutor#CheckLine(lnum)
endfor
endif
endfunction
function! tutor#ApplyMarksOnChanged()
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let lnum = line('.')
if index(keys(b:tutor_metadata['expect']), string(lnum)) > -1
call tutor#CheckLine(lnum)
endif
endif
endfunction
function! tutor#CheckLine(line)
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let bufn = bufnr('%')
let ctext = getline(a:line)
let signs = sign_getplaced(bufn, {'lnum': a:line})[0].signs
if !empty(signs)
call sign_unplace('', {'id': signs[0].id})
endif
if b:tutor_metadata['expect'][string(a:line)] == -1 || ctext ==# b:tutor_metadata['expect'][string(a:line)]
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorok buffer=".bufn
else
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorbad buffer=".bufn
endif
let b:tutor_sign_id+=1
endif
endfunction
" Tutor Cmd: {{{1 " Tutor Cmd: {{{1
function! s:Locale() function! s:Locale()
@@ -127,21 +167,15 @@ function! s:Sort(a, b)
return retval return retval
endfunction endfunction
" returns a list of all tutor files matching the given name function! s:GlobTutorials(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: " search for tutorials:
" 1. non-localized " 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 " 2. localized for current locale
let l:locale_tutors = s:GlobPath(rtp, 'tutor/'.locale.'/'.a:name.'.tutor') let l:locale_tutors = s:GlobPath(&rtp, 'tutor/'.s:Locale()[0].'/'.a:name.'.tutor')
" 3. fallback to 'en' " 3. fallback to 'en'
if len(l:locale_tutors) == 0 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 endif
call extend(l:tutors, l:locale_tutors) call extend(l:tutors, l:locale_tutors)
return uniq(sort(l:tutors, 's:Sort'), 's:Sort') return uniq(sort(l:tutors, 's:Sort'), 's:Sort')
@@ -163,7 +197,7 @@ function! tutor#TutorCmd(tutor_name)
let l:tutor_name = fnamemodify(l:tutor_name, ':r') let l:tutor_name = fnamemodify(l:tutor_name, ':r')
endif endif
let l:tutors = tutor#GlobTutorials(l:tutor_name, s:Locale()[0]) let l:tutors = s:GlobTutorials(l:tutor_name)
if len(l:tutors) == 0 if len(l:tutors) == 0
echom "No tutorial with that name found" echom "No tutorial with that name found"
@@ -191,7 +225,7 @@ function! tutor#TutorCmd(tutor_name)
endfunction endfunction
function! tutor#TutorCmdComplete(lead,line,pos) function! tutor#TutorCmdComplete(lead,line,pos)
let l:tutors = tutor#GlobTutorials('*', s:Locale()[0]) let l:tutors = s:GlobTutorials('*')
let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort')) let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort'))
return join(l:names, "\n") return join(l:names, "\n")
endfunction endfunction
@@ -203,9 +237,9 @@ function! tutor#EnableInteractive(enable)
setlocal buftype=nofile setlocal buftype=nofile
setlocal concealcursor+=inv setlocal concealcursor+=inv
setlocal conceallevel=2 setlocal conceallevel=2
lua require('nvim.tutor').apply_marks() call tutor#ApplyMarks()
augroup tutor_interactive augroup tutor_interactive
autocmd! TextChanged,TextChangedI <buffer> lua require('nvim.tutor').apply_marks_on_changed() autocmd! TextChanged,TextChangedI <buffer> call tutor#ApplyMarksOnChanged()
augroup END augroup END
else else
setlocal buftype< setlocal buftype<

View File

@@ -15,7 +15,6 @@
" 2024 Aug 18 by Vim Project: correctly handle special globbing chars " 2024 Aug 18 by Vim Project: correctly handle special globbing chars
" 2024 Aug 21 by Vim Project: simplify condition to detect MS-Windows " 2024 Aug 21 by Vim Project: simplify condition to detect MS-Windows
" 2025 Mar 11 by Vim Project: handle filenames with leading '-' correctly " 2025 Mar 11 by Vim Project: handle filenames with leading '-' correctly
" 2025 Jul 12 by Vim Project: drop ../ on write to prevent path traversal attacks
" License: Vim License (see vim's :help license) " License: Vim License (see vim's :help license)
" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1 " Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code, " Permission is hereby granted to use and distribute this code,
@@ -72,9 +71,8 @@ fun! s:Mess(group, msg)
echohl Normal echohl Normal
endfun endfun
if !has('nvim-0.10') && v:version < 901 if v:version < 702
" required for defer call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 7.2 or later")
call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 9.1 or later")
finish finish
endif endif
" sanity checks " sanity checks
@@ -237,62 +235,59 @@ endfun
" zip#Write: {{{2 " zip#Write: {{{2
fun! zip#Write(fname) fun! zip#Write(fname)
let dict = s:SetSaneOpts() let dict = s:SetSaneOpts()
let need_rename = 0
defer s:RestoreOpts(dict) defer s:RestoreOpts(dict)
" sanity checks " sanity checks
if !executable(substitute(g:zip_zipcmd,'\s\+.*$','','')) if !executable(substitute(g:zip_zipcmd,'\s\+.*$','',''))
call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program") call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program")
return return
endif
if !exists("*mkdir")
call s:Mess('Error', "***error*** (zip#Write) sorry, mkdir() doesn't work on your system")
return
endif endif
let curdir= getcwd() let curdir= getcwd()
let tmpdir= tempname() let tmpdir= tempname()
if tmpdir =~ '\.' if tmpdir =~ '\.'
let tmpdir= substitute(tmpdir,'\.[^.]*$','','e') let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
endif endif
call mkdir(tmpdir,"p") call mkdir(tmpdir,"p")
" attempt to change to the indicated directory " attempt to change to the indicated directory
if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory") if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory")
return return
endif endif
" place temporary files under .../_ZIPVIM_/ " place temporary files under .../_ZIPVIM_/
if isdirectory("_ZIPVIM_") if isdirectory("_ZIPVIM_")
call delete("_ZIPVIM_", "rf") call delete("_ZIPVIM_", "rf")
endif endif
call mkdir("_ZIPVIM_") call mkdir("_ZIPVIM_")
cd _ZIPVIM_ cd _ZIPVIM_
if has("unix") if has("unix")
let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','') let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','') let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
else else
let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','') let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','') let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
endif
if fname =~ '^[.]\{1,2}/'
call system(g:zip_zipcmd." -d ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
let fname = fname->substitute('^\([.]\{1,2}/\)\+', '', 'g')
let need_rename = 1
endif endif
if fname =~ '/' if fname =~ '/'
let dirpath = substitute(fname,'/[^/]\+$','','e') let dirpath = substitute(fname,'/[^/]\+$','','e')
if has("win32unix") && executable("cygpath") if has("win32unix") && executable("cygpath")
let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e') let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e')
endif endif
call mkdir(dirpath,"p") call mkdir(dirpath,"p")
endif endif
if zipfile !~ '/' if zipfile !~ '/'
let zipfile= curdir.'/'.zipfile let zipfile= curdir.'/'.zipfile
endif endif
" don't overwrite files forcefully exe "w! ".fnameescape(fname)
exe "w ".fnameescape(fname)
if has("win32unix") && executable("cygpath") if has("win32unix") && executable("cygpath")
let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e') let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
endif endif
if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$' if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
@@ -301,24 +296,21 @@ fun! zip#Write(fname)
call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0)) call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
if v:shell_error != 0 if v:shell_error != 0
call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname) call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname)
elseif s:zipfile_{winnr()} =~ '^\a\+://' elseif s:zipfile_{winnr()} =~ '^\a\+://'
" support writing zipfiles across a network " support writing zipfiles across a network
let netzipfile= s:zipfile_{winnr()} let netzipfile= s:zipfile_{winnr()}
1split|enew 1split|enew
let binkeep= &binary let binkeep= &binary
let eikeep = &ei let eikeep = &ei
set binary ei=all set binary ei=all
exe "noswapfile e! ".fnameescape(zipfile) exe "noswapfile e! ".fnameescape(zipfile)
call netrw#NetWrite(netzipfile) call netrw#NetWrite(netzipfile)
let &ei = eikeep let &ei = eikeep
let &binary = binkeep let &binary = binkeep
q! q!
unlet s:zipfile_{winnr()} unlet s:zipfile_{winnr()}
elseif need_rename
exe $"sil keepalt file {fnameescape($"zipfile://{zipfile}::{fname}")}"
call s:Mess('Warning', "***error*** (zip#Browse) Path Traversal Attack detected, dropping relative path")
endif endif
" cleanup and restore current directory " cleanup and restore current directory
@@ -327,6 +319,7 @@ fun! zip#Write(fname)
call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!") call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!")
call delete(tmpdir, "rf") call delete(tmpdir, "rf")
setlocal nomod setlocal nomod
endfun endfun
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
@@ -339,18 +332,15 @@ fun! zip#Extract()
" sanity check " sanity check
if fname =~ '^"' if fname =~ '^"'
return return
endif endif
if fname =~ '/$' if fname =~ '/$'
call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory") call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory")
return return
elseif fname =~ '^[.]\?[.]/'
call s:Mess('Error', "***error*** (zip#Browse) Path Traversal Attack detected, not extracting!")
return
endif endif
if filereadable(fname) if filereadable(fname)
call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!") call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!")
return return
endif endif
let target = fname->substitute('\[', '[[]', 'g') let target = fname->substitute('\[', '[[]', 'g')
" unzip 6.0 does not support -- to denote end-of-arguments " unzip 6.0 does not support -- to denote end-of-arguments
@@ -372,12 +362,13 @@ fun! zip#Extract()
" extract the file mentioned under the cursor " extract the file mentioned under the cursor
call system($"{g:zip_extractcmd} -o {shellescape(b:zipfile)} {target}") call system($"{g:zip_extractcmd} -o {shellescape(b:zipfile)} {target}")
if v:shell_error != 0 if v:shell_error != 0
call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!") call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!")
elseif !filereadable(fname) elseif !filereadable(fname)
call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!") call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!")
else else
echomsg "***note*** successfully extracted ".fname echomsg "***note*** successfully extracted ".fname
endif endif
endfun endfun
" --------------------------------------------------------------------- " ---------------------------------------------------------------------

View File

@@ -47,7 +47,6 @@ hi('WildMenu', { fg = 'Black', bg = 'Yellow', ctermfg = 'Black', cterm
hi('VertSplit', { link = 'Normal' }) hi('VertSplit', { link = 'Normal' })
hi('WinSeparator', { link = 'VertSplit' }) hi('WinSeparator', { link = 'VertSplit' })
hi('WinBarNC', { link = 'WinBar' }) hi('WinBarNC', { link = 'WinBar' })
hi('DiffTextAdd', { link = 'DiffText' })
hi('EndOfBuffer', { link = 'NonText' }) hi('EndOfBuffer', { link = 'NonText' })
hi('LineNrAbove', { link = 'LineNr' }) hi('LineNrAbove', { link = 'LineNr' })
hi('LineNrBelow', { link = 'LineNr' }) hi('LineNrBelow', { link = 'LineNr' })
@@ -62,8 +61,6 @@ hi('PmenuMatchSel', { link = 'PmenuSel' })
hi('PmenuExtra', { link = 'Pmenu' }) hi('PmenuExtra', { link = 'Pmenu' })
hi('PmenuExtraSel', { link = 'PmenuSel' }) hi('PmenuExtraSel', { link = 'PmenuSel' })
hi('ComplMatchIns', {}) hi('ComplMatchIns', {})
hi('ComplHint', { link = 'NonText' })
hi('ComplHintMore', { link = 'MoreMsg' })
hi('Substitute', { link = 'Search' }) hi('Substitute', { link = 'Search' })
hi('Whitespace', { link = 'NonText' }) hi('Whitespace', { link = 'NonText' })
hi('MsgSeparator', { link = 'StatusLine' }) hi('MsgSeparator', { link = 'StatusLine' })
@@ -136,7 +133,6 @@ hi('DiagnosticDeprecated', { sp = 'Red', strikethrough = true, cterm =
hi('DiagnosticUnnecessary', { link = 'Comment' }) hi('DiagnosticUnnecessary', { link = 'Comment' })
hi('LspInlayHint', { link = 'NonText' }) hi('LspInlayHint', { link = 'NonText' })
hi('SnippetTabstop', { link = 'Visual' }) hi('SnippetTabstop', { link = 'Visual' })
hi('SnippetTabstopActive', { link = 'SnippetTabstop' })
-- Text -- Text
hi('@markup.raw', { link = 'Comment' }) hi('@markup.raw', { link = 'Comment' })

View File

@@ -1,25 +0,0 @@
" Vim compiler file
" Language: Gleam
" Maintainer: Kirill Morozov <kirill@robotix.pro>
" Based On: https://github.com/gleam-lang/gleam.vim
" Last Change: 2025 Apr 21
if exists('current_compiler')
finish
endif
let current_compiler = "gleam_build"
CompilerSet makeprg=gleam\ build
" Example error message:
"
" error: Unknown variable
" ┌─ /home/michael/root/projects/tutorials/gleam/try/code/src/main.gleam:19:18
" │
" 19 │ Ok(tuple(name, spot))
" │ ^^^^ did you mean `sport`?
"
" The name `spot` is not in scope here.
CompilerSet errorformat=%Eerror:\ %m,%Wwarning:\ %m,%C\ %#┌─%#\ %f:%l:%c\ %#-%#
" vim: sw=2 sts=2 et

View File

@@ -2,7 +2,6 @@
" Compiler: Pandoc " Compiler: Pandoc
" Maintainer: Konfekt " Maintainer: Konfekt
" Last Change: 2024 Nov 19 " Last Change: 2024 Nov 19
" 2025 May 15 Update the title regex for CompilerSet #17321
" "
" Expects output file extension, say `:make html` or `:make pdf`. " Expects output file extension, say `:make html` or `:make pdf`.
" Passes additional arguments to pandoc, say `:make html --self-contained`. " Passes additional arguments to pandoc, say `:make html --self-contained`.
@@ -52,7 +51,7 @@ endfunction
execute 'CompilerSet makeprg=pandoc'..escape( execute 'CompilerSet makeprg=pandoc'..escape(
\ ' --standalone'.. \ ' --standalone'..
\ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s\+\S\+', 'cnw') > 0)) ? \ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
\ '' : ' --metadata title=%:t:r:S').. \ '' : ' --metadata title=%:t:r:S')..
\ ' '..s:PandocLang().. \ ' '..s:PandocLang()..
\ ' --from='..s:PandocFiletype(&filetype).. \ ' --from='..s:PandocFiletype(&filetype)..

View File

@@ -1,12 +0,0 @@
" Vim compiler file
" Compiler: PHPStan
" Maintainer: Dietrich Moerman <dietrich.moerman@gmail.com>
" Last Change: 2025 Jul 17
if exists("current_compiler")
finish
endif
let current_compiler = "phpstan"
CompilerSet makeprg=composer\ exec\ --\ phpstan\ analyse\ -v\ --no-progress\ --error-format=raw
CompilerSet errorformat=%f:%l:%m,%-G%.%#

File diff suppressed because it is too large Load Diff

View File

@@ -73,16 +73,11 @@ Or use `:execute`: >
Note that special characters (e.g., "%", "<cword>") in the ":autocmd" Note that special characters (e.g., "%", "<cword>") in the ":autocmd"
arguments are not expanded when the autocommand is defined. These will be arguments are not expanded when the autocommand is defined. These will be
expanded when the Event is recognized, and the {cmd} is executed. The only expanded when the Event is recognized, and the {cmd} is executed. The only
exception is that "<sfile>" (unlike "<script>") is expanded when the autocmd exception is that "<sfile>" is expanded when the autocmd is defined. Example:
is defined. Example:
> >
:au BufNewFile,BufRead *.html so <sfile>:h/html.vim :au BufNewFile,BufRead *.html so <sfile>:h/html.vim
Here Vim expands <sfile> to the name of the file containing this line. Here Vim expands <sfile> to the name of the file containing this line.
However, <sfile> works differently in a function, in which case it's better to
use `:execute` with <script> to achieve the same purpose:
>
:exe $'au BufNewFile,BufRead *.html so {expand("<script>:h")}/html.vim'
`:autocmd` adds to the list of autocommands regardless of whether they are `:autocmd` adds to the list of autocommands regardless of whether they are
already present. When your .vimrc file is sourced twice, the autocommands already present. When your .vimrc file is sourced twice, the autocommands
@@ -262,7 +257,7 @@ BufLeave Before leaving to another buffer. Also when
Not used for ":qa" or ":q" when exiting Vim. Not used for ":qa" or ":q" when exiting Vim.
*BufModifiedSet* *BufModifiedSet*
BufModifiedSet After the `'modified'` value of a buffer has BufModifiedSet After the `'modified'` value of a buffer has
been changed. Special-case of |OptionSet|. been changed.
*BufNew* *BufNew*
BufNew After creating a new buffer (except during BufNew After creating a new buffer (except during
startup, see |VimEnter|) or renaming an startup, see |VimEnter|) or renaming an
@@ -306,7 +301,6 @@ BufUnload Before unloading a buffer, when the text in
going to exit. going to exit.
NOTE: Current buffer "%" is not the target NOTE: Current buffer "%" is not the target
buffer "<afile>", "<abuf>". |<buffer=abuf>| buffer "<afile>", "<abuf>". |<buffer=abuf>|
*E1546*
Do not switch buffers or windows! Do not switch buffers or windows!
Not triggered when exiting and v:dying is 2 or Not triggered when exiting and v:dying is 2 or
more. more.
@@ -350,8 +344,7 @@ BufWriteCmd Before writing the whole buffer to a file.
The buffer contents should not be changed. The buffer contents should not be changed.
When the command resets 'modified' the undo When the command resets 'modified' the undo
information is adjusted to mark older undo information is adjusted to mark older undo
states as 'modified', like |:write| does. Use states as 'modified', like |:write| does.
the |'[| and |']| marks for the range of lines.
|Cmd-event| |Cmd-event|
*BufWritePost* *BufWritePost*
BufWritePost After writing the whole buffer to a file BufWritePost After writing the whole buffer to a file
@@ -407,16 +400,6 @@ CmdlineLeave Before leaving the command-line (including
Note: `abort` can only be changed from false Note: `abort` can only be changed from false
to true: cannot execute an already aborted to true: cannot execute an already aborted
cmdline by changing it to false. cmdline by changing it to false.
*CmdlineLeavePre*
CmdlineLeavePre Just before leaving the command line, and
before |CmdlineLeave|. Useful for capturing
completion info with |cmdcomplete_info()|, as
this information is cleared before
|CmdlineLeave| is triggered. Triggered for
non-interactive use of ":" in a mapping, but
not when using |<Cmd>|. Also triggered when
abandoning the command line by typing CTRL-C
or <Esc>. <afile> is set to |cmdline-char|.
*CmdwinEnter* *CmdwinEnter*
CmdwinEnter After entering the command-line window. CmdwinEnter After entering the command-line window.
Useful for setting options specifically for Useful for setting options specifically for
@@ -494,16 +477,27 @@ CompleteDone After Insert mode completion is done. Either
- "accept": completion was - "accept": completion was
accepted by |complete_CTRL-Y|. accepted by |complete_CTRL-Y|.
- "cancel": completion was - "cancel": completion was
stopped by |complete_CTRL-E|. stopped by |complete_CTRL-E.
- "discard": completion was - "discard": completion was
abandoned for other reason. abandoned for other reason.
*CursorHold* *CursorHold*
CursorHold When there is no user input for 'updatetime' CursorHold When the user doesn't press a key for the time
duration, in Normal-mode. Not triggered while specified with 'updatetime'. Not triggered
waiting for a command argument or movement until the user has pressed a key (i.e. doesn't
after an operator, nor while |recording| fire every 'updatetime' ms if you leave Vim to
a macro. See |CursorHold-example|. make some coffee. :) See |CursorHold-example|
for previewing tags.
This event is only triggered in Normal mode.
It is not triggered when waiting for a command
argument to be typed, or a movement after an
operator.
While recording the CursorHold event is not
triggered. |q|
*<CursorHold>*
Internally the autocommand is triggered by the
<CursorHold> key. In an expression mapping
|getchar()| may see this character.
Note: Interactive commands cannot be used for Note: Interactive commands cannot be used for
this event. There is no hit-enter prompt, this event. There is no hit-enter prompt,
@@ -654,14 +648,14 @@ FileType When the 'filetype' option has been set. The
FileWriteCmd Before writing to a file, when not writing the FileWriteCmd Before writing to a file, when not writing the
whole buffer. Should do the writing to the whole buffer. Should do the writing to the
file. Should not change the buffer. Use the file. Should not change the buffer. Use the
|'[| and |']| marks for the range of lines. '[ and '] marks for the range of lines.
|Cmd-event| |Cmd-event|
*FileWritePost* *FileWritePost*
FileWritePost After writing to a file, when not writing the FileWritePost After writing to a file, when not writing the
whole buffer. whole buffer.
*FileWritePre* *FileWritePre*
FileWritePre Before writing to a file, when not writing the FileWritePre Before writing to a file, when not writing the
whole buffer. Use the |'[| and |']| marks for the whole buffer. Use the '[ and '] marks for the
range of lines. range of lines.
*FilterReadPost* *FilterReadPost*
FilterReadPost After reading a file from a filter command. FilterReadPost After reading a file from a filter command.
@@ -788,31 +782,6 @@ ModeChanged After changing the mode. The pattern is
:au ModeChanged [vV\x16]*:* let &l:rnu = mode() =~# '^[vV\x16]' :au ModeChanged [vV\x16]*:* let &l:rnu = mode() =~# '^[vV\x16]'
:au ModeChanged *:[vV\x16]* let &l:rnu = mode() =~# '^[vV\x16]' :au ModeChanged *:[vV\x16]* let &l:rnu = mode() =~# '^[vV\x16]'
:au WinEnter,WinLeave * let &l:rnu = mode() =~# '^[vV\x16]' :au WinEnter,WinLeave * let &l:rnu = mode() =~# '^[vV\x16]'
Progress *Progress*
After a progress message is created or updated via
`nvim_echo`. The pattern is matched against
title of the message. The |event-data| contains:
id: id of the message
text: text of the message
title: title of the progress message
status: status of the progress message
percent: how much progress has been
made for this progress item
Usage example:
>
vim.api.nvim_create_autocmd('Progress', {
pattern={"term"},
callback = function(ev)
print(string.format('event fired: %s', vim.inspect(ev)))
end
})
local id = vim.api.nvim_echo({{'searching...'}}, true,
{kind='progress', status='running', percent=10, title="term"})
vim.api.nvim_echo({{'searching'}}, true,
{id = id, kind='progress', status='running', percent=50, title="term"})
vim.api.nvim_echo({{'done'}}, true,
{id = id, kind='progress', status='success', percent=100, title="term"})
< *OptionSet* < *OptionSet*
OptionSet After setting an option (except during OptionSet After setting an option (except during
|startup|). The |autocmd-pattern| is matched |startup|). The |autocmd-pattern| is matched
@@ -853,10 +822,6 @@ OptionSet After setting an option (except during
always use |:noautocmd| to prevent triggering always use |:noautocmd| to prevent triggering
OptionSet. OptionSet.
Note: Not triggered by the 'modified' option;
the |BufModifiedSet| event may be used to
handle that.
Non-recursive: |:set| in the autocommand does Non-recursive: |:set| in the autocommand does
not trigger OptionSet again. not trigger OptionSet again.
@@ -1069,7 +1034,7 @@ TermRequest When a |:terminal| child process emits an OSC,
autocommand defined without |autocmd-nested|. autocommand defined without |autocmd-nested|.
*TermResponse* *TermResponse*
TermResponse When Nvim receives a DA1, OSC, DCS, or APC response from TermResponse When Nvim receives an OSC or DCS response from
the host terminal. Sets |v:termresponse|. The the host terminal. Sets |v:termresponse|. The
|event-data| is a table with the following fields: |event-data| is a table with the following fields:
@@ -1093,7 +1058,7 @@ TermResponse When Nvim receives a DA1, OSC, DCS, or APC response from
local r, g, b = resp:match("\027%]4;1;rgb:(%w+)/(%w+)/(%w+)") local r, g, b = resp:match("\027%]4;1;rgb:(%w+)/(%w+)/(%w+)")
end, end,
}) })
vim.api.nvim_ui_send("\027]4;1;?\027\\") io.stdout:write("\027]4;1;?\027\\")
< <
*TextChanged* *TextChanged*
TextChanged After a change was made to the text in the TextChanged After a change was made to the text in the
@@ -1221,13 +1186,6 @@ WinScrolled After any window in the current tab page
or changed width or height. See or changed width or height. See
|win-scrolled-resized|. |win-scrolled-resized|.
Note: This can not be skipped with
`:noautocmd`, because it triggers after
processing normal commands when Vim is back in
the main loop. If you want to disable this,
consider setting the 'eventignore' option
instead.
The pattern is matched against the |window-ID| The pattern is matched against the |window-ID|
of the first window that scrolled or resized. of the first window that scrolled or resized.
Both <amatch> and <afile> are set to the Both <amatch> and <afile> are set to the

View File

@@ -1,16 +1,16 @@
*vimfn.txt* Nvim *builtin.txt* Nvim
NVIM REFERENCE MANUAL NVIM REFERENCE MANUAL
Vimscript functions *vimscript-functions* *builtin.txt* Builtin functions *vimscript-functions* *builtin-functions*
For functions grouped by what they are used for see |function-list|. For functions grouped by what they are used for see |function-list|.
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
============================================================================== ==============================================================================
1. Details *vimscript-functions-details* 1. Details *builtin-function-details*
abs({expr}) *abs()* abs({expr}) *abs()*
Return the absolute value of {expr}. When {expr} evaluates to Return the absolute value of {expr}. When {expr} evaluates to
@@ -1008,23 +1008,16 @@ charidx({string}, {idx} [, {countcc} [, {utf16}]]) *charidx()*
Return: ~ Return: ~
(`integer`) (`integer`)
chdir({dir} [, {scope}]) *chdir()* chdir({dir}) *chdir()*
Changes the current working directory to {dir}. The scope of Change the current working directory to {dir}. The scope of
the change is determined as follows: the directory change depends on the directory of the current
If {scope} is not present, the current working directory is window:
changed to the scope of the current directory: - If the current window has a window-local directory
- If the window local directory (|:lcd|) is set, it (|:lcd|), then changes the window local directory.
changes the current working directory for that scope. - Otherwise, if the current tabpage has a local
- Otherwise, if the tab page local directory (|:tcd|) is directory (|:tcd|) then changes the tabpage local
set, it changes the current directory for that scope. directory.
- Otherwise, changes the global directory for that scope. - Otherwise, changes the global directory.
If {scope} is present, changes the current working directory
for the specified scope:
"window" Changes the window local directory. |:lcd|
"tabpage" Changes the tab page local directory. |:tcd|
"global" Changes the global directory. |:cd|
{dir} must be a String. {dir} must be a String.
If successful, returns the previous working directory. Pass If successful, returns the previous working directory. Pass
this to another chdir() to restore the directory. this to another chdir() to restore the directory.
@@ -1040,7 +1033,6 @@ chdir({dir} [, {scope}]) *chdir()*
Parameters: ~ Parameters: ~
• {dir} (`string`) • {dir} (`string`)
• {scope} (`string?`)
Return: ~ Return: ~
(`string`) (`string`)
@@ -1069,29 +1061,6 @@ clearmatches([{win}]) *clearmatches()*
Parameters: ~ Parameters: ~
• {win} (`integer?`) • {win} (`integer?`)
cmdcomplete_info() *cmdcomplete_info()*
Returns a |Dictionary| with information about cmdline
completion. See |cmdline-completion|.
The items are:
cmdline_orig The original command-line string before
completion began.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
matches List of all completion candidates. Each item
is a string.
selected Selected item index. First index is zero.
Index is -1 if no item is selected (showing
typed text only, or the last completion after
no item is selected when using the <Up> or
<Down> keys)
Returns an empty |Dictionary| if no completion was attempted,
if there was only one candidate and it was fully completed, or
if an error occurred.
Return: ~
(`table<string,any>`)
col({expr} [, {winid}]) *col()* col({expr} [, {winid}]) *col()*
The result is a Number, which is the byte index of the column The result is a Number, which is the byte index of the column
position given with {expr}. position given with {expr}.
@@ -1244,7 +1213,6 @@ complete_info([{what}]) *complete_info()*
"omni" Omni completion |i_CTRL-X_CTRL-O| "omni" Omni completion |i_CTRL-X_CTRL-O|
"spell" Spelling suggestions |i_CTRL-X_s| "spell" Spelling suggestions |i_CTRL-X_s|
"eval" |complete()| completion "eval" |complete()| completion
"register" Words from registers |i_CTRL-X_CTRL-R|
"unknown" Other internal modes "unknown" Other internal modes
If the optional {what} list argument is supplied, then only If the optional {what} list argument is supplied, then only
@@ -1272,56 +1240,6 @@ complete_info([{what}]) *complete_info()*
Return: ~ Return: ~
(`table`) (`table`)
complete_match([{lnum}, {col}]) *complete_match()*
Searches backward from the given position and returns a List
of matches according to the 'isexpand' option. When no
arguments are provided, uses the current cursor position.
Each match is represented as a List containing
[startcol, trigger_text] where:
- startcol: column position where completion should start,
or -1 if no trigger position is found. For multi-character
triggers, returns the column of the first character.
- trigger_text: the matching trigger string from 'isexpand',
or empty string if no match was found or when using the
default 'iskeyword' pattern.
When 'isexpand' is empty, uses the 'iskeyword' pattern "\k\+$"
to find the start of the current keyword.
Examples: >vim
set isexpand=.,->,/,/*,abc
func CustomComplete()
let res = complete_match()
if res->len() == 0 | return | endif
let [col, trigger] = res[0]
let items = []
if trigger == '/*'
let items = ['/** */']
elseif trigger == '/'
let items = ['/*! */', '// TODO:', '// fixme:']
elseif trigger == '.'
let items = ['length()']
elseif trigger =~ '^\->'
let items = ['map()', 'reduce()']
elseif trigger =~ '^\abc'
let items = ['def', 'ghk']
endif
if items->len() > 0
let startcol = trigger =~ '^/' ? col : col + len(trigger)
call complete(startcol, items)
endif
endfunc
inoremap <Tab> <Cmd>call CustomComplete()<CR>
<
Parameters: ~
• {lnum} (`integer?`)
• {col} (`integer?`)
Return: ~
(`table`)
confirm({msg} [, {choices} [, {default} [, {type}]]]) *confirm()* confirm({msg} [, {choices} [, {default} [, {type}]]]) *confirm()*
confirm() offers the user a dialog, from which a choice can be confirm() offers the user a dialog, from which a choice can be
made. It returns the number of the choice. For the first made. It returns the number of the choice. For the first
@@ -2106,35 +2024,34 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
done like for the |cmdline-special| variables with their done like for the |cmdline-special| variables with their
associated modifiers. Here is a short overview: associated modifiers. Here is a short overview:
% Current file name % current file name
# Alternate file name # alternate file name
#n Alternate file name n #n alternate file name n
<cfile> File name under the cursor <cfile> file name under the cursor
<afile> Autocmd file name <afile> autocmd file name
<abuf> Autocmd buffer number (as a String!) <abuf> autocmd buffer number (as a String!)
<amatch> Autocmd matched name <amatch> autocmd matched name
<cexpr> C expression under the cursor <cexpr> C expression under the cursor
<sfile> Deprecated, use <script> or <stack> <sfile> sourced script file or function name
<slnum> Sourced script line number or function <slnum> sourced script line number or function
line number line number
<sflnum> Script file line number, also when in <sflnum> script file line number, also when in
a function a function
<SID> "<SNR>123_" where "123" is the <SID> "<SNR>123_" where "123" is the
current script ID |<SID>| current script ID |<SID>|
<script> Sourced script file, or script file <script> sourced script file, or script file
where the current function was defined. where the current function was defined
For Lua see |lua-script-location|. <stack> call stack
<stack> Call stack <cword> word under the cursor
<cword> Word under the cursor
<cWORD> WORD under the cursor <cWORD> WORD under the cursor
<client> The {clientid} of the last received <client> the {clientid} of the last received
message message
Modifiers: Modifiers:
:p Expand to full path :p expand to full path
:h Head (last path component removed) :h head (last path component removed)
:t Tail (last path component only) :t tail (last path component only)
:r Root (one extension removed) :r root (one extension removed)
:e Extension only :e extension only
Example: >vim Example: >vim
let &tags = expand("%:p:h") .. "/tags" let &tags = expand("%:p:h") .. "/tags"
@@ -2467,7 +2384,7 @@ finddir({name} [, {path} [, {count}]]) *finddir()*
• {count} (`integer?`) • {count} (`integer?`)
Return: ~ Return: ~
(`string|string[]`) (`any`)
findfile({name} [, {path} [, {count}]]) *findfile()* findfile({name} [, {path} [, {count}]]) *findfile()*
Just like |finddir()|, but find a file instead of a directory. Just like |finddir()|, but find a file instead of a directory.
@@ -2480,10 +2397,10 @@ findfile({name} [, {path} [, {count}]]) *findfile()*
Parameters: ~ Parameters: ~
• {name} (`string`) • {name} (`string`)
• {path} (`string?`) • {path} (`string?`)
• {count} (`integer?`) • {count} (`any?`)
Return: ~ Return: ~
(`string|string[]`) (`any`)
flatten({list} [, {maxdepth}]) *flatten()* flatten({list} [, {maxdepth}]) *flatten()*
Flatten {list} up to {maxdepth} levels. Without {maxdepth} Flatten {list} up to {maxdepth} levels. Without {maxdepth}
@@ -3124,7 +3041,6 @@ getbufvar({buf}, {varname} [, {def}]) *getbufvar()*
Examples: >vim Examples: >vim
let bufmodified = getbufvar(1, "&mod") let bufmodified = getbufvar(1, "&mod")
echo "todo myvar = " .. getbufvar("todo", "myvar") echo "todo myvar = " .. getbufvar("todo", "myvar")
<
Parameters: ~ Parameters: ~
• {buf} (`integer|string`) • {buf} (`integer|string`)
@@ -3173,7 +3089,8 @@ getchar([{expr} [, {opts}]]) *getchar()*
Return zero otherwise. Return zero otherwise.
If {expr} is 1, only check if a character is available, it is If {expr} is 1, only check if a character is available, it is
not consumed. Return zero if no character available. not consumed. Return zero if no character available.
To always get a string, specify "number" as |FALSE| in {opts}. If you prefer always getting a string use |getcharstr()|, or
specify |FALSE| as "number" in {opts}.
Without {expr} and when {expr} is 0 a whole character or Without {expr} and when {expr} is 0 a whole character or
special key is returned. If it is a single character, the special key is returned. If it is a single character, the
@@ -3358,9 +3275,6 @@ getcmdcompltype() *getcmdcompltype()*
|getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|.
Returns an empty string when completion is not defined. Returns an empty string when completion is not defined.
To get the type of the command-line completion for a specified
string, use |getcompletiontype()|.
Return: ~ Return: ~
(`string`) (`string`)
@@ -3457,14 +3371,13 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
customlist,{func} custom completion, defined via {func} customlist,{func} custom completion, defined via {func}
diff_buffer |:diffget| and |:diffput| completion diff_buffer |:diffget| and |:diffput| completion
dir directory names dir directory names
dir_in_path directory names in 'cdpath' dir_in_path directory names in |'cdpath'|
environment environment variable names environment environment variable names
event autocommand events event autocommand events
expression Vim expression expression Vim expression
file file and directory names file file and directory names
file_in_path file and directory names in 'path' file_in_path file and directory names in |'path'|
filetype filetype names 'filetype' filetype filetype names |'filetype'|
filetypecmd |:filetype| suboptions
function function name function function name
help help subjects help help subjects
highlight highlight groups highlight highlight groups
@@ -3477,13 +3390,12 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
messages |:messages| suboptions messages |:messages| suboptions
option options option options
packadd optional package |pack-add| names packadd optional package |pack-add| names
retab |:retab| suboptions
runtime |:runtime| completion runtime |:runtime| completion
scriptnames sourced script names |:scriptnames| scriptnames sourced script names |:scriptnames|
shellcmd Shell command shellcmd Shell command
shellcmdline Shell command line with filename arguments shellcmdline Shell command line with filename arguments
sign |:sign| suboptions sign |:sign| suboptions
syntax syntax file names 'syntax' syntax syntax file names |'syntax'|
syntime |:syntime| suboptions syntime |:syntime| suboptions
tag tags tag tags
tag_listfiles tags, file names tag_listfiles tags, file names
@@ -3521,19 +3433,6 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
Return: ~ Return: ~
(`string[]`) (`string[]`)
getcompletiontype({pat}) *getcompletiontype()*
Return the type of the command-line completion using {pat}.
When no corresponding completion type is found, an empty
string is returned.
To get the current command-line completion type, use
|getcmdcompltype()|.
Parameters: ~
• {pat} (`string`)
Return: ~
(`string`)
getcurpos([{winid}]) *getcurpos()* getcurpos([{winid}]) *getcurpos()*
Get the position of the cursor. This is like getpos('.'), but Get the position of the cursor. This is like getpos('.'), but
includes an extra "curswant" item in the list: includes an extra "curswant" item in the list:
@@ -3563,7 +3462,7 @@ getcurpos([{winid}]) *getcurpos()*
• {winid} (`integer?`) • {winid} (`integer?`)
Return: ~ Return: ~
(`[integer, integer, integer, integer, integer]`) (`any`)
getcursorcharpos([{winid}]) *getcursorcharpos()* getcursorcharpos([{winid}]) *getcursorcharpos()*
Same as |getcurpos()| but the column number in the returned Same as |getcurpos()| but the column number in the returned
@@ -3872,7 +3771,7 @@ getmatches([{win}]) *getmatches()*
• {win} (`integer?`) • {win} (`integer?`)
Return: ~ Return: ~
(`vim.fn.getmatches.ret.item[]`) (`any`)
getmousepos() *getmousepos()* getmousepos() *getmousepos()*
Returns a |Dictionary| with the last known position of the Returns a |Dictionary| with the last known position of the
@@ -3978,7 +3877,7 @@ getpos({expr}) *getpos()*
• {expr} (`string`) • {expr} (`string`)
Return: ~ Return: ~
(`[integer, integer, integer, integer]`) (`integer[]`)
getqflist([{what}]) *getqflist()* getqflist([{what}]) *getqflist()*
Returns a |List| with all the current quickfix errors. Each Returns a |List| with all the current quickfix errors. Each
@@ -4115,7 +4014,6 @@ getreg([{regname} [, 1 [, {list}]]]) *getreg()*
Parameters: ~ Parameters: ~
• {regname} (`string?`) • {regname} (`string?`)
• {expr} (`any?`)
• {list} (`nil|false?`) • {list} (`nil|false?`)
Return: ~ Return: ~
@@ -4195,10 +4093,6 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()*
- It is evaluated in current window context, which makes a - It is evaluated in current window context, which makes a
difference if the buffer is displayed in a window with difference if the buffer is displayed in a window with
different 'virtualedit' or 'list' values. 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 Examples: >vim
xnoremap <CR> xnoremap <CR>
@@ -4207,9 +4101,9 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()*
< <
Parameters: ~ Parameters: ~
• {pos1} (`[integer, integer, integer, integer]`) • {pos1} (`table`)
• {pos2} (`[integer, integer, integer, integer]`) • {pos2} (`table`)
• {opts} (`{type?:string, exclusive?:boolean}?`) • {opts} (`table?`)
Return: ~ Return: ~
(`string[]`) (`string[]`)
@@ -4247,13 +4141,12 @@ getregionpos({pos1}, {pos2} [, {opts}]) *getregionpos()*
(default: |FALSE|) (default: |FALSE|)
Parameters: ~ Parameters: ~
• {pos1} (`[integer, integer, integer, integer]`) • {pos1} (`table`)
• {pos2} (`[integer, integer, integer, integer]`) • {pos2} (`table`)
• {opts} • {opts} (`table?`)
(`{type?:string, exclusive?:boolean, eol?:boolean}?`)
Return: ~ Return: ~
(`[ [integer, integer, integer, integer], [integer, integer, integer, integer] ][]`) (`integer[][][]`)
getregtype([{regname}]) *getregtype()* getregtype([{regname}]) *getregtype()*
The result is a String, which is type of register {regname}. The result is a String, which is type of register {regname}.
@@ -4546,7 +4439,6 @@ getwinvar({winnr}, {varname} [, {def}]) *getwinvar()*
Examples: >vim Examples: >vim
let list_is_on = getwinvar(2, '&list') let list_is_on = getwinvar(2, '&list')
echo "myvar = " .. getwinvar(1, 'myvar') echo "myvar = " .. getwinvar(1, 'myvar')
<
Parameters: ~ Parameters: ~
• {winnr} (`integer`) • {winnr} (`integer`)
@@ -5246,7 +5138,6 @@ inputlist({textlist}) *inputlist()*
Example: >vim Example: >vim
let color = inputlist(['Select color:', '1. red', let color = inputlist(['Select color:', '1. red',
\ '2. green', '3. blue']) \ '2. green', '3. blue'])
<
Parameters: ~ Parameters: ~
• {textlist} (`string[]`) • {textlist} (`string[]`)
@@ -5424,27 +5315,22 @@ isnan({expr}) *isnan()*
Return: ~ Return: ~
(`0|1`) (`0|1`)
items({expr}) *items()* items({dict}) *items()*
Return a |List| with all key/index and value pairs of {expr}. Return a |List| with all the key-value pairs of {dict}. Each
Each |List| item is a list with two items: |List| item is a list with two items: the key of a {dict}
- for a |Dict|: the key and the value entry and the value of this entry. The |List| is in arbitrary
- for a |List| or |String|: the index and the value order. Also see |keys()| and |values()|.
The returned |List| is in arbitrary order for a |Dict|,
otherwise it's in ascending order of the index.
Also see |keys()| and |values()|.
Example: >vim Example: >vim
let mydict = #{a: 'red', b: 'blue'}
for [key, value] in items(mydict) for [key, value] in items(mydict)
echo $"{key} = {value}" echo key .. ': ' .. value
endfor endfor
echo items([1, 2, 3])
echo items("foobar")
< <
A List or a String argument is also supported. In these
cases, items() returns a List with the index and the value at
the index.
Parameters: ~ Parameters: ~
• {expr} (`table|string`) • {dict} (`table`)
Return: ~ Return: ~
(`any`) (`any`)
@@ -5753,7 +5639,6 @@ libcall({libname}, {funcname}, {argument}) *libcall()* *E364* *E
object code must be compiled as position-independent ('PIC'). object code must be compiled as position-independent ('PIC').
Examples: >vim Examples: >vim
echo libcall("libc.so", "getenv", "HOME") echo libcall("libc.so", "getenv", "HOME")
<
Parameters: ~ Parameters: ~
• {libname} (`string`) • {libname} (`string`)
@@ -7575,19 +7460,6 @@ printf({fmt}, {expr1} ...) *printf()*
Return: ~ Return: ~
(`string`) (`string`)
prompt_getinput({buf}) *prompt_getinput()*
Gets the current user-input in |prompt-buffer| {buf} without invoking
prompt_callback. {buf} can be a buffer name or number.
If the buffer doesn't exist or isn't a prompt buffer, an empty
string is returned.
Parameters: ~
• {buf} (`integer|string`)
Return: ~
(`any`)
prompt_getprompt({buf}) *prompt_getprompt()* prompt_getprompt({buf}) *prompt_getprompt()*
Returns the effective prompt text for buffer {buf}. {buf} can Returns the effective prompt text for buffer {buf}. {buf} can
be a buffer name or number. See |prompt-buffer|. be a buffer name or number. See |prompt-buffer|.
@@ -7897,7 +7769,7 @@ readfile({fname} [, {type} [, {max}]]) *readfile()*
• {max} (`integer?`) • {max} (`integer?`)
Return: ~ Return: ~
(`string[]`) (`any`)
reduce({object}, {func} [, {initial}]) *reduce()* *E998* reduce({object}, {func} [, {initial}]) *reduce()* *E998*
{func} is called for every item in {object}, which can be a {func} is called for every item in {object}, which can be a
@@ -8466,12 +8338,11 @@ searchcount([{options}]) *searchcount()*
To get the last search count when |n| or |N| was pressed, call To get the last search count when |n| or |N| was pressed, call
this function with `recompute: 0` . This sometimes returns this function with `recompute: 0` . This sometimes returns
wrong information because of 'maxsearchcount'. wrong information because |n| and |N|'s maximum count is 99.
If the count exceeded 'maxsearchcount', the result must be If it exceeded 99 the result must be max count + 1 (100). If
'maxsearchcount' + 1. If you want to get correct information, you want to get correct information, specify `recompute: 1`: >vim
specify `recompute: 1`: >vim
" result == 'maxsearchcount' + 1 when many matches " result == maxcount + 1 (100) when many matches
let result = searchcount(#{recompute: 0}) let result = searchcount(#{recompute: 0})
" Below returns correct result (recompute defaults " Below returns correct result (recompute defaults
@@ -8558,7 +8429,7 @@ searchcount([{options}]) *searchcount()*
result. if search exceeded result. if search exceeded
total count, "total" value total count, "total" value
becomes `maxcount + 1` becomes `maxcount + 1`
(default: 'maxsearchcount') (default: 0)
pos |List| `[lnum, col, off]` value pos |List| `[lnum, col, off]` value
when recomputing the result. when recomputing the result.
this changes "current" result this changes "current" result
@@ -8746,23 +8617,13 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])
Return: ~ Return: ~
(`any`) (`any`)
serverlist([{opts}]) *serverlist()* serverlist() *serverlist()*
Returns a list of server addresses, or empty if all servers Returns a list of server addresses, or empty if all servers
were stopped. |serverstart()| |serverstop()| were stopped. |serverstart()| |serverstop()|
The optional argument {opts} is a Dict and supports the following items:
peer : If |TRUE|, servers not started by |serverstart()|
will also be returned. (default: |FALSE|)
Not supported on Windows yet.
Example: >vim Example: >vim
echo serverlist() echo serverlist()
< <
Parameters: ~
• {opts} (`table?`)
Return: ~ Return: ~
(`string[]`) (`string[]`)
@@ -9004,8 +8865,6 @@ setcursorcharpos({list})
call cursor(4, 3) call cursor(4, 3)
< positions the cursor on the first character '여'. < positions the cursor on the first character '여'.
Returns 0 when the position could be set, -1 otherwise.
Parameters: ~ Parameters: ~
• {list} (`integer[]`) • {list} (`integer[]`)
@@ -9119,7 +8978,7 @@ setmatches({list} [, {win}]) *setmatches()*
window ID instead of the current window. window ID instead of the current window.
Parameters: ~ Parameters: ~
• {list} (`vim.fn.getmatches.ret.item[]`) • {list} (`any`)
• {win} (`integer?`) • {win} (`integer?`)
Return: ~ Return: ~
@@ -9360,7 +9219,6 @@ setreg({regname}, {value} [, {options}]) *setreg()*
You can also change the type of a register by appending You can also change the type of a register by appending
nothing: >vim nothing: >vim
call setreg('a', '', 'al') call setreg('a', '', 'al')
<
Parameters: ~ Parameters: ~
• {regname} (`string`) • {regname} (`string`)
@@ -9458,7 +9316,6 @@ setwinvar({nr}, {varname}, {val}) *setwinvar()*
Examples: >vim Examples: >vim
call setwinvar(1, "&list", 0) call setwinvar(1, "&list", 0)
call setwinvar(2, "myvar", "foobar") call setwinvar(2, "myvar", "foobar")
<
Parameters: ~ Parameters: ~
• {nr} (`integer`) • {nr} (`integer`)
@@ -9929,7 +9786,6 @@ sign_unplace({group} [, {dict}]) *sign_unplace()*
" Remove all the placed signs from all the buffers " Remove all the placed signs from all the buffers
call sign_unplace('*') call sign_unplace('*')
<
Parameters: ~ Parameters: ~
• {group} (`string`) • {group} (`string`)
@@ -10387,8 +10243,8 @@ stdpath({what}) *stdpath()* *E610
log String Logs directory (for use by plugins too). log String Logs directory (for use by plugins too).
run String Run directory: temporary, local storage run String Run directory: temporary, local storage
for sockets, named pipes, etc. for sockets, named pipes, etc.
state String Session state: storage for backupdir, state String Session state directory: storage for file
file drafts, |shada|, swap, undo, 'viewdir'. drafts, swap, undo, |shada|.
Example: >vim Example: >vim
echo stdpath("config") echo stdpath("config")
@@ -10586,7 +10442,6 @@ strftime({format} [, {time}]) *strftime()*
echo strftime("%H:%M") " 11:55 echo strftime("%H:%M") " 11:55
echo strftime("%c", getftime("file.c")) echo strftime("%c", getftime("file.c"))
" Show mod time of file.c. " Show mod time of file.c.
<
Parameters: ~ Parameters: ~
• {format} (`string`) • {format} (`string`)
@@ -10776,7 +10631,7 @@ strridx({haystack}, {needle} [, {start}]) *strridx()*
strtrans({string}) *strtrans()* strtrans({string}) *strtrans()*
The result is a String, which is {string} with all unprintable The result is a String, which is {string} with all unprintable
characters translated into printable characters 'isprint'. characters translated into printable characters |'isprint'|.
Like they are shown in a window. Example: >vim Like they are shown in a window. Example: >vim
echo strtrans(@a) echo strtrans(@a)
< This displays a newline in register a as "^@" instead of < This displays a newline in register a as "^@" instead of
@@ -10929,7 +10784,6 @@ swapfilelist() *swapfilelist()*
let &directory = '.' let &directory = '.'
let swapfiles = swapfilelist() let swapfiles = swapfilelist()
let &directory = save_dir let &directory = save_dir
<
Return: ~ Return: ~
(`string[]`) (`string[]`)
@@ -11318,7 +11172,7 @@ taglist({expr} [, {filename}]) *taglist()*
Refer to |tag-regexp| for more information about the tag Refer to |tag-regexp| for more information about the tag
search regular expression pattern. search regular expression pattern.
Refer to 'tags' for information about how the tags file is Refer to |'tags'| for information about how the tags file is
located by Vim. Refer to |tags-file-format| for the format of located by Vim. Refer to |tags-file-format| for the format of
the tags file generated by the different ctags tools. the tags file generated by the different ctags tools.
@@ -11684,15 +11538,12 @@ undotree([{buf}]) *undotree()*
(`vim.fn.undotree.ret`) (`vim.fn.undotree.ret`)
uniq({list} [, {func} [, {dict}]]) *uniq()* *E882* uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
Note: Prefer |vim.list.unique()| in Lua.
Remove second and succeeding copies of repeated adjacent Remove second and succeeding copies of repeated adjacent
{list} items in-place. Returns {list}. If you want a list {list} items in-place. Returns {list}. If you want a list
to remain unmodified make a copy first: >vim to remain unmodified make a copy first: >vim
let newlist = uniq(copy(mylist)) let newlist = uniq(copy(mylist))
< The default compare function uses the string representation of < The default compare function uses the string representation of
each item. For the use of {func} and {dict} see |sort()|. each item. For the use of {func} and {dict} see |sort()|.
For deduplicating text in the current buffer see |:uniq|.
Returns zero if {list} is not a |List|. Returns zero if {list} is not a |List|.
@@ -11772,7 +11623,7 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()*
last character. When "off" is omitted zero is used. When last character. When "off" is omitted zero is used. When
Virtual editing is active in the current mode, a position Virtual editing is active in the current mode, a position
beyond the end of the line can be returned. Also see beyond the end of the line can be returned. Also see
'virtualedit' |'virtualedit'|
If {list} is present and non-zero then virtcol() returns a If {list} is present and non-zero then virtcol() returns a
List with the first and last screen position occupied by the List with the first and last screen position occupied by the
@@ -11806,7 +11657,7 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()*
• {winid} (`integer?`) • {winid} (`integer?`)
Return: ~ Return: ~
(`integer|[integer, integer]`) (`any`)
virtcol2col({winid}, {lnum}, {col}) *virtcol2col()* virtcol2col({winid}, {lnum}, {col}) *virtcol2col()*
The result is a Number, which is the byte index of the The result is a Number, which is the byte index of the
@@ -11900,38 +11751,6 @@ wildmenumode() *wildmenumode()*
Return: ~ Return: ~
(`any`) (`any`)
wildtrigger() *wildtrigger()*
Start wildcard expansion in the command-line, using the
behavior defined by the 'wildmode' and 'wildoptions' settings.
See |cmdline-completion|.
This function also enables completion in search patterns such
as |/|, |?|, |:s|, |:g|, |:v| and |:vimgrep|.
Unlike pressing 'wildchar' manually, this function does not
produce a beep when no matches are found and generally
operates more quietly. This makes it suitable for triggering
completion automatically, such as from an |:autocmd|.
*cmdline-autocompletion*
Example: To make the completion menu pop up automatically as
you type on the command line, use: >vim
autocmd CmdlineChanged [:/\?] call wildtrigger()
set wildmode=noselect:lastused,full wildoptions=pum
<
To retain normal history navigation (up/down keys): >vim
cnoremap <Up> <C-U><Up>
cnoremap <Down> <C-U><Down>
<
To set an option specifically when performing a search, e.g.
to set 'pumheight': >vim
autocmd CmdlineEnter [/\?] set pumheight=8
autocmd CmdlineLeave [/\?] set pumheight&
<
Return value is always 0.
Return: ~
(`number`)
win_execute({id}, {command} [, {silent}]) *win_execute()* win_execute({id}, {command} [, {silent}]) *win_execute()*
Like `execute()` but in the context of window {id}. Like `execute()` but in the context of window {id}.
The window will temporarily be made the current window, The window will temporarily be made the current window,
@@ -12225,8 +12044,7 @@ winline() *winline()*
winnr([{arg}]) *winnr()* winnr([{arg}]) *winnr()*
The result is a Number, which is the number of the current The result is a Number, which is the number of the current
window. The top window has number 1. window. The top window has number 1.
Returns zero for a hidden or non |focusable| window, unless Returns zero for a popup window.
it is the current window.
The optional argument {arg} supports the following values: The optional argument {arg} supports the following values:
$ the number of the last window (the window $ the number of the last window (the window

View File

@@ -22,13 +22,13 @@ For inserting text see |insert.txt|.
"dl". "dl".
The <Del> key does not take a [count]. Instead, it The <Del> key does not take a [count]. Instead, it
deletes the last character of the count. deletes the last character of the count.
See 'whichwrap' for deleting a line break (join See |'whichwrap'| for deleting a line break (join
lines). lines).
*X* *dh* *X* *dh*
["x]X Delete [count] characters before the cursor [into ["x]X Delete [count] characters before the cursor [into
register x] (not |linewise|). Does the same as "dh". register x] (not |linewise|). Does the same as "dh".
Also see 'whichwrap'. Also see |'whichwrap'|.
*d* *d*
["x]d{motion} Delete text that {motion} moves over [into register ["x]d{motion} Delete text that {motion} moves over [into register
@@ -141,8 +141,8 @@ the 'joinspaces' option is on, these commands insert two spaces after a '.',
The 'B' and 'M' flags in 'formatoptions' change the behavior for inserting The 'B' and 'M' flags in 'formatoptions' change the behavior for inserting
spaces before and after a multibyte character |fo-table|. spaces before and after a multibyte character |fo-table|.
The |'[| mark is set at the end of the first line that was joined, |']| at the The '[ mark is set at the end of the first line that was joined, '] at the end
end of the resulting line. of the resulting line.
============================================================================== ==============================================================================
@@ -367,7 +367,7 @@ CTRL-A Add [count] to the number or alphabetic character at
*v_g_CTRL-A* *v_g_CTRL-A*
{Visual}g CTRL-A Add [count] to the number or alphabetic character in {Visual}g CTRL-A Add [count] to the number or alphabetic character in
the highlighted text. If several lines are the highlighted text. If several lines are
highlighted, each one will be incremented by an highlighted, each one will be incremented by an
additional [count] (so effectively creating a additional [count] (so effectively creating a
[count] incrementing sequence). [count] incrementing sequence).
For Example, if you have this list of numbers: For Example, if you have this list of numbers:
@@ -583,9 +583,9 @@ with ".". Vim does not recognize a comment (starting with '"') after the
={motion} Filter {motion} lines through the external program ={motion} Filter {motion} lines through the external program
given with the 'equalprg' option. When the 'equalprg' given with the 'equalprg' option. When the 'equalprg'
option is empty (this is the default), use the option is empty (this is the default), use the
internal formatting function |C-indenting| and 'lisp'. internal formatting function |C-indenting| and
But when 'indentexpr' is not empty, it will be used |'lisp'|. But when 'indentexpr' is not empty, it will
instead |indent-expression|. be used instead |indent-expression|.
*==* *==*
== Filter [count] lines like with ={motion}. == Filter [count] lines like with ={motion}.
@@ -644,9 +644,8 @@ original user.
Repeat last :substitute with same search pattern and Repeat last :substitute with same search pattern and
substitute string, but without the same flags. You substitute string, but without the same flags. You
may add [flags], see |:s_flags|. may add [flags], see |:s_flags|.
Note that after `:substitute` the '&' and '#' flags Note that after `:substitute` the '&' flag can't be
can't be used, they're recognized as a pattern used, it's recognized as a pattern separator.
separator.
The space between `:substitute` and the 'c', 'g', The space between `:substitute` and the 'c', 'g',
'i', 'I' and 'r' flags isn't required, but in scripts 'i', 'I' and 'r' flags isn't required, but in scripts
it's a good idea to keep it to avoid confusion. it's a good idea to keep it to avoid confusion.
@@ -949,26 +948,22 @@ This replaces each 'E' character with a euro sign. Read more in |<Char->|.
4.3 Changing tabs *change-tabs* 4.3 Changing tabs *change-tabs*
*:ret* *:retab* *:retab!* *:ret* *:retab* *:retab!*
:[range]ret[ab][!] [-indentonly] [{new-tabstop}] :[range]ret[ab][!] [new_tabstop]
Replace all sequences of white-space containing a Replace all sequences of white-space containing a
<Tab> with new strings of white-space using <Tab> with new strings of white-space using the new
{new-tabstop}. If you do not specify {new-tabstop} or tabstop value given. If you do not specify a new
it is zero, Vim uses the current value of 'tabstop'. tabstop size or it is zero, Vim uses the current value
of 'tabstop'.
The current value of 'tabstop' is always used to The current value of 'tabstop' is always used to
compute the width of existing tabs. compute the width of existing tabs.
With !, Vim also replaces strings of only normal With !, Vim also replaces strings of only normal
spaces with tabs where appropriate. spaces with tabs where appropriate.
With 'expandtab' on, Vim replaces all tabs with the With 'expandtab' on, Vim replaces all tabs with the
appropriate number of spaces. appropriate number of spaces.
This command sets 'tabstop' to {new-tabstop} and if This command sets 'tabstop' to the new value given,
performed on the whole file, which is default, should and if performed on the whole file, which is default,
not make any visible change. should not make any visible change.
Careful: This command modifies any <Tab> characters
When [-indentonly] is specified, only the leading
white-space will be targeted. Any other consecutive
white-space will not be changed.
Warning: This command modifies any <Tab> characters
inside of strings in a C program. Use "\t" to avoid inside of strings in a C program. Use "\t" to avoid
this (that's a good habit anyway). this (that's a good habit anyway).
`:retab!` may also change a sequence of spaces by `:retab!` may also change a sequence of spaces by
@@ -1110,11 +1105,6 @@ inside of strings can change! Also see 'softtabstop' option. >
:[line]pu[t]! [x] Put the text [from register x] before [line] (default :[line]pu[t]! [x] Put the text [from register x] before [line] (default
current line). current line).
*:ip* *:iput*
:[line]ip[ut] [x] like |:put|, but adjust indent to the current line
:[line]ip[ut]! [x] like |:put|!, but adjust indent to the current line
["x]]p or *]p* *]<MiddleMouse>* ["x]]p or *]p* *]<MiddleMouse>*
["x]]<MiddleMouse> Like "p", but adjust the indent to the current line. ["x]]<MiddleMouse> Like "p", but adjust the indent to the current line.
Using the mouse only works when 'mouse' contains 'n' Using the mouse only works when 'mouse' contains 'n'
@@ -1149,27 +1139,27 @@ the ":put" command, Vim always inserts the text in the next line. You can
exchange two characters with the command sequence "xp". You can exchange two exchange two characters with the command sequence "xp". You can exchange two
lines with the command sequence "ddp". You can exchange two words with the lines with the command sequence "ddp". You can exchange two words with the
command sequence "deep" (start with the cursor in the blank space before the command sequence "deep" (start with the cursor in the blank space before the
first word). You can use the |']| or |`]| command after the put command to first word). You can use the "']" or "`]" command after the put command to
move the cursor to the end of the inserted text, or use |'[| or |`[| to move move the cursor to the end of the inserted text, or use "'[" or "`[" to move
the cursor to the start. the cursor to the start.
*put-Visual-mode* *put-Visual-mode* *v_p* *v_P*
When using a put command like |p| or |P| in Visual mode, Vim will try to When using a put command like |p| or |P| in Visual mode, Vim will try to
replace the selected text with the contents of the register. How this replace the selected text with the contents of the register. Whether this
works depends on the type of selection and the text. With blockwise selection works well depends on the type of selection and the type of the text in the
it also depends on the size of the block and whether the corners are on an register. With blockwise selection it also depends on the size of the block
existing character. (Implementation detail: it actually works by first and whether the corners are on an existing character. (Implementation detail:
putting the register after the selection and then deleting the selection.) it actually works by first putting the register after the selection and then
*v_p* deleting the selection.)
|p| in Visual mode puts text and sets the default register (unnamed, With |p| the previously selected text is put in the unnamed register (and
selection, or clipboard) to the previously-selected text. Useful if you want possibly the selection and/or clipboard). This is useful if you want to put
to put that text somewhere else. But you cannot repeat the same change. that text somewhere else. But you cannot repeat the same change.
*v_P* With |P| the unnamed register is not changed (and neither the selection or
|P| in Visual mode puts text without setting the default register. You can clipboard), you can repeat the same change. But the deleted text cannot be
repeat the change, but the deleted text cannot be used. If you do need it you used. If you do need it you can use |p| with another register. E.g., yank
can use |p| with another register. E.g., yank the text to copy, Visually the text to copy, Visually select the text to replace and use "0p . You can
select the text to replace and use "0p . You can repeat this as many times as repeat this as many times as you like, and the unnamed register will be
you like, and the unnamed register will be changed each time. changed each time.
*blockwise-put* *blockwise-put*
When a register contains text from one line (characterwise), using a When a register contains text from one line (characterwise), using a
blockwise Visual selection, putting that register will paste that text blockwise Visual selection, putting that register will paste that text
@@ -1249,18 +1239,6 @@ mapped. E.g. |%| is mapped by the matchit plugin.
With each successive deletion or change, Vim shifts the previous contents With each successive deletion or change, Vim shifts the previous contents
of register 1 into register 2, 2 into 3, and so forth, losing the previous of register 1 into register 2, 2 into 3, and so forth, losing the previous
contents of register 9. contents of register 9.
*yankring*
To also store yanks (not only deletions) in registers 1-9, try this: >lua
-- Yank-ring: store yanked text in registers 1-9.
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
if vim.v.event.operator == 'y' then
for i = 9, 1, -1 do -- Shift all numbered registers.
vim.fn.setreg(tostring(i), vim.fn.getreg(tostring(i - 1)))
end
end
end,
})
3. Small delete register "- *quote_-* *quote-* 3. Small delete register "- *quote_-* *quote-*
This register contains text from commands that delete less than one line, This register contains text from commands that delete less than one line,
@@ -1736,7 +1714,7 @@ B When joining lines, don't insert a space between two multibyte
j Where it makes sense, remove a comment leader when joining lines. For j Where it makes sense, remove a comment leader when joining lines. For
example, joining: example, joining:
int i; // the index ~ int i; // the index ~
// in the list ~ // in the list ~
Becomes: Becomes:
int i; // the index in the list ~ int i; // the index in the list ~
*fo-p* *fo-p*
@@ -1839,7 +1817,6 @@ And a few warnings:
Vim has a sorting function and a sorting command. The sorting function can be Vim has a sorting function and a sorting command. The sorting function can be
found here: |sort()|, |uniq()|. found here: |sort()|, |uniq()|.
Also see |:uniq|.
*:sor* *:sort* *:sor* *:sort*
:[range]sor[t][!] [b][f][i][l][n][o][r][u][x] [/{pattern}/] :[range]sor[t][!] [b][f][i][l][n][o][r][u][x] [/{pattern}/]
@@ -1849,7 +1826,7 @@ Also see |:uniq|.
With [!] the order is reversed. With [!] the order is reversed.
With [i] case is ignored. With [i] case is ignored.
*:sort-l*
With [l] sort uses the current collation locale. With [l] sort uses the current collation locale.
Implementation details: strcoll() is used to compare Implementation details: strcoll() is used to compare
strings. See |:language| to check or set the collation strings. See |:language| to check or set the collation
@@ -1881,14 +1858,13 @@ Also see |:uniq|.
With [b] sorting is done on the first binary number in With [b] sorting is done on the first binary number in
the line (after or inside a {pattern} match). the line (after or inside a {pattern} match).
*:sort-u* *:sort-uniq*
With [u] (u stands for unique) only keep the first of With [u] (u stands for unique) only keep the first of
a sequence of identical lines (ignoring case when [i] a sequence of identical lines (ignoring case when [i]
is used). Without this flag, a sequence of identical is used). Without this flag, a sequence of identical
lines will be kept in their original order. lines will be kept in their original order.
Note that leading and trailing white space may cause Note that leading and trailing white space may cause
lines to be different. lines to be different.
When you just want to make things unique, use |:uniq|.
When /{pattern}/ is specified and there is no [r] flag When /{pattern}/ is specified and there is no [r] flag
the text matched with {pattern} is skipped, so that the text matched with {pattern} is skipped, so that
@@ -1935,55 +1911,4 @@ The sorting can be interrupted, but if you interrupt it too late in the
process you may end up with duplicated lines. This also depends on the system process you may end up with duplicated lines. This also depends on the system
library function used. library function used.
==============================================================================
8. Deduplicating text *deduplicating* *unique*
Vim has a deduplicating function and a deduplicating command. The
deduplicating function can be found here: |uniq()|.
Also see |:sort-uniq|.
*:uni* *:uniq*
:[range]uni[q][!] [i][l][r][u] [/{pattern}/]
Remove duplicate lines that are adjacent to each other
in [range]. When no range is given, all lines are
processed.
With [i] case is ignored when comparing lines.
With [l] comparison uses the current collation locale.
See |:sort-l| for more details.
With [r] comparison is done on the text that matches
/{pattern}/ instead of the full line.
With [u] only keep lines that do not repeat (i.e., are
not immediately followed by the same line).
With [!] only keep lines that are immediately followed
by a duplicate.
If both [!] and [u] are given, [u] is ignored and [!]
takes effect.
When /{pattern}/ is specified and [r] is not used, the
text matched with {pattern} is skipped and comparison
is done on what comes after the match.
'ignorecase' applies to the pattern, but 'smartcase'
is not used.
Instead of the slash any non-letter can be used.
For example, to remove adjacent duplicate lines based
on the second comma-separated field: >
:uniq /[^,]*,/
< Or to keep only unique lines ignoring the first 5
characters: >
:uniq u /.\{5}/
< If {pattern} is empty (e.g. // is used), the last
search pattern is used.
Note that leading and trailing white space may cause
lines to be considered different.
To remove all duplicates regardless of position, use
|:sort-u| or external tools.
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -177,85 +177,84 @@ Put this in `uppercase.vim` and run: >bash
============================================================================== ==============================================================================
5. Using a prompt buffer *prompt-buffer* 5. Using a prompt buffer *prompt-buffer*
Prompt buffers provide a "prompt" interface: they are like regular buffers, If you want to type input for the job in a Vim window you have a few options:
except only the last section of the buffer is editable, and the user can - Use a normal buffer and handle all possible commands yourself.
"submit" the prompt by hitting Enter. Useful for implementing: This will be complicated, since there are so many possible commands.
- Use a terminal window. This works well if what you type goes directly to
- chat UI the job and the job output is directly displayed in the window.
- REPL or shell plugins See |terminal|.
- advanced "picker" plugins - Use a window with a prompt buffer. This works well when entering a line for
the job in Vim while displaying (possibly filtered) output from the job.
A prompt buffer is created by setting 'buftype' to "prompt". You would A prompt buffer is created by setting 'buftype' to "prompt". You would
normally only do that in a newly created buffer: >vim normally only do that in a newly created buffer.
:set buftype=prompt The user can edit and enter one line of text at the very last line of the
buffer. When pressing Enter in the prompt line the callback set with
|prompt_setcallback()| is invoked. It would normally send the line to a job.
Another callback would receive the output from the job and display it in the
buffer, below the prompt (and above the next prompt).
The user can edit and enter text at the end of the buffer. Pressing Enter in Only the text in the last line, after the prompt, is editable. The rest of the
the prompt section invokes the |prompt_setcallback()| callback, which is buffer is not modifiable with Normal mode commands. It can be modified by
typically expected to process the prompt and show results by appending to the calling functions, such as |append()|. Using other commands may mess up the
buffer. To input multiline text, use Shift+Enter to add a new line without buffer.
submitting the prompt, or just |put| or |paste| multiline text.
Only the "prompt" part of the buffer user-editable, given by the |':| mark. After setting 'buftype' to "prompt" Vim does not automatically start Insert
The rest of the buffer is not modifiable with Normal mode commands, though it mode, use `:startinsert` if you want to enter Insert mode, so that the user
can be modified by functions such as |append()|. Using other commands may can start typing a line.
mess up the buffer.
After setting `buftype=prompt`: The text of the prompt can be set with the |prompt_setprompt()| function. If
- Nvim unsets the 'comments' option. no prompt is set with |prompt_setprompt()|, "% " is used. You can get the
- Nvim does not automatically start Insert mode (use `:startinsert` if you effective prompt text for a buffer, with |prompt_getprompt()|.
want to enter Insert mode)
The prompt prefix defaults to "% ", but can be set with |prompt_setprompt()|.
You can get the effective prompt prefix for with |prompt_getprompt()|.
The user can go to Normal mode and navigate through the buffer. This can be The user can go to Normal mode and navigate through the buffer. This can be
useful to see older output or copy text. useful to see older output or copy text.
By default during prompt insert-mode, the CTRL-W key can be used to start The CTRL-W key can be used to start a window command, such as CTRL-W w to
a window command, such as CTRL-W w to switch to the next window. (Use switch to the next window. This also works in Insert mode (use Shift-CTRL-W
Shift-CTRL-W to delete a word). When leaving the window Insert mode will be to delete a word). When leaving the window Insert mode will be stopped. When
stopped. When coming back to the prompt window Insert mode will be restored. coming back to the prompt window Insert mode will be restored.
Any command that starts Insert mode, such as "a", "i", "A" and "I", will move Any command that starts Insert mode, such as "a", "i", "A" and "I", will move
the cursor to the last line. "A" will move to the end of the line, "I" to the the cursor to the last line. "A" will move to the end of the line, "I" to the
start of the line. start of the line.
Example: start a shell in the background and prompt for the next shell Here is an example for Unix. It starts a shell in the background and prompts
command, displaying shell output above the prompt: >vim for the next shell command. Output from the shell is displayed above the
prompt. >vim
" Handles a line of user input. " Function handling a line of text that has been typed.
func OnSubmit(text) func TextEntered(text)
" Send the text to a shell with Enter appended. " Send the text to a shell with Enter appended.
call chansend(g:shell_job, [a:text, '']) call chansend(g:shell_job, [a:text, ''])
endfunc endfunc
" Handles output from the shell. " Function handling output from the shell: Add it above the prompt.
func OnOutput(channel, msg, name) func GotOutput(channel, msg, name)
" Add shell output above the prompt. call append(line("$") - 1, a:msg)
call append(line('$') - 1, a:msg) endfunc
endfunc
" Handles the shell exit. " Function handling the shell exits: close the window.
func JobExit(job, status, event) func JobExit(job, status, event)
quit! quit!
endfunc endfunc
" Start a shell in the background. " Start a shell in the background.
let shell_job = jobstart(['/bin/sh'], #{ let shell_job = jobstart(["/bin/sh"], #{
\ on_stdout: function('OnOutput'), \ on_stdout: function('GotOutput'),
\ on_stderr: function('OnOutput'), \ on_stderr: function('GotOutput'),
\ on_exit: function('JobExit'), \ on_exit: function('JobExit'),
\ }) \ })
new new
set buftype=prompt set buftype=prompt
let buf = bufnr('') let buf = bufnr('')
call prompt_setcallback(buf, function('OnSubmit')) call prompt_setcallback(buf, function("TextEntered"))
call prompt_setprompt(buf, 'shell command: ') call prompt_setprompt(buf, "shell command: ")
" Start accepting shell commands. " start accepting shell commands
startinsert startinsert
< <
vim:tw=78:ts=8:et:sw=4:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -142,16 +142,13 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
typing CTRL-R and the second character '"' will be displayed typing CTRL-R and the second character '"' will be displayed
to indicate that you are expected to enter the name of a to indicate that you are expected to enter the name of a
register. register.
When used with named or clipboard registers (A-Z,a-z,0-9,+) The text is inserted as if you typed it, but mappings and
text is inserted literally like pasting with "p". For other abbreviations are not used. Command-line completion through
registers, the text is inserted as if you typed it, but 'wildchar' is not triggered though. And characters that end
mappings and abbreviations are not used. Command-line the command line are inserted literally (<Esc>, <CR>, <NL>,
completion through 'wildchar' is not triggered though. And <C-C>). A <BS> or CTRL-W could still end the command line
characters that end the command line are inserted literally though, and remaining characters will then be interpreted in
(<Esc>, <CR>, <NL>, <C-C>). A <BS> or CTRL-W could still end another mode, which might not be what you intended.
the command line though, and remaining characters will then be
interpreted in another mode, which might not be what you
intended.
Special registers: Special registers:
'"' the unnamed register, containing the text of '"' the unnamed register, containing the text of
the last delete or yank the last delete or yank
@@ -179,9 +176,7 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
sure the expression evaluates to an empty sure the expression evaluates to an empty
string. E.g.: > string. E.g.: >
<C-R><C-R>=setcmdpos(2)[-1]<CR> <C-R><C-R>=setcmdpos(2)[-1]<CR>
< You can use this to insert a register as < See |registers| about registers.
typed with CTRL-R =@reg.
See |registers| about registers.
Implementation detail: When using the |expression| register Implementation detail: When using the |expression| register
and invoking setcmdpos(), this sets the position before and invoking setcmdpos(), this sets the position before
inserting the resulting string. Use CTRL-R CTRL-R to set the inserting the resulting string. Use CTRL-R CTRL-R to set the
@@ -393,7 +388,7 @@ CTRL-D List names that match the pattern in front of the cursor.
to the end. to the end.
The 'wildoptions' option can be set to "tagfile" to list the The 'wildoptions' option can be set to "tagfile" to list the
file of matching tags. file of matching tags.
*c_CTRL-I* *c_wildchar* *c_<Tab>* */_<Tab>* *c_CTRL-I* *c_wildchar* *c_<Tab>*
'wildchar' option 'wildchar' option
A match is done on the pattern in front of the cursor. The A match is done on the pattern in front of the cursor. The
match (if there are several, the first match) is inserted match (if there are several, the first match) is inserted
@@ -403,10 +398,6 @@ CTRL-D List names that match the pattern in front of the cursor.
again and there were multiple matches, the next again and there were multiple matches, the next
match is inserted. After the last match, the first is used match is inserted. After the last match, the first is used
again (wrap around). again (wrap around).
In search context use <CTRL-V><Tab> or "\t" to search for a
literal <Tab> instead of triggering completion.
The behavior can be changed with the 'wildmode' option. The behavior can be changed with the 'wildmode' option.
*c_<S-Tab>* *c_<S-Tab>*
<S-Tab> Like 'wildchar' or <Tab>, but begin with the last match and <S-Tab> Like 'wildchar' or <Tab>, but begin with the last match and
@@ -439,7 +430,7 @@ CTRL-G When 'incsearch' is set, entering a search pattern for "/" or
"?" and the current match is displayed then CTRL-G will move "?" and the current match is displayed then CTRL-G will move
to the next match (does not take |search-offset| into account) to the next match (does not take |search-offset| into account)
Use CTRL-T to move to the previous match. Hint: on a regular Use CTRL-T to move to the previous match. Hint: on a regular
keyboard G is below T. keyboard T is above G.
*c_CTRL-T* */_CTRL-T* *c_CTRL-T* */_CTRL-T*
CTRL-T When 'incsearch' is set, entering a search pattern for "/" or CTRL-T When 'incsearch' is set, entering a search pattern for "/" or
"?" and the current match is displayed then CTRL-T will move "?" and the current match is displayed then CTRL-T will move
@@ -456,8 +447,6 @@ When repeating 'wildchar' or CTRL-N you cycle through the matches, eventually
ending up back to what was typed. If the first match is not what you wanted, ending up back to what was typed. If the first match is not what you wanted,
you can use <S-Tab> or CTRL-P to go straight back to what you typed. you can use <S-Tab> or CTRL-P to go straight back to what you typed.
See also |wildtrigger()|.
The 'wildmenu' option can be set to show the matches just above the command The 'wildmenu' option can be set to show the matches just above the command
line. line.
@@ -575,6 +564,7 @@ that see the '"' as part of their argument:
:menu (and the like) :menu (and the like)
:mkspell :mkspell
:normal :normal
:ownsyntax
:popup :popup
:registers :registers
:return :return
@@ -872,7 +862,7 @@ to insert special things while typing you can use the CTRL-R command. For
example, "%" stands for the current file name, while CTRL-R % inserts the example, "%" stands for the current file name, while CTRL-R % inserts the
current file name right away. See |c_CTRL-R|. current file name right away. See |c_CTRL-R|.
Note: If you want to avoid the effects of special characters in a Vim script Note: If you want to avoid the effects of special characters in a Vim script
you may want to use |fnameescape()|. Also see |`=|. you may want to use |fnameescape()|. Also see |`=|.
@@ -947,6 +937,14 @@ Note: these are typed literally, they are not special keys!
events). events).
When the match is with a file name, it is expanded to the When the match is with a file name, it is expanded to the
full path. full path.
*:<sfile>* *<sfile>*
<sfile> When executing a `:source` command, is replaced with the
file name of the sourced file. *E498*
When executing a function, is replaced with the call stack,
as with <stack> (this is for backwards compatibility, using
<stack> or <script> is preferred).
Note that filename-modifiers are useless when <sfile> is
not used inside a script.
*:<stack>* *<stack>* *:<stack>* *<stack>*
<stack> is replaced with the call stack, using <stack> is replaced with the call stack, using
"function {function-name}[{lnum}]" for a function line "function {function-name}[{lnum}]" for a function line
@@ -954,7 +952,7 @@ Note: these are typed literally, they are not special keys!
".." in between items. E.g.: ".." in between items. E.g.:
"function {function-name1}[{lnum}]..{function-name2}[{lnum}]" "function {function-name1}[{lnum}]..{function-name2}[{lnum}]"
If there is no call stack you get error *E489* . If there is no call stack you get error *E489* .
*:<script>* *<script>* *E498* *:<script>* *<script>*
<script> When executing a `:source` command, is replaced with the file <script> When executing a `:source` command, is replaced with the file
name of the sourced file. When executing a function, is name of the sourced file. When executing a function, is
replaced with the file name of the script where it is replaced with the file name of the script where it is
@@ -973,7 +971,7 @@ Note: these are typed literally, they are not special keys!
*filename-modifiers* *filename-modifiers*
*:_%:* *::8* *::p* *::.* *::~* *::h* *::t* *::r* *::e* *::s* *::gs* *::S* *:_%:* *::8* *::p* *::.* *::~* *::h* *::t* *::r* *::e* *::s* *::gs* *::S*
*%:8* *%:p* *%:.* *%:~* *%:h* *%:t* *%:r* *%:e* *%:s* *%:gs* *%:S* *%:8* *%:p* *%:.* *%:~* *%:h* *%:t* *%:r* *%:e* *%:s* *%:gs* *%:S*
The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<script>", The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<sfile>",
"<afile>" or "<abuf>". They are also used with the |fnamemodify()| function. "<afile>" or "<abuf>". They are also used with the |fnamemodify()| function.
These modifiers can be given, in this order: These modifiers can be given, in this order:
:p Make file name a full path. Must be the first modifier. Also :p Make file name a full path. Must be the first modifier. Also
@@ -1244,10 +1242,8 @@ Example: >
:au CmdwinLeave : let &cpt = b:cpt_save :au CmdwinLeave : let &cpt = b:cpt_save
This sets 'complete' to use completion in the current window for |i_CTRL-N|. This sets 'complete' to use completion in the current window for |i_CTRL-N|.
Another example: > Another example: >
:au CmdwinEnter [/\?] startinsert :au CmdwinEnter [/?] startinsert
This will make Vim start in Insert mode in the command-line window. This will make Vim start in Insert mode in the command-line window.
Note: The "?" needs to be escaped, as this is a |file-pattern|. See also
|cmdline-autocompletion|.
*cmdline-char* *cmdwin-char* *cmdline-char* *cmdwin-char*
The character used for the pattern indicates the type of command-line: The character used for the pattern indicates the type of command-line:

View File

@@ -160,4 +160,5 @@ In WinDbg: choose Open Crash Dump on the File menu. Follow the instructions in
Visual Studio 2017 Community Edition can be downloaded for free from: Visual Studio 2017 Community Edition can be downloaded for free from:
https://visualstudio.microsoft.com/downloads/ https://visualstudio.microsoft.com/downloads/
=========================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -12,42 +12,6 @@ They should not be used in new scripts, and old scripts should be updated.
============================================================================== ==============================================================================
Deprecated features Deprecated features
------------------------------------------------------------------------------
DEPRECATED IN 0.12 *deprecated-0.12*
API
• todo
DIAGNOSTICS
• "float" in |vim.diagnostic.JumpOpts|. Use "on_jump" instead.
• "float" in |vim.diagnostic.Opts.Jump|. Use "on_jump" instead.
HIGHLIGHTS
• *:ownsyntax* *w:current_syntax* Use 'winhighlight' instead.
LSP
• *vim.lsp.client_is_stopped()* Use |vim.lsp.get_client_by_id()| instead.
• *vim.lsp.util.stylize_markdown()* Use |vim.treesitter.start()| with
`vim.wo.conceallevel = 2`.
• *vim.lsp.log.should_log()* Use |vim.lsp.log.set_format_func()| instead
and return `nil` to omit entries from the logfile.
• *vim.lsp.semantic_tokens.start()* Use `vim.lsp.semantic_tokens.enable(true)` instead
• *vim.lsp.semantic_tokens.stop()* Use `vim.lsp.semantic_tokens.enable(false)` instead
• *vim.lsp.set_log_level()* Use `vim.lsp.log.set_level()` instead
• *vim.lsp.get_log_path()* Use `vim.lsp.log.get_filename()` instead
LUA
• *vim.diff()* Renamed to |vim.text.diff()|
VIMSCRIPT
• todo
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
DEPRECATED IN 0.11 *deprecated-0.11* DEPRECATED IN 0.11 *deprecated-0.11*
@@ -102,7 +66,7 @@ LUA
• vim.validate(opts: table) Use form 1. See |vim.validate()|. • vim.validate(opts: table) Use form 1. See |vim.validate()|.
VIMSCRIPT VIMSCRIPT
• *termopen()* Use |jobstart()| with `{term: v:true}`. • *termopen()* Use |jobstart() with `{term: v:true}`.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
DEPRECATED IN 0.10 *deprecated-0.10* DEPRECATED IN 0.10 *deprecated-0.10*
@@ -334,12 +298,13 @@ UI EXTENSIONS
• *term_background* Unused. The terminal background color is now detected • *term_background* Unused. The terminal background color is now detected
by the Nvim core directly instead of the TUI. by the Nvim core directly instead of the TUI.
VIMSCRIPT VARIABLES
• *<sfile>* Use |<script>| or |<stack>| instead.
• *b:terminal_job_pid* Use `jobpid(&channel)` instead. • *b:terminal_job_pid* Use `jobpid(&channel)` instead.
• *b:terminal_job_id* Use `&channel` instead. To access in non-current buffer: • *b:terminal_job_id* Use `&channel` instead. To access in non-current buffer:
• Lua: `vim.bo[bufnr].channel` • Lua: `vim.bo[bufnr].channel`
• Vimscript: `getbufvar(bufnr, '&channel')` • Vimscript: `getbufvar(bufnr, '&channel')`
VIMSCRIPT
• *buffer_exists()* Obsolete name for |bufexists()|. • *buffer_exists()* Obsolete name for |bufexists()|.
• *buffer_name()* Obsolete name for |bufname()|. • *buffer_name()* Obsolete name for |bufname()|.
• *buffer_number()* Obsolete name for |bufnr()|. • *buffer_number()* Obsolete name for |bufnr()|.

View File

@@ -53,27 +53,6 @@ Other references:
- https://github.com/neovim/neovim/pull/21605 - https://github.com/neovim/neovim/pull/21605
==============================================================================
API
*dev-api-fast*
API functions and Vimscript "eval" functions may be marked as |api-fast| which
means they are safe to call in Lua callbacks and other scenarios. A functions
CANNOT be marked as "fast" if could trigger `os_breakcheck()`, which may
"yield" the current execution and start a new execution of code not expecting
this:
- accidentally recursing into a function not expecting this.
- changing (global) state without restoring it before returning to the
"yielded" callsite.
In practice, this means any code that could trigger `os_breakcheck()` cannot
be "fast". For example, commit 3940c435e405 fixed such a bug with
`nvim__get_runtime` by explicitly disallowing `os_breakcheck()` via the
`EW_NOBREAK` flag.
Common examples of non-fast code: regexp matching, wildcard expansion,
expression evaluation.
============================================================================== ==============================================================================

View File

@@ -255,7 +255,8 @@ functions. >c
Integration with declarations generator ~ Integration with declarations generator ~
Every C file must contain #include of the generated header file. Every C file must contain #include of the generated header file, guarded by
#ifdef INCLUDE_GENERATED_DECLARATIONS.
Include must go after other #includes and typedefs in .c files and after Include must go after other #includes and typedefs in .c files and after
everything else in header files. It is allowed to omit #include in a .c file everything else in header files. It is allowed to omit #include in a .c file
@@ -271,7 +272,9 @@ contain only non-static function declarations. >c
typedef int FooType; typedef int FooType;
#include "foo.c.generated.h" #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.c.generated.h"
#endif
@@ -281,7 +284,9 @@ contain only non-static function declarations. >c
#include "foo.h.generated.h" #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.h.generated.h"
#endif
64-bit Portability ~ 64-bit Portability ~
@@ -896,8 +901,8 @@ Return Values ~
Do not needlessly surround the `return` expression with parentheses. Do not needlessly surround the `return` expression with parentheses.
Use parentheses in `return expr;` only where you would also use them in Use parentheses in `return expr`; only where you would use them in `x =
`x = expr;`. >c expr;`. >c
return result; return result;
return (some_long_condition && another_condition); return (some_long_condition && another_condition);

View File

@@ -171,8 +171,8 @@ USING GDBSERVER IN TMUX
Consider using a custom makefile Consider using a custom makefile
https://github.com/neovim/neovim/blob/master/BUILD.md#custom-makefile to https://github.com/neovim/neovim/blob/master/BUILD.md#custom-makefile to
quickly start debugging sessions using the `gdbserver` method mentioned above. quickly start debugging sessions using the `gdbserver` method mentioned above.
This example `local.mk` will create the debugging session when you type This example `local.mk` will create the debugging session when you type `make
`make debug`. debug`.
>make >make
.PHONY: dbg-start dbg-attach debug build .PHONY: dbg-start dbg-attach debug build

View File

@@ -201,7 +201,7 @@ Docstring format:
- Markdown is supported. - Markdown is supported.
- Tags are written as `[tag]()`. - Tags are written as `[tag]()`.
- References are written as `[tag]` - References are written as `[tag]`
- Use "```" for code samples. - Use ``` for code samples.
Code samples can be annotated as `vim` or `lua` Code samples can be annotated as `vim` or `lua`
Example: the help for |nvim_open_win()| is generated from a docstring defined Example: the help for |nvim_open_win()| is generated from a docstring defined
@@ -245,7 +245,7 @@ Docstring format:
- Markdown is supported. - Markdown is supported.
- Tags are written as `[tag]()`. - Tags are written as `[tag]()`.
- References are written as `[tag]` - References are written as `[tag]`
- Use "```" for code samples. - Use ``` for code samples.
Code samples can be annotated as `vim` or `lua` Code samples can be annotated as `vim` or `lua`
- Use `@since <api-level>` to note the |api-level| when the function became - Use `@since <api-level>` to note the |api-level| when the function became
"stable". If `<api-level>` is greater than the current stable release (or "stable". If `<api-level>` is greater than the current stable release (or
@@ -353,7 +353,7 @@ Where possible, these patterns apply to _both_ Lua and the API:
- Examples: |vim.lsp.codelens.clear()| |vim.diagnostic.enable()| - Examples: |vim.lsp.codelens.clear()| |vim.diagnostic.enable()|
- Any function signature that accepts a callback (example: |table.foreach()|) - Any function signature that accepts a callback (example: |table.foreach()|)
should place it as the LAST parameter (after opts), if possible (or ALWAYS should place it as the LAST parameter (after opts), if possible (or ALWAYS
for |continuation|s——functions called exactly once). for "continuation callbacks"—functions called exactly once).
- Improves readability by placing the less "noisy" arguments near the start. - Improves readability by placing the less "noisy" arguments near the start.
- Consistent with luv. - Consistent with luv.
- Useful for future async lib which transforms functions of the form - Useful for future async lib which transforms functions of the form
@@ -426,9 +426,6 @@ Use existing common {verb} names (actions) if possible:
- add: Appends or inserts into a collection - add: Appends or inserts into a collection
- attach: Listens to something to get events from it (TODO: rename to "on"?) - attach: Listens to something to get events from it (TODO: rename to "on"?)
- call: Calls a function - call: Calls a function
- callback |continuation|: Function parameter (NOT a field) that
returns the result of an async function. Use the "on_…"
naming-convention for all other callbacks and event handlers.
- cancel: Cancels or dismisses an event or interaction, typically - cancel: Cancels or dismisses an event or interaction, typically
user-initiated and without error. (Compare "abort", which user-initiated and without error. (Compare "abort", which
cancels and signals error/failure.) cancels and signals error/failure.)
@@ -444,15 +441,10 @@ Use existing common {verb} names (actions) if possible:
- get: Gets things. Two variants (overloads): - get: Gets things. Two variants (overloads):
1. `get<T>(id: int): T` returns one item. 1. `get<T>(id: int): T` returns one item.
2. `get<T>(filter: dict): T[]` returns a list. 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 - inspect: Presents a high-level, often interactive, view
- is_enabled: Checks if functionality is enabled. - is_enabled: Checks if functionality is enabled.
- on_…: Handles events or async results, or registers such
a handler. |dev-name-events|
- open: Opens something (a buffer, window, …) - open: Opens something (a buffer, window, …)
- parse: Parses something into a structured form - parse: Parses something into a structured form
- request: Calls a remote (network, RPC) operation.
- send: Writes data or a message to a channel.
- set: Sets a thing (or group of things) - set: Sets a thing (or group of things)
- start: Spin up a long-lived process. Prefer "enable" except when - start: Spin up a long-lived process. Prefer "enable" except when
"start" is obviously more appropriate. "start" is obviously more appropriate.
@@ -460,10 +452,9 @@ Use existing common {verb} names (actions) if possible:
- try_{verb}: Best-effort operation, failure returns null or error obj - try_{verb}: Best-effort operation, failure returns null or error obj
Do NOT use these deprecated verbs: Do NOT use these deprecated verbs:
- contains: Prefer "has".
- disable: Prefer `enable(enable: boolean)`. - disable: Prefer `enable(enable: boolean)`.
- exit: Prefer "cancel" (or "stop" if appropriate). - exit: Prefer "cancel" (or "stop" if appropriate).
- is_disabled: Prefer `!is_enabled()`. - is_disabled: Prefer `is_enabled()`.
- list: Redundant with "get" - list: Redundant with "get"
- notify: Redundant with "print", "echo" - notify: Redundant with "print", "echo"
- show: Redundant with "print", "echo" - show: Redundant with "print", "echo"
@@ -484,6 +475,7 @@ everywhere, not "buffer" in some places and "buf" in others.
Do NOT use these deprecated nouns: Do NOT use these deprecated nouns:
- buffer Use "buf" instead - buffer Use "buf" instead
- callback Use on_foo instead
- command Use "cmd" instead - command Use "cmd" instead
- window Use "win" instead - window Use "win" instead
@@ -501,14 +493,6 @@ Use this format to name API (RPC) events: >
Example: > Example: >
nvim_buf_changedtick_event nvim_buf_changedtick_event
< <
*continuation*
A "continuation" is implemented as a callback function that returns the result
of an async function and is called exactly once. Often accepts `err` as the
first parameter, to avoid erroring on the main thread. Example: >
foo(…, callback: fun(err, …))
Use the name `callback` only for a continuation. All other callbacks and event
handlers should be named with the |dev-name-events| "on_…" convention.
*dev-api-name* *dev-api-name*
Use this format to name new RPC |API| functions: > Use this format to name new RPC |API| functions: >
nvim_{topic}_{verb}_{arbitrary-qualifiers} nvim_{topic}_{verb}_{arbitrary-qualifiers}
@@ -682,8 +666,6 @@ External UIs are expected to implement these common features:
the user). the user).
- Support the text decorations/attributes given by |ui-event-hl_attr_define|. - Support the text decorations/attributes given by |ui-event-hl_attr_define|.
The "url" attr should be presented as a clickable hyperlink. The "url" attr should be presented as a clickable hyperlink.
- Handle the "restart" UI event so that |:restart| works.
- Detect capslock and show an indicator if capslock is active.
vim:tw=78:ts=8:sw=4:et:ft=help:norl: vim:tw=78:ts=8:sw=4:et:ft=help:norl:

View File

@@ -69,16 +69,6 @@ Functions that take a severity as an optional parameter (e.g.
< <
This form allows users to filter for specific severities 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* HANDLERS *diagnostic-handlers*
@@ -190,28 +180,6 @@ the `virtual_lines` handler with the following keymap: >lua
end, { desc = 'Toggle diagnostic virtual_lines' }) end, { desc = 'Toggle diagnostic virtual_lines' })
< <
*diagnostic-on-jump-example*
You can use the `on_jump` option from |vim.diagnostic.jump()| to show the
diagnostic that was jumped to using a specific handler. For example, the
following uses the `virtual_lines` handler when jumping to a diagnostic: >lua
local virt_lines_ns = vim.api.nvim_create_namespace 'on_diagnostic_jump'
--- @param diagnostic? vim.Diagnostic
--- @param bufnr integer
local function on_jump(diagnostic, bufnr)
if not diagnostic then return end
vim.diagnostic.show(
virt_lines_ns,
bufnr,
{ diagnostic },
{ virtual_lines = { current_line = true }, virtual_text = false }
)
end
vim.diagnostic.config({ jump = { on_jump = on_jump } })
<
*diagnostic-loclist-example* *diagnostic-loclist-example*
Whenever the |location-list| is opened, the following `show` handler will show Whenever the |location-list| is opened, the following `show` handler will show
the most recent diagnostics: >lua the most recent diagnostics: >lua
@@ -440,43 +408,27 @@ Example: >lua
Lua module: vim.diagnostic *diagnostic-api* Lua module: vim.diagnostic *diagnostic-api*
*vim.Diagnostic* *vim.Diagnostic*
Extends: |vim.Diagnostic.Set|
*diagnostic-structure* *diagnostic-structure*
Diagnostics use the same indexing as the rest of the Nvim API (i.e. Diagnostics use the same indexing as the rest of the Nvim API (i.e.
0-based rows and columns). |api-indexing| 0-based rows and columns). |api-indexing|
Fields: ~ Fields: ~
• {bufnr} (`integer`) Buffer number • {bufnr}? (`integer`) Buffer number
• {end_lnum} (`integer`) The final line of the diagnostic (0-indexed)
• {col} (`integer`) The starting column of the diagnostic
(0-indexed)
• {end_col} (`integer`) The final column of the diagnostic
(0-indexed)
• {severity} (`vim.diagnostic.Severity`) The severity of the
diagnostic |vim.diagnostic.severity|
• {namespace}? (`integer`)
*vim.Diagnostic.Set*
Diagnostics use the same indexing as the rest of the Nvim API (i.e.
0-based rows and columns). |api-indexing|
Fields: ~
• {lnum} (`integer`) The starting line of the diagnostic • {lnum} (`integer`) The starting line of the diagnostic
(0-indexed) (0-indexed)
• {col}? (`integer`, default: `0`) The starting column of the • {end_lnum}? (`integer`) The final line of the diagnostic (0-indexed)
diagnostic (0-indexed) • {col} (`integer`) The starting column of the diagnostic
• {end_lnum}? (`integer`, default: `lnum`) The final line of the (0-indexed)
diagnostic (0-indexed) • {end_col}? (`integer`) The final column of the diagnostic
• {end_col}? (`integer`, default: `col`) The final column of the (0-indexed)
diagnostic (0-indexed) • {severity}? (`vim.diagnostic.Severity`) The severity of the
• {severity}? (`vim.diagnostic.Severity`, default: `vim.diagnostic.severity.ERROR`) diagnostic |vim.diagnostic.severity|
The severity of the diagnostic |vim.diagnostic.severity|
• {message} (`string`) The diagnostic text • {message} (`string`) The diagnostic text
• {source}? (`string`) The source of the diagnostic • {source}? (`string`) The source of the diagnostic
• {code}? (`string|integer`) The diagnostic code • {code}? (`string|integer`) The diagnostic code
• {user_data}? (`any`) arbitrary data plugins can add • {user_data}? (`any`) arbitrary data plugins can add
• {namespace}? (`integer`)
*vim.diagnostic.GetOpts* *vim.diagnostic.GetOpts*
A table with the following keys: A table with the following keys:
@@ -488,9 +440,6 @@ Lua module: vim.diagnostic *diagnostic-api*
specified line number. specified line number.
• {severity}? (`vim.diagnostic.SeverityFilter`) See • {severity}? (`vim.diagnostic.SeverityFilter`) See
|diagnostic-severity|. |diagnostic-severity|.
• {enabled}? (`boolean`, default: `nil`) Limit diagnostics to only
enabled or disabled. If nil, enablement is ignored. See
|vim.diagnostic.enable()|
*vim.diagnostic.JumpOpts* *vim.diagnostic.JumpOpts*
Extends: |vim.diagnostic.GetOpts| Extends: |vim.diagnostic.GetOpts|
@@ -516,9 +465,13 @@ Lua module: vim.diagnostic *diagnostic-api*
file or not. Similar to 'wrapscan'. file or not. Similar to 'wrapscan'.
• {severity}? (`vim.diagnostic.SeverityFilter`) See • {severity}? (`vim.diagnostic.SeverityFilter`) See
|diagnostic-severity|. |diagnostic-severity|.
• {on_jump}? (`fun(diagnostic:vim.Diagnostic?, bufnr:integer)`) • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: `false`)
Optional callback invoked with the diagnostic that was If `true`, call |vim.diagnostic.open_float()| after
jumped to. moving. If a table, pass the table as the {opts}
parameter to |vim.diagnostic.open_float()|. Unless
overridden, the float will show diagnostics at the new
cursor position (as if "cursor" were passed to the
"scope" option).
• {winid}? (`integer`, default: `0`) Window ID • {winid}? (`integer`, default: `0`) Window ID
*vim.diagnostic.NS* *vim.diagnostic.NS*
@@ -572,8 +525,7 @@ Lua module: vim.diagnostic *diagnostic-api*
Fields: ~ Fields: ~
• {bufnr}? (`integer`, default: current buffer) Buffer number • {bufnr}? (`integer`, default: current buffer) Buffer number
to show diagnostics from. to show diagnostics from.
• {namespace}? (`integer|integer[]`) Limit diagnostics to the given • {namespace}? (`integer`) Limit diagnostics to the given namespace
namespace(s).
• {scope}? (`'line'|'buffer'|'cursor'|'c'|'l'|'b'`, default: • {scope}? (`'line'|'buffer'|'cursor'|'c'|'l'|'b'`, default:
`line`) Show diagnostics from the whole buffer `line`) Show diagnostics from the whole buffer
(`buffer"`, the current cursor line (`line`), or the (`buffer"`, the current cursor line (`line`), or the
@@ -631,8 +583,8 @@ Lua module: vim.diagnostic *diagnostic-api*
*vim.diagnostic.Opts.Jump* *vim.diagnostic.Opts.Jump*
Fields: ~ Fields: ~
• {on_jump}? (`fun(diagnostic:vim.Diagnostic?, bufnr:integer)`) • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: false)
Default value of the {on_jump} parameter of Default value of the {float} parameter of
|vim.diagnostic.jump()|. |vim.diagnostic.jump()|.
• {wrap}? (`boolean`, default: true) Default value of the {wrap} • {wrap}? (`boolean`, default: true) Default value of the {wrap}
parameter of |vim.diagnostic.jump()|. parameter of |vim.diagnostic.jump()|.
@@ -692,12 +644,8 @@ Lua module: vim.diagnostic *diagnostic-api*
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show • {severity}? (`vim.diagnostic.SeverityFilter`) Only show
virtual text for diagnostics matching the given virtual text for diagnostics matching the given
severity |diagnostic-severity| severity |diagnostic-severity|
• {current_line}? (`boolean`) Show or hide diagnostics based on • {current_line}? (`boolean`) Only show diagnostics for the
the current cursor line. If `true`, only current line. (default `false`)
diagnostics on the current cursor line are
shown. If `false`, all diagnostics are shown
except on the current cursor line. If `nil`, all
diagnostics are shown. (default `nil`)
• {source}? (`boolean|"if_many"`) Include the diagnostic • {source}? (`boolean|"if_many"`) Include the diagnostic
source in virtual text. Use `'if_many'` to only source in virtual text. Use `'if_many'` to only
show sources if there is more than one show sources if there is more than one
@@ -956,7 +904,7 @@ set({namespace}, {bufnr}, {diagnostics}, {opts}) *vim.diagnostic.set()*
Parameters: ~ Parameters: ~
• {namespace} (`integer`) The diagnostic namespace • {namespace} (`integer`) The diagnostic namespace
• {bufnr} (`integer`) Buffer number • {bufnr} (`integer`) Buffer number
• {diagnostics} (`vim.Diagnostic.Set[]`) See |vim.Diagnostic.Set|. • {diagnostics} (`vim.Diagnostic[]`) See |vim.Diagnostic|.
• {opts} (`vim.diagnostic.Opts?`) Display options to pass to • {opts} (`vim.diagnostic.Opts?`) Display options to pass to
|vim.diagnostic.show()|. See |vim.diagnostic.Opts|. |vim.diagnostic.show()|. See |vim.diagnostic.Opts|.
@@ -965,8 +913,8 @@ setloclist({opts}) *vim.diagnostic.setloclist()*
Parameters: ~ Parameters: ~
• {opts} (`table?`) Configuration table with the following keys: • {opts} (`table?`) Configuration table with the following keys:
• {namespace}? (`integer[]|integer`) Only add diagnostics from • {namespace}? (`integer`) Only add diagnostics from the given
the given namespace(s). namespace.
• {winnr}? (`integer`, default: `0`) Window number to set • {winnr}? (`integer`, default: `0`) Window number to set
location list for. location list for.
• {open}? (`boolean`, default: `true`) Open the location list • {open}? (`boolean`, default: `true`) Open the location list
@@ -975,19 +923,14 @@ setloclist({opts}) *vim.diagnostic.setloclist()*
"Diagnostics". "Diagnostics".
• {severity}? (`vim.diagnostic.SeverityFilter`) See • {severity}? (`vim.diagnostic.SeverityFilter`) See
|diagnostic-severity|. |diagnostic-severity|.
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
function that takes a diagnostic as input and returns a
string or nil. If the return value is nil, the diagnostic is
not displayed in the location list. Else the output text is
used to display the diagnostic.
setqflist({opts}) *vim.diagnostic.setqflist()* setqflist({opts}) *vim.diagnostic.setqflist()*
Add all diagnostics to the quickfix list. Add all diagnostics to the quickfix list.
Parameters: ~ Parameters: ~
• {opts} (`table?`) Configuration table with the following keys: • {opts} (`table?`) Configuration table with the following keys:
• {namespace}? (`integer[]|integer`) Only add diagnostics from • {namespace}? (`integer`) Only add diagnostics from the given
the given namespace(s). namespace.
• {open}? (`boolean`, default: `true`) Open quickfix list • {open}? (`boolean`, default: `true`) Open quickfix list
after setting. after setting.
• {title}? (`string`) Title of quickfix list. Defaults to • {title}? (`string`) Title of quickfix list. Defaults to
@@ -995,11 +938,6 @@ setqflist({opts}) *vim.diagnostic.setqflist()*
title, it's updated. If not, a new quickfix list is created. title, it's updated. If not, a new quickfix list is created.
• {severity}? (`vim.diagnostic.SeverityFilter`) See • {severity}? (`vim.diagnostic.SeverityFilter`) See
|diagnostic-severity|. |diagnostic-severity|.
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
function that takes a diagnostic as input and returns a
string or nil. If the return value is nil, the diagnostic is
not displayed in the quickfix list. Else the output text is
used to display the diagnostic.
*vim.diagnostic.show()* *vim.diagnostic.show()*
show({namespace}, {bufnr}, {diagnostics}, {opts}) show({namespace}, {bufnr}, {diagnostics}, {opts})
@@ -1019,23 +957,6 @@ show({namespace}, {bufnr}, {diagnostics}, {opts})
• {opts} (`vim.diagnostic.Opts?`) Display options. See • {opts} (`vim.diagnostic.Opts?`) Display options. See
|vim.diagnostic.Opts|. |vim.diagnostic.Opts|.
status({bufnr}) *vim.diagnostic.status()*
Returns formatted string with diagnostics for the current buffer. The
severities with 0 diagnostics are left out. Example `E:2 W:3 I:4 H:5`
To customise appearance, set diagnostic signs text with >lua
vim.diagnostic.config({
signs = { text = { [vim.diagnostic.severity.ERROR] = 'e', ... } }
})
<
Parameters: ~
• {bufnr} (`integer?`) Buffer number to get diagnostics from. Defaults
to 0 for the current buffer
Return: ~
(`string`)
toqflist({diagnostics}) *vim.diagnostic.toqflist()* toqflist({diagnostics}) *vim.diagnostic.toqflist()*
Convert a list of diagnostics to a list of quickfix items that can be Convert a list of diagnostics to a list of quickfix items that can be
passed to |setqflist()| or |setloclist()|. passed to |setqflist()| or |setloclist()|.

View File

@@ -214,28 +214,14 @@ The diffs are highlighted with these groups:
|hl-DiffAdd| DiffAdd Added (inserted) lines. These lines exist in |hl-DiffAdd| DiffAdd Added (inserted) lines. These lines exist in
this buffer but not in another. this buffer but not in another.
|hl-DiffChange| DiffChange Changed lines. |hl-DiffChange| DiffChange Changed lines.
|hl-DiffText| DiffText Changed text inside a Changed line. Exact |hl-DiffText| DiffText Changed text inside a Changed line. Vim
behavior depends on the `inline:` setting in finds the first character that is different,
'diffopt'. and the last character that is different
With `inline:` set to "simple", Vim finds the (searching from the end of the line). The
first character that is different, and the text in between is highlighted. This means
last character that is different (searching that parts in the middle that are still the
from the end of the line). The text in same are highlighted anyway. The 'diffopt'
between is highlighted. This means that parts flags "iwhite" and "icase" are used here.
in the middle that are still the same are
highlighted anyway. The 'diffopt' flags
"iwhite" and "icase" are used here.
With `inline:` set to "char" or "word", Vim
uses the internal diff library to perform a
detailed diff between the changed blocks and
highlight the exact difference between the
two. Will respect any 'diffopt' flag that
affects internal diff.
Not used when `inline:` is set to "none".
|hl-DiffTextAdd| DiffTextAdd Added text inside a Changed line. Similar to
DiffText, but used when there is no
corresponding text in other buffers. Not used
when `inline:` is set to "simple" or "none".
|hl-DiffDelete| DiffDelete Deleted lines. Also called filler lines, |hl-DiffDelete| DiffDelete Deleted lines. Also called filler lines,
because they don't really exist in this because they don't really exist in this
buffer. buffer.
@@ -292,20 +278,18 @@ that the buffers will be equal within the specified range.
When no [range] is given, the diff at the cursor position or just above it is When no [range] is given, the diff at the cursor position or just above it is
affected. There can be deleted lines below the last line of the buffer. When affected. When [range] is used, Vim tries to only put or get the specified
the cursor is on the last line in the buffer and there is no diff above this lines. When there are deleted lines, this may not always be possible.
line, and no [range] is given, the diff below the cursor position will be used
instead.
When [range] is used, Vim tries to only put or get the specified lines. When There can be deleted lines below the last line of the buffer. When the cursor
there are deleted lines, they will be used if they are between the lines is on the last line in the buffer and there is no diff above this line, the
specified by [range]. ":diffget" and "do" commands will obtain lines from the other buffer.
To be able to put or get those lines to/from another buffer in a [range] it's To be able to get those lines from another buffer in a [range] it's allowed to
allowed to use 0 and the last line number plus one. This command gets all use the last line number plus one. This command gets all diffs from the other
diffs from the other buffer: > buffer: >
:0,$+1diffget :1,$+1diffget
Note that deleted lines are displayed, but not counted as text lines. You Note that deleted lines are displayed, but not counted as text lines. You
can't move the cursor into them. To fill the deleted lines with the lines can't move the cursor into them. To fill the deleted lines with the lines
@@ -324,131 +308,9 @@ name or a part of a buffer name. Examples:
diff mode (e.g., "file.c.v2") diff mode (e.g., "file.c.v2")
============================================================================== ==============================================================================
5. Diff anchors *diff-anchors* 5. Diff options *diff-options*
Diff anchors allow you to control where the diff algorithm aligns and Also see |'diffopt'| and the "diff" item of |'fillchars'|.
synchronize text across files. Each anchor matches each other in each file,
allowing you to control the output of a diff.
This is useful when a change involves complicated edits. For example, if a
function was moved to another location and further edited. By default, the
algorithm aims to create the smallest diff, which results in that entire
function being considered to be deleted and added on the other side, making it
hard to see what the actual edit on it was. You can use diff anchors to pin
that function so the diff algorithm will align based on it.
To use it, set anchors using 'diffanchors' which is a comma-separated list of
{address} in each file, and then add "anchor" to 'diffopt'. Internaly, Vim
splits each file up into sections split by the anchors. It performs the diff
on each pair of sections separately before merging the results back.
Setting 'diffanchors' will update the diff immediately. If an anchor is tied
to a mark, and you change what the mark is pointed to, you need to manually
call |:diffupdate| afterwards to get the updated diff results.
Example:
Let's say we have the following files, side-by-side. We are interested in the
change that happened to the function `foo()`, which was both edited and moved.
File A: >
int foo() {
int n = 1;
return n;
}
int g = 1;
int bar(int a) {
a *= 2;
a += 3;
return a;
}
<File B: >
int bar(int a) {
a *= 2;
a += 3;
return a;
}
int foo() {
int n = 999;
return n;
}
int g = 1;
<
A normal diff will usually align the diff result as such: >
int foo() { |----------------
int n = 1; |----------------
return n; |----------------
} |----------------
|----------------
int g = 1; |----------------
|----------------
int bar(int a) {|int bar(int a) {
a *= 2; | a *= 2;
a += 3; | a += 3;
return a; | return a;
} |}
----------------|
----------------|int foo() {
----------------| int n = 999;
----------------| return n;
----------------|}
----------------|
----------------|int g = 1;
<
What we want is to instead ask the diff to align on `foo()`: >
----------------|int bar(int a) {
----------------| a *= 2;
----------------| a += 3;
----------------| return a;
----------------|}
----------------|
int foo() { |int foo() {
int n = 1; | int n = 999;
return n; | return n;
} |}
|
int g = 1; |int g = 1;
|----------------
int bar(int a) {|----------------
a *= 2; |----------------
a += 3; |----------------
return a; |----------------
} |----------------
<
Below are some ways of setting diff anchors to get the above result. In each
example, 'diffopt' needs to have `anchor` set for this to take effect.
Marks: Set the |'a| mark on the `int foo()` lines in each file first before
setting the anchors: >
set diffanchors='a
Pattern: Specify the anchor using a |pattern| (see |:/|). Here, we make sure
to always start search from line 1 for consistency: >
set diffanchors=1/int\ foo(/
<
Selection: Use visual mode to select the entire `foo()` function body in each
file. Here, we use two anchors. This does a better job of making sure only
the function bodies are anchored against each other but not the lines after
it. Note the `'>+1` below. The "+1" is necessary as we want the split to
happen below the last line of the function, not above: >
set diffanchors='<,'>+1
<
Manually set two anchors using line numbers via buffer-local options: >
setlocal diffanchors=1,5
wincmd w
setlocal diffanchors=7,11
<
==============================================================================
6. Diff options *diff-options*
Also see 'diffopt' and the "diff" item of 'fillchars'.
*diff-slow* *diff_translations* *diff-slow* *diff_translations*
For very long lines, the diff syntax highlighting might be slow, especially For very long lines, the diff syntax highlighting might be slow, especially

View File

@@ -1094,8 +1094,8 @@ the 1', 2' and 3' digraphs.
⌕ TR 2315 8981 TELEPHONE RECORDER ⌕ TR 2315 8981 TELEPHONE RECORDER
⌠ Iu 2320 8992 TOP HALF INTEGRAL ⌠ Iu 2320 8992 TOP HALF INTEGRAL
⌡ Il 2321 8993 BOTTOM HALF INTEGRAL ⌡ Il 2321 8993 BOTTOM HALF INTEGRAL
<[ 27E8 10040 LEFT MATHEMATICAL ANGLE BRACKET </ 2329 9001 LEFT-POINTING ANGLE BRACKET
⟩ ]> 27E9 10041 RIGHT MATHEMATICAL ANGLE BRACKET 〉 /> 232A 9002 RIGHT-POINTING ANGLE BRACKET
␣ Vs 2423 9251 OPEN BOX ␣ Vs 2423 9251 OPEN BOX
⑀ 1h 2440 9280 OCR HOOK ⑀ 1h 2440 9280 OCR HOOK
⑁ 3h 2441 9281 OCR CHAIR ⑁ 3h 2441 9281 OCR CHAIR

View File

@@ -630,7 +630,7 @@ list of the current window.
buffer. buffer.
Also see |++opt| and |+cmd|. Also see |++opt| and |+cmd|.
:[count]arge[dit][!] [++opt] [+cmd] {name} ... *:arge* *:argedit* :[count]arge[dit][!] [++opt] [+cmd] {name} .. *:arge* *:argedit*
Add {name}s to the argument list and edit it. Add {name}s to the argument list and edit it.
There is no check for duplicates, it is possible to There is no check for duplicates, it is possible to
add a file to the argument list twice |:argded|. add a file to the argument list twice |:argded|.
@@ -645,7 +645,7 @@ list of the current window.
edited. No check for duplicates is done. edited. No check for duplicates is done.
Also see |++opt| and |+cmd|. Also see |++opt| and |+cmd|.
:[count]arga[dd] {name} ... *:arga* *:argadd* *E479* :[count]arga[dd] {name} .. *:arga* *:argadd* *E479*
:[count]arga[dd] *E1156* :[count]arga[dd] *E1156*
Add the {name}s to the argument list. When {name} is Add the {name}s to the argument list. When {name} is
omitted add the current buffer name to the argument omitted add the current buffer name to the argument
@@ -676,7 +676,7 @@ list of the current window.
If your current file is a duplicate, your current file If your current file is a duplicate, your current file
will change to the original file index. will change to the original file index.
:argd[elete] {pattern} ... *:argd* *:argdelete* *E480* *E610* :argd[elete] {pattern} .. *:argd* *:argdelete* *E480* *E610*
Delete files from the argument list that match the Delete files from the argument list that match the
{pattern}s. {pattern} is used like a file pattern, {pattern}s. {pattern} is used like a file pattern,
see |file-pattern|. "%" can be used to delete the see |file-pattern|. "%" can be used to delete the
@@ -960,9 +960,8 @@ Note: When the 'write' option is off, you are not able to write any file.
executed like with ":!{cmd}", any '!' is replaced with executed like with ":!{cmd}", any '!' is replaced with
the previous command |:!|. the previous command |:!|.
The default [range] for the ":w" command is the whole buffer (1,$). The |'[| The default [range] for the ":w" command is the whole buffer (1,$). If you
and |']| marks will be set to the [range] being used for the write command. write the whole buffer, it is no longer considered changed. When you
If you write the whole buffer, it is no longer considered changed. When you
write it to a different file with ":w somefile" it depends on the "+" flag in write it to a different file with ":w somefile" it depends on the "+" flag in
'cpoptions'. When included, the write command will reset the 'modified' flag, 'cpoptions'. When included, the write command will reset the 'modified' flag,
even though the buffer itself may still be different from its file. even though the buffer itself may still be different from its file.
@@ -1242,10 +1241,10 @@ MULTIPLE WINDOWS AND BUFFERS *window-exit*
*:confirm* *:conf* *:confirm* *:conf*
:conf[irm] {command} Execute {command}, and use a dialog when an :conf[irm] {command} Execute {command}, and use a dialog when an
operation has to be confirmed. Can be used on the operation has to be confirmed. Can be used on the
|:edit|, |:restart|, |:q|, |:qa| and |:w| commands |:edit|, |:q|, |:qa| and |:w| commands (the latter to
(the latter to override a read-only setting), and any override a read-only setting), and any commands that
commands that can fail because of unsaved changes, can fail because of unsaved changes, such as |:only|,
such as |:only|, |:buffer|, |:bdelete|, etc. |:buffer|, |:bdelete|, etc.
Examples: > Examples: >
:confirm w foo :confirm w foo
@@ -1316,15 +1315,9 @@ b:browsefilter variable. You would most likely set b:browsefilter in a
filetype plugin, so that the browse dialog would contain entries related to filetype plugin, so that the browse dialog would contain entries related to
the type of file you are currently editing. Disadvantage: This makes it the type of file you are currently editing. Disadvantage: This makes it
difficult to start editing a file of a different type. To overcome this, you difficult to start editing a file of a different type. To overcome this, you
can add the following as the final filter on Windows: > may want to add "All Files (*.*)\t*\n" as the final filter on Windows or "All
Files (*)\t*\n" on other platforms, so that the user can still access any
All Files\t(*.*)\t*\n desired file.
<
Or the following on other platforms, so that the user can still access any
desired file: >
All Files\t(*)\t*\n
<
To avoid setting browsefilter when Vim does not actually support it, you can To avoid setting browsefilter when Vim does not actually support it, you can
use has("browsefilter"): > use has("browsefilter"): >
@@ -1356,7 +1349,7 @@ exist, the next-higher scope in the hierarchy applies.
:cd[!] {path} Change the current directory to {path}. :cd[!] {path} Change the current directory to {path}.
If {path} is relative, it is searched for in the If {path} is relative, it is searched for in the
directories listed in 'cdpath'. directories listed in |'cdpath'|.
Clear any window-local directory. Clear any window-local directory.
Does not change the meaning of an already opened file, Does not change the meaning of an already opened file,
because its full path name is remembered. Files from because its full path name is remembered. Files from

View File

@@ -1,10 +1,10 @@
*vimeval.txt* Nvim *eval.txt* Nvim
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
Expression evaluation *vimscript* *expression* *expr* *E15* *eval* *eval.txt* Expression evaluation *vimscript* *expression* *expr* *E15* *eval*
Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|. Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|.
@@ -1813,7 +1813,7 @@ functions. Scripts can also define |user-function|s.
See |function-list| to browse functions by topic. See |function-list| to browse functions by topic.
The alphabetic list of all builtin functions and details are in a separate The alphabetic list of all builtin functions and details are in a separate
help file: |vimscript-functions|. help file: |builtin-functions|.
============================================================================== ==============================================================================
5. Defining functions *user-function* 5. Defining functions *user-function*
@@ -2099,7 +2099,7 @@ text...
CODE CODE
< <
*E121* *E121*
:let {var-name} ... List the value of variable {var-name}. Multiple :let {var-name} .. List the value of variable {var-name}. Multiple
variable names may be given. Special names recognized variable names may be given. Special names recognized
here: *E738* here: *E738*
g: global variables g: global variables
@@ -2116,6 +2116,7 @@ text...
# Number # Number
* Funcref * Funcref
:unl[et][!] {name} ... *:unlet* *:unl* *E108* *E795* :unl[et][!] {name} ... *:unlet* *:unl* *E108* *E795*
Remove the internal variable {name}. Several variable Remove the internal variable {name}. Several variable
names can be given, they are all removed. The name names can be given, they are all removed. The name
@@ -2459,7 +2460,7 @@ text...
line and not see the "|" that separates the commands. line and not see the "|" that separates the commands.
*:ec* *:echo* *:ec* *:echo*
:ec[ho] {expr1} ... Echoes each {expr1}, with a space in between. The :ec[ho] {expr1} .. Echoes each {expr1}, with a space in between. The
first {expr1} starts on a new line. first {expr1} starts on a new line.
Also see |:comment|. Also see |:comment|.
Use "\n" to start a new line. Use "\r" to move the Use "\n" to start a new line. Use "\r" to move the
@@ -2492,7 +2493,7 @@ text...
level. level.
*:echon* *:echon*
:echon {expr1} ... Echoes each {expr1}, without anything added. Also see :echon {expr1} .. Echoes each {expr1}, without anything added. Also see
|:comment|. |:comment|.
Uses the highlighting set by the `:echohl` command. Uses the highlighting set by the `:echohl` command.
Cannot be followed by a comment. Cannot be followed by a comment.
@@ -2523,7 +2524,7 @@ text...
otherwise all following echo's will be highlighted. otherwise all following echo's will be highlighted.
*:echom* *:echomsg* *:echom* *:echomsg*
:echom[sg] {expr1} ... Echo the expression(s) as a true message, saving the :echom[sg] {expr1} .. Echo the expression(s) as a true message, saving the
message in the |message-history|. message in the |message-history|.
Spaces are placed between the arguments as with the Spaces are placed between the arguments as with the
`:echo` command. But unprintable characters are `:echo` command. But unprintable characters are
@@ -2538,9 +2539,8 @@ text...
:echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see." :echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see."
< See |:echo-redraw| to avoid the message disappearing < See |:echo-redraw| to avoid the message disappearing
when the screen is redrawn. when the screen is redrawn.
*:echoe* *:echoerr* *:echoe* *:echoerr*
:echoe[rr] {expr1} ... Echo the expression(s) as an error message, saving the :echoe[rr] {expr1} .. Echo the expression(s) as an error message, saving the
message in the |message-history|. When used in a message in the |message-history|. When used in a
script or function the line number will be added. script or function the line number will be added.
Spaces are placed between the arguments as with the Spaces are placed between the arguments as with the
@@ -2572,7 +2572,7 @@ text...
*:exe* *:execute* *:exe* *:execute*
:exe[cute] {expr1} ... Executes the string that results from the evaluation :exe[cute] {expr1} .. Executes the string that results from the evaluation
of {expr1} as an Ex command. of {expr1} as an Ex command.
Multiple arguments are concatenated, with a space in Multiple arguments are concatenated, with a space in
between. To avoid the extra space use the ".." between. To avoid the extra space use the ".."
@@ -3774,7 +3774,7 @@ This is not allowed when the textlock is active:
- etc. - etc.
============================================================================== ==============================================================================
Vim script library *vimscript-library* Vim script library *vim-script-library*
Vim comes bundled with a Vim script library, that can be used by runtime, Vim comes bundled with a Vim script library, that can be used by runtime,
script authors. Currently, it only includes very few functions, but it may script authors. Currently, it only includes very few functions, but it may

View File

@@ -187,19 +187,20 @@ Run |:checkhealth| in Nvim for automatic diagnosis.
Other hints: Other hints:
- Read |provider-python| to learn how to install `pynvim`. - The python `neovim` module was renamed to `pynvim` (long ago).
- Be sure you have the latest version of the `pynvim` Python module: >bash - If you're using pyenv or virtualenv for the `pynvim` module
uv tool install --upgrade pynvim
<
See |provider-python| for other installation options.
- If you're manually creating a Python virtual environment for the `pynvim` module
https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to
the virtualenv's interpreter path. the virtualenv's interpreter path.
- Read |provider-python|.
- Be sure you have the latest version of the `pynvim` Python module: >bash
python -m pip install setuptools
python -m pip install --upgrade pynvim
python3 -m pip install --upgrade pynvim
<
- Try with `nvim -u NORC` to make sure your config (|init.vim|) isn't causing a - Try with `nvim -u NORC` to make sure your config (|init.vim|) isn't causing a
problem. If you get `E117: Unknown function`, that means there's a runtime problem. If you get `E117: Unknown function`, that means there's a runtime
issue: |faq-runtime|. issue: |faq-runtime|.
- The python `neovim` module was renamed to `pynvim` (long ago).
:CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME ~ :CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME ~
@@ -449,7 +450,10 @@ grow and enhance it. Changing the rules of Lua gains nothing in this context.
WILL NEOVIM TRANSLATE VIMSCRIPT TO LUA, INSTEAD OF EXECUTING VIMSCRIPT DIRECTLY? ~ WILL NEOVIM TRANSLATE VIMSCRIPT TO LUA, INSTEAD OF EXECUTING VIMSCRIPT DIRECTLY? ~
We have no plans for transpiling Vimscript. It was explored in https://github.com/tjdevries/vim9jit - We are experimenting with vim9jit https://github.com/tjdevries/vim9jit to
transpile Vim9script (Vim9's Vimscript variant) to Lua and have used this to
port Vim9 plugins https://github.com/neovim/neovim/pull/21662 to Nvim Lua.
- We have no plans for transpiling legacy Vimscript.
ARE PLUGIN AUTHORS ENCOURAGED TO PORT THEIR PLUGINS FROM VIMSCRIPT TO LUA? DO YOU PLAN ON SUPPORTING VIMSCRIPT INDEFINITELY? (#1152) ~ ARE PLUGIN AUTHORS ENCOURAGED TO PORT THEIR PLUGINS FROM VIMSCRIPT TO LUA? DO YOU PLAN ON SUPPORTING VIMSCRIPT INDEFINITELY? (#1152) ~
@@ -464,8 +468,4 @@ emphatically a fork of Vim in order to leverage the work already spent on
thousands of Vim plugins, while enabling new types of plugins and thousands of Vim plugins, while enabling new types of plugins and
integrations. integrations.
That being said, reimplementing legacy plugins in Lua in order to make use of
Nvim API and to integrate with Nvim-specific features such as treesitter can
be worthwhile.
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -156,8 +156,6 @@ variables can be used to overrule the filetype used for certain extensions:
`*.inc` g:filetype_inc `*.inc` g:filetype_inc
`*.lsl` g:filetype_lsl `*.lsl` g:filetype_lsl
`*.m` g:filetype_m |ft-mathematica-syntax| `*.m` g:filetype_m |ft-mathematica-syntax|
`*[mM]makefile,*.mk,*.mak,[mM]akefile*`
g:make_flavor |ft-make-syntax|
`*.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md` `*.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md`
g:filetype_md |ft-pandoc-syntax| g:filetype_md |ft-pandoc-syntax|
`*.mod` g:filetype_mod `*.mod` g:filetype_mod
@@ -264,7 +262,7 @@ D. If your filetype can only be detected by inspecting the contents of the
item of the 'runtimepath' option. Example for Unix: > item of the 'runtimepath' option. Example for Unix: >
:!mkdir -p ~/.config/nvim :!mkdir -p ~/.config/nvim
< <
2. Create a Vim script file for doing this. Example: > 2. Create a vim script file for doing this. Example: >
if did_filetype() " filetype already set.. if did_filetype() " filetype already set..
finish " ..don't do these checks finish " ..don't do these checks
endif endif
@@ -625,16 +623,6 @@ possibilities: >
The `:Cycle` command is also mapped to the CTRL-A and CTRL-X keys. The `:Cycle` command is also mapped to the CTRL-A and CTRL-X keys.
For details, see `git-rebase --help`. For details, see `git-rebase --help`.
GLEAM *ft-gleam-plugin*
By default the following options are set for the recommended gleam style: >
setlocal expandtab shiftwidth=2 softtabstop=2
To disable this behavior, set the following variable in your vimrc: >
let g:gleam_recommended_style = 0
GO *ft-go-plugin* GO *ft-go-plugin*
By default the following options are set, based on Golang official docs: > By default the following options are set, based on Golang official docs: >
@@ -661,32 +649,6 @@ HARE *ft-hare*
Since the text for this plugin is rather long it has been put in a separate Since the text for this plugin is rather long it has been put in a separate
file: |ft_hare.txt|. file: |ft_hare.txt|.
HTML *ft-html-plugin*
Tag folding poses a few difficulties. Many elements, e.g. `blockquote`, are
always delimited by start and end tags; end tags for some elements, e.g. `p`,
can be omitted in certain contexts; void elements, e.g. `hr`, have no end tag.
Although the rules for supporting omissible end tags are ad-hoc and involved
[0], they apply to elements in scope. Assuming syntactical wellformedness, an
end tag can be associated with its nearest matching start tag discoverable in
scope [1] and towards the beginning of a file, whereas all unbalanced tags and
inlined tags can be disregarded. Having syntax highlighting in effect, tag
folding using the |fold-expr| method can be enabled with: >
let g:html_expr_folding = 1
<
By default, tag folding will be redone from scratch after each occurrence of
a |TextChanged| or an |InsertLeave| event. Such frequency may not be desired,
especially for large files, and this recomputation can be disabled with: >
let g:html_expr_folding_without_recomputation = 1
doautocmd FileType
<
To force another recomputation, do: >
unlet! b:foldsmap
normal zx
<
[0] https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
[1] https://en.wikipedia.org/wiki/Dangling_else
IDRIS2 *ft-idris2-plugin* IDRIS2 *ft-idris2-plugin*
By default the following options are set: > By default the following options are set: >
@@ -823,8 +785,8 @@ Variables:
For example in C one usually wants section 3 or 2: > For example in C one usually wants section 3 or 2: >
:let b:man_default_sections = '3,2' :let b:man_default_sections = '3,2'
*g:man_hardwrap* Hard-wrap to $MANWIDTH or window width if $MANWIDTH is *g:man_hardwrap* Hard-wrap to $MANWIDTH or window width if $MANWIDTH is
empty or larger than the window width. Enabled by empty. Enabled by default. Set |FALSE| to enable soft
default. Set |FALSE| to enable soft wrapping. wrapping.
To use Nvim as a manpager: >bash To use Nvim as a manpager: >bash
export MANPAGER='nvim +Man!' export MANPAGER='nvim +Man!'
@@ -1155,13 +1117,6 @@ functions with [[ and ]]. Move around comments with ]" and [".
The mappings can be disabled with: > The mappings can be disabled with: >
let g:no_vim_maps = 1 let g:no_vim_maps = 1
YAML *ft-yaml-plugin*
By default, the YAML filetype plugin enables the following options: >
setlocal shiftwidth=2 softtabstop=2
To disable this, set the following variable: >
let g:yaml_recommended_style = 0
ZIG *ft-zig-plugin* ZIG *ft-zig-plugin*

View File

@@ -632,17 +632,14 @@ what you type!
When using an operator, a closed fold is included as a whole. Thus "dl" When using an operator, a closed fold is included as a whole. Thus "dl"
deletes the whole closed fold under the cursor. deletes the whole closed fold under the cursor.
For Ex commands that operate on buffer lines, the range is adjusted to always For Ex commands that work on buffer lines the range is adjusted to always
start at the first line of a closed fold and end at the last line of a closed start at the first line of a closed fold and end at the last line of a closed
fold. Thus, this command: > fold. Thus this command: >
:s/foo/bar/g :s/foo/bar/g
when used with the cursor on a closed fold, will replace "foo" with "bar" in when used with the cursor on a closed fold, will replace "foo" with "bar" in
all lines of the fold. all lines of the fold.
This does not happen for |:folddoopen| and |:folddoclosed|. This does not happen for |:folddoopen| and |:folddoclosed|.
Note that for some Ex commands like |:source| the range is only adjusted when
using a two line specifiers [range].
When editing a buffer that has been edited before, the last used folding When editing a buffer that has been edited before, the last used folding
settings are used again. For manual folding the defined folds are restored. settings are used again. For manual folding the defined folds are restored.
For all folding methods the manually opened and closed folds are restored. For all folding methods the manually opened and closed folds are restored.
@@ -650,4 +647,5 @@ If this buffer has been edited in this window, the values from back then are
used. Otherwise the values from the window where the buffer was edited last used. Otherwise the values from the window where the buffer was edited last
are used. are used.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -76,8 +76,8 @@ The Ada plug-in provides support for:
- user completion (|i_CTRL-X_CTRL-U|) - user completion (|i_CTRL-X_CTRL-U|)
- tag searches (|tagsrch.txt|) - tag searches (|tagsrch.txt|)
- Quick Fix (|quickfix.txt|) - Quick Fix (|quickfix.txt|)
- backspace handling ('backspace') - backspace handling (|'backspace'|)
- comment handling ('comments', 'commentstring') - comment handling (|'comments'|, |'commentstring'|)
The plug-in only activates the features of the Ada mode whenever an Ada The plug-in only activates the features of the Ada mode whenever an Ada
file is opened and adds Ada related entries to the main and pop-up menu. file is opened and adds Ada related entries to the main and pop-up menu.
@@ -197,7 +197,7 @@ g:gnat.Project_File string
*g:gnat.Make_Command* *g:gnat.Make_Command*
g:gnat.Make_Command string g:gnat.Make_Command string
External command used for |g:gnat.Make()| ('makeprg'). External command used for |g:gnat.Make()| (|'makeprg'|).
*g:gnat.Pretty_Program* *g:gnat.Pretty_Program*
g:gnat.Pretty_Program string g:gnat.Pretty_Program string
@@ -213,7 +213,7 @@ g:gnat.Tags_Command string
*g:gnat.Error_Format* *g:gnat.Error_Format*
g:gnat.Error_Format string g:gnat.Error_Format string
Error format ('errorformat') Error format (|'errorformat'|)
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
4.2 Dec Ada ~ 4.2 Dec Ada ~
@@ -243,11 +243,11 @@ g:decada.Unit_Name() function
*g:decada.Make_Command* *g:decada.Make_Command*
g:decada.Make_Command string g:decada.Make_Command string
External command used for |g:decada.Make()| ('makeprg'). External command used for |g:decada.Make()| (|'makeprg'|).
*g:decada.Error_Format* *g:decada.Error_Format*
g:decada.Error_Format string g:decada.Error_Format string
Error format ('errorformat'). Error format (|'errorformat'|).
============================================================================== ==============================================================================
5. References ~ 5. References ~
@@ -507,4 +507,6 @@ taglist.vim
The GNU Ada Project distribution (http://gnuada.sourceforge.net) of Vim The GNU Ada Project distribution (http://gnuada.sourceforge.net) of Vim
contains all of the above. contains all of the above.
vim:tw=78:ts=8:noet:ft=help:norl: ==============================================================================
vim: textwidth=78 nowrap tabstop=8 shiftwidth=4 softtabstop=4 noexpandtab
vim: filetype=help

View File

@@ -73,4 +73,5 @@ The maximum search depth can be set to any integer, but using values higher
than 2 is not recommended, and will likely provide no tangible benefit in most than 2 is not recommended, and will likely provide no tangible benefit in most
situations. situations.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -60,4 +60,5 @@ Many other distributions are available for Windows like
https://chocolatey.org/packages/less/. Make sure `less` is in a directory https://chocolatey.org/packages/less/. Make sure `less` is in a directory
listed in the `PATH` environment variable, which chocolatey above does. listed in the `PATH` environment variable, which chocolatey above does.
------------------------------------------------------------------------------
vim:ft=help: vim:ft=help:

View File

@@ -160,18 +160,7 @@ g:rustfmt_emit_files ~
provided) instead of '--write-mode=overwrite'. >vim provided) instead of '--write-mode=overwrite'. >vim
let g:rustfmt_emit_files = 0 let g:rustfmt_emit_files = 0
< <
*g:rustfmt_detect_version*
g:rustfmt_detect_version ~
When set to 1, will try to parse the version output from "rustfmt".
Disabled by default for performance reasons >vim
let g:rustfmt_detect_version = 1
<
*g:rustfmt_find_toml*
g:rustfmt_emit_files ~
When set to 1, will try to find "rustfmt.toml" file by searching from
current path upwards. Disabled by default for performance reasons >vim
let g:rustfmt_find_toml = 1
<
*g:rust_playpen_url* *g:rust_playpen_url*
g:rust_playpen_url ~ g:rust_playpen_url ~
Set this option to override the url for the playpen to use: >vim Set this option to override the url for the playpen to use: >vim
@@ -486,4 +475,4 @@ MAPPINGS *rust-mappings*
This plugin defines mappings for |[[| and |]]| to support hanging indents. This plugin defines mappings for |[[| and |]]| to support hanging indents.
vim:tw=78:sw=4:noet:ts=8:ft=help:norl: vim:tw=78:sw=4:noet:ts=8:ft=help:norl:

View File

@@ -172,7 +172,7 @@ with comments: >
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
1.4 Macros *sql-macros* 1.4 Macros *sql-macros*
Vim's feature to find macro definitions, 'define', is supported using this Vim's feature to find macro definitions, |'define'|, is supported using this
regular expression: > regular expression: >
\c\<\(VARIABLE\|DECLARE\|IN\|OUT\|INOUT\)\> \c\<\(VARIABLE\|DECLARE\|IN\|OUT\|INOUT\)\>
@@ -249,7 +249,7 @@ key to complete the optional parameter.
After typing the function name and a space, you can use the completion to After typing the function name and a space, you can use the completion to
supply a parameter. The function takes the name of the Vim script you want to supply a parameter. The function takes the name of the Vim script you want to
source. Using the |cmdline-completion| feature, the SQLSetType function will source. Using the |cmdline-completion| feature, the SQLSetType function will
search the 'runtimepath' for all Vim scripts with a name containing "sql". search the |'runtimepath'| for all Vim scripts with a name containing "sql".
This takes the guess work out of the spelling of the names. The following are This takes the guess work out of the spelling of the names. The following are
examples: > examples: >
:SQLSetType :SQLSetType
@@ -412,7 +412,7 @@ Here are some examples of the entries which are pulled from the syntax files: >
Dynamic mode populates the popups with data directly from a database. In Dynamic mode populates the popups with data directly from a database. In
order for the dynamic feature to be enabled you must have the dbext.vim order for the dynamic feature to be enabled you must have the dbext.vim
plugin installed, (https://www.vim.org/scripts/script.php?script_id=356). plugin installed, (https://vim.sourceforge.net/script.php?script_id=356).
Dynamic mode is used by several features of the SQL completion plugin. Dynamic mode is used by several features of the SQL completion plugin.
After installing the dbext plugin see the dbext-tutorial for additional After installing the dbext plugin see the dbext-tutorial for additional
@@ -496,7 +496,7 @@ depending on the syntax file you are using. The SQL Anywhere syntax file
Dynamic features ~ Dynamic features ~
To take advantage of the dynamic features you must first install the To take advantage of the dynamic features you must first install the
dbext.vim plugin (https://www.vim.org/scripts/script.php?script_id=356). It dbext.vim plugin (https://vim.sourceforge.net/script.php?script_id=356). It
also comes with a tutorial. From the SQL completion plugin's perspective, also comes with a tutorial. From the SQL completion plugin's perspective,
the main feature dbext provides is a connection to a database. dbext the main feature dbext provides is a connection to a database. dbext
connection profiles are the most efficient mechanism to define connection connection profiles are the most efficient mechanism to define connection
@@ -760,7 +760,7 @@ Step 1 ~
Begins by editing a Perl file. Vim automatically sets the filetype to Begins by editing a Perl file. Vim automatically sets the filetype to
"perl". By default, Vim runs the appropriate filetype file "perl". By default, Vim runs the appropriate filetype file
ftplugin/perl.vim. If you are using the syntax completion plugin by following ftplugin/perl.vim. If you are using the syntax completion plugin by following
the directions at |ft-syntax-omni| then the 'omnifunc' option has been set to the directions at |ft-syntax-omni| then the |'omnifunc'| option has been set to
"syntax#Complete". Pressing <C-X><C-O> will display the omni popup containing "syntax#Complete". Pressing <C-X><C-O> will display the omni popup containing
the syntax items for Perl. the syntax items for Perl.
@@ -772,7 +772,7 @@ maps for SQL completion, see |sql-completion-maps|. Now these maps have
been created and the SQL completion plugin has been initialized. All SQL been created and the SQL completion plugin has been initialized. All SQL
syntax items have been cached in preparation. The SQL filetype script detects syntax items have been cached in preparation. The SQL filetype script detects
we are attempting to use two different completion plugins. Since the SQL maps we are attempting to use two different completion plugins. Since the SQL maps
begin with <C-C>, the maps will toggle the 'omnifunc' when in use. So you begin with <C-C>, the maps will toggle the |'omnifunc'| when in use. So you
can use <C-X><C-O> to continue using the completion for Perl (using the syntax can use <C-X><C-O> to continue using the completion for Perl (using the syntax
completion plugin) and <C-C> to use the SQL completion features. completion plugin) and <C-C> to use the SQL completion features.

View File

@@ -17,8 +17,6 @@ TUI and GUI (assuming the UI supports the given feature). See |TUI| for notes
specific to the terminal UI. Help tags with the "gui-" prefix refer to UI specific to the terminal UI. Help tags with the "gui-" prefix refer to UI
features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|. features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|.
Type |gO| to see the table of contents.
============================================================================== ==============================================================================
Third-party GUIs *third-party-guis* *vscode* Third-party GUIs *third-party-guis* *vscode*
@@ -36,6 +34,8 @@ a Nvim GUI.
- VimR (macOS) https://github.com/qvacua/vimr - VimR (macOS) https://github.com/qvacua/vimr
- Others https://github.com/neovim/neovim/wiki/Related-projects#gui - Others https://github.com/neovim/neovim/wiki/Related-projects#gui
Type |gO| to see the table of contents.
============================================================================== ==============================================================================
Starting the GUI *gui-config* *gui-start* Starting the GUI *gui-config* *gui-start*
@@ -64,50 +64,7 @@ Stop or detach the current UI
the channel to be closed, it may be (incorrectly) reported as the channel to be closed, it may be (incorrectly) reported as
an error. an error.
Note: Not supported on Windows yet. Note: Not supported on Windows, currently.
------------------------------------------------------------------------------
Restart Nvim
*:restart*
:restart [+cmd] [command]
Restarts Nvim.
1. Stops Nvim using `:qall!` (or |+cmd|, if given).
2. Starts a new Nvim server using the same |v:argv|,
optionally running [command] at startup. |-c|
3. Attaches the current UI to the new Nvim server. Other UIs
(if any) will not reattach on restart (this may change in
the future).
Use with `:confirm` to prompt if changes have been made.
Example: stop with `:qall!`, then restart: >
:restart +qall!
< Example: restart and restore the current session: >
:mksession! Session.vim | restart source Session.vim
< Example: restart and update plugins: >
:restart +qall! lua vim.pack.update()
<
Note: Only works if the UI and server are on the same system.
Note: If the UI hasn't implemented the "restart" UI event,
this command is equivalent to `:qall!`.
------------------------------------------------------------------------------
Connect UI to a different server
*:connect*
:connect {address}
Detaches the UI from the server it is currently attached to
and attaches it to the server at {address} instead.
Note: If the current UI hasn't implemented the "connect" UI
event, this command is equivalent to |:detach|.
:connect! {address}
Same as |:connect| but it also stops the detached server if
no other UI is currently attached to it.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
GUI commands GUI commands

View File

@@ -112,6 +112,7 @@ API (EXTENSIBILITY/SCRIPTING/PLUGINS)
|channel| Nvim asynchronous IO |channel| Nvim asynchronous IO
|vimscript| Vimscript reference |vimscript| Vimscript reference
|vimscript-functions| Vimscript functions |vimscript-functions| Vimscript functions
|testing.txt| Vimscript testing functions
|remote-plugin| Nvim remote plugins |remote-plugin| Nvim remote plugins
|health| Health checking |health| Health checking

View File

@@ -337,7 +337,7 @@ in such a modeline, that can have undesired consequences.
TAGS TAGS
To define a help tag, place the name between asterisks ("*tag-name*"). The To define a help tag, place the name between asterisks (*tag-name*). The
tag-name should be different from all the Vim help tag names and ideally tag-name should be different from all the Vim help tag names and ideally
should begin with the name of the Vim plugin. The tag name is usually right should begin with the name of the Vim plugin. The tag name is usually right
aligned on a line. aligned on a line.
@@ -373,17 +373,11 @@ To quote a block of ex-commands verbatim, place a greater than (>) character
at the end of the line before the block and a less than (<) character as the at the end of the line before the block and a less than (<) character as the
first non-blank on a line following the block. Any line starting in column 1 first non-blank on a line following the block. Any line starting in column 1
also implicitly stops the block of ex-commands before it. E.g. > also implicitly stops the block of ex-commands before it. E.g. >
function Example_Func() function Example_Func()
echo "Example" echo "Example"
endfunction endfunction
< <
To enable syntax highlighting for a block of code, place a language name
annotation (e.g. "vim") after a greater than (>) character. E.g. >vim
function Example_Func()
echo "Example"
endfunction
<
*help-notation*
The following are highlighted differently in a Vim help file: The following are highlighted differently in a Vim help file:
- a special key name expressed either in <> notation as in <PageDown>, or - a special key name expressed either in <> notation as in <PageDown>, or
as a Ctrl character as in CTRL-X as a Ctrl character as in CTRL-X
@@ -397,10 +391,4 @@ highlighting. So do these:
You can find the details in $VIMRUNTIME/syntax/help.vim You can find the details in $VIMRUNTIME/syntax/help.vim
FILETYPE COMPLETION *ft-help-omni*
To get completion for help tags when writing a tag reference, you can use the
|i_CTRL-X_CTRL-O| command.
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -268,4 +268,5 @@ These are also available via the "main" package:
$main::curwin The current Window object. $main::curwin The current Window object.
$main::curbuf The current Buffer object. $main::curbuf The current Buffer object.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -645,6 +645,6 @@ To check if `pyx*` functions and commands are available: >vim
if has('pythonx') if has('pythonx')
echo 'pyx* commands are available. (Python ' .. &pyx .. ')' echo 'pyx* commands are available. (Python ' .. &pyx .. ')'
endif endif
<
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -189,4 +189,5 @@ evaluate Ruby expressions and pass their values to Vim script.
The Ruby value "true", "false" and "nil" are converted to v:true, v:false and The Ruby value "true", "false" and "nil" are converted to v:true, v:false and
v:null, respectively. v:null, respectively.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -146,7 +146,6 @@ commands in CTRL-X submode *i_CTRL-X_index*
|i_CTRL-X_CTRL-N| CTRL-X CTRL-N next completion |i_CTRL-X_CTRL-N| CTRL-X CTRL-N next completion
|i_CTRL-X_CTRL-O| CTRL-X CTRL-O omni completion |i_CTRL-X_CTRL-O| CTRL-X CTRL-O omni completion
|i_CTRL-X_CTRL-P| CTRL-X CTRL-P previous completion |i_CTRL-X_CTRL-P| CTRL-X CTRL-P previous completion
|i_CTRL-X_CTRL-R| CTRL-X CTRL-R complete contents from registers
|i_CTRL-X_CTRL-S| CTRL-X CTRL-S spelling suggestions |i_CTRL-X_CTRL-S| CTRL-X CTRL-S spelling suggestions
|i_CTRL-X_CTRL-T| CTRL-X CTRL-T complete identifiers from thesaurus |i_CTRL-X_CTRL-T| CTRL-X CTRL-T complete identifiers from thesaurus
|i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down |i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down
@@ -516,7 +515,7 @@ tag command action in op-pending and Visual mode ~
tag command action in Normal mode ~ tag command action in Normal mode ~
------------------------------------------------------------------------------ ~ ------------------------------------------------------------------------------ ~
|CTRL-W_CTRL-B| CTRL-W CTRL-B same as "CTRL-W b" |CTRL-W_CTRL-B| CTRL-W CTRL-B same as "CTRL-W b"
|CTRL-W_CTRL-C| CTRL-W CTRL-C no-op |CTRL-W_CTRL-C| CTRL-W CTRL-C same as "CTRL-W c"
|CTRL-W_CTRL-D| CTRL-W CTRL-D same as "CTRL-W d" |CTRL-W_CTRL-D| CTRL-W CTRL-D same as "CTRL-W d"
|CTRL-W_CTRL-F| CTRL-W CTRL-F same as "CTRL-W f" |CTRL-W_CTRL-F| CTRL-W CTRL-F same as "CTRL-W f"
CTRL-W CTRL-G same as "CTRL-W g .." CTRL-W CTRL-G same as "CTRL-W g .."
@@ -1017,7 +1016,7 @@ tag command action in Command-line editing mode ~
|c_CTRL-D| CTRL-D list completions that match the pattern in |c_CTRL-D| CTRL-D list completions that match the pattern in
front of the cursor front of the cursor
|c_CTRL-E| CTRL-E cursor to end of command-line |c_CTRL-E| CTRL-E cursor to end of command-line
'cedit' CTRL-F default value for 'cedit': opens the |'cedit'| CTRL-F default value for 'cedit': opens the
command-line window; otherwise not used command-line window; otherwise not used
|c_CTRL-G| CTRL-G next match when 'incsearch' is active |c_CTRL-G| CTRL-G next match when 'incsearch' is active
|c_<BS>| <BS> delete the character in front of the cursor |c_<BS>| <BS> delete the character in front of the cursor
@@ -1266,7 +1265,6 @@ tag command action ~
|:delcommand| :delc[ommand] delete user-defined command |:delcommand| :delc[ommand] delete user-defined command
|:delfunction| :delf[unction] delete a user function |:delfunction| :delf[unction] delete a user function
|:delmarks| :delm[arks] delete marks |:delmarks| :delm[arks] delete marks
|:detach| :detach detach the current UI
|:diffupdate| :dif[fupdate] update 'diff' buffers |:diffupdate| :dif[fupdate] update 'diff' buffers
|:diffget| :diffg[et] remove differences in current buffer |:diffget| :diffg[et] remove differences in current buffer
|:diffoff| :diffo[ff] switch off diff mode |:diffoff| :diffo[ff] switch off diff mode
@@ -1350,8 +1348,6 @@ tag command action ~
|:inoreabbrev| :inorea[bbrev] like ":noreabbrev" but for Insert mode |:inoreabbrev| :inorea[bbrev] like ":noreabbrev" but for Insert mode
|:inoremenu| :inoreme[nu] like ":noremenu" but for Insert mode |:inoremenu| :inoreme[nu] like ":noremenu" but for Insert mode
|:intro| :int[ro] print the introductory message |:intro| :int[ro] print the introductory message
|:iput| :ip[ut] like |:put|, but adjust the indent to the
current line
|:isearch| :is[earch] list one line where identifier matches |:isearch| :is[earch] list one line where identifier matches
|:isplit| :isp[lit] split window and jump to definition of |:isplit| :isp[lit] split window and jump to definition of
identifier identifier
@@ -1473,6 +1469,7 @@ tag command action ~
|:options| :opt[ions] open the options-window |:options| :opt[ions] open the options-window
|:ounmap| :ou[nmap] like ":unmap" but for Operator-pending mode |:ounmap| :ou[nmap] like ":unmap" but for Operator-pending mode
|:ounmenu| :ounme[nu] remove menu for Operator-pending mode |:ounmenu| :ounme[nu] remove menu for Operator-pending mode
|:ownsyntax| :ow[nsyntax] set new local syntax highlight for this window
|:packadd| :pa[ckadd] add a plugin from 'packpath' |:packadd| :pa[ckadd] add a plugin from 'packpath'
|:packloadall| :packl[oadall] load all packages under 'packpath' |:packloadall| :packl[oadall] load all packages under 'packpath'
|:pbuffer| :pb[uffer] edit buffer in the preview window |:pbuffer| :pb[uffer] edit buffer in the preview window
@@ -1525,7 +1522,6 @@ tag command action ~
|:redrawtabline| :redrawt[abline] force a redraw of the tabline |:redrawtabline| :redrawt[abline] force a redraw of the tabline
|:registers| :reg[isters] display the contents of registers |:registers| :reg[isters] display the contents of registers
|:resize| :res[ize] change current window height |:resize| :res[ize] change current window height
|:restart| :restart restart the Nvim server
|:retab| :ret[ab] change tab size |:retab| :ret[ab] change tab size
|:return| :retu[rn] return from a user function |:return| :retu[rn] return from a user function
|:rewind| :rew[ind] go to the first file in the argument list |:rewind| :rew[ind] go to the first file in the argument list
@@ -1667,7 +1663,6 @@ tag command action ~
|:unabbreviate| :una[bbreviate] remove abbreviation |:unabbreviate| :una[bbreviate] remove abbreviation
|:unhide| :unh[ide] open a window for each loaded file in the |:unhide| :unh[ide] open a window for each loaded file in the
buffer list buffer list
|:uniq| :uni[q] uniq lines
|:unlet| :unl[et] delete variable |:unlet| :unl[et] delete variable
|:unlockvar| :unlo[ckvar] unlock variables |:unlockvar| :unlo[ckvar] unlock variables
|:unmap| :unm[ap] remove mapping |:unmap| :unm[ap] remove mapping

View File

@@ -29,7 +29,7 @@ use "CTRL-V 003" to insert a CTRL-C. Note: When CTRL-V is mapped you can
often use CTRL-Q instead |i_CTRL-Q|. often use CTRL-Q instead |i_CTRL-Q|.
If you are working in a special language mode when inserting text, see the If you are working in a special language mode when inserting text, see the
'langmap' option, 'langmap', on how to avoid switching this mode on and off 'langmap' option, |'langmap'|, on how to avoid switching this mode on and off
all the time. all the time.
char action ~ char action ~
@@ -101,15 +101,13 @@ CTRL-N Find next keyword (see |i_CTRL-N|).
CTRL-P Find previous keyword (see |i_CTRL-P|). CTRL-P Find previous keyword (see |i_CTRL-P|).
CTRL-R {register} *i_CTRL-R* CTRL-R {register} *i_CTRL-R*
Insert the contents of a register. Between typing CTRL-R and Insert the contents of a register. Between typing CTRL-R and
the second character, '"' will be displayed to indicate that the second character, '"' will be displayed to indicate that
you are expected to enter the name of a register. When used you are expected to enter the name of a register.
with named or clipboard registers (A-Z,a-z,0-9,+) text is The text is inserted as if you typed it, but mappings and
inserted literally like pasting with "p". For other registers,
the text is inserted as if you typed it, but mappings and
abbreviations are not used. If you have options like abbreviations are not used. If you have options like
'textwidth', 'formatoptions', or 'autoindent' set, this will 'textwidth', 'formatoptions', or 'autoindent' set, this will
influence what will be inserted. This is different from what influence what will be inserted. This is different from what
happens with the "p" command and pasting with the mouse. happens with the "p" command and pasting with the mouse.
Special registers: Special registers:
'"' the unnamed register, containing the text of '"' the unnamed register, containing the text of
@@ -133,8 +131,6 @@ CTRL-R {register} *i_CTRL-R*
special keys. E.g., you can use this to move special keys. E.g., you can use this to move
the cursor up: the cursor up:
CTRL-R ="\<Up>" CTRL-R ="\<Up>"
you can use this to insert a register as
typed with CTRL-R =@reg.
Use CTRL-R CTRL-R to insert text literally. Use CTRL-R CTRL-R to insert text literally.
When the result is a |List| the items are used When the result is a |List| the items are used
as lines. They can have line breaks inside as lines. They can have line breaks inside
@@ -273,17 +269,15 @@ The effect of the <BS>, CTRL-W, and CTRL-U depend on the 'backspace' option
item action ~ item action ~
indent allow backspacing over autoindent indent allow backspacing over autoindent
eol allow backspacing over line breaks (join lines) eol allow backspacing over end-of-line (join lines)
start allow backspacing over the start of insert; CTRL-W and CTRL-U stop start allow backspacing over the start position of insert; CTRL-W and
once at the start of insert. CTRL-U stop once at the start position
nostop like start, except CTRL-W and CTRL-U do not stop at the start of
insert.
When 'backspace' is empty, Vi compatible backspacing is used. You cannot When 'backspace' is empty, Vi compatible backspacing is used. You cannot
backspace over autoindent, before column 1 or before where insert started. backspace over autoindent, before column 1 or before where insert started.
For backwards compatibility the values "0", "1", "2" and "3" are also allowed, For backwards compatibility the values "0", "1", "2" and "3" are also allowed,
see 'backspace'. see |'backspace'|.
If the 'backspace' option does contain "eol" and the cursor is in column 1 If the 'backspace' option does contain "eol" and the cursor is in column 1
when one of the three keys is used, the current line is joined with the when one of the three keys is used, the current line is joined with the
@@ -516,7 +510,7 @@ paragraph, no matter where the cursor currently is. Or you can use Visual
mode: hit "v", move to the end of the block, and type "gq". See also |gq|. mode: hit "v", move to the end of the block, and type "gq". See also |gq|.
============================================================================== ==============================================================================
4. 'expandtab', 'softtabstop' and 'smarttab' options *ins-expandtab* 4. 'expandtab', 'smarttab' and 'softtabstop' options *ins-expandtab*
If the 'expandtab' option is on, spaces will be used to fill the amount of If the 'expandtab' option is on, spaces will be used to fill the amount of
whitespace of the tab. If you want to enter a real <Tab>, type CTRL-V first whitespace of the tab. If you want to enter a real <Tab>, type CTRL-V first
@@ -527,6 +521,13 @@ number of characters in the line increases. Backspacing will delete one
space at a time. The original character will be put back for only one space space at a time. The original character will be put back for only one space
that you backspace over (the last one). that you backspace over (the last one).
*ins-smarttab*
When the 'smarttab' option is on, a <Tab> inserts 'shiftwidth' positions at
the beginning of a line and 'tabstop' positions in other places. This means
that often spaces instead of a <Tab> character are inserted. When 'smarttab'
is off, a <Tab> always inserts 'tabstop' positions, and 'shiftwidth' is only
used for ">>" and the like.
*ins-softtabstop* *ins-softtabstop*
When the 'softtabstop' option is non-zero, a <Tab> inserts 'softtabstop' When the 'softtabstop' option is non-zero, a <Tab> inserts 'softtabstop'
positions, and a <BS> used to delete white space, will delete 'softtabstop' positions, and a <BS> used to delete white space, will delete 'softtabstop'
@@ -541,13 +542,6 @@ the cursor. Otherwise you cannot always delete a single character before the
cursor. You will have to delete 'softtabstop' characters first, and then type cursor. You will have to delete 'softtabstop' characters first, and then type
extra spaces to get where you want to be. extra spaces to get where you want to be.
*ins-smarttab*
When the 'smarttab' option is on, the <Tab> key indents by 'shiftwidth' if the
cursor is in leading whitespace. The <BS> key has the opposite effect. This
behaves as if 'softtabstop' were set to the value of 'shiftwidth'. This option
allows the user to set 'softtabstop' to a value other than 'shiftwidth' and
still use the <Tab> key for indentation.
============================================================================== ==============================================================================
5. Replace mode *Replace* *Replace-mode* *mode-replace* 5. Replace mode *Replace* *Replace-mode* *mode-replace*
@@ -605,7 +599,7 @@ In 'list' mode, Virtual Replace mode acts as if it was not in 'list' mode,
unless "L" is in 'cpoptions'. unless "L" is in 'cpoptions'.
Note that the only situations for which characters beyond the cursor should Note that the only situations for which characters beyond the cursor should
appear to move are in List mode 'list', and occasionally when 'wrap' is set appear to move are in List mode |'list'|, and occasionally when 'wrap' is set
(and the line changes length to become shorter or wider than the width of the (and the line changes length to become shorter or wider than the width of the
screen). In other cases spaces may be inserted to avoid following characters screen). In other cases spaces may be inserted to avoid following characters
to move. to move.
@@ -634,8 +628,7 @@ Completion can be done for:
10. User defined completion |i_CTRL-X_CTRL-U| 10. User defined completion |i_CTRL-X_CTRL-U|
11. omni completion |i_CTRL-X_CTRL-O| 11. omni completion |i_CTRL-X_CTRL-O|
12. Spelling suggestions |i_CTRL-X_s| 12. Spelling suggestions |i_CTRL-X_s|
13. completions from 'complete' |i_CTRL-N| |i_CTRL-P| 13. keywords in 'complete' |i_CTRL-N| |i_CTRL-P|
14. contents from registers |i_CTRL-X_CTRL-R|
Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text. Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text.
@@ -645,9 +638,6 @@ and one of the CTRL-X commands. You exit CTRL-X mode by typing a key that is
not a valid CTRL-X mode command. Valid keys are the CTRL-X command itself, not a valid CTRL-X mode command. Valid keys are the CTRL-X command itself,
CTRL-N (next), and CTRL-P (previous). CTRL-N (next), and CTRL-P (previous).
By default, the possible completions are showed in a menu and the first
completion is inserted into the text. This can be adjusted with 'completeopt'.
To get the current completion information, |complete_info()| can be used. To get the current completion information, |complete_info()| can be used.
Also see the 'infercase' option if you want to adjust the case of the match. Also see the 'infercase' option if you want to adjust the case of the match.
@@ -661,11 +651,10 @@ When completion is active you can use CTRL-E to stop it and go back to the
originally typed text. The CTRL-E will not be inserted. originally typed text. The CTRL-E will not be inserted.
*complete_CTRL-Y* *complete_CTRL-Y*
When the popup menu is displayed, CTRL-Y stops completion and accepts the When the popup menu is displayed you can use CTRL-Y to stop completion and
currently selected entry. Typing a space, Enter, or some other unprintable accept the currently selected entry. The CTRL-Y is not inserted. Typing a
character will leave completion mode and insert that typed character. If you space, Enter, or some other unprintable character will leave completion mode
want to use <Enter> to accept a completion item, use this mapping: >vim and insert that typed character.
inoremap <expr> <cr> pumvisible() ? '<c-y>' : '<cr>'
When the popup menu is displayed there are a few more special keys, see When the popup menu is displayed there are a few more special keys, see
|popupmenu-keys|. |popupmenu-keys|.
@@ -1009,25 +998,6 @@ CTRL-X CTRL-V Guess what kind of item is in front of the cursor and
completion, for example: > completion, for example: >
:imap <Tab> <C-X><C-V> :imap <Tab> <C-X><C-V>
Completing contents from registers *compl-register-words*
*i_CTRL-X_CTRL-R*
CTRL-X CTRL-R Guess what kind of item is in front of the cursor from
all registers and find the first match for it.
Further use of CTRL-R (without CTRL-X) will insert the
register content, see |i_CTRL-R|.
'ignorecase' applies to the matching.
CTRL-N Search forwards for next match. This match replaces
the previous one.
CTRL-P Search backwards for previous match. This match
replaces the previous one.
CTRL-X CTRL-R Further use of CTRL-X CTRL-R will copy the line
following the previous expansion in other contexts
unless a double CTRL-X is used (e.g. this switches
from completing register words to register contents).
User defined completion *compl-function* User defined completion *compl-function*
Completion is done by a function that can be defined by the user with the Completion is done by a function that can be defined by the user with the
@@ -1088,23 +1058,25 @@ CTRL-X s Locate the word in front of the cursor and find the
previous one. previous one.
Completing from different sources *compl-generic* Completing keywords from different sources *compl-generic*
*i_CTRL-N* *i_CTRL-N*
CTRL-N Find the next match for a word ending at the cursor, CTRL-N Find next match for words that start with the
using the sources specified in the 'complete' option. keyword in front of the cursor, looking in places
All sources complete from keywords, except functions, specified with the 'complete' option. The found
which may complete from non-keyword. The matched keyword is inserted in front of the cursor.
text is inserted before the cursor.
*i_CTRL-P* *i_CTRL-P*
CTRL-P Same as CTRL-N, but find the previous match. CTRL-P Find previous match for words that start with the
keyword in front of the cursor, looking in places
specified with the 'complete' option. The found
keyword is inserted in front of the cursor.
CTRL-N Search forward through the matches and insert the CTRL-N Search forward for next matching keyword. This
next one. keyword replaces the previous matching keyword.
CTRL-P Search backward through the matches and insert the CTRL-P Search backwards for next matching keyword. This
previous one. keyword replaces the previous matching keyword.
CTRL-X CTRL-N or CTRL-X CTRL-N or
CTRL-X CTRL-P Further use of CTRL-X CTRL-N or CTRL-X CTRL-P will CTRL-X CTRL-P Further use of CTRL-X CTRL-N or CTRL-X CTRL-P will
@@ -1118,25 +1090,26 @@ Stop completion *compl-stop*
CTRL-X CTRL-Z Stop completion without changing the text. CTRL-X CTRL-Z Stop completion without changing the text.
AUTOCOMPLETION *ins-autocompletion* AUTO-COMPLETION *compl-autocomplete*
Vim can display a completion menu as you type, similar to using |i_CTRL-N|, To get LSP-driven auto-completion, see |lsp-completion|. To get basic
but triggered automatically. See 'autocomplete'. The menu items are collected auto-completion without installing plugins or LSP, try this: >lua
from the sources listed in the 'complete' option, in order.
A decaying timeout keeps Vim responsive. Sources earlier in the 'complete'
list get more time (higher priority), but all sources receive at least a small
time slice.
This mode is fully compatible with other completion modes. You can invoke
any of them at any time by typing |CTRL-X|, which temporarily suspends
autocompletion. To use |i_CTRL-N| or |i_CTRL-X_CTRL-N| specifically, press
|CTRL-E| first to dismiss the popup menu (see |complete_CTRL-E|).
See also 'autocomplete', 'autocompletetimeout' and 'autocompletedelay'.
To get LSP-driven auto-completion, see |lsp-completion|.
local triggers = {'.'}
vim.api.nvim_create_autocmd('InsertCharPre', {
buffer = vim.api.nvim_get_current_buf(),
callback = function()
if vim.fn.pumvisible() == 1 or vim.fn.state('m') == 'm' then
return
end
local char = vim.v.char
if vim.list_contains(triggers, char) then
local key = vim.keycode('<C-x><C-n>')
vim.api.nvim_feedkeys(key, 'm', false)
end
end
})
<
FUNCTIONS FOR FINDING COMPLETIONS *complete-functions* FUNCTIONS FOR FINDING COMPLETIONS *complete-functions*
@@ -1189,9 +1162,6 @@ For example, the function can contain this: >
let matches = ... list of words ... let matches = ... list of words ...
return {'words': matches, 'refresh': 'always'} return {'words': matches, 'refresh': 'always'}
< <
If looking for matches is time-consuming, |complete_check()| may be used to
maintain responsiveness.
*complete-items* *complete-items*
Each list item can either be a string or a Dictionary. When it is a string it Each list item can either be a string or a Dictionary. When it is a string it
is used as the completion. When it is a Dictionary it can contain these is used as the completion. When it is a Dictionary it can contain these
@@ -1326,7 +1296,6 @@ use all space available.
The 'pumwidth' option can be used to set a minimum width. The default is 15 The 'pumwidth' option can be used to set a minimum width. The default is 15
characters. characters.
*compl-states*
There are three states: There are three states:
1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P. 1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P.
2. A cursor key has been used to select another match. The match was not 2. A cursor key has been used to select another match. The match was not

View File

@@ -89,7 +89,7 @@ To uninstall Nvim:
- Scoop (Windows): `scoop uninstall neovim` - Scoop (Windows): `scoop uninstall neovim`
============================================================================== ==============================================================================
Sponsor Vim/Nvim development *sponsor* Sponsor Vim/Nvim development *sponsor* *register*
Fixing bugs and adding new features takes a lot of time and effort. To show Fixing bugs and adding new features takes a lot of time and effort. To show
your appreciation for the work and motivate developers to continue working on your appreciation for the work and motivate developers to continue working on
@@ -605,7 +605,7 @@ status messages will only be used if an option is on: >
command characters 'showcmd' on off command characters 'showcmd' on off
cursor position 'ruler' off off cursor position 'ruler' off off
The current mode is "-- INSERT --" or "-- REPLACE --", see 'showmode'. The The current mode is "-- INSERT --" or "-- REPLACE --", see |'showmode'|. The
command characters are those that you typed but were not used yet. command characters are those that you typed but were not used yet.
If you have a slow terminal you can switch off the status messages to speed If you have a slow terminal you can switch off the status messages to speed
@@ -711,4 +711,5 @@ Arbitrary code registered via |:UpdateRemotePlugins|, that runs in a separate
process and communicates with Nvim via the |api|. process and communicates with Nvim via the |api|.
==============================================================================
vim:tw=78:ts=8:et:sw=4:ft=help:norl: vim:tw=78:ts=8:et:sw=4:ft=help:norl:

View File

@@ -140,4 +140,5 @@ A job may be killed at any time with the |jobstop()| function:
< <
Individual streams can be closed without killing the job, see |chanclose()|. Individual streams can be closed without killing the job, see |chanclose()|.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

File diff suppressed because it is too large Load Diff

View File

@@ -376,7 +376,8 @@ strongly advised not to rely on undefined or implementation-defined behavior.
============================================================================== ==============================================================================
COPYRIGHT COPYRIGHT
Lua BitOp is Copyright (C) 2008-2025 Mike Pall. Lua BitOp is Copyright (C) 2008-2012 Mike Pall.
Lua BitOp is free software, released under the MIT license. Lua BitOp is free software, released under the MIT license.
==============================================================================
vim:tw=78:ts=4:sw=4:sts=4:et:ft=help:norl: vim:tw=78:ts=4:sw=4:sts=4:et:ft=help:norl:

View File

@@ -10,18 +10,19 @@
============================================================================== ==============================================================================
Introduction *lua-guide* Introduction *lua-guide*
This guide introduces the basics of everyday Lua usage for configuring and This guide will go through the basics of using Lua in Nvim. It is not meant
controlling Nvim. It assumes some familiarity with the (non-Lua) basics of to be a comprehensive encyclopedia of all available features, nor will it
Nvim (commands, options, mappings, autocommands), which are covered in the detail all intricacies. Think of it as a survival kit -- the bare minimum
needed to know to comfortably get started on using Lua in Nvim.
An important thing to note is that this isn't a guide to the Lua language
itself. Rather, this is a guide on how to configure and modify Nvim through
the Lua language and the functions we provide to help with this. Take a look
at |luaref| and |lua-concepts| if you'd like to learn more about Lua itself.
Similarly, this guide assumes some familiarity with the basics of Nvim
(commands, options, mappings, autocommands), which are covered in the
|user-manual|. |user-manual|.
This is not a comprehensive encyclopedia of all available features. Think of
it as a survival kit: the bare minimum needed to comfortably get started on
using Lua in Nvim.
See |lua-plugin| for guidance on developing Lua plugins.
See |luaref| and |lua-concepts| for details on the Lua programming language.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Some words on the API *lua-guide-api* Some words on the API *lua-guide-api*
@@ -29,17 +30,16 @@ The purpose of this guide is to introduce the different ways of interacting
with Nvim through Lua (the "API"). This API consists of three different with Nvim through Lua (the "API"). This API consists of three different
layers: layers:
1. The "Vim API" inherited from Vim: |Ex-commands| and |vimscript-functions| 1. The "Vim API" inherited from Vim: |Ex-commands| and |builtin-functions| as
as well as |user-function|s in Vimscript. These are accessed through well as |user-function|s in Vimscript. These are accessed through |vim.cmd()|
|vim.cmd()| and |vim.fn| respectively, which are discussed under and |vim.fn| respectively, which are discussed under |lua-guide-vimscript|
|lua-guide-vimscript| below. below.
2. The "Nvim API" written in C for use in remote plugins and GUIs; see |api|. 2. The "Nvim API" written in C for use in remote plugins and GUIs; see |api|.
These functions are accessed through |vim.api|. These functions are accessed through |vim.api|.
3. The "Lua API" written in and specifically for Lua. These are any other 3. The "Lua API" written in and specifically for Lua. These are any other
functions accessible through `vim.*` not mentioned already; see functions accessible through `vim.*` not mentioned already; see |lua-stdlib|.
|lua-stdlib|.
This distinction is important, as API functions inherit behavior from their This distinction is important, as API functions inherit behavior from their
original layer: For example, Nvim API functions always need all arguments to original layer: For example, Nvim API functions always need all arguments to
@@ -121,6 +121,7 @@ Let's assume you have the following directory structure:
|-- syntax/ |-- syntax/
|-- init.vim |-- init.vim
< <
Then the following Lua code will load `myluamodule.lua`: Then the following Lua code will load `myluamodule.lua`:
>lua >lua
require("myluamodule") require("myluamodule")
@@ -133,6 +134,7 @@ Similarly, loading `other_modules/anothermodule.lua` is done via
-- or -- or
require('other_modules.anothermodule') require('other_modules.anothermodule')
< <
Note how "submodules" are just subdirectories; the `.` is equivalent to the Note how "submodules" are just subdirectories; the `.` is equivalent to the
path separator `/` (even on Windows). path separator `/` (even on Windows).
@@ -164,7 +166,7 @@ the cache manually first:
< <
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
See also: See also:
• |lua-module-load|: how `require()` finds modules • |lua-module-load|
• |pcall()| • |pcall()|
============================================================================== ==============================================================================
@@ -223,7 +225,7 @@ Vimscript are automatically converted:
vim.fn.jobstart('ls', { on_stdout = print_stdout }) vim.fn.jobstart('ls', { on_stdout = print_stdout })
< <
This works for both |vimscript-functions| and |user-function|s. This works for both |builtin-functions| and |user-function|s.
Note that hashes (`#`) are not valid characters for identifiers in Lua, so, Note that hashes (`#`) are not valid characters for identifiers in Lua, so,
e.g., |autoload| functions have to be called with this syntax: e.g., |autoload| functions have to be called with this syntax:
@@ -232,9 +234,10 @@ e.g., |autoload| functions have to be called with this syntax:
< <
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
See also: See also:
• |vimscript-functions|: descriptions of all Vimscript functions • |builtin-functions|: alphabetic list of all Vimscript functions
• |function-list|: Vimscript functions grouped by topic • |function-list|: list of all Vimscript functions grouped by topic
• |:runtime|: run all Lua scripts matching a pattern in |'runtimepath'| • |:runtime|: run all Lua scripts matching a pattern in |'runtimepath'|
• |package.path|: list of all paths searched by `require()`
============================================================================== ==============================================================================
Variables *lua-guide-variables* Variables *lua-guide-variables*
@@ -527,6 +530,7 @@ Examples:
callback = function() print("My Plugin Works!") end, callback = function() print("My Plugin Works!") end,
}) })
< <
Nvim will always call a Lua function with a single table containing information Nvim will always call a Lua function with a single table containing information
about the triggered autocommand. The most useful keys are about the triggered autocommand. The most useful keys are
• `match`: a string that matched the `pattern` (see |<amatch>|) • `match`: a string that matched the `pattern` (see |<amatch>|)

View File

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

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