mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Compare commits
111 Commits
v0.10.2
...
release-0.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0c995c0efb | ||
![]() |
aab7129abe | ||
![]() |
52ad6adc8d | ||
![]() |
c5eeb1b9ee | ||
![]() |
3e7f0a13e1 | ||
![]() |
2010f398f4 | ||
![]() |
f0790c565c | ||
![]() |
ecaece926e | ||
![]() |
28a8d59cc7 | ||
![]() |
3c57ee079d | ||
![]() |
e6432b0094 | ||
![]() |
00d3956109 | ||
![]() |
d65ce60f49 | ||
![]() |
0f0959ca32 | ||
![]() |
6b6abb8969 | ||
![]() |
6ca2ef8dfe | ||
![]() |
3fd08c2eb2 | ||
![]() |
7e5b7ae4e0 | ||
![]() |
c40057f372 | ||
![]() |
c7bb6bbdea | ||
![]() |
c3866cea60 | ||
![]() |
d6da862ce0 | ||
![]() |
452ed57b71 | ||
![]() |
44c6fbaf9a | ||
![]() |
e96f75a4e6 | ||
![]() |
8d420a32db | ||
![]() |
fdcdf560da | ||
![]() |
22a327a20e | ||
![]() |
d63848c918 | ||
![]() |
a6c54fdfc1 | ||
![]() |
a7392c04d9 | ||
![]() |
7908900859 | ||
![]() |
a8eddf1eb1 | ||
![]() |
938a600847 | ||
![]() |
3a50639331 | ||
![]() |
f132efaefb | ||
![]() |
46cc8a52b2 | ||
![]() |
a3cc513b67 | ||
![]() |
a986048cb0 | ||
![]() |
d7ee06124d | ||
![]() |
ca10442e01 | ||
![]() |
4b25fe09cc | ||
![]() |
baaaf6a9e7 | ||
![]() |
e477ac7c45 | ||
![]() |
3b5c2213fd | ||
![]() |
5aabe5695f | ||
![]() |
b0b383bff9 | ||
![]() |
323c43e1c4 | ||
![]() |
2bc5e1be0f | ||
![]() |
87440e7bc5 | ||
![]() |
357ee88606 | ||
![]() |
6a6c6b2658 | ||
![]() |
79030bf196 | ||
![]() |
aa2b69b178 | ||
![]() |
b36cadcb8e | ||
![]() |
d8149e5af9 | ||
![]() |
4e1b1b6fd7 | ||
![]() |
9b5ee7df4e | ||
![]() |
1a030f6e04 | ||
![]() |
bf66871113 | ||
![]() |
424a452401 | ||
![]() |
01fe4fc589 | ||
![]() |
7abc58349e | ||
![]() |
8fbe3e3941 | ||
![]() |
71faa2be88 | ||
![]() |
650dcbbafe | ||
![]() |
6a63034b51 | ||
![]() |
b5b84b806a | ||
![]() |
950048b206 | ||
![]() |
7ca0408a1f | ||
![]() |
78a36cdd55 | ||
![]() |
694c3992ea | ||
![]() |
9695650c0c | ||
![]() |
7781111fef | ||
![]() |
4007c42b77 | ||
![]() |
584b811aee | ||
![]() |
a930b2666e | ||
![]() |
c36c4ddae2 | ||
![]() |
308e9719cf | ||
![]() |
e80e8a0980 | ||
![]() |
163a532cfa | ||
![]() |
1a12dea191 | ||
![]() |
6f2786433d | ||
![]() |
085f1cc99d | ||
![]() |
3c0e1a89d9 | ||
![]() |
57b0fecd47 | ||
![]() |
f8ee92feec | ||
![]() |
98ec48eefb | ||
![]() |
34a976ec2b | ||
![]() |
6a07b199ff | ||
![]() |
6550227110 | ||
![]() |
b7f025e45b | ||
![]() |
6c12cfe18c | ||
![]() |
7774ca9107 | ||
![]() |
348a939168 | ||
![]() |
9455686b6f | ||
![]() |
1a4e78832f | ||
![]() |
fb5a0e28db | ||
![]() |
b286ba419a | ||
![]() |
94f44122ad | ||
![]() |
0b0385ea6a | ||
![]() |
84bbbd9fbe | ||
![]() |
bbefbc995e | ||
![]() |
97aaea3478 | ||
![]() |
1a02f1835f | ||
![]() |
2d1a13bdf5 | ||
![]() |
27fca9c7d2 | ||
![]() |
5480c0bd75 | ||
![]() |
c257fe5582 | ||
![]() |
ee7885aa21 | ||
![]() |
82ea8a7c3f |
@@ -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
|
||||
|
6
.github/scripts/install_deps.sh
vendored
6
.github/scripts/install_deps.sh
vendored
@@ -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
|
||||
|
10
.github/scripts/reviewers_add.js
vendored
10
.github/scripts/reviewers_add.js
vendored
@@ -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");
|
||||
}
|
||||
|
||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -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"
|
||||
|
46
.github/workflows/notes.md
vendored
46
.github/workflows/notes.md
vendored
@@ -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}
|
||||
```
|
||||
|
80
.github/workflows/release.yml
vendored
80
.github/workflows/release.yml
vendored
@@ -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/*
|
||||
|
67
.github/workflows/test.yml
vendored
67
.github/workflows/test.yml
vendored
@@ -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
|
||||
|
7
.github/workflows/test_windows.yml
vendored
7
.github/workflows/test_windows.yml
vendored
@@ -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'
|
||||
|
2
BUILD.md
2
BUILD.md
@@ -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`.
|
||||
|
@@ -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.
|
||||
|
21
INSTALL.md
21
INSTALL.md
@@ -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.
|
||||
|
12
MAINTAIN.md
12
MAINTAIN.md
@@ -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,
|
||||
|
3
Makefile
3
Makefile
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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'.
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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|
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
6
runtime/lua/vim/_meta/api.lua
generated
6
runtime/lua/vim/_meta/api.lua
generated
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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))
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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|)
|
||||
|
@@ -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
|
||||
|
@@ -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),
|
||||
|
@@ -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,
|
||||
|
@@ -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]
|
||||
|
@@ -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%-._~!$&'()*+,;=:@/",
|
||||
|
@@ -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"/>
|
||||
|
@@ -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"
|
||||
|
@@ -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".)
|
||||
|
||||
|
@@ -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
4
runtime/windows_icon.rc
Normal 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"
|
@@ -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'
|
||||
|
@@ -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;
|
||||
|
@@ -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})
|
||||
|
@@ -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}
|
||||
|
@@ -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,
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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--;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)));
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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__); \
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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(®match, 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
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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))
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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 =
|
||||
|
@@ -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 = [=[
|
||||
|
@@ -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()
|
||||
|
@@ -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'
|
||||
|
@@ -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(
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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')
|
||||
|
@@ -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()
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
81
test/functional/editor/defaults_spec.lua
Normal file
81
test/functional/editor/defaults_spec.lua
Normal 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)
|
@@ -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(_)
|
||||
|
@@ -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', '.', {})
|
||||
|
||||
|
@@ -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')
|
||||
|
@@ -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)
|
||||
|
@@ -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
Reference in New Issue
Block a user