Compare commits

...

111 Commits

Author SHA1 Message Date
zeertzjq
0c995c0efb vim-patch:9.1.1204: MS-Windows: crash when passing long string to expand() (#32902)
Problem:  MS-Windows: crash when passing long string to expand() with
          'wildignorecase'.
Solution: Use the same buflen as unix_expandpath() in dos_expandpath().
          Remove an unnecessary STRLEN() while at it (zeertzjq).

closes: vim/vim#16896

00a749bd90
(cherry picked from commit ec8fc28743)
2025-03-15 11:21:12 +00:00
zeertzjq
aab7129abe vim-patch:9.0.1458: buffer overflow when expanding long file name
Problem:    Buffer overflow when expanding long file name.
Solution:   Use a larger buffer and avoid overflowing it. (Yee Cheng Chin,
            closes vim/vim#12201)

a77670726e

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
(cherry picked from commit b0b61c42b3)
2025-03-15 01:11:50 +00:00
zeertzjq
52ad6adc8d vim-patch:8.2.4963: expanding path with "/**" may overrun end of buffer
Problem:    Expanding path with "/**" may overrun end of buffer.
Solution:   Use vim_snprintf().

386c24cd26

Co-authored-by: Bram Moolenaar <Bram@vim.org>
(cherry picked from commit ad5bced637)
2025-03-15 01:11:50 +00:00
zeertzjq
c5eeb1b9ee Merge pull request #32880 from zeertzjq/backport
Backport #32739 to release-0.10
2025-03-14 07:52:06 +08:00
zeertzjq
3e7f0a13e1 vim-patch:9.1.1172: [security]: overflow with 'nostartofline' and Ex command in tag file (#32739)
Problem:  heap-buffer-overflow with 'nostartofline' and Ex command in
          tag file.
Solution: Set cursor column when moving cursor to line 1 (zeertzjq).

closes: vim/vim#16796

3ed6659549
2025-03-14 07:32:33 +08:00
zeertzjq
2010f398f4 vim-patch:8.2.3579: CI sometimes fails for MinGW
Problem:    CI sometimes fails for MinGW.
Solution:   Use backslashes in HandleSwapExists(). (Christian Brabandt,
            closes vim/vim#9078)

4b2c804767

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 24bd7a4a9c)
2025-03-11 01:51:54 +00:00
zeertzjq
f0790c565c vim-patch:8.2.3311: Vim9: check for DO_NOT_FREE_CNT is very slow
Problem:    Vim9: check for DO_NOT_FREE_CNT is very slow.
Solution:   Move to a separate function so it can be skipped by setting
            $TEST_SKIP_PAT.

dae453f339

Co-authored-by: Bram Moolenaar <Bram@vim.org>
(cherry picked from commit 1bf9a7ce95)
2025-03-11 01:51:54 +00:00
neovim-backports[bot]
ecaece926e vim-patch:9.1.1155: Mode message not cleared after :silent message (#32672)
Problem:  Mode message not cleared after :silent message
          (after 9.0.1634).
Solution: Don't reset mode_displayed when the message is empty.
          (zeertzjq)

fixes: neovim/neovim#32641
closes: vim/vim#16744

fce1fa5b61
(cherry picked from commit df0328521f)

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2025-02-28 00:22:31 +00:00
James McCoy
28a8d59cc7 fix(vim_snprintf): special-case handling of binary format
A binary format spec always expects a corresponding unsigned long long
value. However, that explicit handling didn't get included when porting
the code from Vim, so binary format spec was falling through to the
"unsigned" and "length_modifier = NUL" portion of the code:

        } else {
          // unsigned
          switch (length_modifier) {
          case NUL:
            uarg = (tvs
                    ? (unsigned)tv_nr(tvs, &arg_idx)
                    : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
                                   &arg_cur, fmt),
                       va_arg(ap, unsigned)));
            break;

This incorrectly read an "unsigned" value from an "unsigned long long"
variable, which would produce incorrect results on certain platforms.

(cherry picked from commit 453f2c52d2)
2025-02-26 11:53:08 +00:00
James McCoy
3c57ee079d test(unit/strings_spec): show ctx when vim_snprintf content check fails #32570
Same idea as a7be4b7bf8, but that only showed the context if the
length of the string differed. Since these tests check both string
length and string content, the ctx should be provided for both.

    ERROR    test/unit/testutil.lua @ 797: vim_snprintf() positional arguments
    test/unit/testutil.lua:769: test/unit/testutil.lua:753: (string) '
    test/unit/strings_spec.lua:159: snprintf(buf, 4, "%1$0.*2$b", 12ULL, cdata<int>: 0xf78c8ed8) = 001100
    Expected objects to be the same.
    Passed in:
    (string) '000'
    Expected:
    (string) '001''

(cherry picked from commit 1c81734871)
2025-02-23 01:39:41 +00:00
Sören Tempel
e6432b0094 fix(tests): filter out lines with __typeof__ keyword (#32524)
Problem: On 32-bit architectures, musl libc makes heavy use of
__typeof__ as part of its __REDIR macro for optional backwards
compatibility with 32-bit time_t values. Unfortunately, the
__typeof__ keyword is not supported by the LuaJIT C parser.

Solution: Filter out the keyword in filter_complex_blocks.
(cherry picked from commit db2c3d1143)
2025-02-22 00:09:59 +00:00
Riley Bruins
00d3956109 fix(treesitter): don't spam query errors in the highlighter
**Problem:** An erroneous query in the treesitter highlighter gives a
deluge of errors that makes the editor almost unusable.

**Solution:** Detach the highlighter after an error is detected, so that
it only gets displayed once (per highlighter instance).

(cherry picked from commit b0bbe25c48)
2025-02-20 01:32:10 +00:00
zeertzjq
d65ce60f49 Merge pull request #32501 from zeertzjq/backport
Backport #32483 to release-0.10
2025-02-18 07:14:58 +08:00
Sören Tempel
0f0959ca32 fix(tests): remove the __extension__ keyword in filter_complex_blocks (#32483)
Problem: This keyword is used by GCC and Clang to prevent -Wpedantic
(and other options) from emitting warnings for many GNU C extensions.
This is used heavily in Alpine Linux through musl libc and
foritfy-headers. Without filtering the __extension__ keyword some type
definitions are duplicated. For example, timeval is defined once as

  struct timeval { time_t tv_sec; suseconds_t tv_usec; };

and once as:

  __extension__ struct timeval { time_t tv_sec; suseconds_t tv_usec; };

Without this patch, the LuaJIT C parser doesn't recognize that these
definitions are equivalent, causing unit test to fail on Alpine Linux.

Solution: Filter out the keyword in filter_complex_blocks.
2025-02-18 06:48:28 +08:00
zeertzjq
6b6abb8969 vim-patch:9.1.1108: 'smoothscroll' gets stuck with 'listchars' "eol" (#32434)
Problem:  'smoothscroll' gets stuck with 'listchars' "eol".
Solution: Count size of 'listchars' "eol" in line size when scrolling.
          (zeertzjq)

related: neovim/neovim#32405
closes: vim/vim#16627

2c47ab8fcd
(cherry picked from commit 9f85dace94)
2025-02-13 23:48:31 +00:00
Christian Clason
6ca2ef8dfe ci(cirrus): update to freebsd-14-2
Previous `freebsd-14-0` image was dropped

(cherry picked from commit 8117db48ed)
2025-02-12 17:12:05 +00:00
luukvbaal
3fd08c2eb2 fix(memline): don't check line count for closed memline #32403
Problem:  Error thrown when for invalid line number which may be accessed
          in an `on_detach` callback at which point line count is
          intentionally set to 0.
Solution: Move empty memline check to before line number check.
(cherry picked from commit 15bc930fca)
2025-02-12 16:49:02 +00:00
Jaehwang Jung
7e5b7ae4e0 fix(lsp): prevent desync due to empty buffer (#29904)
Problem:
Some language servers (e.g., rust-analyzer, texlab) are desynced when
the user deletes the entire contents of the buffer. This is due to the
discrepancy between how nvim computes diff and how nvim treats empty
buffer.
* diff: If the buffer became empty, then the diff includes the last
  line's eol.
* empty buffer: Even if the buffer is empty, nvim regards it as having
  a single empty line with eol.

Solution:
Add special case for diff computation when the buffer becomes empty so
that it does not include the eol of the last line.
2025-02-08 10:48:31 +01:00
Evgeni Chasnovski
c40057f372 fix(lsp): check for valid buf before processing semantic tokens response
Problem: There is no check for buffer validity before processing
  semantic tokens response. This can lead to `Invalid buffer id` error
  if processing request takes a long time and the buffer is wiped out.

  For example, this can happen after by accident navigating to a buffer
  from different project which leads to first loading project's
  workspace and *then* processing semantic tokens. During that time
  a buffer can be wiped out, as navigation to it was by accident.

Solution: Add extra check for buffer validity before processing semantic
  tokens response.
(cherry picked from commit a9cdf76e3a)
2025-02-08 01:24:58 +00:00
zeertzjq
c7bb6bbdea vim-patch:9.1.1077: included syntax items do not understand contains=TOP (#32343)
Problem:  Syntax engine interpreted contains=TOP as matching nothing
          inside included files, since :syn-include forces HL_CONTAINED
          on for every included item. After 8.2.2761, interprets
          contains=TOP as contains=@INCLUDED, which is also not correct
          since it doesn't respect exclusions, and doesn't work if there
          is no @INCLUDED cluster.
Solution: revert patch 8.2.2761, instead track groups that have had
          HL_CONTAINED forced, and interpret contains=TOP and
          contains=CONTAINED using this. (Theodore Dubois)

fixes: vim/vim#11277
closes: vim/vim#16571

f50d5364d7

Co-authored-by: Theodore Dubois <tblodt@icloud.com>
(cherry picked from commit 878b3b89c3)
2025-02-06 00:33:50 +00:00
alex-tdrn
c3866cea60 feat(win32): embed executable icon
Problem: on windows, the neovim executable (and thus the filetypes
associated to open with neovim) has no embedded icon

Solution: create a windows resource file pointing to the icon, and
add it to the nvim binary target

(cherry picked from commit cb84cd5d9f)
2025-02-05 20:54:05 +00:00
James McCoy
d6da862ce0 test(unit/strings_spec): use correct type for binary values
When 9.0.1856 was ported, the numbers being formatted as binary were cast
to "unsigned int" rather than uvarnumber_T, as is done upstream.

(cherry picked from commit 1426f3f3ce)
2025-01-29 20:25:38 +00:00
James McCoy
452ed57b71 test(unit/strings_spec): provide context for vim_snprintf tests
Since these assertions all use a common function to perform the test
assertions, it's difficult to figure out which test failed:

    ERROR    test/unit/testutil.lua @ 785: vim_snprintf() positional arguments
    test/unit/testutil.lua:757: test/unit/testutil.lua:741: (string) '
    test/unit/strings_spec.lua:143: Expected objects to be the same.
    Passed in:
    (number) 6400
    Expected:
    (number) 6'
    exit code: 256

Adding context to the assertion makes it clearer what the problem is:

    ERROR    test/unit/testutil.lua @ 785: vim_snprintf() positional arguments
    test/unit/testutil.lua:757: test/unit/testutil.lua:741: (string) '
    test/unit/strings_spec.lua:149: snprintf(buf, 0, "%1$0.*2$b", cdata<unsigned int>: 0xf78d0f38, cdata<int>: 0xf78dc4e0) = 001100
    Expected objects to be the same.
    Passed in:
    (number) 6400
    Expected:
    (number) 6'
    exit code: 256

(cherry picked from commit a7be4b7bf8)
2025-01-29 20:25:38 +00:00
bfredl
44c6fbaf9a version bump 2025-01-29 11:20:06 +01:00
bfredl
e96f75a4e6 NVIM 0.10.4
This is maintenance release, focusing on bug fixes. It also contains changes
to the available binary releases.

A Linux AArch64 binary has been added as part of the binary releases.
In addition, the previous "linux64" binary has been renamed to "linux-x86_64".
This is a BREAKING changes for scripts which consumes our binary releases.

FIXES
--------------------------------------------------------------------------------
- a8eddf1eb1 checkhealth: failed if 'lua' in plugin name
- 2bc5e1be0f decor: set invalid flag for end of invalidated paired marks
- d8149e5af9 inspect: use correct default highlight
- 357ee88606 jobs: do not block UI when jobwait() doesn't block (#31803)
- b0b383bff9 lsp: minimum height for floating popup #31990
- 4b25fe09cc lua: prevent SIGSEGV when lua error is NULL in libuv_worker (#32091)
- e477ac7c45 marks: revise metadata for start mark of revalidated pair #32017
- 22a327a20e mpack: remove invalid bool definition
- 87440e7bc5 runtime: let matchit and matchparen skips fallback on treesitter captures
- f132efaefb search: avoid quadratic time complexity when computing fuzzy score (#32153)
- ca10442e01 treesitter: don't open fold when o/O adds a line below #28709
- 323c43e1c4 treesitter: uv_dlclose after uv_dlerror
- a3cc513b67 treesitter.foldexpr: only refresh valid buffers
- a986048cb0 treesitter.foldexpr: refresh in the buffers affected by OptionSet
- d7ee06124d treesitter.foldexpr: robustness against ctrl-c
- 79030bf196 ui: ensure screen update before waiting for input #30576
- 3a50639331 9.1.0699: "dvgo" is not always an inclusive motion (#30173)
- 6a6c6b2658 9.1.0708: Recursive window update does not account for reset skipcol (#30217)
- 938a600847 9.1.1048: crash after scrolling and pasting in silent Ex mode (#32168)

BUILD
--------------------------------------------------------------------------------
- fdcdf560da release: add linux-arm64 appimage and tarball
- a7392c04d9 tests: add arm64 runner
2025-01-29 11:10:58 +01:00
dundargoc
8d420a32db ci(release)!: remove backwards compatible releases
Remove `nvim-linux64.tar.gz` and `nvim.appimage` as maintaining
these is too much work.

Also fix directory names to be consistent.

(cherry picked from commit 318676ad13)
2025-01-28 11:12:21 +01:00
Christian Clason
fdcdf560da ci(release): add linux-arm64 appimage and tarball
Problem: No releases for ARM Linux.

Solution: Provide appimages and tarballs for `linux-arm64`. Rename
x86 releases to `linux-x86_64` for consistency.

(cherry picked from commit c1718d6863)
2025-01-28 11:12:21 +01:00
Andreas Schneider
22a327a20e fix(mpack): remove invalid bool definition
This causes build failures with gcc 15.

Fixes #31723

(cherry picked from commit 83479b95ab)
2025-01-28 03:33:12 +00:00
zeertzjq
d63848c918 Merge pull request #32197 from zeertzjq/backport
ci(tests): add arm64 runner
2025-01-28 11:16:55 +08:00
Christian Clason
a6c54fdfc1 ci(tests): remove build-types jobs
Problem: Some CI jobs are redundant: `RelWithDebInfo` is already tested
on Linux-Arm64; `MinSizeRel` and Ninja Multi Config are not sufficiently
relevant in practice to spend CI cycles on.

Solution: Remove `build-types` job.
(cherry picked from commit 0fd4ef5da7)
2025-01-25 08:28:06 +08:00
Christian Clason
a7392c04d9 ci(tests): add arm64 runner
Problem: Linux `aarch64`/`arm64` builds are not tested.

Solution: Add `ubuntu-arm` runners to test matrix (using
`RelWithDebInfo` build).

(cherry picked from commit 3702bcb139)
2025-01-25 08:27:55 +08:00
zeertzjq
7908900859 docs(support): update tested macOS and FreeBSD versions (#32191) 2025-01-24 10:07:05 +00:00
phanium
a8eddf1eb1 fix(checkhealth): failed if 'lua' in plugin name
(cherry picked from commit 4c9f3689a1)
2025-01-23 08:25:31 +00:00
zeertzjq
938a600847 vim-patch:9.1.1048: crash after scrolling and pasting in silent Ex mode (#32168)
Problem:  Crash after scrolling and pasting in silent Ex mode.
          (fizz-is-on-the-way)
Solution: Don't move cursor to line 0 when scrolling.
          (zeertzjq)

closes: vim/vim#16506

df098fedbc
(cherry picked from commit a9c12d4c29)
2025-01-23 00:36:43 +00:00
zeertzjq
3a50639331 vim-patch:9.1.0699: "dvgo" is not always an inclusive motion (#30173)
Problem:  "dvgo" is not always an inclusive motion
          (Iain King-Speir)
Solution: initialize the inclusive flag to false

fixes: vim/vim#15580
closes: vim/vim#15582

f8702aeb8f

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 0346666f71)
2025-01-22 07:17:20 +00:00
zeertzjq
f132efaefb fix(search): avoid quadratic time complexity when computing fuzzy score (#32153)
(cherry picked from commit a8b6fa07c4)
2025-01-22 01:54:04 +00:00
Justin M. Keyes
46cc8a52b2 Merge pull request #32102 from tomtomjhj/cherrypick-ts-foldexpr
Backport treesitter foldexpr fixes
2025-01-19 11:31:47 -08:00
Igor
a3cc513b67 fix(treesitter.foldexpr): only refresh valid buffers
Problem: autocmd to refresh folds always uses the current buffer if the
option type is local. However, the current buffer may not have a parser,
and thus the assert that checks for a parser could fail.

Solution: check if the foldinfo contains the buffer, and only refresh if
so.
2025-01-20 00:27:42 +09:00
Jaehwang Jung
a986048cb0 fix(treesitter.foldexpr): refresh in the buffers affected by OptionSet 2025-01-20 00:27:39 +09:00
Jaehwang Jung
d7ee06124d fix(treesitter.foldexpr): robustness against ctrl-c
Problem:
Exiting the insert mode with ctrl-c does not trigger InsertLeave
autocmd. This may lead to nil error in treesitter foldexpr.

Solution:
Check nil. Folds still can be stale after exiting the insert mode with
ctrl-c, but it will be eventually updated correctly.

An alternative solution would be to ensure that exiting the insert mode
always triggers do_foldupdate. This can be done either by "fixing"
ctrl-c or with on_key callback that checks ctrl-c (nvim-cmp does this).
2025-01-20 00:26:52 +09:00
Jaehwang Jung
ca10442e01 fix(treesitter): don't open fold when o/O adds a line below #28709
Problem:
`o`-ing on a folded line opens the fold, because the new line gets the
fold level from the above line (level '='), which extends the fold to
the new line. `O` has a similar problem when run on the line below a
fold.

Solution:
Use -1 for the added line to get the lower level from the above/below
line.
2025-01-20 00:26:03 +09:00
neovim-backports[bot]
4b25fe09cc fix(lua): prevent SIGSEGV when lua error is NULL in libuv_worker (#32091)
Problem:
Calling `xstrdup` with a NULL pointer causes a SIGSEGV if `lua_tostring` returns
NULL in `nlua_luv_thread_common_cfpcall`.

Crash stack trace:
- `_platform_strlen` → `xstrdup` (memory.c:469)
- `nlua_luv_thread_common_cfpcall` (executor.c:281)

Solution:
Check if `lua_tostring` returns NULL and pass NULL to `event_create` to avoid the crash.

(cherry picked from commit a5b1b83a26)

Co-authored-by: 林玮 (Jade Lin) <linw1995@icloud.com>
2025-01-19 01:00:18 +00:00
dundargoc
baaaf6a9e7 build: fix install 2025-01-15 21:27:02 +01:00
luukvbaal
e477ac7c45 fix(marks): revise metadata for start mark of revalidated pair #32017
Problem:  Metadata may be revised for end mark of a revalidated pair.
Solution: Revise metadata for start mark of a revalidated pair.
(cherry picked from commit 5cc93ef472)
2025-01-15 10:56:52 +00:00
dundargoc
3b5c2213fd build: fix make install on cmake 3.13 and 3.14
Closes https://github.com/neovim/neovim/issues/30756.
2025-01-15 09:33:30 +01:00
Justin M. Keyes
5aabe5695f Update test/functional/plugin/lsp_spec.lua 2025-01-14 12:36:42 +00:00
Xuyuan Pang
b0b383bff9 fix(lsp): minimum height for floating popup #31990
Problem:
The floating window for hover and signature help always cuts off a few lines,
because the `_make_floating_popup_size` function counts empty lines as having
zero height.

Solution:
Ensure the height is at least 1.

(cherry picked from commit a4f575abd8)
2025-01-14 12:36:42 +00:00
Horror Proton
323c43e1c4 fix(treesitter): uv_dlclose after uv_dlerror
(cherry picked from commit 5a54681025)
2025-01-14 09:48:10 +00:00
Luuk van Baal
2bc5e1be0f fix(decor): set invalid flag for end of invalidated paired marks
(cherry picked from commit 87610d82db)
2025-01-10 07:41:32 +00:00
Emilia Simmons
87440e7bc5 fix(runtime): let matchit and matchparen skips fallback on treesitter captures
When treesitter is enabled, by default syntax groups are not defined, but these
groups are used to identify where to skip matches in matchit and matchparen.

This patch does three things:
1. If syntax is enabled regardless of treesitter (`vim.bo.syntax='on'`):
   Use original implementation.
2. If treesitter is enabled and syntax is not:
   Match the syntax groups (i.e. `comment\|string`) against treesitter captures
   to check for skipped groups.
3. Add an explicit treesitter syntax for marking captures to skip:
   matchit uses `b:match_skip` to determine what counts as skippable
   Where 's:comment\|string' uses a match of the named syntax groups against
   a regex match of comment\|string, 't:comment\|string' now uses vim regex
   to match against the names of the treesitter capture groups.

(cherry picked from commit 69aa33d890)
2025-01-04 19:48:25 +00:00
Gregory Anders
357ee88606 fix(jobs): do not block UI when jobwait() doesn't block (#31803)
(cherry picked from commit efe1732c6f)
2025-01-03 17:16:40 +00:00
luukvbaal
6a6c6b2658 vim-patch:9.1.0708: Recursive window update does not account for reset skipcol (#30217)
Problem:  Window is updated with potentially invalid skipcol in recursive
          window update path. I.e. cursor outside of visible range in
          large line that does not fit.
Solution: Make sure it is valid (Luuk van Baal).

3d5065fc75
2024-12-28 17:16:37 +00:00
fredizzimo
79030bf196 fix(ui): ensure screen update before waiting for input #30576
Ensure the screen is fully updated before blocking for input. This did
not always happen before, for example when setting `cursorline
scrolloff=9999`, which lead to jerky movement when using some GUI
applications.

Because of the duality of redraw_later, this can't be done in
command-line or when waiting for "Press ENTER". In many of those cases
the redraw is expected AFTER the key press, while normally it should
update the screen immediately. So, those special cases are excluded.

(cherry picked from commit 7eba016c86)
2024-12-28 17:16:37 +00:00
dundargoc
aa2b69b178 ci(build.yml): disable security restriction
A new security restriction in Ubuntu 24.04 prevents users from using
`unshare`, so we need to disable it in order for the test to work
properly.
2024-12-26 22:35:35 +01:00
dundargoc
b36cadcb8e build: specify POST_BUILD when using add_custom_command
This is needed specifically for the second signature of
add_custom_command, which appends an operation to an existing target.
This will prevent the cmake warning CMP0175.

Reference: https://cmake.org/cmake/help/latest/policy/CMP0175.html
(cherry picked from commit 07b14c8e2e)
2024-12-26 15:22:07 +01:00
Christian Clason
d8149e5af9 fix(inspect): use correct default highlight
Problem: `vim.highlight` was renamed on `master`, breaking the
backported fix.

Solution: Use old name.

Fixup for 650dcbbafe
2024-12-23 11:23:41 +01:00
bfredl
4e1b1b6fd7 version bump 2024-12-21 18:16:24 +01:00
bfredl
9b5ee7df4e NVIM 0.10.3
Christmas edition. This is a maintenance release, focusing on fixes.

FEATURES
--------------------------------------------------------------------------------
- 085f1cc99d main: expand file ~\ or ~/ prefix on Windows

FIXES
--------------------------------------------------------------------------------
- f8ee92feec deps build for ARM64 MSVC
- 163a532cfa api: make `nvim_set_hl()` respect all `cterm` attributes (#31390)
- 6a63034b51 completion: avoid deleting text when completion leader changes #31448
- c257fe5582 coverity/510275: linematch out of bounds access (#30687)
- 7ca0408a1f defaults: don't replace keycodes in Visual search mappings (#31460)
- 71faa2be88 events: don't expand `args.file` for Lua callback (#31473)
- e80e8a0980 extmark: builtin completion can still affect nearby extmarks #31387
- 7abc58349e filetype: make filetype detection work with :doautocmd (#31470)
- 98ec48eefb inccommand: ensure cursor is where it belongs
- 650dcbbafe inspect: always show priority
- b5b84b806a inspect: show priority for treesitter highlights
- bf66871113 lsp: cancel pending requests before refreshing (#31500)
- 308e9719cf lsp: retrigger diagnostics request on server cancellation (#31345) (#31427)
- 84bbbd9fbe lsp: str_byteindex_enc bounds checking #30747
- 01fe4fc589 marks: skip right_gravity marks when deleting text
- 57b0fecd47 startup: report --startuptime error to stderr (#31131)
- 3c0e1a89d9 treesitter: show proper node name error messages
- bbefbc995e tui: avoid flushing buffer halfway an OSC 2 sequence (#30793)
- 424a452401 uri: uri_encode encodes brackets incorrectly for RFC2732 #31284
- 1a030f6e04 vim.system: invalid MAX_TIMEOUT for 32-bit systems #31638
- ee7885aa21 9.1.0759: screenpos() may return invalid position (#30681)

REFACTOR
--------------------------------------------------------------------------------
- b286ba419a fix incorrect use of enum (#30924)
- fb5a0e28db sort various Lua tables in src/ alphabetically (#30978)

DOCUMENTATION
--------------------------------------------------------------------------------
- 9455686b6f misc (#29410)
- 5480c0bd75 lua: "vim.bo" is always equivalent to :setlocal (#30733)
- 27fca9c7d2 lua: clarify when on_key "typed" will be empty (#30774)
2024-12-21 18:15:18 +01:00
Dan Pascu
1a030f6e04 fix(vim.system): invalid MAX_TIMEOUT for 32-bit systems #31638
The maximum signed value on 32-bit systems is 2 ^ 31 - 1. When using 2 ^ 31 for
the default timeout, the value would overflow on such systems resulting in
a negative value, which caused a stack trace when calling wait() without
a timeout.

(cherry picked from commit 4e130c1ee4)
2024-12-20 14:06:53 +00:00
Tristan Knight
bf66871113 fix(lsp): cancel pending requests before refreshing (#31500)
Problem:
Diagnostics and inlay hints can be expensive to calculate, and we
shouldn't stack them as this can cause noticeable lag.

Solution:
Check for duplicate inflight requests and cancel them before issuing a new one.
This ensures that only the latest request is processed, improving
performance and preventing potential conflicts.
2024-12-16 03:17:40 -08:00
Jonny Kong
424a452401 fix(uri): uri_encode encodes brackets incorrectly for RFC2732 #31284
**Problem:**
The brackets in the RFC2732 regular expression are currently unescaped,
causing them to be misinterpreted as special characters denoting
character groups rather than as literal characters.

**Solution:**
Escape the brackets.
Fix #31270

(cherry picked from commit 442d338cb5)
2024-12-11 14:14:33 +00:00
Luuk van Baal
01fe4fc589 fix(marks): skip right_gravity marks when deleting text
Problem:  Marks that are properly restored by the splice associated with
          an undo edit, are unnecessarily pushed to the undo header. This
          results in incorrect mark tracking in the "copy_only"
          save/restore completion path.
Solution: Avoid pushing left gravity marks at the beginning of the range,
          and right gravity marks at the end of the range to the undo
          header.
(cherry picked from commit c4f76299f0)
2024-12-10 12:50:54 +00:00
zeertzjq
7abc58349e fix(filetype): make filetype detection work with :doautocmd (#31470)
(cherry picked from commit 1077843b9b)
2024-12-10 03:17:12 +00:00
zeertzjq
8fbe3e3941 Merge pull request #31532 from zeertzjq/backport
fix(events): don't expand `args.file` for Lua callback (#31473)
2024-12-10 10:51:40 +08:00
zeertzjq
71faa2be88 fix(events): don't expand args.file for Lua callback (#31473)
Problem:  In an autocommand Lua callback whether `args.file` is expanded
          depends on whether `expand('<afile>')` has been called.
Solution: Always use the unexpanded file name for `args.file`.

Related to #31306 and vim/vim#16106. This doesn't provide `sfname`, but
at least makes `args.file` have a consistent value.
2024-12-10 10:19:01 +08:00
Christian Clason
650dcbbafe fix(inspect): always show priority
Problem: It is not obvious if a treesitter highlight priority shown in
`:Inspect` is higher or lower than the default.

Solution: Also print default priority (`vim.hl.priorities.treesitter`).
Add padding for better readability.

(cherry picked from commit b52ffd0a59)
2024-12-07 16:51:17 +00:00
luukvbaal
6a63034b51 fix(completion): avoid deleting text when completion leader changes #31448
Problem:  When completion leader changes, text that might be reinserted
          immediately after is deleted. This unnecessarily affects
          extmarks. #31387 restored the original extmarks but that
          prevents end_right_gravity marks from growing.
Solution: Avoid deleting leader text that will be reinserted.
(cherry picked from commit e788d1a3a9)
2024-12-07 14:54:33 +00:00
Christian Clason
b5b84b806a fix(inspect): show priority for treesitter highlights
Problem: `:Inspect` does not show priority for treesitter highlights,
leading to confusion why sometimes earlier highlights override later
highlights.

Solution: Also print priority metadata if set.
(cherry picked from commit 9c278af7cc)
2024-12-07 09:51:46 +00:00
zeertzjq
950048b206 Merge pull request #31461 from zeertzjq/backport
fix(defaults): don't replace keycodes in Visual search mappings (#31460)
2024-12-05 19:52:55 +08:00
zeertzjq
7ca0408a1f fix(defaults): don't replace keycodes in Visual search mappings (#31460)
Also remove "silent" to be more consistent with Normal mode search.
2024-12-05 19:33:33 +08:00
James McCoy
78a36cdd55 Merge pull request #31452 from jamessan/backport-31358
Backport release build test fixes
2024-12-04 19:51:39 -07:00
James McCoy
694c3992ea test(marktree): expose test functions in release builds
In order to run the marktree unit test in release mode, the test functions need to be available even when NDEBUG is defined.

Keep the body of marktree_check a nop during release builds, which limits the usefulness of the testing, but at least lets the tests run.
2024-12-04 21:30:53 -05:00
James McCoy
9695650c0c ci: run tests directly rather than via the Makefile
Since the Makefile is not used to build, running the tests via the Makefile causes cmake to reconfigure and revert the release build back to debug.
2024-12-04 21:30:52 -05:00
James McCoy
7781111fef test(main_spec): make "nvim -v" test agnostic to build type
In release builds, the Compilation: line is omitted so the build is reproducible. Since the "fall-back for $VIM" line is always present, check for that instead.
2024-12-04 21:30:52 -05:00
James McCoy
4007c42b77 test(version_spec): expect vim.NIL, not nil, for "build" if not in a git clone 2024-12-04 21:30:52 -05:00
James McCoy
584b811aee test(main_spec): use CMakePresets.json instead of .git for root marker 2024-12-04 21:30:51 -05:00
James McCoy
a930b2666e ci(test): remove the .git directory for Linux
Tests should not rely on being run inside a git clone, so the Linux
builds cover this use case. The macOS builds will continue running with
the .git directory so there's still unix-ish coverage within a git
clone.
2024-12-04 21:30:51 -05:00
James McCoy
c36c4ddae2 ci: run one set of tests with a release build
This ensures that no tests fail due to differences between release and debug builds.

The release build-type check is now unnecessary, too, so remove it.
2024-12-04 21:30:43 -05:00
Gregory Anders
308e9719cf fix(lsp): retrigger diagnostics request on server cancellation (#31345) (#31427)
Co-authored-by: Jesse <github@jessebakker.com>
(cherry picked from commit 29c72cdf4a)
2024-12-02 12:13:23 -06:00
luukvbaal
e80e8a0980 fix(extmark): builtin completion can still affect nearby extmarks #31387
Problem:
Built-in completion can still affect nearby extmarks. #31384

Solution:
Restore extmarks when completion leader changes.

(cherry picked from commit c7ec010ade)
2024-12-02 15:28:38 +00:00
Evgeni Chasnovski
163a532cfa fix(api): make nvim_set_hl() respect all cterm attributes (#31390)
(cherry picked from commit 8de1dc6923)
2024-12-02 00:51:14 +00:00
zeertzjq
1a12dea191 test(filetype): symlink detection works after expand('<afile>') (#31307)
Also add a test for #31306, which currently fails.

(cherry picked from commit c697c49a76)
2024-11-22 11:44:04 +00:00
zeertzjq
6f2786433d test(autocmd/termxx_spec): fix TextChangedT test flakiness (#31296)
Problem:  The E937 error appears for too short in TextChangedT test.
Solution: Only feed an Enter key after seeing the error.
(cherry picked from commit 3597633075)
2024-11-22 00:32:36 +00:00
Rafael Kitover
085f1cc99d feat(main): expand file ~\ or ~/ prefix on Windows
In command_line_scan() for MSWIN, expand "~\" or "~/" prefixed paths to
the USERPROFILE environment variable for the user's profile directory.

Rename the static os_homedir() to os_uv_homedir() to emphasize that it
is a wrapper around a libuv function.

Add the function os_get_homedir() to os/env.c to return the cached
homedir value as a const. Must be called after homedir is initialized or
it fails.

The difference between this function and the static os_uv_homedir() is
that the latter gets the homedir from libuv and is used to initialize
homedir in init_homedir(), while os_get_homedir() just returns homedir
as a const if it's initialized and is public.

Use the os_get_homedir() accessor for ~/ expansion on Windows to make
the code more concise.

Add a Windows section to main_spec.lua with tests for expanding ~/ and
~\ prefixes for files passed in on the command-line.

Fix #23901

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-11-19 07:26:37 +08:00
Riley Bruins
3c0e1a89d9 fix(treesitter): show proper node name error messages
**Problem:** Currently node names with non-alphanumeric, non
underscore/hyphen characters (only possible with anonymous nodes) are
not given a proper error message. See tree-sitter issue 3892 for more
details.

**Solution:** Apply a different scanning logic to anonymous nodes to
correctly identify the entire node name (i.e., up until the final double
quote)

(cherry picked from commit 36990f324d)
2024-11-13 13:03:00 +00:00
zeertzjq
57b0fecd47 fix(startup): report --startuptime error to stderr (#31131)
Problem:  Crash when initializing for --startuptime errors.
Solution: Report the error to stderr, as neither logging nor messages
          have been initialized yet.
(cherry picked from commit 17e00d0cc6)
2024-11-13 05:47:28 +00:00
Johnny Shaw
f8ee92feec fix: deps build for ARM64 MSVC
Problem:

Neovim will not build for ARM64 using MSVC due to misconfigured
gettext dependency build settings.

Solution:

Fix the dependency build settings for gettext when building with MSVC.

(cherry picked from commit 7737f89206)
2024-11-09 15:48:00 +00:00
Luuk van Baal
98ec48eefb fix(inccommand): ensure cursor is where it belongs
Problem:  Inccommand preview callback may flush inaccurate cmdline cursor position.
Solution: Ensure cursor is where it belongs when doing command preview.
(cherry picked from commit 59e130b6ca)
2024-11-09 15:26:32 +00:00
dundargoc
34a976ec2b ci: downgrade to clang 19
Clang 20 is still in development at the time of this commit and is
unsuitable for CI.

(cherry picked from commit 7d8dd8234a)
2024-11-09 15:09:52 +00:00
zeertzjq
6a07b199ff vim-patch:9.1.0003: Cannot build against Ruby 33 dynamically (#30683)
Problem:  Cannot build against Ruby 33 dynamically
Solution: Ruby 33 removed transient heap, so do not use
          rb_ary_transient anymore, NoMethodError format changed,
          so update test for expected error message
          (Isao Sato)

- ruby-3.3 removed transient heap for ruby/dyn

when +ruby/dyn with ruby-3.3 do command :ruby, E448 occur.
ruby-3.3 has no transient heap anymore, so disable rb_ary_transient etc.

$ LC_ALL=C VIMRUNTIME=runtime ./src/vim -u NONE -c 'ruby puts RUBY_VERSION'
"=> Error detected while processing command line:
"=> E448: Could not load library function rb_ary_detransient
"=> E266: Sorry, this command is disabled, the Ruby library could not be
    loaded.

- ruby-3.3 changed NoMethodError format:

$ rvm 3.2.2, 3.3.0-rc1 do ruby -e 'begin; nil.name; rescue => e; puts "%s : %s"%[RUBY_VERSION, e.message]; end '
=> 3.2.2 : undefined method `name' for nil:NilClass
=> 3.3.0 : undefined method `name' for nil

so loose pattern in Test_ruby_Vim_buffer_get()

closes: vim/vim#13741

443657b32b

Co-authored-by: Isao Sato <svardew@gmail.com>
2024-11-09 13:11:47 +01:00
Christian Clason
6550227110 ci: bump Intel macOS runners to 13
Problem: macos-12 GH runners are deprecated and will be removed soon.

Solution: use macos-13 runners instead.
2024-11-09 13:11:47 +01:00
dundargoc
b7f025e45b ci: adjust reviewers 2024-11-09 13:11:47 +01:00
dundargoc
6c12cfe18c ci: work around flaky python tests (#31063)
It's the same workaround as 88ed9ffcd1,
which was later removed in f707ce76ac
after it turned out to be stable after a while.
2024-11-09 13:11:47 +01:00
dundargoc
7774ca9107 ci: bump macos runner version to macos-15 2024-11-09 13:11:47 +01:00
Justin M. Keyes
348a939168 tests: skip watch.watchdirs test on macos 14 CI
Problem:
Strange failure only in macos 14 CI

    FAILED   test/functional/lua/watch_spec.lua @ 82: vim._watch watchdirs() detects file changes
    test/functional/lua/watch_spec.lua:149: Expected objects to be the same.
    Passed in:
    (table: 0x0116023758) {
     *[1] = {
        [change_type] = 3
       *[path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/nvim_KFMvPbXk9a' }
      [2] = {
        [change_type] = 3
        [path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/file' } }
    Expected:
    (table: 0x010d9d6548) {
     *[1] = {
        [change_type] = 1
       *[path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/file' }
      [2] = {
        [change_type] = 3
        [path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/file' } }

    stack traceback:
            test/functional/lua/watch_spec.lua:149: in function <test/functional/lua/watch_spec.lua:82>

Solution:
Skip test for that exact version.
2024-11-09 13:11:47 +01:00
dundargoc
9455686b6f docs: misc (#29410)
Co-authored-by: Michael Härtl <haertl.mike@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2024-11-09 13:11:47 +01:00
dundargoc
1a4e78832f ci: bump ubuntu runner version to ubuntu-24.04
Also bump clang to version 20.
2024-11-09 13:11:47 +01:00
neovim-backports[bot]
fb5a0e28db refactor: sort various Lua tables in src/ alphabetically (#30978)
refactor: sort various Lua tables in src/ alphabetically (#30977)

(cherry picked from commit 42fa3d080e)

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2024-10-29 08:14:08 +08:00
neovim-backports[bot]
b286ba419a refactor: fix incorrect use of enum (#30924)
refactor: fix incorrect use of enum (#30631)

(cherry picked from commit 184d5e7543)

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2024-10-24 12:43:15 +08:00
neovim-backports[bot]
94f44122ad test(012_directory_spec): fix flakiness on Windows (#30921)
test(012_directory_spec): fix flakiness on Windows (#30920)

Problem:  012_directory_spec is flaky on Windows.
Solution: Use :%bwipe! instead :qall!.
(cherry picked from commit fffcb88ad6)

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2024-10-24 11:57:40 +08:00
neovim-backports[bot]
0b0385ea6a test(rpc): retry flaky 'vim.rpcrequest and vim.rpcnotify' test (#30922)
Problem: 'vim.rpcrequest and vim.rpcnotify' is flaky on Windows.

Solution: retry it.
(cherry picked from commit 6fd13eedda)

Co-authored-by: Christian Clason <c.clason@uni-graz.at>
2024-10-24 11:45:24 +08:00
Tristan Knight
84bbbd9fbe fix(lsp): str_byteindex_enc bounds checking #30747
Problem:
Previously the index was only checked against the UTF8 length. This
could cause unexpected behaviours for strings containing multibyte chars

Solution:
Check indicies correctly against their max value before returning the
fallback length

(cherry picked from commit 80e37aa533)
2024-10-16 17:25:37 +00:00
zeertzjq
bbefbc995e fix(tui): avoid flushing buffer halfway an OSC 2 sequence (#30793)
Problem:  Setting title while TUI buffer is almost full may cause the
          end of a flush to be treated as a part of an OSC 2 or OSC 0
          sequence, leading to problems like invisible cursor.
Solution: Make the whole sequence to set title a unibi_ext string.
(cherry picked from commit 4846bf05dc)
2024-10-15 00:18:12 +00:00
zeertzjq
97aaea3478 test(tui_spec): use Unicode in cursor_address test (#30807)
Now that #16425 is fixed, use Unicode again to reduce screen height.
Unfortunately composing chars still can't be used, as it turns out that
composing chars may be missing when sent separately from the base char
at the last char a screen line.

(cherry picked from commit 1189c5ce59)
2024-10-14 08:20:44 +00:00
zeertzjq
1a02f1835f test(autocmd/termxx_spec): properly setup TextChangedT tests (#30788) 2024-10-13 11:29:29 +08:00
zeertzjq
2d1a13bdf5 vim-patch:9.1.0776: test_strftime may fail because of missing TZ data (#30780)
Problem:  test_strftime may fail because of missing TZ data
Solution: Use GMT offsets to validate timezone differences (James McCoy)

Some systems only provide timezones that follow the geographical region
naming (e.g. America/New_York) by default and require an additional
install for other names (like EST).

The GMT+<offset> format must always be honored, so use that to generate
distinct data for the test.

closes: vim/vim#15848

ea997edc7a

Co-authored-by: James McCoy <jamessan@jamessan.com>
(cherry picked from commit b0ddc1783a)
2024-10-12 22:54:59 +00:00
zeertzjq
27fca9c7d2 docs(lua): clarify when on_key "typed" will be empty (#30774)
(cherry picked from commit 45f8f957c0)
2024-10-12 04:42:41 +00:00
zeertzjq
5480c0bd75 docs(lua): "vim.bo" is always equivalent to :setlocal (#30733)
vim.bo

    :lua vim.bo.textwidth = 80
    :setglobal textwidth?
      textwidth=0

:setlocal

    :setlocal textwidth=80
    :setglobal textwidth?
      textwidth=0

:set

    :set textwidth=80
    :setglobal textwidth?
      textwidth=80

(cherry picked from commit 8ef3dd3afa)
2024-10-09 12:00:53 +00:00
Devon Gardner
c257fe5582 fix(coverity/510275): linematch out of bounds access (#30687)
Problem:
Int pointer cast to unsigned long pointer causes potential memory
corruption.

Solution:
Cast and store value first, then pass the new pointer.

(cherry picked from commit 60e1862ccb)
2024-10-07 23:45:57 +00:00
zeertzjq
ee7885aa21 vim-patch:9.1.0759: screenpos() may return invalid position (#30681)
Problem:  screenpos() may return invalid position
          after switching buffers (Greg Hurrell)
Solution: reset w_leftcol if wrapping has been set
          after copying wrap option

fixes: vim/vim#15792
closes: vim/vim#15803

b065a10e24

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 9f26bdc416)
2024-10-05 23:14:33 +00:00
bfredl
82ea8a7c3f version bump 2024-10-03 10:52:41 +02:00
126 changed files with 2036 additions and 675 deletions

View File

@@ -6,7 +6,7 @@ freebsd_task:
name: FreeBSD
only_if: $BRANCH != "master"
freebsd_instance:
image_family: freebsd-14-0
image_family: freebsd-14-2
timeout_in: 30m
install_script:
- pkg install -y cmake gmake ninja unzip wget gettext python git

View File

@@ -16,7 +16,7 @@ if [[ $os == Linux ]]; then
if [[ $CC == clang ]]; then
DEFAULT_CLANG_VERSION=$(echo | clang -dM -E - | grep __clang_major | awk '{print $3}')
CLANG_VERSION=18
CLANG_VERSION=19
if ((DEFAULT_CLANG_VERSION >= CLANG_VERSION)); then
echo "Default clang version is $DEFAULT_CLANG_VERSION, which equal or larger than wanted version $CLANG_VERSION. Aborting!"
exit 1
@@ -30,10 +30,10 @@ if [[ $os == Linux ]]; then
fi
if [[ -n $TEST ]]; then
sudo apt-get install -y locales-all cpanminus attr libattr1-dev gdb fswatch
sudo apt-get install -y locales-all cpanminus attr libattr1-dev gdb fswatch xdg-utils
# Use default CC to avoid compilation problems when installing Python modules
CC=cc python3 -m pip -q install --user --upgrade pynvim
CC=cc python3 -m pip -q install --user --upgrade --break-system-packages pynvim
fi
elif [[ $os == Darwin ]]; then
brew update --quiet

View File

@@ -39,10 +39,6 @@ module.exports = async ({ github, context }) => {
reviewers.add("lewis6991");
}
if (labels.includes("documentation")) {
reviewers.add("clason");
}
if (labels.includes("editorconfig")) {
reviewers.add("gpanders");
}
@@ -53,7 +49,6 @@ module.exports = async ({ github, context }) => {
if (labels.includes("filetype")) {
reviewers.add("clason");
reviewers.add("gpanders");
}
if (labels.includes("inccommand")) {
@@ -90,10 +85,6 @@ module.exports = async ({ github, context }) => {
reviewers.add("famiu");
}
if (labels.includes("test")) {
reviewers.add("justinmk");
}
if (labels.includes("treesitter")) {
reviewers.add("bfredl");
reviewers.add("clason");
@@ -110,7 +101,6 @@ module.exports = async ({ github, context }) => {
}
if (labels.includes("vim-patch")) {
reviewers.add("seandewar");
reviewers.add("zeertzjq");
}

View File

@@ -74,7 +74,9 @@ jobs:
for d in *; do (cd "$d"; rm -rf ./autom4te.cache; make clean || true; make distclean || true); done
- name: Re-build bundled dependencies with no network access
run: unshare --map-root-user --net make deps DEPS_CMAKE_FLAGS=-DUSE_EXISTING_SRC_DIR=ON
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
unshare --map-root-user --net make deps DEPS_CMAKE_FLAGS=-DUSE_EXISTING_SRC_DIR=ON
- name: Build
run: make CMAKE_FLAGS="-D CI_BUILD=ON"

View File

@@ -32,26 +32,45 @@ ${NVIM_VERSION}
3. Extract: `tar xzvf nvim-macos-arm64.tar.gz`
4. Run `./nvim-macos-arm64/bin/nvim`
### Linux (x64)
### Linux (x86_64)
Minimum glibc version to run these releases is 2.31. People requiring releases
that work on older glibc versions can find them at
https://github.com/neovim/neovim-releases.
#### AppImage
1. Download **nvim.appimage**
2. Run `chmod u+x nvim.appimage && ./nvim.appimage`
1. Download **nvim-linux-x86_64.appimage**
2. Run `chmod u+x nvim-linux-x86_64.appimage && ./nvim-linux-x86_64.appimage`
- If your system does not have FUSE you can [extract the appimage](https://github.com/AppImage/AppImageKit/wiki/FUSE#type-2-appimage):
```
./nvim.appimage --appimage-extract
./nvim-linux-x86_64.appimage --appimage-extract
./squashfs-root/usr/bin/nvim
```
#### Tarball
1. Download **nvim-linux64.tar.gz**
2. Extract: `tar xzvf nvim-linux64.tar.gz`
3. Run `./nvim-linux64/bin/nvim`
1. Download **nvim-linux-x86_64.tar.gz**
2. Extract: `tar xzvf nvim-linux-x86_64.tar.gz`
3. Run `./nvim-linux-x86_64/bin/nvim`
### Linux (arm64)
#### AppImage
1. Download **nvim-linux-arm64.appimage**
2. Run `chmod u+x nvim-linux-arm64.appimage && ./nvim-linux-arm64.appimage`
- If your system does not have FUSE you can [extract the appimage](https://github.com/AppImage/AppImageKit/wiki/FUSE#type-2-appimage):
```
./nvim-linux-arm64.appimage --appimage-extract
./squashfs-root/usr/bin/nvim
```
#### Tarball
1. Download **nvim-linux-arm64.tar.gz**
2. Extract: `tar xzvf nvim-linux-arm64.tar.gz`
3. Run `./nvim-linux-arm64/bin/nvim`
### Other
@@ -60,11 +79,14 @@ https://github.com/neovim/neovim-releases.
## SHA256 Checksums
```
${SHA_LINUX_64_TAR}
${SHA_APP_IMAGE}
${SHA_APP_IMAGE_ZSYNC}
${SHA_MACOS_X86_64}
${SHA_APPIMAGE_ARM64}
${SHA_APPIMAGE_ARM64_ZSYNC}
${SHA_LINUX_ARM64_TAR}
${SHA_APPIMAGE_X86_64}
${SHA_APPIMAGE_X86_64_ZSYNC}
${SHA_LINUX_X86_64_TAR}
${SHA_MACOS_ARM64}
${SHA_WIN_64_ZIP}
${SHA_MACOS_X86_64}
${SHA_WIN_64_MSI}
${SHA_WIN_64_ZIP}
```

View File

@@ -39,10 +39,21 @@ jobs:
printf "appimage_tag=${APPIMAGE_TAG}\n" >> $GITHUB_OUTPUT
linux:
runs-on: ubuntu-20.04
needs: setup
strategy:
fail-fast: false
matrix:
runner: [ ubuntu-20.04, ubuntu-24.04-arm ]
include:
- runner: ubuntu-20.04
arch: x86_64
cc: gcc-10
- runner: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
env:
CC: gcc-10
CC: ${{ matrix.cc }}
LDAI_NO_APPSTREAM: 1 # skip checking (broken) AppStream metadata for issues
outputs:
version: ${{ steps.build.outputs.version }}
steps:
@@ -52,22 +63,25 @@ jobs:
fetch-depth: 0
- run: ./.github/scripts/install_deps.sh
- run: echo "CMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}" >> $GITHUB_ENV
- if: matrix.arch == 'arm64'
run: sudo apt-get update && sudo apt-get install -y libfuse2t64
- name: appimage
run: ./scripts/genappimage.sh ${{ needs.setup.outputs.appimage_tag }}
run: |
./scripts/genappimage.sh ${{ needs.setup.outputs.appimage_tag }}
- name: tar.gz
run: cpack --config build/CPackConfig.cmake -G TGZ
- uses: actions/upload-artifact@v4
with:
name: appimage
name: appimage-${{ matrix.arch }}
path: |
build/bin/nvim.appimage
build/bin/nvim.appimage.zsync
build/bin/nvim-linux-${{ matrix.arch }}.appimage
build/bin/nvim-linux-${{ matrix.arch }}.appimage.zsync
retention-days: 1
- uses: actions/upload-artifact@v4
with:
name: nvim-linux64
name: nvim-linux-${{ matrix.arch }}
path: |
build/nvim-linux64.tar.gz
build/nvim-linux-${{ matrix.arch }}.tar.gz
retention-days: 1
- name: Export version
id: build
@@ -75,15 +89,14 @@ jobs:
printf 'version<<END\n' >> $GITHUB_OUTPUT
./build/bin/nvim --version | head -n 3 >> $GITHUB_OUTPUT
printf 'END\n' >> $GITHUB_OUTPUT
macos:
needs: setup
strategy:
fail-fast: false
matrix:
runner: [ macos-12, macos-14 ]
runner: [ macos-13, macos-14 ]
include:
- runner: macos-12
- runner: macos-13
arch: x86_64
- runner: macos-14
arch: arm64
@@ -104,7 +117,6 @@ jobs:
-D CMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }} \
-D CMAKE_FIND_FRAMEWORK=NEVER
cmake --build .deps
- name: Build neovim
run: |
cmake -B build -G Ninja \
@@ -112,7 +124,6 @@ jobs:
-D ENABLE_LIBINTL=OFF \
-D CMAKE_FIND_FRAMEWORK=NEVER
cmake --build build
- name: Package
run: cpack --config build/CPackConfig.cmake
@@ -187,21 +198,36 @@ jobs:
git push origin :stable || true
# `sha256sum` outputs <sha> <path>, so we cd into each dir to drop the
# containing folder from the output.
- name: Generate Linux64 SHA256 checksums
- name: Generate Linux x86_64 SHA256 checksums
run: |
cd ./nvim-linux64
sha256sum nvim-linux64.tar.gz > nvim-linux64.tar.gz.sha256sum
echo "SHA_LINUX_64_TAR=$(cat nvim-linux64.tar.gz.sha256sum)" >> $GITHUB_ENV
- name: Generate App Image SHA256 checksums
cd ./nvim-linux-x86_64
sha256sum nvim-linux-x86_64.tar.gz > nvim-linux-x86_64.tar.gz.sha256sum
echo "SHA_LINUX_X86_64_TAR=$(cat nvim-linux-x86_64.tar.gz.sha256sum)" >> $GITHUB_ENV
- name: Generate Linux arm64 SHA256 checksums
run: |
cd ./appimage
sha256sum nvim.appimage > nvim.appimage.sha256sum
echo "SHA_APP_IMAGE=$(cat nvim.appimage.sha256sum)" >> $GITHUB_ENV
- name: Generate App Image Zsync SHA256 checksums
cd ./nvim-linux-arm64
sha256sum nvim-linux-arm64.tar.gz > nvim-linux-arm64.tar.gz.sha256sum
echo "SHA_LINUX_ARM64_TAR=$(cat nvim-linux-arm64.tar.gz.sha256sum)" >> $GITHUB_ENV
- name: Generate AppImage x64_64 SHA256 checksums
run: |
cd ./appimage
sha256sum nvim.appimage.zsync > nvim.appimage.zsync.sha256sum
echo "SHA_APP_IMAGE_ZSYNC=$(cat nvim.appimage.zsync.sha256sum)" >> $GITHUB_ENV
cd ./appimage-x86_64
sha256sum nvim-linux-x86_64.appimage > nvim-linux-x86_64.appimage.sha256sum
echo "SHA_APPIMAGE_X86_64=$(cat nvim-linux-x86_64.appimage.sha256sum)" >> $GITHUB_ENV
- name: Generate AppImage x86_64 Zsync SHA256 checksums
run: |
cd ./appimage-x86_64
sha256sum nvim-linux-x86_64.appimage.zsync > nvim-linux-x86_64.appimage.zsync.sha256sum
echo "SHA_APPIMAGE_X86_64_ZSYNC=$(cat nvim-linux-x86_64.appimage.zsync.sha256sum)" >> $GITHUB_ENV
- name: Generate AppImage x64_64 SHA256 checksums
run: |
cd ./appimage-arm64
sha256sum nvim-linux-arm64.appimage > nvim-linux-arm64.appimage.sha256sum
echo "SHA_APPIMAGE_ARM64=$(cat nvim-linux-arm64.appimage.sha256sum)" >> $GITHUB_ENV
- name: Generate AppImage arm64 Zsync SHA256 checksums
run: |
cd ./appimage-arm64
sha256sum nvim-linux-arm64.appimage.zsync > nvim-linux-arm64.appimage.zsync.sha256sum
echo "SHA_APPIMAGE_ARM64_ZSYNC=$(cat nvim-linux-arm64.appimage.zsync.sha256sum)" >> $GITHUB_ENV
- name: Generate macos x86_64 SHA256 checksums
run: |
cd ./nvim-macos-x86_64
@@ -226,6 +252,6 @@ jobs:
run: |
envsubst < "$GITHUB_WORKSPACE/.github/workflows/notes.md" > "$RUNNER_TEMP/notes.md"
if [ "$TAG_NAME" != "nightly" ]; then
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux64/* appimage/* nvim-win64/*
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/* appimage-x86_64/* appimage-arm64/* nvim-win64/*
fi
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux64/* appimage/* nvim-win64/*
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/* appimage-x86_64/* appimage-arm64/* nvim-win64/*

View File

@@ -28,7 +28,7 @@ env:
jobs:
lint:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
timeout-minutes: 10
env:
CC: clang
@@ -78,7 +78,7 @@ jobs:
run: cmake --build build --target lintc-uncrustify
clang-analyzer:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
timeout-minutes: 20
env:
CC: clang
@@ -104,12 +104,13 @@ jobs:
# or if github introduces a wildcard for required checks in the future.
build:
[
{ runner: ubuntu-22.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON },
{ runner: ubuntu-22.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON },
{ runner: ubuntu-22.04, os: ubuntu, cc: gcc },
{ runner: macos-12, os: macos, flavor: 12, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: macos-14, os: macos, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: ubuntu-22.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: 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: release, cc: gcc, flags: -D CMAKE_BUILD_TYPE=Release },
{ 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-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 },
]
test: [unittest, functionaltest, oldtest]
exclude:
@@ -145,6 +146,10 @@ jobs:
sudo cpanm -n Neovim::Ext || cat "$HOME/.cpanm/build.log"
perl -W -e 'use Neovim::Ext; print $Neovim::Ext::VERSION'
- name: Remove .git directory
if: ${{ matrix.build.os == 'ubuntu' }}
run: cmake -E rm -rf -- .git
- name: Build third-party deps
run: |
cmake -S cmake.deps --preset ci -D CMAKE_BUILD_TYPE=Debug ${{ matrix.build.deps_flags }}
@@ -155,9 +160,15 @@ jobs:
cmake --preset ci -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX ${{ matrix.build.flags }}
cmake --build build
- name: ${{ matrix.test }}
- if: ${{ matrix.test == 'oldtest' }}
name: ${{ matrix.test }}
timeout-minutes: 20
run: make ${{ matrix.test }}
run: make -C test/old/testdir NVIM_PRG=$(realpath build)/bin/nvim
- if: ${{ matrix.test != 'oldtest' }}
name: ${{ matrix.test }}
timeout-minutes: 20
run: cmake --build build --target ${{ matrix.test }}
- name: Install
run: |
@@ -193,42 +204,8 @@ jobs:
windows:
uses: ./.github/workflows/test_windows.yml
# This job tests the following things:
# - Check if Release, MinSizeRel and RelWithDebInfo compiles correctly.
# - Test the above build types with the GCC compiler specifically.
# Empirically the difference in warning levels between GCC and other
# compilers is particularly big.
# - Test if the build works with multi-config generators. We mostly use
# single-config generators so it's nice to have a small sanity check for
# multi-config.
build-types:
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CC: gcc
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Build third-party deps
run: |
cmake -S cmake.deps -B .deps -G "Ninja Multi-Config"
cmake --build .deps
- name: Configure
run: cmake --preset ci -G "Ninja Multi-Config"
- name: Release
run: cmake --build build --config Release
- name: RelWithDebInfo
run: cmake --build build --config RelWithDebInfo
- name: MinSizeRel
run: cmake --build build --config MinSizeRel
with-external-deps:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
timeout-minutes: 10
env:
CC: gcc

View File

@@ -31,6 +31,13 @@ jobs:
cmake --preset ci -D CMAKE_BUILD_TYPE='RelWithDebInfo' ${{ inputs.build_flags }}
cmake --build build
# FIXME(dundargoc): this workaround is needed as the python3 provider
# tests suddenly started to become extremely flaky, and this removes the
# flakiness for some reason.
- uses: actions/setup-python@v4
with:
python-version: '3.13'
- name: Install test deps
run: |
$PSNativeCommandArgumentPassing = 'Legacy'

View File

@@ -12,7 +12,7 @@
- To build on Windows, see the [Building on Windows](#building-on-windows) section. _MSVC (Visual Studio) is recommended._
4. `sudo make install`
- Default install location is `/usr/local`
- On Debian/Ubuntu, instead of installing files directly with `sudo make install`, you can run `cd build && cpack -G DEB && sudo dpkg -i nvim-linux64.deb` to build DEB-package and install it. This should help ensuring the clean removal of installed files.
- On Debian/Ubuntu, instead of `sudo make install`, you can try `cd build && cpack -G DEB && sudo dpkg -i nvim-linux-<arch>.deb` (with `<arch>` either `x86_64` or `arm64`) to build DEB-package and install it. This helps ensure clean removal of installed files. Note: This is an unsupported, "best-effort" feature of the Nvim build.
**Notes**:
- From the repository's root directory, running `make` will download and build all the needed dependencies and put the `nvim` executable in `build/bin`.

View File

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

View File

@@ -15,9 +15,10 @@ Install from download
Downloads are available on the [Releases](https://github.com/neovim/neovim/releases) page.
* Latest [stable release](https://github.com/neovim/neovim/releases/latest)
* [macOS x86](https://github.com/neovim/neovim/releases/latest/download/nvim-macos-x86_64.tar.gz)
* [macOS arm](https://github.com/neovim/neovim/releases/latest/download/nvim-macos-arm64.tar.gz)
* [Linux](https://github.com/neovim/neovim/releases/latest/download/nvim-linux64.tar.gz)
* [macOS x86_64](https://github.com/neovim/neovim/releases/latest/download/nvim-macos-x86_64.tar.gz)
* [macOS arm64](https://github.com/neovim/neovim/releases/latest/download/nvim-macos-arm64.tar.gz)
* [Linux x86_64](https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz)
* [Linux arm64](https://github.com/neovim/neovim/releases/latest/download/nvim-linux-arm64.tar.gz)
* [Windows](https://github.com/neovim/neovim/releases/latest/download/nvim-win64.msi)
* Latest [development prerelease](https://github.com/neovim/neovim/releases/nightly)
@@ -118,24 +119,24 @@ After this step add this to `~/.bashrc`:
### AppImage ("universal" Linux package)
The [Releases](https://github.com/neovim/neovim/releases) page provides an [AppImage](https://appimage.org) that runs on most Linux systems. No installation is needed, just download `nvim.appimage` and run it. (It might not work if your Linux distribution is more than 4 years old.)
The [Releases](https://github.com/neovim/neovim/releases) page provides an [AppImage](https://appimage.org) that runs on most Linux systems. No installation is needed, just download `nvim-linux-x86_64.appimage` and run it. (It might not work if your Linux distribution is more than 4 years old.) The following instructions assume an `x86_64` architecture; on ARM Linux replace with `arm64`.
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim.appimage
chmod u+x nvim.appimage
./nvim.appimage
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-86_64.appimage
chmod u+x nvim-linux-x86_64.appimage
./nvim-linux-x86_64.appimage
To expose nvim globally:
mkdir -p /opt/nvim
mv nvim.appimage /opt/nvim/nvim
mv nvim-linux-x86_64.appimage /opt/nvim/nvim
And the following line to `~/.bashrc`:
export PATH="$PATH:/opt/nvim/"
If the `./nvim.appimage` command fails, try:
If the `./nvim-linux-x86_64.appimage` command fails, try:
```sh
./nvim.appimage --appimage-extract
./nvim-linux-x86_64.appimage --appimage-extract
./squashfs-root/AppRun --version
# Optional: exposing nvim globally.

View File

@@ -211,12 +211,12 @@ https://github.com/neovim/neovim-backup
* For special-purpose jobs where the runner version doesn't really matter,
prefer `-latest` tags so we don't need to manually bump the versions. An
example of a special-purpose workflow is `labeler_pr.yml`.
* For our testing job `test.yml`, prefer to use the latest stable (i.e.
non-beta) version explicitly. Avoid using the `-latest` tags here as it
makes it difficult to determine from an unrelated PR if a failure is due
to the PR itself or due to GitHub bumping the `-latest` tag without our
knowledge. There's also a high risk that automatically bumping the CI
versions will fail due to manual work being required from experience.
* For our testing job `test.yml`, prefer to use the latest version
explicitly. Avoid using the `-latest` tags here as it makes it difficult
to determine from an unrelated PR if a failure is due to the PR itself or
due to GitHub bumping the `-latest` tag without our knowledge. There's
also a high risk that automatically bumping the CI versions will fail due
to manual work being required from experience.
* For our release job, which is `release.yml`, prefer to use the oldest
stable (i.e. non-deprecated) versions available. The reason is that we're
trying to produce images that work in the broadest number of environments,

View File

@@ -15,6 +15,7 @@ else
RM := rm -rf
CMAKE := $(shell (command -v cmake3 || command -v cmake || echo cmake))
CMAKE_GENERATOR ?= "$(shell (command -v ninja > /dev/null 2>&1 && echo "Ninja") || echo "Unix Makefiles")"
GENERATOR_CMD ?= "$(shell (command -v ninja > /dev/null 2>&1 && echo "ninja") || echo "make")"
define rmdir
rm -rf $1
endef
@@ -157,7 +158,7 @@ distclean:
$(MAKE) clean
install: checkprefix nvim
$(CMAKE) --install build
$(GENERATOR_CMD) -C build install
appimage:
bash scripts/genappimage.sh

View File

@@ -15,15 +15,20 @@ string(REPLACE "#undef HAVE_LONG_LONG_INT" "#define HAVE_LONG_LONG_INT 1" CONFIG
string(REPLACE "#undef HAVE_ICONV_H" "#define HAVE_ICONV_H 1" CONFIG_CONTENT ${CONFIG_CONTENT})
string(REPLACE "#undef HAVE_ICONV" "#define HAVE_ICONV 1" CONFIG_CONTENT ${CONFIG_CONTENT})
string(REPLACE "#undef ICONV_CONST" "#define ICONV_CONST const" CONFIG_CONTENT ${CONFIG_CONTENT})
string(REPLACE "#undef uintmax_t" "
#if _WIN64
# define intmax_t long long
# define uintmax_t unsigned long long
#elif _WIN32
# define intmax_t long
# define uintmax_t unsigned long
#endif"
CONFIG_CONTENT ${CONFIG_CONTENT})
if(MSVC)
string(REPLACE "#undef HAVE_STDINT_H_WITH_UINTMAX" "#define HAVE_STDINT_H_WITH_UINTMAX 1" CONFIG_CONTENT ${CONFIG_CONTENT})
string(REPLACE "#undef HAVE_STDINT_H" "#define HAVE_STDINT_H 1" CONFIG_CONTENT ${CONFIG_CONTENT})
else()
string(REPLACE "#undef uintmax_t" "
#if _WIN64
# define intmax_t long long
# define uintmax_t unsigned long long
#elif _WIN32
# define intmax_t long
# define uintmax_t unsigned long
#endif"
CONFIG_CONTENT ${CONFIG_CONTENT})
endif()
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gettext-runtime/config.h ${CONFIG_CONTENT})
set(HAVE_NEWLOCALE 0)

View File

@@ -1,3 +1,7 @@
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(CMAKE_SYSTEM_PROCESSOR arm64)
endif()
set(CPACK_PACKAGE_NAME "Neovim")
set(CPACK_PACKAGE_VENDOR "neovim.io")
set(CPACK_PACKAGE_FILE_NAME "nvim")
@@ -49,7 +53,7 @@ elseif(APPLE)
set(CPACK_GENERATOR TGZ)
set(CPACK_PACKAGE_ICON ${CMAKE_CURRENT_LIST_DIR}/neovim.icns)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CPACK_PACKAGE_FILE_NAME "nvim-linux64")
set(CPACK_PACKAGE_FILE_NAME "nvim-linux-${CMAKE_SYSTEM_PROCESSOR}")
set(CPACK_GENERATOR TGZ DEB)
set(CPACK_DEBIAN_PACKAGE_NAME "Neovim") # required
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Neovim.io") # required

View File

@@ -61,6 +61,7 @@ function(add_glob_target)
if(NOT ARG_COMMAND)
add_custom_target(${ARG_TARGET})
add_custom_command(TARGET ${ARG_TARGET}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET} SKIP: ${ARG_COMMAND} not found")
return()
endif()

View File

@@ -3496,9 +3496,9 @@ nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()*
• event: (string) name of the triggered event
|autocmd-events|
• group: (number|nil) autocommand group id, if any
match: (string) expanded value of <amatch>
buf: (number) expanded value of <abuf>
file: (string) expanded value of <afile>
file: (string) <afile> (not expanded to a full path)
match: (string) <amatch> (expanded to a full path)
buf: (number) <abuf>
• data: (any) arbitrary data passed from
|nvim_exec_autocmds()| *event-data*
• command (string) optional: Vim command to execute on event.

View File

@@ -1472,7 +1472,7 @@ get_namespace({client_id}, {is_pull})
client. Defaults to push
*vim.lsp.diagnostic.on_diagnostic()*
on_diagnostic({_}, {result}, {ctx}, {config})
on_diagnostic({error}, {result}, {ctx}, {config})
|lsp-handler| for the method "textDocument/diagnostic"
See |vim.diagnostic.config()| for configuration options. Handler-specific
@@ -1497,6 +1497,7 @@ on_diagnostic({_}, {result}, {ctx}, {config})
<
Parameters: ~
• {error} (`lsp.ResponseError?`)
• {result} (`lsp.DocumentDiagnosticReport`)
• {ctx} (`lsp.HandlerContext`)
• {config} (`vim.diagnostic.Opts`) Configuration table (see

View File

@@ -1426,12 +1426,9 @@ Option:remove({value}) *vim.opt:remove()*
• {value} (`string`) Value to remove
vim.bo[{bufnr}] *vim.bo*
Get or set buffer-scoped |options| for the buffer with number {bufnr}. If
{bufnr} is omitted then the current buffer is used. Invalid {bufnr} or key
is an error.
Note: this is equivalent to `:setlocal` for |global-local| options and
`:set` otherwise.
Get or set buffer-scoped |options| for the buffer with number {bufnr}.
Like `:setlocal`. If {bufnr} is omitted then the current buffer is used.
Invalid {bufnr} or key is an error.
Example: >lua
local bufnr = vim.api.nvim_get_current_buf()
@@ -1646,12 +1643,15 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()*
• {fn} will not be cleared by |nvim_buf_clear_namespace()|
Parameters: ~
• {fn} (`fun(key: string, typed: string)?`) Function invoked on
every key press. |i_CTRL-V| {key} is the key after mappings
have been applied, and {typed} is the key(s) before mappings
are applied, which may be empty if {key} is produced by
non-typed keys. When {fn} is nil and {ns_id} is specified,
the callback associated with namespace {ns_id} is removed.
• {fn} (`fun(key: string, typed: string)?`) Function invoked for
every input key, after mappings have been applied but before
further processing. Arguments {key} and {typed} are raw
keycodes, where {key} is the key after mappings are applied,
and {typed} is the key(s) before mappings are applied.
{typed} may be empty if {key} is produced by non-typed key(s)
or by the same typed key(s) that produced a previous {key}.
When {fn} is `nil` and {ns_id} is specified, the callback
associated with namespace {ns_id} is removed.
• {ns_id} (`integer?`) Namespace ID. If nil or 0, generates and returns
a new |nvim_create_namespace()| id.
@@ -1659,6 +1659,9 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()*
(`integer`) Namespace id associated with {fn}. Or count of all
callbacks if on_key() is called without arguments.
See also: ~
• |keytrans()|
vim.paste({lines}, {phase}) *vim.paste()*
Paste handler, invoked by |nvim_paste()| when a conforming UI (such as the
|TUI|) pastes text into the editor.

View File

@@ -354,11 +354,11 @@ gg Goto line [count], default first line, on the first
See also 'startofline' option.
:[range]go[to] [count] *:go* *:goto* *go*
[count]go Go to [count] byte in the buffer. Default [count] is
one, start of the file. When giving [range], the
last number in it used as the byte count. End-of-line
characters are counted depending on the current
'fileformat' setting.
[count]go Go to [count] byte in the buffer. |exclusive| motion.
Default [count] is one, start of the file. When
giving [range], the last number in it used as the byte
count. End-of-line characters are counted depending
on the current 'fileformat' setting.
Also see the |line2byte()| function, and the 'o'
option in 'statusline'.

View File

@@ -12,11 +12,12 @@ Support *support*
Supported platforms *supported-platforms*
`System` `Tier` `Versions` `Tested versions`
Linux 1 >= 2.6.32, glibc >= 2.12 Ubuntu 22.04
macOS (Intel) 1 >= 11 macOS 12
macOS (M1) 2 >= 11 macOS 14
Linux (x86_64) 1 >= 2.6.32, glibc >= 2.12 Ubuntu 24.04
Linux (arm64) 1 >= 2.6.32, glibc >= 2.12 Ubuntu 24.04
macOS (x86_64) 1 >= 11 macOS 13
macOS (arm64) 1 >= 11 macOS 15
Windows 64-bit 1 >= Windows 10 Version 1809 Windows Server 2022
FreeBSD 1 >= 10 FreeBSD 13
FreeBSD 1 >= 10 FreeBSD 14
OpenBSD 2 >= 7
MinGW 2 MinGW-w64
Windows 64-bit 3 < Windows 10 Version 1809
@@ -28,10 +29,10 @@ your Windows version, run the "winver" command and look for "Version xxxx"
Support types ~
* Tier 1: Officially supported and tested with CI. Any contributed patch
MUST NOT break such systems.
MUST NOT break support for such platforms.
* Tier 2: Officially supported, but not necessarily tested with CI. These
systems are maintained to the best of our ability, without being a top
* Tier 2: Officially supported, but not necessarily tested with CI. Support
for these platforms are maintained by best effort, without being a top
priority.
* Tier 3: Not tested and no guarantees, and not all features may work.
@@ -47,7 +48,8 @@ Common
Some common notes when adding support for new platforms:
Cmake is the only supported build system. The platform must be buildable with cmake.
CMake is the only supported build system. Nvim must be buildable on the
platform with CMake.
All functionality related to the new platform must be implemented in its own
file inside `src/nvim/os` unless it's already done in a common file, in which

View File

@@ -13,8 +13,8 @@ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile', 'StdinReadPost' }, {
end
local ft, on_detect = vim.filetype.match({
-- The unexpanded file name is needed here. #27914
-- Neither args.file nor args.match are guaranteed to be unexpanded.
filename = vim.fn.bufname(args.buf),
-- However, bufname() can't be used, as it doesn't work with :doautocmd. #31306
filename = args.file,
buf = args.buf,
})
if not ft then

View File

@@ -49,10 +49,10 @@ do
vim.keymap.set('x', '*', function()
return _visual_search('/')
end, { desc = ':help v_star-default', expr = true, silent = true })
end, { desc = ':help v_star-default', expr = true, replace_keycodes = false })
vim.keymap.set('x', '#', function()
return _visual_search('?')
end, { desc = ':help v_#-default', expr = true, silent = true })
end, { desc = ':help v_#-default', expr = true, replace_keycodes = false })
end
--- Map Y to y$. This mimics the behavior of D and C. See |Y-default|

View File

@@ -656,15 +656,18 @@ local on_key_cbs = {} --- @type table<integer,function>
---@note {fn} will be removed on error.
---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
---
---@param fn fun(key: string, typed: string)?
--- Function invoked on every key press. |i_CTRL-V|
--- {key} is the key after mappings have been applied, and
--- {typed} is the key(s) before mappings are applied, which
--- may be empty if {key} is produced by non-typed keys.
--- When {fn} is nil and {ns_id} is specified, the callback
--- associated with namespace {ns_id} is removed.
---@param fn fun(key: string, typed: string)? Function invoked for every input key,
--- after mappings have been applied but before further processing. Arguments
--- {key} and {typed} are raw keycodes, where {key} is the key after mappings
--- are applied, and {typed} is the key(s) before mappings are applied.
--- {typed} may be empty if {key} is produced by non-typed key(s) or by the
--- same typed key(s) that produced a previous {key}.
--- When {fn} is `nil` and {ns_id} is specified, the callback associated with
--- namespace {ns_id} is removed.
---@param ns_id integer? Namespace ID. If nil or 0, generates and returns a
--- new |nvim_create_namespace()| id.
--- new |nvim_create_namespace()| id.
---
---@see |keytrans()|
---
---@return integer Namespace id associated with {fn}. Or count of all callbacks
---if on_key() is called without arguments.

View File

@@ -169,7 +169,7 @@ function vim.show_pos(bufnr, row, col, filter)
if data.hl_group ~= data.hl_group_link then
append('links to ', 'MoreMsg')
append(data.hl_group_link, data.hl_group_link)
append(' ')
append(' ')
end
if comment then
append(comment, 'Comment')
@@ -182,7 +182,14 @@ function vim.show_pos(bufnr, row, col, filter)
append('Treesitter', 'Title')
nl()
for _, capture in ipairs(items.treesitter) do
item(capture, capture.lang)
item(
capture,
string.format(
'priority: %d language: %s',
capture.metadata.priority or vim.highlight.priorities.treesitter,
capture.lang
)
)
end
nl()
end

View File

@@ -956,9 +956,9 @@ function vim.api.nvim_create_augroup(name, opts) end
--- • event: (string) name of the triggered event
--- `autocmd-events`
--- • group: (number|nil) autocommand group id, if any
--- • match: (string) expanded value of <amatch>
--- • buf: (number) expanded value of <abuf>
--- • file: (string) expanded value of <afile>
--- • file: (string) <afile> (not expanded to a full path)
--- • match: (string) <amatch> (expanded to a full path)
--- • buf: (number) <abuf>
--- • data: (any) arbitrary data passed from
--- `nvim_exec_autocmds()` *event-data*
--- • command (string) optional: Vim command to execute on event.

View File

@@ -276,11 +276,9 @@ vim.go = setmetatable({}, {
})
--- Get or set buffer-scoped |options| for the buffer with number {bufnr}.
--- If {bufnr} is omitted then the current buffer is used.
--- Like `:setlocal`. If {bufnr} is omitted then the current buffer is used.
--- Invalid {bufnr} or key is an error.
---
--- Note: this is equivalent to `:setlocal` for |global-local| options and `:set` otherwise.
---
--- Example:
---
--- ```lua

View File

@@ -88,7 +88,8 @@ function SystemObj:_timeout(signal)
self:kill(signal or SIG.TERM)
end
local MAX_TIMEOUT = 2 ^ 31
-- Use max 32-bit signed int value to avoid overflow on 32-bit systems. #31633
local MAX_TIMEOUT = 2 ^ 31 - 1
--- @param timeout? integer
--- @return vim.SystemCompleted

View File

@@ -13,7 +13,7 @@ local function filepath_to_healthcheck(path)
func = 'health#' .. name .. '#check'
filetype = 'v'
else
local subpath = path:gsub('.*lua/', '')
local subpath = path:gsub('.*/lua/', '')
if vim.fs.basename(subpath) == 'health.lua' then
-- */health.lua
name = assert(vim.fs.dirname(subpath))

View File

@@ -315,11 +315,19 @@ end
--- )
--- ```
---
---@param _ lsp.ResponseError?
---@param error lsp.ResponseError?
---@param result lsp.DocumentDiagnosticReport
---@param ctx lsp.HandlerContext
---@param config vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|).
function M.on_diagnostic(_, result, ctx, config)
function M.on_diagnostic(error, result, ctx, config)
if error ~= nil and error.code == protocol.ErrorCodes.ServerCancelled then
if error.data == nil or error.data.retriggerRequest ~= false then
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
client.request(ctx.method, ctx.params)
end
return
end
if result == nil or result.kind == 'unchanged' then
return
end

View File

@@ -716,7 +716,8 @@ for k, fn in pairs(M) do
})
end
if err then
-- ServerCancelled errors should be propagated to the request handler
if err and err.code ~= protocol.ErrorCodes.ServerCancelled then
-- LSP spec:
-- interface ResponseError:
-- code: integer;

View File

@@ -166,6 +166,7 @@ local constants = {
-- Defined by the protocol.
RequestCancelled = -32800,
ContentModified = -32801,
ServerCancelled = -32802,
},
-- Describes the content type that a client supports in various

View File

@@ -343,6 +343,10 @@ function STHighlighter:process_response(response, client, version)
return
end
if not api.nvim_buf_is_valid(self.bufnr) then
return
end
-- if we have a response to a delta request, update the state of our tokens
-- appropriately. if it's a full response, just use that
local tokens ---@type integer[]
@@ -382,8 +386,10 @@ function STHighlighter:process_response(response, client, version)
current_result.highlights = highlights
current_result.namespace_cleared = false
-- redraw all windows displaying buffer
api.nvim__redraw({ buf = self.bufnr, valid = true })
-- redraw all windows displaying buffer (if still valid)
if api.nvim_buf_is_valid(self.bufnr) then
api.nvim__redraw({ buf = self.bufnr, valid = true })
end
end
--- on_win handler for the decoration provider (see |nvim_set_decoration_provider|)

View File

@@ -212,7 +212,8 @@ end
---@param lastline integer
---@param new_lastline integer
---@param offset_encoding string
---@return vim.lsp.sync.Range, vim.lsp.sync.Range
---@return vim.lsp.sync.Range prev_end_range
---@return vim.lsp.sync.Range curr_end_range
local function compute_end_range(
prev_lines,
curr_lines,
@@ -222,6 +223,16 @@ local function compute_end_range(
new_lastline,
offset_encoding
)
-- A special case for the following `firstline == new_lastline` case where lines are deleted.
-- Even if the buffer has become empty, nvim behaves as if it has an empty line with eol.
if #curr_lines == 1 and curr_lines[1] == '' then
local prev_line = prev_lines[lastline - 1]
return {
line_idx = lastline - 1,
byte_idx = #prev_line + 1,
char_idx = compute_line_length(prev_line, offset_encoding) + 1,
}, { line_idx = 1, byte_idx = 1, char_idx = 1 }
end
-- If firstline == new_lastline, the first change occurred on a line that was deleted.
-- In this case, the last_byte...
if firstline == new_lastline then

View File

@@ -155,25 +155,24 @@ end
---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
---@return integer byte (utf-8) index of `encoding` index `index` in `line`
function M._str_byteindex_enc(line, index, encoding)
local len = #line
if index > len then
-- LSP spec: if character > line length, default to the line length.
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
return len
end
-- LSP spec: if character > line length, default to the line length.
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
local len8 = #line
if not encoding then
encoding = 'utf-16'
end
if encoding == 'utf-8' then
if index then
if index and index <= len8 then
return index
else
return len
return len8
end
elseif encoding == 'utf-16' then
return vim.str_byteindex(line, index, true)
end
local len32, len16 = vim.str_utfindex(line)
if encoding == 'utf-16' then
return index <= len16 and vim.str_byteindex(line, index, true) or len8
elseif encoding == 'utf-32' then
return vim.str_byteindex(line, index)
return index <= len32 and vim.str_byteindex(line, index) or len8
else
error('Invalid encoding: ' .. vim.inspect(encoding))
end
@@ -1627,7 +1626,7 @@ function M._make_floating_popup_size(contents, opts)
if vim.tbl_isempty(line_widths) then
for _, line in ipairs(contents) do
local line_width = vim.fn.strdisplaywidth(line:gsub('%z', '\n'))
height = height + math.ceil(line_width / wrap_at)
height = height + math.max(1, math.ceil(line_width / wrap_at))
end
else
for i = 1, #contents do
@@ -2307,6 +2306,11 @@ function M._refresh(method, opts)
local first = vim.fn.line('w0', window)
local last = vim.fn.line('w$', window)
for _, client in ipairs(clients) do
for rid, req in pairs(client.requests) do
if req.method == method and req.type == 'pending' and req.bufnr == bufnr then
client.cancel_request(rid)
end
end
client.request(method, {
textDocument = textDocument,
range = make_line_range_params(bufnr, first - 1, last - 1, client.offset_encoding),

View File

@@ -87,7 +87,7 @@ end
---@param srow integer
---@param erow integer 0-indexed, exclusive
function FoldInfo:add_range(srow, erow)
list_insert(self.levels, srow + 1, erow, '=')
list_insert(self.levels, srow + 1, erow, -1)
list_insert(self.levels0, srow + 1, erow, -1)
end
@@ -268,6 +268,15 @@ end
---@package
function FoldInfo:do_foldupdate(bufnr)
-- InsertLeave is not executed when <C-C> is used for exiting the insert mode, leaving
-- do_foldupdate untouched. If another execution of foldupdate consumes foldupdate_range, the
-- InsertLeave do_foldupdate gets nil foldupdate_range. In that case, skip the update. This is
-- correct because the update that consumed the range must have incorporated the range that
-- InsertLeave meant to update.
if not self.foldupdate_range then
return
end
local srow, erow = self.foldupdate_range[1], self.foldupdate_range[2]
self.foldupdate_range = nil
for _, win in ipairs(vim.fn.win_findbuf(bufnr)) do
@@ -421,9 +430,15 @@ api.nvim_create_autocmd('OptionSet', {
pattern = { 'foldminlines', 'foldnestmax' },
desc = 'Refresh treesitter folds',
callback = function()
for bufnr, _ in pairs(foldinfos) do
local buf = api.nvim_get_current_buf()
local bufs = vim.v.option_type == 'global' and vim.tbl_keys(foldinfos)
or foldinfos[buf] and { buf }
or {}
for _, bufnr in ipairs(bufs) do
foldinfos[bufnr] = FoldInfo.new()
compute_folds_levels(bufnr, foldinfos[bufnr])
api.nvim_buf_call(bufnr, function()
compute_folds_levels(bufnr, foldinfos[bufnr])
end)
foldinfos[bufnr]:foldupdate(bufnr, 0, api.nvim_buf_line_count(bufnr))
end
end,

View File

@@ -240,7 +240,12 @@ end
---@return vim.treesitter.highlighter.Query
function TSHighlighter:get_query(lang)
if not self._queries[lang] then
self._queries[lang] = TSHighlighterQuery.new(lang)
local success, result = pcall(TSHighlighterQuery.new, lang)
if not success then
self:destroy()
error(result)
end
self._queries[lang] = result
end
return self._queries[lang]

View File

@@ -15,7 +15,7 @@ local PATTERNS = {
rfc2396 = "^A-Za-z0-9%-_.!~*'()",
-- RFC 2732
-- https://tools.ietf.org/html/rfc2732
rfc2732 = "^A-Za-z0-9%-_.!~*'()[]",
rfc2732 = "^A-Za-z0-9%-_.!~*'()%[%]",
-- RFC 3986
-- https://tools.ietf.org/html/rfc3986#section-2.2
rfc3986 = "^A-Za-z0-9%-._~!$&'()*+,;=:@/",

View File

@@ -26,6 +26,8 @@
</screenshots>
<releases>
<release date="2025-01-29" version="0.10.4"/>
<release date="2024-12-21" version="0.10.3"/>
<release date="2024-10-03" version="0.10.2"/>
<release date="2024-07-24" version="0.10.1"/>
<release date="2024-05-16" version="0.10.0"/>

View File

@@ -218,6 +218,7 @@ function matchit#Match_wrapper(word, forward, mode) range
let view = winsaveview()
call cursor(0, curcol + 1)
if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
\ || skip =~ 'v:lua.vim.treesitter' && !exists('b:ts_highlight')
let skip = "0"
else
execute "if " .. skip .. "| let skip = '0' | endif"
@@ -672,6 +673,7 @@ fun! matchit#MultiMatch(spflag, mode)
let middlepat = substitute(middlepat, ',', '\\|', 'g')
if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
\ || skip =~ 'v:lua.vim.treesitter' && !exists('b:ts_highlight')
let skip = '0'
else
try
@@ -754,10 +756,16 @@ endfun
" S:foo becomes (current syntax item) !~ foo
" r:foo becomes (line before cursor) =~ foo
" R:foo becomes (line before cursor) !~ foo
" t:foo becomes (current treesitter captures) =~ foo
" T:foo becomes (current treesitter captures) !~ foo
fun! s:ParseSkip(str)
let skip = a:str
if skip[1] == ":"
if skip[0] ==# "s"
if skip[0] ==# "t" || skip[0] ==# "s" && &syntax != 'on' && exists("b:ts_highlight")
let skip = "match(v:lua.vim.treesitter.get_captures_at_cursor(), '" .. strpart(skip,2) .. "') != -1"
elseif skip[0] ==# "T" || skip[0] ==# "S" && &syntax != 'on' && exists("b:ts_highlight")
let skip = "match(v:lua.vim.treesitter.get_captures_at_cursor(), '" .. strpart(skip,2) .. "') == -1"
elseif skip[0] ==# "s"
let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" ..
\ strpart(skip,2) .. "'"
elseif skip[0] ==# "S"

View File

@@ -237,6 +237,8 @@ supported by matchit.vim:
S:foo becomes (current syntax item) !~ foo
r:foo becomes (line before cursor) =~ foo
R:foo becomes (line before cursor) !~ foo
t:foo becomes (current treesitter captures) =~ foo
T:foo becomes (current treesitter captures) !~ foo
(The "s" is meant to suggest "syntax", and the "r" is meant to suggest
"regular expression".)

View File

@@ -106,6 +106,10 @@ func s:Highlight_Matching_Pair()
if !has("syntax") || !exists("g:syntax_on")
let s_skip = "0"
elseif exists("b:ts_highlight") && &syntax != 'on'
let s_skip = "match(v:lua.vim.treesitter.get_captures_at_cursor(), '"
\ .. 'string\|character\|singlequote\|escape\|symbol\|comment'
\ .. "') != -1"
else
" Build an expression that detects whether the current cursor position is
" in certain syntax types (string, comment, etc.), for use as

4
runtime/windows_icon.rc Normal file
View File

@@ -0,0 +1,4 @@
// NOTE: this resource file *must* be in the same folder as the icon.
// Otherwise, absolute paths would need to be used.
// see https://learn.microsoft.com/en-us/windows/win32/menurc/icon-resource
NEOVIM_ICON ICON "neovim.ico"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/bash -e
########################################################################
# Package the binaries built as an AppImage
@@ -11,6 +11,7 @@ if [ -z "$ARCH" ]; then
ARCH="$(arch)"
export ARCH
fi
ARCH_ORIGINAL=$ARCH
TAG=$1
@@ -40,16 +41,16 @@ export VERSION
cd "$APP_BUILD_DIR" || exit
# Only downloads linuxdeploy if the remote file is different from local
if [ -e "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage ]; then
curl -Lo "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage \
-z "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage \
https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
if [ -e "$APP_BUILD_DIR"/linuxdeploy-"$ARCH".AppImage ]; then
curl -Lo "$APP_BUILD_DIR"/linuxdeploy-"$ARCH".AppImage \
-z "$APP_BUILD_DIR"/linuxdeploy-"$ARCH".AppImage \
https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-"$ARCH".AppImage
else
curl -Lo "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage \
https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
curl -Lo "$APP_BUILD_DIR"/linuxdeploy-"$ARCH".AppImage \
https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-"$ARCH".AppImage
fi
chmod +x "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage
chmod +x "$APP_BUILD_DIR"/linuxdeploy-"$ARCH".AppImage
# metainfo is not packaged automatically by linuxdeploy
mkdir -p "$APP_DIR/usr/share/metainfo/"
@@ -75,24 +76,30 @@ chmod 755 AppRun
cd "$APP_BUILD_DIR" || exit # Get out of AppImage directory.
# We want to be consistent, so always use arm64 over aarch64
if [[ "$ARCH" == 'aarch64' ]]; then
ARCH="arm64"
export ARCH
fi
# Set the name of the file generated by appimage
export OUTPUT=nvim.appimage
export OUTPUT=nvim-linux-"$ARCH".appimage
# If it's a release generate the zsync file
if [ -n "$TAG" ]; then
export UPDATE_INFORMATION="gh-releases-zsync|neovim|neovim|$TAG|nvim.appimage.zsync"
export UPDATE_INFORMATION="gh-releases-zsync|neovim|neovim|$TAG|nvim-linux-$ARCH.appimage.zsync"
fi
# Generate AppImage.
# - Expects: $ARCH, $APP, $VERSION env vars
# - Expects: ./$APP.AppDir/ directory
# - Produces: ./nvim.appimage
./linuxdeploy-x86_64.AppImage --appdir $APP.AppDir -d "$ROOT_DIR"/runtime/nvim.desktop -i \
# - Produces: ./nvim-linux-$ARCH.appimage
./linuxdeploy-"$ARCH_ORIGINAL".AppImage --appdir $APP.AppDir -d "$ROOT_DIR"/runtime/nvim.desktop -i \
"$ROOT_DIR/runtime/nvim.png" --output appimage
# Moving the final executable to a different folder so it isn't in the
# way for a subsequent build.
mv "$ROOT_DIR"/build/nvim.appimage* "$ROOT_DIR"/build/bin
mv "$ROOT_DIR"/build/nvim-linux-"$ARCH".appimage* "$ROOT_DIR"/build/bin
echo 'genappimage.sh: finished'

View File

@@ -14,10 +14,6 @@ typedef mpack_sint32_t mpack_sintmax_t;
typedef mpack_uint32_t mpack_uintmax_t;
#endif
#ifndef bool
# define bool unsigned
#endif
MPACK_API mpack_token_t mpack_pack_nil(void) FUNUSED FPURE;
MPACK_API mpack_token_t mpack_pack_boolean(unsigned v) FUNUSED FPURE;
MPACK_API mpack_token_t mpack_pack_uint(mpack_uintmax_t v) FUNUSED FPURE;

View File

@@ -708,6 +708,12 @@ target_sources(main_lib INTERFACE
${EXTERNAL_SOURCES}
${EXTERNAL_HEADERS})
if(WIN32)
# add windows resource file pointing to the neovim icon
# this makes the icon appear for the neovim exe and associated filetypes
target_sources(nvim_bin PRIVATE ${NVIM_RUNTIME_DIR}/windows_icon.rc)
endif()
target_sources(nlua0 PUBLIC ${NLUA0_SOURCES})
target_link_libraries(nvim_bin PRIVATE main_lib PUBLIC libuv)
@@ -731,6 +737,7 @@ add_custom_target(nvim_runtime_deps)
if(WIN32)
# Copy DLLs and third-party tools to bin/ and install them along with nvim
add_custom_command(TARGET nvim_runtime_deps
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${PROJECT_BINARY_DIR}/windows_runtime_deps/
${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
install(DIRECTORY ${PROJECT_BINARY_DIR}/windows_runtime_deps/
@@ -772,7 +779,10 @@ file(MAKE_DIRECTORY ${BINARY_LIB_DIR})
# install treesitter parser if bundled
if(EXISTS ${DEPS_PREFIX}/lib/nvim/parser)
add_custom_command(TARGET nvim_runtime_deps COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${DEPS_PREFIX}/lib/nvim/parser ${BINARY_LIB_DIR}/parser)
add_custom_command(
TARGET nvim_runtime_deps
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${DEPS_PREFIX}/lib/nvim/parser ${BINARY_LIB_DIR}/parser)
endif()
install(DIRECTORY ${BINARY_LIB_DIR}
@@ -843,8 +853,11 @@ add_glob_target(
-clang-analyzer-core.NullDereference,
-clang-analyzer-core.UndefinedBinaryOperatorResult,
-clang-analyzer-core.uninitialized.Assign,
-clang-analyzer-optin.core.EnumCastOutOfRange,
-clang-analyzer-optin.performance.Padding,
-clang-analyzer-security.insecureAPI.strcpy,
-clang-analyzer-unix.StdCLibraryFunctions,
-clang-analyzer-unix.Stream,
${CLANG_ANALYZER_IGNORE}
'
EXCLUDE ${EXCLUDE_CLANG_TIDY})

View File

@@ -386,9 +386,9 @@ cleanup:
/// - id: (number) autocommand id
/// - event: (string) name of the triggered event |autocmd-events|
/// - group: (number|nil) autocommand group id, if any
/// - match: (string) expanded value of [<amatch>]
/// - buf: (number) expanded value of [<abuf>]
/// - file: (string) expanded value of [<afile>]
/// - file: (string) [<afile>] (not expanded to a full path)
/// - match: (string) [<amatch>] (expanded to a full path)
/// - buf: (number) [<abuf>]
/// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]()
/// - command (string) optional: Vim command to execute on event. Cannot be used with
/// {callback}

View File

@@ -72,10 +72,10 @@ return {
'InsertLeavePre', -- just before leaving Insert mode
'LspAttach', -- after an LSP client attaches to a buffer
'LspDetach', -- after an LSP client detaches from a buffer
'LspRequest', -- after an LSP request is started, canceled, or completed
'LspNotify', -- after an LSP notice has been sent to the server
'LspTokenUpdate', -- after a visible LSP token is updated
'LspProgress', -- after a LSP progress update
'LspRequest', -- after an LSP request is started, canceled, or completed
'LspTokenUpdate', -- after a visible LSP token is updated
'MenuPopup', -- just before popup menu is displayed
'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
@@ -159,8 +159,8 @@ return {
LspAttach = true,
LspDetach = true,
LspNotify = true,
LspRequest = true,
LspProgress = true,
LspRequest = true,
LspTokenUpdate = true,
RecordingEnter = true,
RecordingLeave = true,

View File

@@ -1665,7 +1665,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
} else {
autocmd_fname = fname_io;
}
char *afile_orig = NULL; ///< Unexpanded <afile>
if (autocmd_fname != NULL) {
afile_orig = xstrdup(autocmd_fname);
// Allocate MAXPATHL for when eval_vars() resolves the fullpath.
autocmd_fname = xstrnsave(autocmd_fname, MAXPATHL);
}
@@ -1783,6 +1785,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
// save vector size, to avoid an endless loop when more patterns
// are added when executing autocommands
.ausize = kv_size(autocmds[(int)event]),
.afile_orig = afile_orig,
.fname = fname,
.sfname = sfname,
.tail = tail,
@@ -1850,6 +1853,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
autocmd_nested = save_autocmd_nested;
xfree(SOURCING_NAME);
estack_pop();
xfree(afile_orig);
xfree(autocmd_fname);
autocmd_fname = save_autocmd_fname;
autocmd_fname_full = save_autocmd_fname_full;
@@ -2014,8 +2018,8 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc)
MAXSIZE_TEMP_DICT(data, 7);
PUT_C(data, "id", INTEGER_OBJ(ac->id));
PUT_C(data, "event", CSTR_AS_OBJ(event_nr2name(apc->event)));
PUT_C(data, "file", CSTR_AS_OBJ(apc->afile_orig));
PUT_C(data, "match", CSTR_AS_OBJ(autocmd_match));
PUT_C(data, "file", CSTR_AS_OBJ(autocmd_fname));
PUT_C(data, "buf", INTEGER_OBJ(autocmd_bufnr));
if (apc->data) {

View File

@@ -52,6 +52,7 @@ struct AutoPatCmd_S {
AutoPat *lastpat; ///< Last matched AutoPat
size_t auidx; ///< Current autocmd index to execute
size_t ausize; ///< Saved AutoCmd vector size
char *afile_orig; ///< Unexpanded <afile>
char *fname; ///< Fname to match with
char *sfname; ///< Sfname to match with
char *tail; ///< Tail of fname

View File

@@ -342,8 +342,8 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
&& (last < wp->w_topline
|| (wp->w_topline >= lnum
&& wp->w_topline < lnume
&& win_linetabsize(wp, wp->w_topline, ml_get_buf(buf, wp->w_topline), MAXCOL)
<= (wp->w_skipcol + sms_marker_overlap(wp, -1))))) {
&& (linetabsize_eol(wp, wp->w_topline)
<= wp->w_skipcol + sms_marker_overlap(wp, -1))))) {
wp->w_skipcol = 0;
}

View File

@@ -129,7 +129,7 @@ static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, col
&& wp->w_width_inner != 0
&& wcol >= (colnr_T)width
&& width > 0) {
csize = linetabsize(wp, pos->lnum);
csize = linetabsize_eol(wp, pos->lnum);
if (csize > 0) {
csize--;
}

View File

@@ -2493,10 +2493,12 @@ redr_statuscol:
recursive = true;
curwin->w_valid &= ~VALID_TOPLINE;
update_topline(curwin); // may invalidate w_botline again
// New redraw either due to updated topline or reset skipcol.
if (must_redraw != 0) {
// Don't update for changes in buffer again.
int mod_set = curbuf->b_mod_set;
curbuf->b_mod_set = false;
curs_columns(curwin, true);
win_update(curwin);
must_redraw = 0;
curbuf->b_mod_set = mod_set;

View File

@@ -597,7 +597,7 @@ static int insert_execute(VimState *state, int key)
|| (ins_compl_enter_selects()
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
&& stop_arrow() == OK) {
ins_compl_delete();
ins_compl_delete(false);
ins_compl_insert(false);
}
}

View File

@@ -10766,6 +10766,44 @@ M.funcs = {
params = { { 'expr', 'any' } },
signature = 'srand([{expr}])',
},
state = {
args = { 0, 1 },
base = 1,
desc = [=[
Return a string which contains characters indicating the
current state. Mostly useful in callbacks that want to do
work that may not always be safe. Roughly this works like:
- callback uses state() to check if work is safe to do.
Yes: then do it right away.
No: add to work queue and add a |SafeState| autocommand.
- When SafeState is triggered and executes your autocommand,
check with `state()` if the work can be done now, and if yes
remove it from the queue and execute.
Remove the autocommand if the queue is now empty.
Also see |mode()|.
When {what} is given only characters in this string will be
added. E.g, this checks if the screen has scrolled: >vim
if state('s') == ''
" screen has not scrolled
<
These characters indicate the state, generally indicating that
something is busy:
m halfway a mapping, :normal command, feedkeys() or
stuffed command
o operator pending, e.g. after |d|
a Insert mode autocomplete active
x executing an autocommand
S not triggering SafeState, e.g. after |f| or a count
c callback invoked, including timer (repeats for
recursiveness up to "ccc")
s screen has scrolled for messages
]=],
fast = true,
name = 'state',
params = { { 'what', 'string' } },
signature = 'state([{what}])',
},
stdioopen = {
args = 1,
desc = [=[
@@ -10824,44 +10862,6 @@ M.funcs = {
returns = 'string|string[]',
signature = 'stdpath({what})',
},
state = {
args = { 0, 1 },
base = 1,
desc = [=[
Return a string which contains characters indicating the
current state. Mostly useful in callbacks that want to do
work that may not always be safe. Roughly this works like:
- callback uses state() to check if work is safe to do.
Yes: then do it right away.
No: add to work queue and add a |SafeState| autocommand.
- When SafeState is triggered and executes your autocommand,
check with `state()` if the work can be done now, and if yes
remove it from the queue and execute.
Remove the autocommand if the queue is now empty.
Also see |mode()|.
When {what} is given only characters in this string will be
added. E.g, this checks if the screen has scrolled: >vim
if state('s') == ''
" screen has not scrolled
<
These characters indicate the state, generally indicating that
something is busy:
m halfway a mapping, :normal command, feedkeys() or
stuffed command
o operator pending, e.g. after |d|
a Insert mode autocomplete active
x executing an autocommand
S not triggering SafeState, e.g. after |f| or a count
c callback invoked, including timer (repeats for
recursiveness up to "ccc")
s screen has scrolled for messages
]=],
fast = true,
name = 'state',
params = { { 'what', 'string' } },
signature = 'state([{what}])',
},
str2float = {
args = 1,
base = 1,

View File

@@ -4562,8 +4562,6 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
ui_busy_start();
ui_flush();
list_T *args = argvars[0].vval.v_list;
Channel **jobs = xcalloc((size_t)tv_list_len(args), sizeof(*jobs));
MultiQueue *waiting_jobs = multiqueue_new_parent(loop_on_put, &main_loop);
@@ -4600,6 +4598,13 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
before = os_hrtime();
}
// Only mark the UI as busy when jobwait() blocks
const bool busy = remaining != 0;
if (busy) {
ui_busy_start();
ui_flush();
}
for (i = 0; i < tv_list_len(args); i++) {
if (remaining == 0) {
break; // Timeout.
@@ -4641,7 +4646,9 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
multiqueue_free(waiting_jobs);
xfree(jobs);
ui_busy_stop();
if (busy) {
ui_busy_stop();
}
tv_list_ref(rv);
rettv->v_type = VAR_LIST;
rettv->vval.v_list = rv;

View File

@@ -1169,7 +1169,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
linenr_T read_linecount = curbuf->b_ml.ml_line_count;
// Pass on the kShellOptDoOut flag when the output is being redirected.
call_shell(cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL);
call_shell(cmd_buf, kShellOptFilter | shell_flags, NULL);
xfree(cmd_buf);
did_check_timestamps = false;
@@ -1314,7 +1314,7 @@ void do_shell(char *cmd, int flags)
// This ui_cursor_goto is required for when the '\n' resulted in a "delete line
// 1" command to the terminal.
ui_cursor_goto(msg_row, msg_col);
call_shell(cmd, (ShellOpts)flags, NULL);
call_shell(cmd, flags, NULL);
if (msg_silent == 0) {
msg_didout = true;
}

View File

@@ -2543,6 +2543,9 @@ static bool cmdpreview_may_show(CommandLineState *s)
goto end;
}
// Cursor may be at the end of the message grid rather than at cmdspos.
// Place it there in case preview callback flushes it. #30696
cursorcmd();
// Flush now: external cmdline may itself wish to update the screen which is
// currently disallowed during cmdpreview(no longer needed in case that changes).
cmdline_ui_flush();

View File

@@ -111,10 +111,10 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool
{
MarkTreeIter itr[1] = { 0 };
MTKey key = marktree_lookup(buf->b_marktree, mark, itr);
bool move = key.pos.row >= 0 && (key.pos.row != row || key.pos.col != col);
// Already valid keys were being revalidated, presumably when encountering a
// SavePos from a modified mark. Avoid adding that to the decor again.
invalid = invalid && mt_invalid(key);
bool move = key.pos.row != row || key.pos.col != col;
if (key.pos.row < 0 || (!move && !invalid)) {
return; // Mark was deleted or no change needed
}
// Only the position before undo needs to be redrawn here,
// as the position after undo should be marked as changed.
@@ -124,13 +124,16 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool
int row1 = 0;
int row2 = 0;
MarkTreeIter altitr[1] = { *itr };
MTKey alt = marktree_get_alt(buf->b_marktree, key, altitr);
if (invalid) {
mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_INVALID;
marktree_revise_meta(buf->b_marktree, itr, key);
} else if (move && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) {
MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL);
row1 = MIN(end.row, MIN(key.pos.row, row));
row2 = MAX(end.row, MAX(key.pos.row, row));
mt_itr_rawkey(altitr).flags &= (uint16_t) ~MT_FLAG_INVALID;
marktree_revise_meta(buf->b_marktree, mt_end(key) ? altitr : itr, mt_end(key) ? alt : key);
} else if (!mt_invalid(key) && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) {
row1 = MIN(alt.pos.row, MIN(key.pos.row, row));
row2 = MAX(alt.pos.row, MAX(key.pos.row, row));
buf_signcols_count_range(buf, row1, row2, 0, kTrue);
}
@@ -139,9 +142,8 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool
}
if (invalid) {
row2 = mt_paired(key) ? marktree_get_altpos(buf->b_marktree, key, NULL).row : row;
buf_put_decor(buf, mt_decor(key), row, row2);
} else if (move && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) {
buf_put_decor(buf, mt_decor(key), MIN(row, key.pos.row), MAX(row, key.pos.row));
} else if (!mt_invalid(key) && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) {
buf_signcols_count_range(buf, row1, row2, 0, kNone);
}
}
@@ -367,16 +369,28 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
marktree_itr_get(buf->b_marktree, (int32_t)l_row, l_col, itr);
while (true) {
MTKey mark = marktree_itr_current(itr);
if (mark.pos.row < 0
|| mark.pos.row > u_row
|| (mark.pos.row == u_row && mark.pos.col > u_col)) {
if (mark.pos.row < 0 || mark.pos.row > u_row) {
break;
}
bool copy = true;
// No need to copy left gravity marks at the beginning of the range,
// and right gravity marks at the end of the range, unless invalidated.
if (mark.pos.row == l_row && mark.pos.col - !mt_right(mark) < l_col) {
copy = false;
} else if (mark.pos.row == u_row) {
if (mark.pos.col > u_col + 1) {
break;
} else if (mark.pos.col + mt_right(mark) > u_col) {
copy = false;
}
}
bool invalidated = false;
// Invalidate/delete mark
if (!only_copy && !mt_invalid(mark) && mt_invalidate(mark) && !mt_end(mark)) {
MTPos endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
MarkTreeIter enditr[1] = { *itr };
MTPos endpos = marktree_get_altpos(buf->b_marktree, mark, enditr);
// Invalidate unpaired marks in deleted lines and paired marks whose entire
// range has been deleted.
if ((!mt_paired(mark) && mark.pos.row < u_row)
@@ -388,8 +402,10 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
extmark_del(buf, itr, mark, true);
continue;
} else {
copy = true;
invalidated = true;
mt_itr_rawkey(itr).flags |= MT_FLAG_INVALID;
mt_itr_rawkey(enditr).flags |= MT_FLAG_INVALID;
marktree_revise_meta(buf->b_marktree, itr, mark);
buf_decor_remove(buf, mark.pos.row, endpos.row, mark.pos.col, mt_decor(mark), false);
}
@@ -397,7 +413,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
}
// Push mark to undo header
if (only_copy || (uvp != NULL && op == kExtmarkUndo && !mt_no_undo(mark))) {
if (copy && (only_copy || (uvp != NULL && op == kExtmarkUndo && !mt_no_undo(mark)))) {
ExtmarkSavePos pos = {
.mark = mt_lookup_key(mark),
.invalidated = invalidated,
@@ -541,10 +557,8 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
if (old_row > 0 || old_col > 0) {
// Copy and invalidate marks that would be effected by delete
// TODO(bfredl): Be "smart" about gravity here, left-gravity at the
// beginning and right-gravity at the end need not be preserved.
// Also be smart about marks that already have been saved (important for
// merge!)
// TODO(bfredl): Be smart about marks that already have been
// saved (important for merge!)
int end_row = start_row + old_row;
int end_col = (old_row ? 0 : start_col) + old_col;
u_header_T *uhp = u_force_get_undo_header(buf);

View File

@@ -1098,6 +1098,9 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(cterm, cterm_mask, italic, , HL_ITALIC);
CHECK_FLAG(cterm, cterm_mask, underline, , HL_UNDERLINE);
CHECK_FLAG(cterm, cterm_mask, undercurl, , HL_UNDERCURL);
CHECK_FLAG(cterm, cterm_mask, underdouble, , HL_UNDERDOUBLE);
CHECK_FLAG(cterm, cterm_mask, underdotted, , HL_UNDERDOTTED);
CHECK_FLAG(cterm, cterm_mask, underdashed, , HL_UNDERDASHED);
CHECK_FLAG(cterm, cterm_mask, standout, , HL_STANDOUT);
CHECK_FLAG(cterm, cterm_mask, strikethrough, , HL_STRIKETHROUGH);
CHECK_FLAG(cterm, cterm_mask, altfont, , HL_ALTFONT);

View File

@@ -934,14 +934,14 @@ static void ins_compl_longest_match(compl_T *match)
compl_leader = xstrdup(match->cp_str);
bool had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete();
ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len());
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
// again after redrawing.
if (!had_match) {
ins_compl_delete();
ins_compl_delete(false);
}
compl_used_match = false;
@@ -968,14 +968,14 @@ static void ins_compl_longest_match(compl_T *match)
// Leader was shortened, need to change the inserted text.
*p = NUL;
bool had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete();
ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len());
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
// again after redrawing.
if (!had_match) {
ins_compl_delete();
ins_compl_delete(false);
}
}
@@ -1336,6 +1336,12 @@ bool compl_match_curr_select(int selected)
#define DICT_FIRST (1) ///< use just first element in "dict"
#define DICT_EXACT (2) ///< "dict" is the exact name of a file
/// Get current completion leader
char *ins_compl_leader(void)
{
return compl_leader != NULL ? compl_leader : compl_orig_text;
}
/// Add any identifiers that match the given pattern "pat" in the list of
/// dictionary files "dict_start" to the list of completions.
///
@@ -1733,7 +1739,7 @@ static bool ins_compl_need_restart(void)
static void ins_compl_new_leader(void)
{
ins_compl_del_pum();
ins_compl_delete();
ins_compl_delete(true);
ins_bytes(compl_leader + get_compl_len());
compl_used_match = false;
@@ -2056,7 +2062,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
// CTRL-E means completion is Ended, go back to the typed text.
// but only do this, if the Popup is still visible
if (c == Ctrl_E) {
ins_compl_delete();
ins_compl_delete(false);
char *p = NULL;
if (compl_leader != NULL) {
p = compl_leader;
@@ -3502,11 +3508,24 @@ static void ins_compl_update_shown_match(void)
}
/// Delete the old text being completed.
void ins_compl_delete(void)
void ins_compl_delete(bool new_leader)
{
// Avoid deleting text that will be reinserted when changing leader. This
// allows marks present on the original text to shrink/grow appropriately.
int orig_col = 0;
if (new_leader) {
char *orig = compl_orig_text;
char *leader = ins_compl_leader();
while (*orig != NUL && utf_ptr2char(orig) == utf_ptr2char(leader)) {
leader += utf_ptr2len(leader);
orig += utf_ptr2len(orig);
}
orig_col = (int)(orig - compl_orig_text);
}
// In insert mode: Delete the typed part.
// In replace mode: Put the old characters back, if any.
int col = compl_col + (compl_status_adding() ? compl_length : 0);
int col = compl_col + (compl_status_adding() ? compl_length : orig_col);
if ((int)curwin->w_cursor.col > col) {
if (stop_arrow() == FAIL) {
return;
@@ -3701,7 +3720,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
if (allow_get_expansion && insert_match
&& (!compl_get_longest || compl_used_match)) {
// Delete old text to be replaced
ins_compl_delete();
ins_compl_delete(false);
}
// When finding the longest common text we stick at the original text,
@@ -3754,7 +3773,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
// Delete old text to be replaced, since we're still searching and
// don't want to match ourselves!
ins_compl_delete();
ins_compl_delete(false);
}
// Enter will select a match when the match wasn't inserted and the popup

View File

@@ -149,7 +149,9 @@ static int count_n_matched_chars(mmfile_t **sp, const size_t n, bool iwhite)
mmfile_t fastforward_buf_to_lnum(mmfile_t s, linenr_T lnum)
{
for (int i = 0; i < lnum - 1; i++) {
s.ptr = strnchr(s.ptr, (size_t *)&s.size, '\n');
size_t n = (size_t)s.size;
s.ptr = strnchr(s.ptr, &n, '\n');
s.size = (int)n;
if (!s.ptr) {
break;
}

View File

@@ -274,10 +274,9 @@ static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nres
#endif
}
const char *error = lua_tostring(lstate, -1);
loop_schedule_deferred(&main_loop,
event_create(nlua_luv_error_event,
xstrdup(error),
error != NULL ? xstrdup(error) : NULL,
(void *)(intptr_t)(is_callback
? kThreadCallback
: kThread)));

View File

@@ -67,9 +67,9 @@ static TSLanguage *load_language(lua_State *L, const char *path, const char *lan
{
uv_lib_t lib;
if (uv_dlopen(path, &lib)) {
xstrlcpy(IObuff, uv_dlerror(&lib), sizeof(IObuff));
uv_dlclose(&lib);
luaL_error(L, "Failed to load parser for language '%s': uv_dlopen: %s",
lang_name, uv_dlerror(&lib));
luaL_error(L, "Failed to load parser for language '%s': uv_dlopen: %s", lang_name, IObuff);
}
char symbol_buf[128];
@@ -77,8 +77,9 @@ static TSLanguage *load_language(lua_State *L, const char *path, const char *lan
TSLanguage *(*lang_parser)(void);
if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) {
xstrlcpy(IObuff, uv_dlerror(&lib), sizeof(IObuff));
uv_dlclose(&lib);
luaL_error(L, "Failed to load parser: uv_dlsym: %s", uv_dlerror(&lib));
luaL_error(L, "Failed to load parser: uv_dlsym: %s", IObuff);
}
TSLanguage *lang = lang_parser();
@@ -1390,10 +1391,25 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err
|| error_type == TSQueryErrorField
|| error_type == TSQueryErrorCapture) {
const char *suffix = src + error_offset;
bool is_anonymous = error_type == TSQueryErrorNodeType && suffix[-1] == '"';
int suffix_len = 0;
char c = suffix[suffix_len];
while (isalnum(c) || c == '_' || c == '-' || c == '.') {
c = suffix[++suffix_len];
if (is_anonymous) {
int backslashes = 0;
// Stop when we hit an unescaped double quote
while (c != '"' || backslashes % 2 != 0) {
if (c == '\\') {
backslashes += 1;
} else {
backslashes = 0;
}
c = suffix[++suffix_len];
}
} else {
// Stop when we hit the end of the identifier
while (isalnum(c) || c == '_' || c == '-' || c == '.') {
c = suffix[++suffix_len];
}
}
snprintf(err, errlen, "\"%.*s\":\n", suffix_len, suffix);
offset = strlen(err);

View File

@@ -1442,6 +1442,17 @@ scripterror:
ga_grow(&global_alist.al_ga, 1);
char *p = xstrdup(argv[0]);
// On Windows expand "~\" or "~/" prefix in file names to profile directory.
#ifdef MSWIN
if (*p == '~' && (p[1] == '\\' || p[1] == '/')) {
size_t size = strlen(os_get_homedir()) + strlen(p);
char *tilde_expanded = xmalloc(size);
snprintf(tilde_expanded, size, "%s%s", os_get_homedir(), p + 1);
xfree(p);
p = tilde_expanded;
}
#endif
if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0
&& !os_isdir(alist_name(&GARGLIST[0]))) {
char *r = concat_fnames(p, path_tail(alist_name(&GARGLIST[0])), true);

View File

@@ -2330,7 +2330,6 @@ void marktree_check(MarkTree *b)
#endif
}
#ifndef NDEBUG
size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right,
const uint32_t *meta_node_ref)
{
@@ -2485,8 +2484,6 @@ bool mt_recurse_nodes_compare(MTNode *x, PMap(ptr_t) *checked)
return true;
}
#endif
// TODO(bfredl): kv_print
#define GA_PUT(x) ga_concat(ga, (char *)(x))
#define GA_PRINT(fmt, ...) snprintf(buf, sizeof(buf), fmt, __VA_ARGS__); \

View File

@@ -1880,6 +1880,11 @@ static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change)
static int recursive = 0;
static char questions[4];
if (buf->b_ml.ml_mfp == NULL) { // there are no lines
buf->b_ml.ml_line_len = 1;
return "";
}
if (lnum > buf->b_ml.ml_line_count) { // invalid line number
if (recursive == 0) {
// Avoid giving this message for a recursive call, may happen when
@@ -1899,11 +1904,6 @@ errorret:
lnum = 1;
}
if (buf->b_ml.ml_mfp == NULL) { // there are no lines
buf->b_ml.ml_line_len = 1;
return "";
}
// See if it is the same line as requested last time.
// Otherwise may need to flush last used line.
// Don't use the last used line when 'swapfile' is reset, need to load all

View File

@@ -1576,7 +1576,7 @@ int msg_outtrans_len(const char *msgstr, int len, int attr)
// When drawing over the command line no need to clear it later or remove
// the mode message.
if (msg_row >= cmdline_row && msg_col == 0) {
if (msg_silent == 0 && len > 0 && msg_row >= cmdline_row && msg_col == 0) {
clear_cmdline = false;
mode_displayed = false;
}

View File

@@ -1208,9 +1208,7 @@ static void cursor_correct_sms(win_T *wp)
int width2 = width1 + win_col_off2(wp);
int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
int space_cols = (wp->w_height_inner - 1) * width2;
int size = so == 0 ? 0 : win_linetabsize(wp, wp->w_topline,
ml_get_buf(wp->w_buffer, wp->w_topline),
(colnr_T)MAXCOL);
int size = so == 0 ? 0 : linetabsize_eol(wp, wp->w_topline);
if (wp->w_topline == 1 && wp->w_skipcol == 0) {
so_cols = 0; // Ignore 'scrolloff' at top of buffer.
@@ -1226,9 +1224,10 @@ static void cursor_correct_sms(win_T *wp)
so_cols -= width1;
}
// If there is no marker or we have non-zero scrolloff, just ignore it.
int overlap = (wp->w_skipcol == 0 || so_cols != 0) ? 0 : sms_marker_overlap(wp, -1);
int top = wp->w_skipcol + overlap + so_cols;
int overlap = wp->w_skipcol == 0
? 0 : sms_marker_overlap(wp, wp->w_width_inner - width2);
// If we have non-zero scrolloff, ignore marker overlap.
int top = wp->w_skipcol + (so_cols != 0 ? so_cols : overlap);
int bot = wp->w_skipcol + width1 + (wp->w_height_inner - 1) * width2 - so_cols;
validate_virtcol(wp);
@@ -1249,10 +1248,22 @@ static void cursor_correct_sms(win_T *wp)
if (col != wp->w_virtcol) {
wp->w_curswant = col;
coladvance(wp, wp->w_curswant);
int rc = coladvance(wp, wp->w_curswant);
// validate_virtcol() marked various things as valid, but after
// moving the cursor they need to be recomputed
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
if (rc == FAIL && wp->w_skipcol > 0
&& wp->w_cursor.lnum < wp->w_buffer->b_ml.ml_line_count) {
validate_virtcol(wp);
if (wp->w_virtcol < wp->w_skipcol + overlap) {
// Cursor still not visible: move it to the next line instead.
wp->w_cursor.lnum++;
wp->w_cursor.col = 0;
wp->w_cursor.coladd = 0;
wp->w_curswant = 0;
wp->w_valid &= ~VALID_VIRTCOL;
}
}
}
}
@@ -1365,8 +1376,7 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold)
wp->w_topline = first;
} else {
if (do_sms) {
int size = win_linetabsize(wp, wp->w_topline,
ml_get_buf(wp->w_buffer, wp->w_topline), MAXCOL);
int size = linetabsize_eol(wp, wp->w_topline);
if (size > width1) {
wp->w_skipcol = width1;
size -= width1;
@@ -1449,7 +1459,7 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
const colnr_T prev_skipcol = wp->w_skipcol;
if (do_sms) {
size = linetabsize(wp, wp->w_topline);
size = linetabsize_eol(wp, wp->w_topline);
}
// diff mode: first consume "topfill"
@@ -1492,7 +1502,7 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
wp->w_topfill = win_get_fill(wp, lnum);
wp->w_skipcol = 0;
if (todo > 1 && do_sms) {
size = linetabsize(wp, wp->w_topline);
size = linetabsize_eol(wp, wp->w_topline);
}
}
}
@@ -1563,7 +1573,7 @@ void adjust_skipcol(void)
}
validate_virtcol(curwin);
int overlap = sms_marker_overlap(curwin, -1);
int overlap = sms_marker_overlap(curwin, curwin->w_width_inner - width2);
while (curwin->w_skipcol > 0
&& curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) {
// scroll a screen line down
@@ -1584,8 +1594,7 @@ void adjust_skipcol(void)
// Avoid adjusting for 'scrolloff' beyond the text line height.
if (scrolloff_cols > 0) {
int size = win_linetabsize(curwin, curwin->w_topline,
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
int size = linetabsize_eol(curwin, curwin->w_topline);
size = width1 + width2 * ((size - width1 + width2 - 1) / width2);
while (col > size) {
col -= width2;
@@ -2523,7 +2532,10 @@ int pagescroll(Direction dir, int count, bool half)
if (!nochange) {
// Place cursor at top or bottom of window.
validate_botline(curwin);
curwin->w_cursor.lnum = (dir == FORWARD ? curwin->w_topline : curwin->w_botline - 1);
linenr_T lnum = (dir == FORWARD ? curwin->w_topline : curwin->w_botline - 1);
// In silent Ex mode the value of w_botline - 1 may be 0,
// but cursor lnum needs to be at least 1.
curwin->w_cursor.lnum = MAX(lnum, 1);
}
}

View File

@@ -5197,7 +5197,7 @@ void nv_g_home_m_cmd(cmdarg_T *cap)
// When ending up below 'smoothscroll' marker, move just beyond it so
// that skipcol is not adjusted later.
if (curwin->w_skipcol > 0 && curwin->w_cursor.lnum == curwin->w_topline) {
int overlap = sms_marker_overlap(curwin, -1);
int overlap = sms_marker_overlap(curwin, curwin->w_width_inner - width2);
if (overlap > 0 && i == curwin->w_skipcol) {
i += overlap;
}
@@ -5616,6 +5616,7 @@ static void nv_g_cmd(cmdarg_T *cap)
// "go": goto byte count from start of buffer
case 'o':
oap->inclusive = false;
goto_byte(cap->count0);
break;

View File

@@ -5076,6 +5076,12 @@ void clear_winopt(winopt_T *wop)
void didset_window_options(win_T *wp, bool valid_cursor)
{
// Set w_leftcol or w_skipcol to zero.
if (wp->w_p_wrap) {
wp->w_leftcol = 0;
} else {
wp->w_skipcol = 0;
}
check_colorcolumn(wp);
briopt_check(wp);
fill_culopt_flags(NULL, wp);

View File

@@ -400,17 +400,28 @@ void os_get_hostname(char *hostname, size_t size)
/// 2. if $HOME is not set, try the following
/// For Windows:
/// 1. assemble homedir using HOMEDRIVE and HOMEPATH
/// 2. try os_homedir()
/// 2. try os_uv_homedir()
/// 3. resolve a direct reference to another system variable
/// 4. guess C drive
/// For Unix:
/// 1. try os_homedir()
/// 1. try os_uv_homedir()
/// 2. go to that directory
/// This also works with mounts and links.
/// Don't do this for Windows, it will change the "current dir" for a drive.
/// 3. fall back to current working directory as a last resort
static char *homedir = NULL;
static char *os_homedir(void);
static char *os_uv_homedir(void);
/// Public accessor for the cached "real", resolved user home directory. See
/// comment on `homedir`.
const char *os_get_homedir(void)
{
if (!homedir) {
emsg("os_get_homedir failed: homedir not initialized");
return NULL;
}
return homedir;
}
void init_homedir(void)
{
@@ -440,7 +451,7 @@ void init_homedir(void)
}
}
if (var == NULL) {
var = os_homedir();
var = os_uv_homedir();
}
// Weird but true: $HOME may contain an indirect reference to another
@@ -471,7 +482,7 @@ void init_homedir(void)
#ifdef UNIX
if (var == NULL) {
var = os_homedir();
var = os_uv_homedir();
}
// Get the actual path. This resolves links.
@@ -492,7 +503,7 @@ void init_homedir(void)
static char homedir_buf[MAXPATHL];
static char *os_homedir(void)
static char *os_uv_homedir(void)
{
homedir_buf[0] = NUL;
size_t homedir_size = MAXPATHL;

View File

@@ -122,7 +122,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
size_t len;
char *p;
char *extra_shell_arg = NULL;
ShellOpts shellopts = kShellOptExpand | kShellOptSilent;
int shellopts = kShellOptExpand | kShellOptSilent;
int j;
char *tempname;
#define STYLE_ECHO 0 // use "echo", the default
@@ -666,7 +666,7 @@ char *shell_argv_to_str(char **const argv)
/// @param extra_args Extra arguments to the shell, or NULL.
///
/// @return shell command exit code
int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
int os_call_shell(char *cmd, int opts, char *extra_args)
{
DynamicBuffer input = DYNAMIC_BUFFER_INIT;
char *output = NULL;
@@ -721,8 +721,10 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
/// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error.
/// Invalidates cached tags.
///
/// @param opts a combination of ShellOpts flags
///
/// @return shell command exit code
int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg)
int call_shell(char *cmd, int opts, char *extra_shell_arg)
{
int retval;
proftime_T wait_time;
@@ -766,7 +768,7 @@ int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg)
/// @param ret_len length of the stdout
///
/// @return an allocated string, or NULL for error.
char *get_cmd_output(char *cmd, char *infile, ShellOpts flags, size_t *ret_len)
char *get_cmd_output(char *cmd, char *infile, int flags, size_t *ret_len)
{
char *buffer = NULL;

View File

@@ -619,7 +619,6 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
FUNC_ATTR_NONNULL_ALL
{
int start_len = gap->ga_len;
size_t len;
bool starstar = false;
static int stardepth = 0; // depth for "**" expansion
@@ -631,9 +630,9 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
}
}
// Make room for file name. When doing encoding conversion the actual
// length may be quite a bit longer, thus use the maximum possible length.
char *buf = xmalloc(MAXPATHL);
// Make room for file name (a bit too much to stay on the safe side).
const size_t buflen = strlen(path) + MAXPATHL;
char *buf = xmalloc(buflen);
// Find the first part in the path name that contains a wildcard.
// When EW_ICASE is set every letter is considered to be a wildcard.
@@ -662,10 +661,10 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
) {
e = p;
}
len = (size_t)(utfc_ptr2len(path_end));
memcpy(p, path_end, len);
p += len;
path_end += len;
int charlen = utfc_ptr2len(path_end);
memcpy(p, path_end, (size_t)charlen);
p += charlen;
path_end += charlen;
}
e = p;
*e = NUL;
@@ -719,13 +718,14 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
return 0;
}
size_t len = (size_t)(s - buf);
// If "**" is by itself, this is the first time we encounter it and more
// is following then find matches without any directory.
if (!didstar && stardepth < 100 && starstar && e - s == 2
&& *path_end == '/') {
STRCPY(s, path_end + 1);
vim_snprintf(s, buflen - len, "%s", path_end + 1);
stardepth++;
do_path_expand(gap, buf, (size_t)(s - buf), flags, true);
do_path_expand(gap, buf, len, flags, true);
stardepth--;
}
*s = NUL;
@@ -737,6 +737,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
const char *name;
scandir_next_with_dots(NULL); // initialize
while (!got_int && (name = scandir_next_with_dots(&dir)) != NULL) {
len = (size_t)(s - buf);
if ((name[0] != '.'
|| starts_with_dot
|| ((flags & EW_DODOT)
@@ -744,21 +745,22 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
&& (name[1] != '.' || name[2] != NUL)))
&& ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0))
|| ((flags & EW_NOTWILD)
&& path_fnamencmp(path + (s - buf), name, (size_t)(e - s)) == 0))) {
STRCPY(s, name);
len = strlen(buf);
&& path_fnamencmp(path + len, name, (size_t)(e - s)) == 0))) {
len += (size_t)vim_snprintf(s, buflen - len, "%s", name);
if (len + 1 >= buflen) {
continue;
}
if (starstar && stardepth < 100) {
// For "**" in the pattern first go deeper in the tree to
// find matches.
STRCPY(buf + len, "/**"); // NOLINT
STRCPY(buf + len + 3, path_end);
vim_snprintf(buf + len, buflen - len, "/**%s", path_end); // NOLINT
stardepth++;
do_path_expand(gap, buf, len + 1, flags, true);
stardepth--;
}
STRCPY(buf + len, path_end);
vim_snprintf(buf + len, buflen - len, "%s", path_end);
if (path_has_exp_wildcard(path_end)) { // handle more wildcards
// need to expand another component of the path
// remove backslashes for the remaining components only

View File

@@ -74,11 +74,19 @@ int linetabsize_col(int startvcol, char *s)
/// Return the number of cells line "lnum" of window "wp" will take on the
/// screen, taking into account the size of a tab and inline virtual text.
/// Doesn't count the size of 'listchars' "eol".
int linetabsize(win_T *wp, linenr_T lnum)
{
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), MAXCOL);
}
/// Like linetabsize(), but counts the size of 'listchars' "eol".
int linetabsize_eol(win_T *wp, linenr_T lnum)
{
return linetabsize(wp, lnum)
+ ((wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) ? 1 : 0);
}
static const uint32_t inline_filter[4] = {[kMTMetaInline] = kMTFilterSelect };
/// Prepare the structure passed to charsize functions.

View File

@@ -81,6 +81,7 @@ static inline int win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE;
/// Like linetabsize_str(), but for a given window instead of the current one.
/// Doesn't count the size of 'listchars' "eol".
///
/// @param wp
/// @param line

View File

@@ -955,7 +955,7 @@ void time_init(const char *fname, const char *process_name)
const size_t bufsize = 8192; // Big enough for the entire --startuptime report.
time_fd = fopen(fname, "a");
if (time_fd == NULL) {
semsg(_(e_notopen), fname);
fprintf(stderr, _(e_notopen), fname);
return;
}
startuptime_buf = xmalloc(sizeof(char) * (bufsize + 1));
@@ -967,8 +967,7 @@ void time_init(const char *fname, const char *process_name)
XFREE_CLEAR(startuptime_buf);
fclose(time_fd);
time_fd = NULL;
ELOG("time_init: setvbuf failed: %d %s", r, uv_err_name(r));
semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r));
fprintf(stderr, "time_init: setvbuf failed: %d %s", r, uv_err_name(r));
return;
}
fprintf(time_fd, "--- Startup times for process: %s ---\n", process_name);

View File

@@ -2964,6 +2964,8 @@ static int fuzzy_match_compute_score(const char *const str, const int strSz,
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
assert(numMatches > 0); // suppress clang "result of operation is garbage"
const char *p = str;
uint32_t sidx = 0;
// Initialize score
int score = 100;
@@ -2996,12 +2998,12 @@ static int fuzzy_match_compute_score(const char *const str, const int strSz,
// Check for bonuses based on neighbor character value
if (currIdx > 0) {
// Camel case
const char *p = str;
int neighbor = ' ';
for (uint32_t sidx = 0; sidx < currIdx; sidx++) {
while (sidx < currIdx) {
neighbor = utf_ptr2char(p);
MB_PTR_ADV(p);
sidx++;
}
const int curr = utf_ptr2char(p);

View File

@@ -66,9 +66,11 @@ getkey:
// Event was made available after the last multiqueue_process_events call
key = K_EVENT;
} else {
// Duplicate display updating logic in vgetorpeek()
if (((State & MODE_INSERT) != 0 || p_lz) && (State & MODE_CMDLINE) == 0
&& must_redraw != 0 && !need_wait_return) {
// Ensure the screen is fully updated before blocking for input. Because of the duality of
// redraw_later, this can't be done in command-line or when waiting for "Press ENTER".
// In many of those cases the redraw is expected AFTER the key press, while normally it should
// update the screen immediately.
if (must_redraw != 0 && !need_wait_return && (State & MODE_CMDLINE) == 0) {
update_screen();
setcursor(); // put cursor back where it belongs
}

View File

@@ -1677,8 +1677,6 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
}
switch (fmt_spec) {
case 'b':
case 'B':
case 'd':
case 'u':
case 'o':
@@ -1802,6 +1800,13 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
if (ptr_arg) {
arg_sign = 1;
}
} else if (fmt_spec == 'b' || fmt_spec == 'B') {
uarg = (tvs
? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT(runtime/int)
: (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
&arg_cur, fmt),
va_arg(ap, unsigned long long))); // NOLINT(runtime/int)
arg_sign = (uarg != 0);
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {

View File

@@ -1649,7 +1649,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
? !(spp->sp_flags & HL_CONTAINED)
: in_id_list(cur_si,
cur_si->si_cont_list, &spp->sp_syn,
spp->sp_flags & HL_CONTAINED)))) {
spp->sp_flags)))) {
// If we already tried matching in this line, and
// there isn't a match before next_match_col, skip
// this item.
@@ -2774,7 +2774,7 @@ static keyentry_T *match_keyword(char *keyword, hashtab_T *ht, stateitem_T *cur_
: (cur_si == NULL
? !(kp->flags & HL_CONTAINED)
: in_id_list(cur_si, cur_si->si_cont_list,
&kp->k_syn, kp->flags & HL_CONTAINED))) {
&kp->k_syn, kp->flags))) {
return kp;
}
}
@@ -3927,7 +3927,7 @@ static void syn_incl_toplevel(int id, int *flagsp)
if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0) {
return;
}
*flagsp |= HL_CONTAINED;
*flagsp |= HL_CONTAINED | HL_INCLUDED_TOPLEVEL;
if (curwin->w_s->b_syn_topgrp >= SYNID_CLUSTER) {
// We have to alloc this, because syn_combine_list() will free it.
int16_t *grp_list = xmalloc(2 * sizeof(*grp_list));
@@ -4968,16 +4968,13 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list,
break;
}
if (name[1] == 'A') {
id = SYNID_ALLBUT + current_syn_inc_tag;
id = SYNID_ALLBUT;
} else if (name[1] == 'T') {
if (curwin->w_s->b_syn_topgrp >= SYNID_CLUSTER) {
id = curwin->w_s->b_syn_topgrp;
} else {
id = SYNID_TOP + current_syn_inc_tag;
}
id = SYNID_TOP;
} else {
id = SYNID_CONTAINED + current_syn_inc_tag;
id = SYNID_CONTAINED;
}
id += current_syn_inc_tag;
} else if (name[1] == '@') {
if (skip) {
id = -1;
@@ -5095,8 +5092,8 @@ static int16_t *copy_id_list(const int16_t *const list)
/// @param cur_si current item or NULL
/// @param list id list
/// @param ssp group id and ":syn include" tag of group
/// @param contained group id is contained
static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, int contained)
/// @param flags group flags
static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, int flags)
{
int retval;
int16_t id = ssp->id;
@@ -5114,8 +5111,7 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in
// cur_si->si_idx is -1 for keywords, these never contain anything.
if (cur_si->si_idx >= 0 && in_id_list(NULL, ssp->cont_in_list,
&(SYN_ITEMS(syn_block)[cur_si->si_idx].sp_syn),
SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags &
HL_CONTAINED)) {
SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags)) {
return true;
}
}
@@ -5127,9 +5123,14 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in
// If list is ID_LIST_ALL, we are in a transparent item that isn't
// inside anything. Only allow not-contained groups.
if (list == ID_LIST_ALL) {
return !contained;
return !(flags & HL_CONTAINED);
}
// Is this top-level (i.e. not 'contained') in the file it was declared in?
// For included files, this is different from HL_CONTAINED, which is set
// unconditionally.
bool toplevel = !(flags & HL_CONTAINED) || (flags & HL_INCLUDED_TOPLEVEL);
// If the first item is "ALLBUT", return true if "id" is NOT in the
// contains list. We also require that "id" is at the same ":syn include"
// level as the list.
@@ -5142,12 +5143,12 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in
}
} else if (item < SYNID_CONTAINED) {
// TOP: accept all not-contained groups in the same file
if (item - SYNID_TOP != ssp->inc_tag || contained) {
if (item - SYNID_TOP != ssp->inc_tag || !toplevel) {
return false;
}
} else {
// CONTAINED: accept all contained groups in the same file
if (item - SYNID_CONTAINED != ssp->inc_tag || !contained) {
if (item - SYNID_CONTAINED != ssp->inc_tag || toplevel) {
return false;
}
}
@@ -5168,7 +5169,7 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in
// cluster that includes itself (indirectly)
if (scl_list != NULL && depth < 30) {
depth++;
int r = in_id_list(NULL, scl_list, ssp, contained);
int r = in_id_list(NULL, scl_list, ssp, flags);
depth--;
if (r) {
return retval;

View File

@@ -7,25 +7,26 @@
#include "nvim/types_defs.h" // IWYU pragma: keep
enum {
HL_CONTAINED = 0x01, ///< not used on toplevel
HL_TRANSP = 0x02, ///< has no highlighting
HL_ONELINE = 0x04, ///< match within one line only
HL_HAS_EOL = 0x08, ///< end pattern that matches with $
HL_SYNC_HERE = 0x10, ///< sync point after this item (syncing only)
HL_SYNC_THERE = 0x20, ///< sync point at current line (syncing only)
HL_MATCH = 0x40, ///< use match ID instead of item ID
HL_SKIPNL = 0x80, ///< nextgroup can skip newlines
HL_SKIPWHITE = 0x100, ///< nextgroup can skip white space
HL_SKIPEMPTY = 0x200, ///< nextgroup can skip empty lines
HL_KEEPEND = 0x400, ///< end match always kept
HL_EXCLUDENL = 0x800, ///< exclude NL from match
HL_DISPLAY = 0x1000, ///< only used for displaying, not syncing
HL_FOLD = 0x2000, ///< define fold
HL_EXTEND = 0x4000, ///< ignore a keepend
HL_MATCHCONT = 0x8000, ///< match continued from previous line
HL_TRANS_CONT = 0x10000, ///< transparent item without contains arg
HL_CONCEAL = 0x20000, ///< can be concealed
HL_CONCEALENDS = 0x40000, ///< can be concealed
HL_CONTAINED = 0x01, ///< not used on toplevel
HL_TRANSP = 0x02, ///< has no highlighting
HL_ONELINE = 0x04, ///< match within one line only
HL_HAS_EOL = 0x08, ///< end pattern that matches with $
HL_SYNC_HERE = 0x10, ///< sync point after this item (syncing only)
HL_SYNC_THERE = 0x20, ///< sync point at current line (syncing only)
HL_MATCH = 0x40, ///< use match ID instead of item ID
HL_SKIPNL = 0x80, ///< nextgroup can skip newlines
HL_SKIPWHITE = 0x100, ///< nextgroup can skip white space
HL_SKIPEMPTY = 0x200, ///< nextgroup can skip empty lines
HL_KEEPEND = 0x400, ///< end match always kept
HL_EXCLUDENL = 0x800, ///< exclude NL from match
HL_DISPLAY = 0x1000, ///< only used for displaying, not syncing
HL_FOLD = 0x2000, ///< define fold
HL_EXTEND = 0x4000, ///< ignore a keepend
HL_MATCHCONT = 0x8000, ///< match continued from previous line
HL_TRANS_CONT = 0x10000, ///< transparent item without contains arg
HL_CONCEAL = 0x20000, ///< can be concealed
HL_CONCEALENDS = 0x40000, ///< can be concealed
HL_INCLUDED_TOPLEVEL = 0x80000, ///< toplevel item in included syntax, allowed by contains=TOP
};
#define SYN_GROUP_STATIC(s) syn_check_group(S_LEN(s))

View File

@@ -3014,6 +3014,8 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help)
secure = 1;
sandbox++;
curwin->w_cursor.lnum = 1; // start command in line 1
curwin->w_cursor.col = 0;
curwin->w_cursor.coladd = 0;
do_cmdline_cmd(pbuf);
retval = OK;

View File

@@ -132,11 +132,12 @@ struct TUIData {
int resize_screen;
int reset_scroll_region;
int set_cursor_style, reset_cursor_style;
int save_title, restore_title;
int save_title, restore_title, set_title;
int set_underline_style;
int set_underline_color;
int sync;
} unibi_ext;
char *set_title;
char *space_buf;
size_t space_buf_len;
bool stopped;
@@ -510,6 +511,7 @@ static void terminfo_stop(TUIData *tui)
abort();
}
unibi_destroy(tui->ut);
XFREE_CLEAR(tui->set_title);
}
static void tui_terminal_start(TUIData *tui)
@@ -1532,8 +1534,7 @@ void tui_suspend(TUIData *tui)
void tui_set_title(TUIData *tui, String title)
{
if (!(unibi_get_str(tui->ut, unibi_to_status_line)
&& unibi_get_str(tui->ut, unibi_from_status_line))) {
if (!unibi_get_ext_str(tui->ut, (unsigned)tui->unibi_ext.set_title)) {
return;
}
if (title.size > 0) {
@@ -1542,9 +1543,9 @@ void tui_set_title(TUIData *tui, String title)
unibi_out_ext(tui, tui->unibi_ext.save_title);
tui->title_enabled = true;
}
unibi_out(tui, unibi_to_status_line);
out(tui, title.data, title.size);
unibi_out(tui, unibi_from_status_line);
UNIBI_SET_NUM_VAR(tui->params[0], 0);
UNIBI_SET_STR_VAR(tui->params[1], title.data);
unibi_out_ext(tui, tui->unibi_ext.set_title);
} else if (tui->title_enabled) {
// Restore title/icon from the "stack". #4063
unibi_out_ext(tui, tui->unibi_ext.restore_title);
@@ -1762,12 +1763,17 @@ static void unibi_goto(TUIData *tui, int row, int col)
memset(&vars, 0, sizeof(vars)); \
tui->cork = true; \
retry: \
/* Copy parameters on every retry, as unibi_format() may modify them. */ \
memcpy(params, tui->params, sizeof(params)); \
unibi_format(vars, vars + 26, str, params, out, tui, pad, tui); \
if (tui->overflow) { \
tui->bufpos = orig_pos; \
flush_buf(tui); \
goto retry; \
/* If orig_pos is 0, there's nothing to flush and retrying won't work. */ \
/* TODO(zeertzjq): should this situation still be handled? */ \
if (orig_pos > 0) { \
flush_buf(tui); \
goto retry; \
} \
} \
tui->cork = false; \
} \
@@ -1799,6 +1805,7 @@ static void out(void *ctx, const char *str, size_t len)
}
flush_buf(tui);
}
// TODO(zeertzjq): handle string longer than buffer size? #30794
memcpy(tui->buf + tui->bufpos, str, len);
tui->bufpos += len;
@@ -2337,6 +2344,19 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in
tui->unibi_ext.save_title = (int)unibi_add_ext_str(ut, "ext.save_title", "\x1b[22;0t");
tui->unibi_ext.restore_title = (int)unibi_add_ext_str(ut, "ext.restore_title", "\x1b[23;0t");
const char *tsl = unibi_get_str(ut, unibi_to_status_line);
const char *fsl = unibi_get_str(ut, unibi_from_status_line);
if (tsl != NULL && fsl != NULL) {
// Add a single extended capability for the whole sequence to set title,
// as it is usually an OSC sequence that cannot be cut in half.
// Use %p2 for the title string, as to_status_line may take an argument.
size_t set_title_len = strlen(tsl) + strlen("%p2%s") + strlen(fsl);
char *set_title = xmallocz(set_title_len);
snprintf(set_title, set_title_len + 1, "%s%s%s", tsl, "%p2%s", fsl);
tui->unibi_ext.set_title = (int)unibi_add_ext_str(ut, "ext.set_title", set_title);
tui->set_title = set_title;
}
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
tui->unibi_ext.enable_lr_margin =

View File

@@ -41,6 +41,15 @@ M.vars = {
included here, because it will be executed anyway.
]=],
},
cmdbang = {
type = 'integer',
desc = [=[
Set like v:cmdarg for a file read/write command. When a "!"
was used the value is 1, otherwise it is 0. Note that this
can only be used in autocommands. For user commands |<bang>|
can be used.
]=],
},
collate = {
type = 'string',
desc = [=[
@@ -53,15 +62,6 @@ M.vars = {
See |multi-lang|.
]=],
},
cmdbang = {
type = 'integer',
desc = [=[
Set like v:cmdarg for a file read/write command. When a "!"
was used the value is 1, otherwise it is 0. Note that this
can only be used in autocommands. For user commands |<bang>|
can be used.
]=],
},
completed_item = {
desc = [=[
Dictionary containing the |complete-items| for the most
@@ -118,15 +118,6 @@ M.vars = {
VimLeave autocommands will not be executed.
]=],
},
exiting = {
desc = [=[
Exit code, or |v:null| before invoking the |VimLeavePre|
and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
Example: >vim
:au VimLeave * echo "Exit value is " .. v:exiting
<
]=],
},
echospace = {
type = 'integer',
desc = [=[
@@ -242,18 +233,13 @@ M.vars = {
or |expr7| when used with numeric operators). Read-only.
]=],
},
fcs_reason = {
type = 'string',
exiting = {
desc = [=[
The reason why the |FileChangedShell| event was triggered.
Can be used in an autocommand to decide what to do and/or what
to set v:fcs_choice to. Possible values:
deleted file no longer exists
conflict file contents, mode or timestamp was
changed and buffer is modified
changed file contents has changed
mode mode of file changed
time only file timestamp changed
Exit code, or |v:null| before invoking the |VimLeavePre|
and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
Example: >vim
:au VimLeave * echo "Exit value is " .. v:exiting
<
]=],
},
fcs_choice = {
@@ -279,6 +265,20 @@ M.vars = {
Vim behaves like it is empty, there is no warning message.
]=],
},
fcs_reason = {
type = 'string',
desc = [=[
The reason why the |FileChangedShell| event was triggered.
Can be used in an autocommand to decide what to do and/or what
to set v:fcs_choice to. Possible values:
deleted file no longer exists
conflict file contents, mode or timestamp was
changed and buffer is modified
changed file contents has changed
mode mode of file changed
time only file timestamp changed
]=],
},
fname = {
type = 'string',
desc = [=[
@@ -286,6 +286,13 @@ M.vars = {
detected. Empty otherwise.
]=],
},
fname_diff = {
type = 'string',
desc = [=[
The name of the diff (patch) file. Only valid while
evaluating 'patchexpr'.
]=],
},
fname_in = {
type = 'string',
desc = [=[
@@ -297,6 +304,13 @@ M.vars = {
And set to the swap file name for |SwapExists|.
]=],
},
fname_new = {
type = 'string',
desc = [=[
The name of the new version of the file. Only valid while
evaluating 'diffexpr'.
]=],
},
fname_out = {
type = 'string',
desc = [=[
@@ -312,20 +326,6 @@ M.vars = {
file and different from v:fname_in.
]=],
},
fname_new = {
type = 'string',
desc = [=[
The name of the new version of the file. Only valid while
evaluating 'diffexpr'.
]=],
},
fname_diff = {
type = 'string',
desc = [=[
The name of the diff (patch) file. Only valid while
evaluating 'patchexpr'.
]=],
},
folddashes = {
type = 'string',
desc = [=[
@@ -334,13 +334,6 @@ M.vars = {
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
foldlevel = {
type = 'integer',
desc = [=[
Used for 'foldtext': foldlevel of closed fold.
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
foldend = {
type = 'integer',
desc = [=[
@@ -348,6 +341,13 @@ M.vars = {
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
foldlevel = {
type = 'integer',
desc = [=[
Used for 'foldtext': foldlevel of closed fold.
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
foldstart = {
type = 'integer',
desc = [=[
@@ -434,6 +434,22 @@ M.vars = {
2147483647 on all systems.
]=],
},
mouse_col = {
type = 'integer',
desc = [=[
Column number for a mouse click obtained with |getchar()|.
This is the screen column number, like with |virtcol()|. The
value is zero when there was no mouse button click.
]=],
},
mouse_lnum = {
type = 'integer',
desc = [=[
Line number for a mouse click obtained with |getchar()|.
This is the text line number, not the screen line number. The
value is zero when there was no mouse button click.
]=],
},
mouse_win = {
type = 'integer',
desc = [=[
@@ -449,22 +465,6 @@ M.vars = {
The value is zero when there was no mouse button click.
]=],
},
mouse_lnum = {
type = 'integer',
desc = [=[
Line number for a mouse click obtained with |getchar()|.
This is the text line number, not the screen line number. The
value is zero when there was no mouse button click.
]=],
},
mouse_col = {
type = 'integer',
desc = [=[
Column number for a mouse click obtained with |getchar()|.
This is the screen column number, like with |virtcol()|. The
value is zero when there was no mouse button click.
]=],
},
msgpack_types = {
desc = [=[
Dictionary containing msgpack types used by |msgpackparse()|
@@ -515,51 +515,6 @@ M.vars = {
than String this will cause trouble.
]=],
},
option_new = {
desc = [=[
New value of the option. Valid while executing an |OptionSet|
autocommand.
]=],
},
option_old = {
desc = [=[
Old value of the option. Valid while executing an |OptionSet|
autocommand. Depending on the command used for setting and the
kind of option this is either the local old value or the
global old value.
]=],
},
option_oldlocal = {
desc = [=[
Old local value of the option. Valid while executing an
|OptionSet| autocommand.
]=],
},
option_oldglobal = {
desc = [=[
Old global value of the option. Valid while executing an
|OptionSet| autocommand.
]=],
},
option_type = {
type = 'string',
desc = [=[
Scope of the set command. Valid while executing an
|OptionSet| autocommand. Can be either "global" or "local"
]=],
},
option_command = {
type = 'string',
desc = [=[
Command used to set the option. Valid while executing an
|OptionSet| autocommand.
value option was set via ~
"setlocal" |:setlocal| or `:let l:xxx`
"setglobal" |:setglobal| or `:let g:xxx`
"set" |:set| or |:let|
"modeline" |modeline|
]=],
},
operator = {
type = 'string',
desc = [=[
@@ -577,6 +532,51 @@ M.vars = {
Read-only.
]=],
},
option_command = {
type = 'string',
desc = [=[
Command used to set the option. Valid while executing an
|OptionSet| autocommand.
value option was set via ~
"setlocal" |:setlocal| or `:let l:xxx`
"setglobal" |:setglobal| or `:let g:xxx`
"set" |:set| or |:let|
"modeline" |modeline|
]=],
},
option_new = {
desc = [=[
New value of the option. Valid while executing an |OptionSet|
autocommand.
]=],
},
option_old = {
desc = [=[
Old value of the option. Valid while executing an |OptionSet|
autocommand. Depending on the command used for setting and the
kind of option this is either the local old value or the
global old value.
]=],
},
option_oldglobal = {
desc = [=[
Old global value of the option. Valid while executing an
|OptionSet| autocommand.
]=],
},
option_oldlocal = {
desc = [=[
Old local value of the option. Valid while executing an
|OptionSet| autocommand.
]=],
},
option_type = {
type = 'string',
desc = [=[
Scope of the set command. Valid while executing an
|OptionSet| autocommand. Can be either "global" or "local"
]=],
},
prevcount = {
type = 'integer',
desc = [=[
@@ -640,6 +640,17 @@ M.vars = {
hit-enter prompt.
]=],
},
searchforward = {
type = 'integer',
desc = [=[
Search direction: 1 after a forward search, 0 after a
backward search. It is reset to forward when directly setting
the last search pattern, see |quote/|.
Note that the value is restored when returning from a
function. |function-search-undo|.
Read-write.
]=],
},
servername = {
type = 'string',
desc = [=[
@@ -663,17 +674,6 @@ M.vars = {
Note the contents of $NVIM may change in the future.
]=],
},
searchforward = {
type = 'integer',
desc = [=[
Search direction: 1 after a forward search, 0 after a
backward search. It is reset to forward when directly setting
the last search pattern, see |quote/|.
Note that the value is restored when returning from a
function. |function-search-undo|.
Read-write.
]=],
},
shell_error = {
type = 'integer',
desc = [=[
@@ -708,14 +708,6 @@ M.vars = {
<
]=],
},
swapname = {
type = 'string',
desc = [=[
Name of the swapfile found.
Only valid during |SwapExists| event.
Read-only.
]=],
},
swapchoice = {
type = 'string',
desc = [=[
@@ -742,6 +734,14 @@ M.vars = {
For ":edit +cmd file" the value is ":cmd\r".
]=],
},
swapname = {
type = 'string',
desc = [=[
Name of the swapfile found.
Only valid during |SwapExists| event.
Read-only.
]=],
},
t_blob = {
type = 'integer',
tags = { 'v:t_TYPE' },
@@ -775,15 +775,6 @@ M.vars = {
type = 'integer',
desc = 'Value of |String| type. Read-only. See: |type()|',
},
termresponse = {
type = 'string',
desc = [=[
The value of the most recent OSC or DCS control sequence
received by Nvim from the terminal. This can be read in a
|TermResponse| event handler after querying the terminal using
another escape sequence.
]=],
},
termrequest = {
type = 'string',
desc = [=[
@@ -793,6 +784,15 @@ M.vars = {
to queries from embedded applications.
]=],
},
termresponse = {
type = 'string',
desc = [=[
The value of the most recent OSC or DCS control sequence
received by Nvim from the terminal. This can be read in a
|TermResponse| event handler after querying the terminal using
another escape sequence.
]=],
},
testing = {
desc = [=[
Must be set before using `test_garbagecollect_now()`.
@@ -848,6 +848,13 @@ M.vars = {
<
]=],
},
vim_did_enter = {
type = 'integer',
desc = [=[
0 during startup, 1 just before |VimEnter|.
Read-only.
]=],
},
virtnum = {
type = 'integer',
desc = [=[
@@ -858,13 +865,6 @@ M.vars = {
Read-only.
]=],
},
vim_did_enter = {
type = 'integer',
desc = [=[
0 during startup, 1 just before |VimEnter|.
Read-only.
]=],
},
warningmsg = {
type = 'string',
desc = [=[

View File

@@ -273,54 +273,72 @@ describe('autocmd api', function()
eq({}, api.nvim_get_autocmds({ event = 'User', pattern = 'Test' }))
end)
it('receives an args table', function()
local function test_autocmd_args(event)
local function get_amatch(pat)
return event == 'User' and pat or vim.fs.normalize(n.fn.fnamemodify(pat, ':p'))
end
local group_id = api.nvim_create_augroup('TestGroup', {})
-- Having an existing autocmd calling expand("<afile>") shouldn't change args #18964
api.nvim_create_autocmd('User', {
api.nvim_create_autocmd(event, {
group = 'TestGroup',
pattern = 'Te*',
command = 'call expand("<afile>")',
})
local autocmd_id = exec_lua [[
return vim.api.nvim_create_autocmd("User", {
local autocmd_id = exec_lua(([[
return vim.api.nvim_create_autocmd(%q, {
group = "TestGroup",
pattern = "Te*",
callback = function(args)
vim.g.autocmd_args = args
end,
})
]]
]]):format(event))
api.nvim_exec_autocmds('User', { pattern = 'Test pattern' })
local exec_pat = 'Test pattern'
local amatch = get_amatch(exec_pat)
api.nvim_exec_autocmds(event, { pattern = exec_pat })
eq({
id = autocmd_id,
group = group_id,
event = 'User',
match = 'Test pattern',
file = 'Test pattern',
event = event,
match = amatch,
file = exec_pat,
buf = 1,
}, api.nvim_get_var('autocmd_args'))
-- Test without a group
autocmd_id = exec_lua [[
return vim.api.nvim_create_autocmd("User", {
autocmd_id = exec_lua(([[
return vim.api.nvim_create_autocmd(%q, {
pattern = "*",
callback = function(args)
vim.g.autocmd_args = args
end,
})
]]
]]):format(event))
api.nvim_exec_autocmds('User', { pattern = 'some_pat' })
exec_pat = 'some_pat'
amatch = get_amatch(exec_pat)
api.nvim_exec_autocmds(event, { pattern = exec_pat })
eq({
id = autocmd_id,
group = nil,
event = 'User',
match = 'some_pat',
file = 'some_pat',
event = event,
match = amatch,
file = exec_pat,
buf = 1,
}, api.nvim_get_var('autocmd_args'))
end
describe('receives correct args table', function()
it('for event that takes non-file pattern', function()
test_autocmd_args('User')
end)
it('for event that takes file pattern', function()
test_autocmd_args('BufEnter')
end)
end)
it('can receive arbitrary data', function()

View File

@@ -249,7 +249,7 @@ describe('API/extmarks', function()
set_extmark(ns, 2, 1, 0, { right_gravity = false })
eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
feed('u')
eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
eq({ { 1, 0, 0 }, { 2, 0, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
@@ -1797,6 +1797,16 @@ describe('API/extmarks', function()
eq({}, get_extmark_by_id(ns, 4, {}))
end)
it('no crash checking invalidated flag of sign pair end key #31856', function()
api.nvim_buf_set_lines(0, 0, 1, false, { '', '' })
api.nvim_set_option_value('signcolumn', 'auto:2', {})
set_extmark(ns, 1, 0, 0, { sign_text = 'S1', invalidate = true, end_row = 0 })
set_extmark(ns, 2, 1, 0, { sign_text = 'S2', end_row = 1 })
command('d')
api.nvim_buf_clear_namespace(0, ns, 0, -1)
n.assert_alive()
end)
it('can set a URL', function()
local url1 = 'https://example.com'
local url2 = 'http://127.0.0.1'

View File

@@ -309,6 +309,15 @@ describe('API: set highlight', function()
eq({ underdotted = true }, api.nvim_get_hl_by_name('Test_hl', true))
end)
it('can set all underline cterm attributes #31385', function()
local ns = get_ns()
local attrs = { 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed' }
for _, attr in ipairs(attrs) do
api.nvim_set_hl(ns, 'Test_' .. attr, { cterm = { [attr] = true } })
eq({ [attr] = true }, api.nvim_get_hl_by_name('Test_' .. attr, false))
end
end)
it('can set a highlight in the global namespace', function()
api.nvim_set_hl(0, 'Test_hl', highlight2_config)
eq(

View File

@@ -43,7 +43,7 @@ describe("api_info()['version']", function()
eq(0, fn.has('nvim-' .. major .. '.' .. minor .. '.' .. (patch + 1)))
eq(0, fn.has('nvim-' .. major .. '.' .. (minor + 1) .. '.' .. patch))
eq(0, fn.has('nvim-' .. (major + 1) .. '.' .. minor .. '.' .. patch))
assert(build == nil or type(build) == 'string')
assert(build == vim.NIL or type(build) == 'string')
end)
end)

View File

@@ -198,8 +198,11 @@ it('autocmd TermEnter, TermLeave', function()
end)
describe('autocmd TextChangedT', function()
clear()
local screen = tt.screen_setup()
local screen
before_each(function()
clear()
screen = tt.screen_setup()
end)
it('works', function()
command('autocmd TextChangedT * ++once let g:called = 1')
@@ -210,9 +213,11 @@ describe('autocmd TextChangedT', function()
end)
it('cannot delete terminal buffer', function()
command([[autocmd TextChangedT * call nvim_input('<CR>') | bwipe!]])
command('autocmd TextChangedT * bwipe!')
tt.feed_data('a')
screen:expect({ any = 'E937: ' })
feed('<CR>')
command('autocmd! TextChangedT')
matches(
'^E937: Attempt to delete a buffer that is in use: term://',
api.nvim_get_vvar('errmsg')

View File

@@ -943,6 +943,40 @@ describe('jobs', function()
feed('<CR>')
fn.jobstop(api.nvim_get_var('id'))
end)
it('does not set UI busy with zero timeout #31712', function()
local screen = Screen.new(50, 6)
screen:attach()
command([[let g:id = jobstart(['sleep', '0.3'])]])
local busy = 0
screen._handle_busy_start = (function(orig)
return function()
orig(screen)
busy = busy + 1
end
end)(screen._handle_busy_start)
source([[
func PrintAndPoll()
echon "aaa\nbbb"
call jobwait([g:id], 0)
echon "\nccc"
endfunc
]])
feed_command('call PrintAndPoll()')
screen:expect {
grid = [[
|
{3: }|
aaa |
bbb |
ccc |
{6:Press ENTER or type command to continue}^ |
]],
}
feed('<CR>')
fn.jobstop(api.nvim_get_var('id'))
eq(0, busy)
end)
end)
pending('exit event follows stdout, stderr', function()

View File

@@ -189,8 +189,30 @@ describe('command-line option', function()
it('nvim -v, :version', function()
matches('Run ":verbose version"', fn.execute(':version'))
matches('Compilation: .*Run :checkhealth', fn.execute(':verbose version'))
matches('fall%-back for %$VIM: .*Run :checkhealth', fn.execute(':verbose version'))
matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' }))
matches('Compilation: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' }))
matches('fall%-back for %$VIM: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' }))
end)
if is_os('win') then
for _, prefix in ipairs({ '~/', '~\\' }) do
it('expands ' .. prefix .. ' on Windows', function()
local fname = os.getenv('USERPROFILE') .. '\\nvim_test.txt'
finally(function()
os.remove(fname)
end)
write_file(fname, 'some text')
eq(
'some text',
fn.system({
nvim_prog_abs(),
'-es',
'+%print',
'+q',
prefix .. 'nvim_test.txt',
}):gsub('\n', '')
)
end)
end
end
end)

View File

@@ -82,6 +82,25 @@ describe('startup', function()
assert_log("require%('vim%._editor'%)", testfile, 100)
end)
it('--startuptime does not crash on error #31125', function()
eq(
"E484: Can't open file .",
fn.system({
nvim_prog,
'-u',
'NONE',
'-i',
'NONE',
'--headless',
'--startuptime',
'.',
'-c',
'42cquit',
})
)
eq(42, api.nvim_get_vvar('shell_error'))
end)
it('-D does not hang #12647', function()
clear()
local screen

View File

@@ -1151,7 +1151,7 @@ describe('completion', function()
command([[
call setline(1, ['aaaa'])
let ns_id = nvim_create_namespace('extmark')
let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error'})
let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error' })
let mark = nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })
inoremap <C-x> <C-r>=Complete()<CR>
function Complete() abort
@@ -1188,5 +1188,28 @@ describe('completion', function()
aaaaa |
{5:-- INSERT --} |
]])
-- Also when completion leader is changed #31384
feed('<Esc>hi<C-N><C-P>a')
screen:expect({
grid = [[
{9:aa}a^aa |
{4:aaaa } |
{4:aaaaa } |
{5:-- Keyword completion (^N^P) }{19:Back at original} |
]],
})
-- But still grows with end_right_gravity #31437
command(
"call nvim_buf_set_extmark(0, ns_id, 1, 0, { 'end_col':2, 'hl_group':'Error', 'end_right_gravity': 1 })"
)
feed('<Esc>ji<C-N>a')
screen:expect({
grid = [[
{9:aa}aaa |
{9:aaa}^aa |
aaaaa |
{5:-- INSERT --} |
]],
})
end)
end)

View File

@@ -0,0 +1,81 @@
--
-- Tests for default autocmds, mappings, commands, and menus.
--
-- See options/defaults_spec.lua for default options and environment decisions.
--
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
describe('default', function()
describe('key mappings', function()
describe('Visual mode search mappings', function()
it('handle various chars properly', function()
n.clear({ args_rm = { '--cmd' } })
local screen = Screen.new(60, 8)
screen:attach()
screen:set_default_attr_ids({
[1] = { foreground = Screen.colors.NvimDarkGray4 },
[2] = {
foreground = Screen.colors.NvimDarkGray3,
background = Screen.colors.NvimLightGray3,
},
[3] = {
foreground = Screen.colors.NvimLightGrey1,
background = Screen.colors.NvimDarkYellow,
},
[4] = {
foreground = Screen.colors.NvimDarkGrey1,
background = Screen.colors.NvimLightYellow,
},
})
n.api.nvim_buf_set_lines(0, 0, -1, true, {
[[testing <CR> /?\!1]],
[[testing <CR> /?\!2]],
[[testing <CR> /?\!3]],
[[testing <CR> /?\!4]],
})
n.feed('gg0vf!o*')
screen:expect([[
{3:testing <CR> /?\!}1 |
{4:^testing <CR> /?\!}2 |
{3:testing <CR> /?\!}3 |
{3:testing <CR> /?\!}4 |
{1:~ }|*2
{2:[No Name] [+] 2,1 All}|
/\Vtesting <CR> \/?\\! [2/4] |
]])
n.feed('n')
screen:expect([[
{3:testing <CR> /?\!}1 |
{3:testing <CR> /?\!}2 |
{4:^testing <CR> /?\!}3 |
{3:testing <CR> /?\!}4 |
{1:~ }|*2
{2:[No Name] [+] 3,1 All}|
/\Vtesting <CR> \/?\\! [3/4] |
]])
n.feed('G0vf!o#')
screen:expect([[
{3:testing <CR> /?\!}1 |
{3:testing <CR> /?\!}2 |
{4:^testing <CR> /?\!}3 |
{3:testing <CR> /?\!}4 |
{1:~ }|*2
{2:[No Name] [+] 3,1 All}|
?\Vtesting <CR> /?\\! [3/4] |
]])
n.feed('n')
screen:expect([[
{3:testing <CR> /?\!}1 |
{4:^testing <CR> /?\!}2 |
{3:testing <CR> /?\!}3 |
{3:testing <CR> /?\!}4 |
{1:~ }|*2
{2:[No Name] [+] 2,1 All}|
?\Vtesting <CR> /?\\! [2/4] |
]])
end)
end)
end)
end)

View File

@@ -386,6 +386,21 @@ function tests.check_forward_content_modified()
}
end
function tests.check_forward_server_cancelled()
skeleton {
on_init = function()
return { capabilities = {} }
end,
body = function()
expect_request('error_code_test', function()
return { code = -32802 }, nil, { method = 'error_code_test', client_id = 1 }
end)
expect_notification('finish')
notify('finish')
end,
}
end
function tests.check_pending_request_tracked()
skeleton {
on_init = function(_)

View File

@@ -15,7 +15,6 @@ local clear = n.clear
local insert = n.insert
local command = n.command
local write_file = t.write_file
local expect_exit = n.expect_exit
local mkdir = t.mkdir
local function ls_dir_sorted(dirname)
@@ -44,7 +43,9 @@ describe("'directory' option", function()
clear()
end)
teardown(function()
expect_exit(command, 'qall!')
command('%bwipe!')
api.nvim_set_option_value('swapfile', false, {})
api.nvim_set_option_value('directory', '.', {})
n.rmdir('Xtest.je')
n.rmdir('Xtest2')
os.remove('Xtest1')
@@ -57,7 +58,6 @@ describe("'directory' option", function()
line 3 Abcdefghij
end of testfile]])
api.nvim_set_option_value('swapfile', true, {})
api.nvim_set_option_value('swapfile', true, {})
api.nvim_set_option_value('directory', '.', {})

View File

@@ -89,6 +89,34 @@ describe('messages', function()
]])
end)
-- oldtest: Test_mode_cleared_after_silent_message()
it('mode is cleared properly after slient message', function()
screen = Screen.new(60, 10)
screen:attach()
exec([[
edit XsilentMessageMode.txt
call setline(1, 'foobar')
autocmd TextChanged * silent update
]])
finally(function()
os.remove('XsilentMessageMode.txt')
end)
feed('v')
screen:expect([[
^foobar |
{1:~ }|*8
{5:-- VISUAL --} |
]])
feed('d')
screen:expect([[
^oobar |
{1:~ }|*8
|
]])
end)
describe('more prompt', function()
before_each(function()
command('set more')

View File

@@ -1306,16 +1306,15 @@ describe('smoothscroll', function()
set smoothscroll scrolloff=3
call setline(1, ['one', 'two long '->repeat(100), 'three', 'four', 'five', 'six'])
]])
--FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans
feed(':norm j721|<CR>')
screen:expect([[
two long two long two long two long two |
{1:<<<}two long two long two long two long t|
wo long two long two long two long two l|
ong two long two long two long two long |
^two long two long two long two long two |
long two long two long two long two long|
two long two long two long two long two|
^ long two long two long two long two lon|
g two long two long two long two long tw|
o long two long two long two long two lo|
ng two long two long two long two long t|
long two long two long two long two lon|
:norm j721| |
]])
feed('gj')
@@ -1374,15 +1373,14 @@ describe('smoothscroll', function()
:norm j721| |
]])
feed('gk')
--FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans
screen:expect([[
{1:<<<}long two long two long two long two l|
ong two long two long two long two long |
two long two long two long two long two |
long two long two long two long two long|
two long two long two long two long two|
long two long two long two long two lon|
g two long two long two long two long tw|
o long two long two long two long two lo|
^ng two long two long two long two long t|
^g two long two long |
:norm j721| |
]])
end)

View File

@@ -300,6 +300,24 @@ describe('lua buffer event callbacks: on_lines', function()
n.assert_alive()
end)
it('no invalid lnum error for closed memline in on_detach #31251', function()
eq(vim.NIL, exec_lua('return _G.did_detach'))
exec_lua([[
vim.api.nvim_buf_set_lines(0, 0, -1, false, { '' })
local bufname = 'buf2'
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(buf, bufname)
vim.bo[buf].bufhidden = 'wipe'
vim.cmd('vertical diffsplit '..bufname)
vim.api.nvim_buf_attach(0, false, { on_detach = function()
vim.cmd("redraw")
_G.did_detach = true
end})
vim.cmd.bdelete()
]])
eq(true, exec_lua('return _G.did_detach'))
end)
it('#12718 lnume', function()
api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' })
exec_lua([[

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