Compare commits

..

33 Commits

Author SHA1 Message Date
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
42 changed files with 663 additions and 160 deletions

View File

@@ -30,7 +30,7 @@ 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 --break-system-packages pynvim

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,7 +89,6 @@ 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:
@@ -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

@@ -107,6 +107,7 @@ jobs:
{ runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON },
{ runner: ubuntu-24.04, os: ubuntu, flavor: 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 },
@@ -203,37 +204,6 @@ jobs:
windows:
uses: ./.github/workflows/test_windows.yml
# This job tests the following things:
# - Check if 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-24.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: RelWithDebInfo
run: cmake --build build --config RelWithDebInfo
- name: MinSizeRel
run: cmake --build build --config MinSizeRel
with-external-deps:
runs-on: ubuntu-24.04
timeout-minutes: 10

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

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

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

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

@@ -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 24.04
macOS (Intel) 1 >= 11 macOS 12
macOS (M1) 1 >= 11 macOS 15
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

View File

@@ -186,7 +186,7 @@ function vim.show_pos(bufnr, row, col, filter)
capture,
string.format(
'priority: %d language: %s',
capture.metadata.priority or vim.hl.priorities.treesitter,
capture.metadata.priority or vim.highlight.priorities.treesitter,
capture.lang
)
)

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

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

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

@@ -26,6 +26,7 @@
</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"/>

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

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

@@ -731,6 +731,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 +773,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}

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

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

@@ -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);
}
}
@@ -387,7 +389,8 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
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)
@@ -402,6 +405,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
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);
}

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();

View File

@@ -2523,7 +2523,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

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

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

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

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

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

@@ -27,6 +27,26 @@ describe('thread', function()
})
end)
it('handle non-string error', function()
exec_lua [[
local thread = vim.uv.new_thread(function()
error()
end)
vim.uv.thread_join(thread)
]]
screen:expect([[
|
{1:~ }|*5
{2: }|
{3:Error in luv thread:} |
{3:[NULL]} |
{4:Press ENTER or type command to continue}^ |
]])
feed('<cr>')
assert_alive()
end)
it('entry func is executed in protected mode', function()
exec_lua [[
local thread = vim.uv.new_thread(function()

View File

@@ -3357,6 +3357,19 @@ describe('LSP', function()
command('set display+=uhex')
eq({ 40, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
end)
it('handles empty line', function()
exec_lua([[
_G.contents = {
'',
}
]])
eq(
{ 20, 1 },
exec_lua([[
return { vim.lsp.util._make_floating_popup_size(_G.contents, { width = 20 }) }
]])
)
end)
end)
describe('lsp.util.trim.trim_empty_lines', function()

View File

@@ -646,6 +646,67 @@ t3]])
}
end)
it('does not extend closed fold with `o`/`O`', function()
local screen = Screen.new(60, 24)
screen:attach()
insert(test_text)
parse('c')
command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1]])
feed('5ggzco')
screen:expect({
grid = [[
{7:-}void ui_refresh(void) |
{7:│}{ |
{7:│} int width = INT_MAX, height = INT_MAX; |
{7:│} bool ext_widgets[kUIExtCount]; |
{7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}|
{7:│}^ |
{7:│} |
{7:│} bool inclusive = ui_override(); |
{7:-} for (size_t i = 0; i < ui_count; i++) { |
{7:2} UI *ui = uis[i]; |
{7:2} width = MIN(ui->width, width); |
{7:2} height = MIN(ui->height, height); |
{7:2} foo = BAR(ui->bazaar, bazaar); |
{7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
{7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
{7:3} } |
{7:2} } |
{7:│}} |
{1:~ }|*5
{5:-- INSERT --} |
]],
})
feed('<Esc>O')
screen:expect({
grid = [[
{7:-}void ui_refresh(void) |
{7:│}{ |
{7:│} int width = INT_MAX, height = INT_MAX; |
{7:│} bool ext_widgets[kUIExtCount]; |
{7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}|
{7:│}^ |
{7:│} |*2
{7:│} bool inclusive = ui_override(); |
{7:-} for (size_t i = 0; i < ui_count; i++) { |
{7:2} UI *ui = uis[i]; |
{7:2} width = MIN(ui->width, width); |
{7:2} height = MIN(ui->height, height); |
{7:2} foo = BAR(ui->bazaar, bazaar); |
{7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
{7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
{7:3} } |
{7:2} } |
{7:│}} |
{1:~ }|*4
{5:-- INSERT --} |
]],
})
end)
it("doesn't open folds that are not touched", function()
local screen = Screen.new(40, 8)
screen:set_default_attr_ids({
@@ -674,7 +735,7 @@ t2]])
grid = [[
{1:-}# h1 |
{1:│}t1 |
{1:}^ |
{1:-}^ |
{1:+}{2:+-- 2 lines: # h2·····················}|
{3:~ }|*3
{4:-- INSERT --} |

View File

@@ -2598,4 +2598,257 @@ describe('ext_multigrid', function()
]])
eq(1, api.nvim_get_option_value('cmdheight', {}))
end)
describe('centered cursorline', function()
before_each(function()
-- Force a centered cursorline, this caused some redrawing problems described in #30576.
-- Most importantly, win_viewport was not received in time, and sum_scroll_delta did not refresh.
command('set cursorline scrolloff=9999')
end)
it('insert line scrolls correctly', function()
for i = 1, 11 do
insert('line' .. i .. '\n')
end
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
line1 |
line2 |
line3 |
line4 |
line5 |
line6 |
line7 |
line8 |
line9 |
line10 |
line11 |
{23:^ }|
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 0, botline = 12, curline = 11, curcol = 0, linecount = 12, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
insert('line12\n')
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
line2 |
line3 |
line4 |
line5 |
line6 |
line7 |
line8 |
line9 |
line10 |
line11 |
line12 |
{23:^ }|
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 1, botline = 13, curline = 12, curcol = 0, linecount = 13, sum_scroll_delta = 1};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
end)
it('got to top scrolls correctly', function()
for i = 1, 20 do
insert('line' .. i .. '\n')
end
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
line10 |
line11 |
line12 |
line13 |
line14 |
line15 |
line16 |
line17 |
line18 |
line19 |
line20 |
{23:^ }|
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
feed('gg')
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
{23:^line1 }|
line2 |
line3 |
line4 |
line5 |
line6 |
line7 |
line8 |
line9 |
line10 |
line11 |
line12 |
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 0, botline = 13, curline = 0, curcol = 0, linecount = 21, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
end)
it('scrolls in the middle', function()
for i = 1, 20 do
insert('line' .. i .. '\n')
end
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
line10 |
line11 |
line12 |
line13 |
line14 |
line15 |
line16 |
line17 |
line18 |
line19 |
line20 |
{23:^ }|
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
feed('M')
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
line10 |
line11 |
line12 |
line13 |
line14 |
{23:^line15 }|
line16 |
line17 |
line18 |
line19 |
line20 |
|
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 9, botline = 21, curline = 14, curcol = 0, linecount = 21, sum_scroll_delta = 9};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
feed('k')
screen:expect({
grid = [[
## grid 1
[2:-----------------------------------------------------]|*12
{11:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
line9 |
line10 |
line11 |
line12 |
line13 |
{23:^line14 }|
line15 |
line16 |
line17 |
line18 |
line19 |
line20 |
## grid 3
|
]], win_viewport={
[2] = {win = 1000, topline = 8, botline = 21, curline = 13, curcol = 0, linecount = 21, sum_scroll_delta = 8};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
}
}})
end)
end)
end)

View File

@@ -1338,11 +1338,27 @@ func Test_scroll_in_ex_mode()
call writefile(['done'], 'Xdone')
qa!
END
call writefile(lines, 'Xscript')
call writefile(lines, 'Xscript', 'D')
call assert_equal(1, RunVim([], [], '--clean -X -Z -e -s -S Xscript'))
call assert_equal(['done'], readfile('Xdone'))
call delete('Xscript')
call delete('Xdone')
endfunc
func Test_scroll_and_paste_in_ex_mode()
throw 'Skipped: does not work when Nvim is run from :!'
" This used to crash because of moving cursor to line 0.
let lines =<< trim END
v/foo/vi|YY9PYQ
v/bar/vi|YY9PYQ
v/bar/exe line('.') == 1 ? "vi|Y\<C-B>9PYQ" : "vi|YQ"
call writefile(['done'], 'Xdone')
qa!
END
call writefile(lines, 'Xscript', 'D')
call assert_equal(1, RunVim([], [], '-u NONE -i NONE -n -X -Z -e -s -S Xscript'))
call assert_equal(['done'], readfile('Xdone'))
call delete('Xdone')
endfunc
@@ -4291,4 +4307,18 @@ func Test_scroll_longline_no_loop()
exe "normal! \<C-E>"
bwipe!
endfunc
" Test for go command
func Test_normal_go()
new
call setline(1, ['one two three four'])
call cursor(1, 5)
norm! dvgo
call assert_equal('wo three four', getline(1))
norm! ...
call assert_equal('three four', getline(1))
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab nofoldenable

View File

@@ -1195,7 +1195,6 @@ func Test_smooth_long_scrolloff()
END
call writefile(lines, 'XSmoothLongScrolloff', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothLongScrolloff', #{rows: 8, cols: 40})
"FIXME: empty screen due to reset_skipcol()/curs_columns() shenanigans
call term_sendkeys(buf, ":norm j721|\<CR>")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_1', {})
@@ -1215,7 +1214,6 @@ func Test_smooth_long_scrolloff()
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_6', {})
call term_sendkeys(buf, "gk")
"FIXME: empty screen due to reset_skipcol()/curs_columns() shenanigans
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_7', {})
call StopVimInTerminal(buf)