mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
Compare commits
174 Commits
v0.11.2
...
release-0.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8c311386c3 | ||
![]() |
4c8486e1f2 | ||
![]() |
d31953d532 | ||
![]() |
c5262c4ca8 | ||
![]() |
dd8e3d7aa5 | ||
![]() |
a7491e1457 | ||
![]() |
1063aff643 | ||
![]() |
e415fae42e | ||
![]() |
7b099d2b2b | ||
![]() |
cec0ecabd8 | ||
![]() |
edfb447ff8 | ||
![]() |
b032c2b53f | ||
![]() |
09f702bc13 | ||
![]() |
c4845f3a12 | ||
![]() |
a2603016ce | ||
![]() |
d70d469c04 | ||
![]() |
99817471d7 | ||
![]() |
4c5cb950c6 | ||
![]() |
ec8900f1e6 | ||
![]() |
a3590afba5 | ||
![]() |
e841d653af | ||
![]() |
6fd8ba05a6 | ||
![]() |
e6ea97a691 | ||
![]() |
3cf9dac2ba | ||
![]() |
8dd88056f1 | ||
![]() |
1bea812953 | ||
![]() |
fa64f2d09b | ||
![]() |
3ab06d5188 | ||
![]() |
37b2d42459 | ||
![]() |
53db7fc3ef | ||
![]() |
3343ee971b | ||
![]() |
abfbd155da | ||
![]() |
39ae9a9971 | ||
![]() |
5ec7d98857 | ||
![]() |
744d96bd76 | ||
![]() |
30b801eff2 | ||
![]() |
27282696fe | ||
![]() |
4b957a4d18 | ||
![]() |
819e545c28 | ||
![]() |
d21db345ef | ||
![]() |
bd4b45dd1b | ||
![]() |
6c2f06b537 | ||
![]() |
fb6c677d57 | ||
![]() |
e68d3ef886 | ||
![]() |
35a66f74c7 | ||
![]() |
ced4eed733 | ||
![]() |
e299430ff5 | ||
![]() |
53a0d99702 | ||
![]() |
a65c4be2de | ||
![]() |
30db74de66 | ||
![]() |
6fd842a4fd | ||
![]() |
7f1e112a32 | ||
![]() |
54c2ea142a | ||
![]() |
f4b4c27a35 | ||
![]() |
5551da79c1 | ||
![]() |
8f2d6f7ce2 | ||
![]() |
09b0003d38 | ||
![]() |
41fa343484 | ||
![]() |
2e4baa3679 | ||
![]() |
6b820258cd | ||
![]() |
990b320592 | ||
![]() |
a05b70baa6 | ||
![]() |
359d65c902 | ||
![]() |
62aae1084f | ||
![]() |
e534afa5ab | ||
![]() |
2124146164 | ||
![]() |
64afa93187 | ||
![]() |
e6a0f0ee71 | ||
![]() |
685302682a | ||
![]() |
5e7021eb1b | ||
![]() |
44b8255fa2 | ||
![]() |
407fc0bb16 | ||
![]() |
657540945c | ||
![]() |
9261aef2f3 | ||
![]() |
d185057bc7 | ||
![]() |
6cfaa9c204 | ||
![]() |
b2684d9f66 | ||
![]() |
7da0c46e1b | ||
![]() |
91ef8606f2 | ||
![]() |
89959ab9dc | ||
![]() |
adf31505d8 | ||
![]() |
f9f0345eba | ||
![]() |
6f8efea940 | ||
![]() |
388b559848 | ||
![]() |
c97ad3cb41 | ||
![]() |
2ddb5d21bb | ||
![]() |
6889f9168b | ||
![]() |
2d3a4154c5 | ||
![]() |
87ba1d7465 | ||
![]() |
0ab089add4 | ||
![]() |
2d13ae0dd4 | ||
![]() |
730a5e0599 | ||
![]() |
85c9014c09 | ||
![]() |
282f9fb816 | ||
![]() |
d1214da08f | ||
![]() |
f0f163b267 | ||
![]() |
2df746e4e8 | ||
![]() |
b9dbdfef0e | ||
![]() |
0f81af53b0 | ||
![]() |
a80bdf0d9b | ||
![]() |
37fb09c162 | ||
![]() |
e732cbe36c | ||
![]() |
2d3517012a | ||
![]() |
41ceefe804 | ||
![]() |
7b2119dbd9 | ||
![]() |
ef68eae09a | ||
![]() |
43804477ca | ||
![]() |
bfcf541a9e | ||
![]() |
28531d18f0 | ||
![]() |
d5cbc99358 | ||
![]() |
db3b856779 | ||
![]() |
e6eb910496 | ||
![]() |
7286e514f2 | ||
![]() |
ae05e0399b | ||
![]() |
4621527f59 | ||
![]() |
638bc951b2 | ||
![]() |
0613faf596 | ||
![]() |
203d4f916d | ||
![]() |
68d204462c | ||
![]() |
70b4e7948f | ||
![]() |
ee06d0e64d | ||
![]() |
1976ca68b5 | ||
![]() |
4303337c77 | ||
![]() |
ecf5164d2d | ||
![]() |
6396bfb29f | ||
![]() |
ea8db9003b | ||
![]() |
ff8acfffd2 | ||
![]() |
9ffa94b07b | ||
![]() |
1077374380 | ||
![]() |
3d5be364bc | ||
![]() |
ce292026ea | ||
![]() |
742ea00742 | ||
![]() |
a34b8e42df | ||
![]() |
77eb278adf | ||
![]() |
d0a24ea03e | ||
![]() |
ec84c8df0e | ||
![]() |
c4a760c734 | ||
![]() |
902c946bcd | ||
![]() |
0f1cada0f7 | ||
![]() |
c5bc0289ed | ||
![]() |
d28ad6e03f | ||
![]() |
b0ced63e43 | ||
![]() |
0eec4a8ecc | ||
![]() |
36c6f488e4 | ||
![]() |
5d0766ddce | ||
![]() |
718b3ffe74 | ||
![]() |
7184230e94 | ||
![]() |
d9b9514e8e | ||
![]() |
dfeec113be | ||
![]() |
8183eb32e1 | ||
![]() |
8d3b7b57c8 | ||
![]() |
c0201909c7 | ||
![]() |
a03057560a | ||
![]() |
95e5c9f33e | ||
![]() |
07d9197840 | ||
![]() |
c13eba5254 | ||
![]() |
d32a4dd4b0 | ||
![]() |
7ef602d470 | ||
![]() |
9d8c5119e2 | ||
![]() |
f7b1b0595d | ||
![]() |
25a869a097 | ||
![]() |
243c15ea83 | ||
![]() |
33cec55a26 | ||
![]() |
e0ddf93bb0 | ||
![]() |
aa6136f956 | ||
![]() |
222b3d5021 | ||
![]() |
0d66963089 | ||
![]() |
f2c4305114 | ||
![]() |
d519b77d2b | ||
![]() |
d9c10ea753 | ||
![]() |
1eb33f7d00 | ||
![]() |
92dc936ca7 | ||
![]() |
68677eb477 | ||
![]() |
f4a79230c8 |
20
.github/scripts/env.ps1
vendored
20
.github/scripts/env.ps1
vendored
@@ -1,9 +1,17 @@
|
||||
# This script enables Developer Command Prompt
|
||||
# See https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt#using-powershell
|
||||
$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
||||
if ($installationPath -and (Test-Path "$installationPath\Common7\Tools\vsdevcmd.bat")) {
|
||||
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | ForEach-Object {
|
||||
$name, $value = $_ -split '=', 2
|
||||
"$name=$value" >> $env:GITHUB_ENV
|
||||
}
|
||||
if ($env:BUILD_ARCH -eq "arm64") {
|
||||
$arch = "arm64"
|
||||
$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.arm64 -property installationPath
|
||||
} else {
|
||||
$arch = "x64"
|
||||
$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
||||
}
|
||||
|
||||
if ($installationPath) {
|
||||
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=$arch -no_logo && set" |
|
||||
ForEach-Object {
|
||||
$name, $value = $_ -split '=', 2
|
||||
"$name=$value" >> $env:GITHUB_ENV
|
||||
}
|
||||
}
|
||||
|
15
.github/workflows/notes.md
vendored
15
.github/workflows/notes.md
vendored
@@ -2,21 +2,26 @@
|
||||
${NVIM_VERSION}
|
||||
```
|
||||
|
||||
## Release notes
|
||||
|
||||
- [Changelog](https://github.com/neovim/neovim/commit/${NVIM_COMMIT}) (fixes + features)
|
||||
- [News](./runtime/doc/news.txt) (`:help news` in Nvim)
|
||||
|
||||
## Install
|
||||
|
||||
### Windows
|
||||
|
||||
#### Zip
|
||||
|
||||
1. Download **nvim-win64.zip**
|
||||
1. Download **nvim-win64.zip** (or **nvim-win-arm64.zip** for ARM)
|
||||
2. Extract the zip
|
||||
3. Run `nvim.exe` on your CLI of choice
|
||||
3. Run `nvim.exe` in your terminal
|
||||
|
||||
#### MSI
|
||||
|
||||
1. Download **nvim-win64.msi**
|
||||
1. Download **nvim-win64.msi** (or **nvim-win-arm64.msi** for ARM)
|
||||
2. Run the MSI
|
||||
3. Run `nvim.exe` on your CLI of choice
|
||||
3. Run `nvim.exe` in your terminal
|
||||
|
||||
Note: On Windows "Server" you may need to [install vcruntime140.dll](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
|
||||
|
||||
@@ -75,5 +80,3 @@ If your system does not have the [required glibc version](https://neovim.io/doc/
|
||||
### Other
|
||||
|
||||
- Install by [package manager](https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-package)
|
||||
|
||||
## SHA256 Checksums
|
||||
|
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@@ -132,27 +132,44 @@ jobs:
|
||||
|
||||
windows:
|
||||
needs: setup
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- runner: windows-2022
|
||||
arch: x86_64
|
||||
archive_name: nvim-win64
|
||||
- runner: windows-11-arm
|
||||
arch: arm64
|
||||
archive_name: nvim-win-arm64
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Perform a full checkout #13471
|
||||
fetch-depth: 0
|
||||
- run: .github/scripts/env.ps1
|
||||
env:
|
||||
BUILD_ARCH: ${{ matrix.arch }}
|
||||
- name: Install Wix
|
||||
run: |
|
||||
Invoke-WebRequest -Uri "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip" -OutFile "wix314-binaries.zip"
|
||||
Expand-Archive -Path "wix314-binaries.zip" -DestinationPath "C:/wix"
|
||||
echo "C:\wix" >> $env:GITHUB_PATH
|
||||
- name: Build deps
|
||||
run: |
|
||||
cmake -S cmake.deps -B .deps -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}
|
||||
cmake --build .deps
|
||||
- name: build package
|
||||
- name: Build package
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ needs.setup.outputs.build_type }}
|
||||
cmake --build build --target package
|
||||
- uses: actions/upload-artifact@v4
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nvim-win64
|
||||
name: nvim-win-${{ matrix.arch }}
|
||||
path: |
|
||||
build/nvim-win64.msi
|
||||
build/nvim-win64.zip
|
||||
build/${{ matrix.archive_name }}.zip
|
||||
build/${{ matrix.archive_name }}.msi
|
||||
retention-days: 1
|
||||
|
||||
publish:
|
||||
@@ -193,25 +210,14 @@ jobs:
|
||||
echo 'PRERELEASE=') >> $GITHUB_ENV
|
||||
gh release delete stable --yes || true
|
||||
git push origin :stable || true
|
||||
# `sha256sum` outputs <sha> <path>, so we cd into each dir to drop the
|
||||
# containing folder from the output.
|
||||
- run: |
|
||||
for i in nvim-*; do
|
||||
(
|
||||
cd $i || exit
|
||||
sha256sum * >> $GITHUB_WORKSPACE/shasum.txt
|
||||
)
|
||||
done
|
||||
- name: Publish release
|
||||
env:
|
||||
NVIM_VERSION: ${{ needs.linux.outputs.version }}
|
||||
NVIM_COMMIT: ${{ github.sha }}
|
||||
DEBUG: api
|
||||
run: |
|
||||
envsubst < "$GITHUB_WORKSPACE/.github/workflows/notes.md" > "$RUNNER_TEMP/notes.md"
|
||||
echo '```' >> "$RUNNER_TEMP/notes.md"
|
||||
cat shasum.txt >> "$RUNNER_TEMP/notes.md"
|
||||
echo '```' >> "$RUNNER_TEMP/notes.md"
|
||||
if [ "$TAG_NAME" != "nightly" ]; then
|
||||
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/* shasum.txt
|
||||
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win-x86_64/* nvim-win-arm64/*
|
||||
fi
|
||||
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/* shasum.txt
|
||||
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win-x86_64/* nvim-win-arm64/*
|
||||
|
23
BUILD.md
23
BUILD.md
@@ -259,6 +259,29 @@ cmake --build build
|
||||
- Using `ninja` is strongly recommended.
|
||||
4. If treesitter parsers are not bundled, they need to be available in a `parser/` runtime directory (e.g. `/usr/share/nvim/runtime/parser/`).
|
||||
|
||||
### How to build static binary (on Linux)
|
||||
|
||||
1. Use a linux distribution which uses musl C. We will use Alpine Linux but any distro with musl should work. (glibc does not support static linking)
|
||||
2. Run make passing the `STATIC_BUILD` variable: `make CMAKE_EXTRA_FLAGS="-DSTATIC_BUILD=1"`
|
||||
|
||||
In case you are not using Alpine Linux you can use a container to do the build the binary:
|
||||
|
||||
```bash
|
||||
podman run \
|
||||
--rm \
|
||||
-it \
|
||||
-v "$PWD:/workdir" \
|
||||
-w /workdir \
|
||||
alpine:latest \
|
||||
bash -c 'apk add build-base cmake coreutils curl gettext-tiny-dev && make CMAKE_EXTRA_FLAGS="-DSTATIC_BUILD=1"'
|
||||
```
|
||||
|
||||
The resulting binary in `build/bin/nvim` will have all the dependencies statically linked:
|
||||
|
||||
```
|
||||
build/bin/nvim: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[sha1]=b93fa8e678d508ac0a76a2e3da20b119105f1b2d, with debug_info, not stripped
|
||||
```
|
||||
|
||||
#### Debian 10 (Buster) example:
|
||||
|
||||
```sh
|
||||
|
@@ -141,8 +141,8 @@ endif()
|
||||
# version string, else they are combined with the result of `git describe`.
|
||||
set(NVIM_VERSION_MAJOR 0)
|
||||
set(NVIM_VERSION_MINOR 11)
|
||||
set(NVIM_VERSION_PATCH 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 13) # Bump this after any API/stdlib change.
|
||||
|
@@ -273,7 +273,7 @@ If you need to modify or debug the documentation flow, these are the main files:
|
||||
runtime/lua/vim/* => runtime/doc/lua.txt
|
||||
runtime/lua/vim/lsp/ => runtime/doc/lsp.txt
|
||||
src/nvim/api/* => runtime/doc/api.txt
|
||||
src/nvim/eval.lua => runtime/doc/builtin.txt
|
||||
src/nvim/eval.lua => runtime/doc/vimfn.txt
|
||||
src/nvim/options.lua => runtime/doc/options.txt
|
||||
```
|
||||
|
||||
|
10
INSTALL.md
10
INSTALL.md
@@ -66,11 +66,13 @@ Several Neovim GUIs are available from scoop (extras): [scoop.sh/#/apps?q=neovim
|
||||
You can then copy your spell files over (for English, located
|
||||
[here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.spl) and
|
||||
[here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.sug));
|
||||
- For Python plugins you need the `pynvim` module. "Virtual envs" are recommended. After activating the virtual env do `pip install pynvim` (in *both*). Edit your `init.vim` so that it contains the path to the env's Python executable:
|
||||
```vim
|
||||
let g:python3_host_prog='C:/Users/foo/Envs/neovim3/Scripts/python.exe'
|
||||
- For Python plugins you need the `pynvim` module. Installation via uv
|
||||
(https://docs.astral.sh/uv/) is recommended; the `--upgrade` switch ensures
|
||||
installation of the latest version:
|
||||
```
|
||||
- Run `:checkhealth` and read `:help provider-python`.
|
||||
uv tool install --upgrade pynvim
|
||||
```
|
||||
- Run `:checkhealth` and read `:help provider-python` for more details.
|
||||
- **init.vim ("vimrc"):** If you already have Vim installed you can copy `%userprofile%\_vimrc` to `%userprofile%\AppData\Local\nvim\init.vim` to use your Vim config with Neovim.
|
||||
|
||||
|
||||
|
@@ -73,7 +73,7 @@ if(HAS_OG_FLAG)
|
||||
set(DEFAULT_MAKE_CFLAGS CFLAGS+=-Og ${DEFAULT_MAKE_CFLAGS})
|
||||
endif()
|
||||
|
||||
set(DEPS_INCLUDE_FLAGS "-I${DEPS_INSTALL_DIR}/include -I${DEPS_INSTALL_DIR}/include/luajit-2.1")
|
||||
set(DEPS_INCLUDE_FLAGS "-I\"${DEPS_INSTALL_DIR}/include\" -I\"${DEPS_INSTALL_DIR}/include/luajit-2.1\"")
|
||||
|
||||
# If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET),
|
||||
# fall back to local system version. Needs to be done here and in top-level CMakeLists.txt.
|
||||
@@ -96,10 +96,10 @@ else()
|
||||
find_package(Lua 5.1 EXACT)
|
||||
if(LUAJIT_FOUND)
|
||||
set(LUA_ENGINE LuaJit)
|
||||
string(APPEND DEPS_INCLUDE_FLAGS " -I${LUAJIT_INCLUDE_DIR}")
|
||||
string(APPEND DEPS_INCLUDE_FLAGS " -I\"${LUAJIT_INCLUDE_DIR}\"")
|
||||
elseif(LUA_FOUND)
|
||||
set(LUA_ENGINE Lua)
|
||||
string(APPEND DEPS_INCLUDE_FLAGS " -I${LUA_INCLUDE_DIR}")
|
||||
string(APPEND DEPS_INCLUDE_FLAGS " -I\"${LUA_INCLUDE_DIR}\"")
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find system lua or luajit")
|
||||
endif()
|
||||
|
@@ -7,5 +7,6 @@ ExternalProject_Add(wasmtime
|
||||
-D WASMTIME_FASTEST_RUNTIME=ON # build with full LTO
|
||||
-D WASMTIME_DISABLE_ALL_FEATURES=ON # don't need all that crap...
|
||||
-D WASMTIME_FEATURE_CRANELIFT=ON # ...except this one (compiles wasm to platform code)
|
||||
-D WASMTIME_FEATURE_GC_DRC=ON # ...and this one (needed by ts to create engines)
|
||||
USES_TERMINAL_BUILD TRUE
|
||||
${EXTERNALPROJECT_OPTIONS})
|
||||
|
@@ -34,20 +34,20 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
|
||||
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/v2.10.0.tar.gz
|
||||
UTF8PROC_SHA256 6f4f1b639daa6dca9f80bc5db1233e9cbaa31a67790887106160b33ef743f136
|
||||
|
||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.4.tar.gz
|
||||
TREESITTER_C_SHA256 b66c5043e26d84e5f17a059af71b157bcf202221069ed220aa1696d7d1d28a7a
|
||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.3.0.tar.gz
|
||||
TREESITTER_LUA_SHA256 a34cc70abfd8d2d4b0fabf01403ea05f848e1a4bc37d8a4bfea7164657b35d31
|
||||
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.5.0.tar.gz
|
||||
TREESITTER_VIM_SHA256 90019d12d2da0751c027124f27f5335babf069a050457adaed53693b5e9cf10a
|
||||
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.1.tar.gz
|
||||
TREESITTER_VIMDOC_SHA256 76b65e5bee9ff78eb21256619b1995aac4d80f252c19e1c710a4839481ded09e
|
||||
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.5.1.tar.gz
|
||||
TREESITTER_QUERY_SHA256 fe8c712880a529d454347cd4c58336ac2db22243bae5055bdb5844fb3ea56192
|
||||
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.4.1.tar.gz
|
||||
TREESITTER_MARKDOWN_SHA256 e0fdb2dca1eb3063940122e1475c9c2b069062a638c95939e374c5427eddee9f
|
||||
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.3.tar.gz
|
||||
TREESITTER_SHA256 862fac52653bc7bc9d2cd0630483e6bdf3d02bcd23da956ca32663c4798a93e3
|
||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.24.1.tar.gz
|
||||
TREESITTER_C_SHA256 25dd4bb3dec770769a407e0fc803f424ce02c494a56ce95fedc525316dcf9b48
|
||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.4.0.tar.gz
|
||||
TREESITTER_LUA_SHA256 b0977aced4a63bb75f26725787e047b8f5f4a092712c840ea7070765d4049559
|
||||
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.7.0.tar.gz
|
||||
TREESITTER_VIM_SHA256 44eabc31127c4feacda19f2a05a5788272128ff561ce01093a8b7a53aadcc7b2
|
||||
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v4.0.0.tar.gz
|
||||
TREESITTER_VIMDOC_SHA256 8096794c0f090b2d74b7bff94548ac1be3285b929ec74f839bd9b3ff4f4c6a0b
|
||||
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.6.2.tar.gz
|
||||
TREESITTER_QUERY_SHA256 90682e128d048fbf2a2a17edca947db71e326fa0b3dba4136e041e096538b4eb
|
||||
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.5.0.tar.gz
|
||||
TREESITTER_MARKDOWN_SHA256 14c2c948ccf0e9b606eec39b09286c59dddf28307849f71b7ce2b1d1ef06937e
|
||||
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.6.tar.gz
|
||||
TREESITTER_SHA256 ac6ed919c6d849e8553e246d5cd3fa22661f6c7b6497299264af433f3629957c
|
||||
|
||||
WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v29.0.1.tar.gz
|
||||
WASMTIME_SHA256 b94b6c6fd6aebaf05d4c69c1b12b5dc217b0d42c1a95f435b33af63dddfa5304
|
||||
|
@@ -1,4 +1,4 @@
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|ARM64|aarch64)$")
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm64)
|
||||
endif()
|
||||
|
||||
@@ -27,9 +27,13 @@ set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md)
|
||||
|
||||
|
||||
if(WIN32)
|
||||
set(CPACK_PACKAGE_FILE_NAME "nvim-win64")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(CPACK_PACKAGE_FILE_NAME "nvim-win-arm64")
|
||||
else()
|
||||
set(CPACK_PACKAGE_FILE_NAME "nvim-win64")
|
||||
endif()
|
||||
|
||||
set(CPACK_GENERATOR ZIP WIX)
|
||||
|
||||
# WIX
|
||||
# CPACK_WIX_UPGRADE_GUID should be set, but should never change.
|
||||
# CPACK_WIX_PRODUCT_GUID should not be set (leave as default to auto-generate).
|
||||
|
@@ -268,13 +268,11 @@ function! provider#clipboard#Executable() abort
|
||||
endfunction
|
||||
|
||||
function! s:clipboard.get(reg) abort
|
||||
if type(s:paste[a:reg]) == v:t_func
|
||||
return s:paste[a:reg]()
|
||||
elseif s:selections[a:reg].owner > 0
|
||||
if s:selections[a:reg].owner > 0
|
||||
return s:selections[a:reg].data
|
||||
end
|
||||
|
||||
let clipboard_data = s:try_cmd(s:paste[a:reg])
|
||||
let clipboard_data = type(s:paste[a:reg]) == v:t_func ? s:paste[a:reg]() : s:try_cmd(s:paste[a:reg])
|
||||
if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0
|
||||
\ && type(clipboard_data) == v:t_list
|
||||
\ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data
|
||||
@@ -294,13 +292,12 @@ function! s:clipboard.set(lines, regtype, reg) abort
|
||||
return 0
|
||||
end
|
||||
|
||||
if type(s:copy[a:reg]) == v:t_func
|
||||
call s:copy[a:reg](a:lines, a:regtype)
|
||||
return 0
|
||||
end
|
||||
|
||||
if s:cache_enabled == 0
|
||||
call s:try_cmd(s:copy[a:reg], a:lines)
|
||||
if s:cache_enabled == 0 || type(s:copy[a:reg]) == v:t_func
|
||||
if type(s:copy[a:reg]) == v:t_func
|
||||
call s:copy[a:reg](a:lines, a:regtype)
|
||||
else
|
||||
call s:try_cmd(s:copy[a:reg], a:lines)
|
||||
endif
|
||||
"Cache it anyway we can compare it later to get regtype of the yank
|
||||
let s:selections[a:reg] = copy(s:selection)
|
||||
let s:selections[a:reg].data = [a:lines, a:regtype]
|
||||
|
@@ -77,46 +77,6 @@ function! tutor#TutorFolds()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Marks: {{{1
|
||||
|
||||
function! tutor#ApplyMarks()
|
||||
hi! link tutorExpect Special
|
||||
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
|
||||
let b:tutor_sign_id = 1
|
||||
for expct in keys(b:tutor_metadata['expect'])
|
||||
let lnum = eval(expct)
|
||||
call matchaddpos('tutorExpect', [lnum])
|
||||
call tutor#CheckLine(lnum)
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! tutor#ApplyMarksOnChanged()
|
||||
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
|
||||
let lnum = line('.')
|
||||
if index(keys(b:tutor_metadata['expect']), string(lnum)) > -1
|
||||
call tutor#CheckLine(lnum)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! tutor#CheckLine(line)
|
||||
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
|
||||
let bufn = bufnr('%')
|
||||
let ctext = getline(a:line)
|
||||
let signs = sign_getplaced(bufn, {'lnum': a:line})[0].signs
|
||||
if !empty(signs)
|
||||
call sign_unplace('', {'id': signs[0].id})
|
||||
endif
|
||||
if b:tutor_metadata['expect'][string(a:line)] == -1 || ctext ==# b:tutor_metadata['expect'][string(a:line)]
|
||||
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorok buffer=".bufn
|
||||
else
|
||||
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorbad buffer=".bufn
|
||||
endif
|
||||
let b:tutor_sign_id+=1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Tutor Cmd: {{{1
|
||||
|
||||
function! s:Locale()
|
||||
@@ -167,15 +127,21 @@ function! s:Sort(a, b)
|
||||
return retval
|
||||
endfunction
|
||||
|
||||
function! s:GlobTutorials(name)
|
||||
" returns a list of all tutor files matching the given name
|
||||
function! tutor#GlobTutorials(name, locale)
|
||||
let locale = a:locale
|
||||
" pack/*/start/* are not reported in &rtp
|
||||
let rtp = nvim_list_runtime_paths()
|
||||
\ ->map({_, v -> escape(v:lua.vim.fs.normalize(v), ',')})
|
||||
\ ->join(',')
|
||||
" search for tutorials:
|
||||
" 1. non-localized
|
||||
let l:tutors = s:GlobPath(&rtp, 'tutor/'.a:name.'.tutor')
|
||||
let l:tutors = s:GlobPath(rtp, 'tutor/'.a:name.'.tutor')
|
||||
" 2. localized for current locale
|
||||
let l:locale_tutors = s:GlobPath(&rtp, 'tutor/'.s:Locale()[0].'/'.a:name.'.tutor')
|
||||
let l:locale_tutors = s:GlobPath(rtp, 'tutor/'.locale.'/'.a:name.'.tutor')
|
||||
" 3. fallback to 'en'
|
||||
if len(l:locale_tutors) == 0
|
||||
let l:locale_tutors = s:GlobPath(&rtp, 'tutor/en/'.a:name.'.tutor')
|
||||
let l:locale_tutors = s:GlobPath(rtp, 'tutor/en/'.a:name.'.tutor')
|
||||
endif
|
||||
call extend(l:tutors, l:locale_tutors)
|
||||
return uniq(sort(l:tutors, 's:Sort'), 's:Sort')
|
||||
@@ -197,7 +163,7 @@ function! tutor#TutorCmd(tutor_name)
|
||||
let l:tutor_name = fnamemodify(l:tutor_name, ':r')
|
||||
endif
|
||||
|
||||
let l:tutors = s:GlobTutorials(l:tutor_name)
|
||||
let l:tutors = tutor#GlobTutorials(l:tutor_name, s:Locale()[0])
|
||||
|
||||
if len(l:tutors) == 0
|
||||
echom "No tutorial with that name found"
|
||||
@@ -225,7 +191,7 @@ function! tutor#TutorCmd(tutor_name)
|
||||
endfunction
|
||||
|
||||
function! tutor#TutorCmdComplete(lead,line,pos)
|
||||
let l:tutors = s:GlobTutorials('*')
|
||||
let l:tutors = tutor#GlobTutorials('*', s:Locale()[0])
|
||||
let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort'))
|
||||
return join(l:names, "\n")
|
||||
endfunction
|
||||
@@ -237,9 +203,9 @@ function! tutor#EnableInteractive(enable)
|
||||
setlocal buftype=nofile
|
||||
setlocal concealcursor+=inv
|
||||
setlocal conceallevel=2
|
||||
call tutor#ApplyMarks()
|
||||
lua require('nvim.tutor').apply_marks()
|
||||
augroup tutor_interactive
|
||||
autocmd! TextChanged,TextChangedI <buffer> call tutor#ApplyMarksOnChanged()
|
||||
autocmd! TextChanged,TextChangedI <buffer> lua require('nvim.tutor').apply_marks_on_changed()
|
||||
augroup END
|
||||
else
|
||||
setlocal buftype<
|
||||
|
@@ -1183,10 +1183,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
|
||||
ANSI termcodes, so you can use Nvim as a "scrollback pager" (for terminals
|
||||
like kitty): *ansi-colorize* *terminal-scrollback-pager* >lua
|
||||
vim.api.nvim_create_user_command('TermHl', function()
|
||||
local b = vim.api.nvim_create_buf(false, true)
|
||||
local chan = vim.api.nvim_open_term(b, {})
|
||||
vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
|
||||
vim.api.nvim_win_set_buf(0, b)
|
||||
vim.api.nvim_open_term(0, {})
|
||||
end, { desc = 'Highlights ANSI termcodes in curbuf' })
|
||||
<
|
||||
|
||||
@@ -3539,7 +3536,8 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
|
||||
the duration of the call.
|
||||
• fixed: If true when anchor is NW or SW, the float window
|
||||
would be kept fixed even if the window would be truncated.
|
||||
• hide: If true the floating window will be hidden.
|
||||
• hide: If true the floating window will be hidden and the
|
||||
cursor will be invisible when focused on it.
|
||||
• vertical: Split vertically |:vertical|.
|
||||
• split: Split direction: "left", "right", "above", "below".
|
||||
|
||||
|
@@ -441,6 +441,7 @@ Use existing common {verb} names (actions) if possible:
|
||||
- get: Gets things. Two variants (overloads):
|
||||
1. `get<T>(id: int): T` returns one item.
|
||||
2. `get<T>(filter: dict): T[]` returns a list.
|
||||
- has: Checks for the presence of an item, feature, etc.
|
||||
- inspect: Presents a high-level, often interactive, view
|
||||
- is_enabled: Checks if functionality is enabled.
|
||||
- open: Opens something (a buffer, window, …)
|
||||
@@ -452,6 +453,7 @@ Use existing common {verb} names (actions) if possible:
|
||||
- try_{verb}: Best-effort operation, failure returns null or error obj
|
||||
|
||||
Do NOT use these deprecated verbs:
|
||||
- contains: Prefer "has".
|
||||
- disable: Prefer `enable(enable: boolean)`.
|
||||
- exit: Prefer "cancel" (or "stop" if appropriate).
|
||||
- is_disabled: Prefer `is_enabled()`.
|
||||
|
@@ -69,6 +69,16 @@ Functions that take a severity as an optional parameter (e.g.
|
||||
<
|
||||
This form allows users to filter for specific severities
|
||||
|
||||
==============================================================================
|
||||
DEFAULTS *diagnostic-defaults*
|
||||
|
||||
These diagnostic keymaps are created unconditionally when Nvim starts:
|
||||
- `]d` jumps to the next diagnostic in the buffer. |]d-default|
|
||||
- `[d` jumps to the previous diagnostic in the buffer. |[d-default|
|
||||
- `]D` jumps to the last diagnostic in the buffer. |]D-default|
|
||||
- `[D` jumps to the first diagnostic in the buffer. |[D-default|
|
||||
- `<C-w>d` shows diagnostic at cursor in a floating window. |CTRL-W_d-default|
|
||||
|
||||
==============================================================================
|
||||
HANDLERS *diagnostic-handlers*
|
||||
|
||||
|
@@ -187,20 +187,19 @@ Run |:checkhealth| in Nvim for automatic diagnosis.
|
||||
|
||||
Other hints:
|
||||
|
||||
- The python `neovim` module was renamed to `pynvim` (long ago).
|
||||
- If you're using pyenv or virtualenv for the `pynvim` module
|
||||
https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to
|
||||
the virtualenv's interpreter path.
|
||||
- Read |provider-python|.
|
||||
- Read |provider-python| to learn how to install `pynvim`.
|
||||
- Be sure you have the latest version of the `pynvim` Python module: >bash
|
||||
|
||||
python -m pip install setuptools
|
||||
python -m pip install --upgrade pynvim
|
||||
python3 -m pip install --upgrade pynvim
|
||||
uv tool install --upgrade pynvim
|
||||
<
|
||||
See |provider-python| for other installation options.
|
||||
- If you're manually creating a Python virtual environment for the `pynvim` module
|
||||
https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to
|
||||
the virtualenv's interpreter path.
|
||||
- Try with `nvim -u NORC` to make sure your config (|init.vim|) isn't causing a
|
||||
problem. If you get `E117: Unknown function`, that means there's a runtime
|
||||
issue: |faq-runtime|.
|
||||
- The python `neovim` module was renamed to `pynvim` (long ago).
|
||||
|
||||
|
||||
:CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME ~
|
||||
|
@@ -373,11 +373,17 @@ To quote a block of ex-commands verbatim, place a greater than (>) character
|
||||
at the end of the line before the block and a less than (<) character as the
|
||||
first non-blank on a line following the block. Any line starting in column 1
|
||||
also implicitly stops the block of ex-commands before it. E.g. >
|
||||
function Example_Func()
|
||||
echo "Example"
|
||||
endfunction
|
||||
function Example_Func()
|
||||
echo "Example"
|
||||
endfunction
|
||||
<
|
||||
|
||||
To enable syntax highlighting for a block of code, place a language name
|
||||
annotation (e.g. "vim") after a greater than (>) character. E.g. >vim
|
||||
function Example_Func()
|
||||
echo "Example"
|
||||
endfunction
|
||||
<
|
||||
*help-notation*
|
||||
The following are highlighted differently in a Vim help file:
|
||||
- a special key name expressed either in <> notation as in <PageDown>, or
|
||||
as a Ctrl character as in CTRL-X
|
||||
|
@@ -28,39 +28,42 @@ Follow these steps to get LSP features:
|
||||
upstream installation instructions. You can find language servers here:
|
||||
https://microsoft.github.io/language-server-protocol/implementors/servers/
|
||||
|
||||
2. Use |vim.lsp.config()| to define a configuration for an LSP client.
|
||||
Example: >lua
|
||||
vim.lsp.config['luals'] = {
|
||||
-- Command and arguments to start the server.
|
||||
cmd = { 'lua-language-server' },
|
||||
2. Use |vim.lsp.config()| to define a configuration for an LSP client
|
||||
(see https://github.com/neovim/nvim-lspconfig for examples).
|
||||
Example: >lua
|
||||
vim.lsp.config['luals'] = {
|
||||
-- Command and arguments to start the server.
|
||||
cmd = { 'lua-language-server' },
|
||||
|
||||
-- Filetypes to automatically attach to.
|
||||
filetypes = { 'lua' },
|
||||
-- Filetypes to automatically attach to.
|
||||
filetypes = { 'lua' },
|
||||
|
||||
-- Sets the "root directory" to the parent directory of the file in the
|
||||
-- current buffer that contains either a ".luarc.json" or a
|
||||
-- ".luarc.jsonc" file. Files that share a root directory will reuse
|
||||
-- the connection to the same LSP server.
|
||||
-- Nested lists indicate equal priority, see |vim.lsp.Config|.
|
||||
root_markers = { { '.luarc.json', '.luarc.jsonc' }, '.git' },
|
||||
-- Sets the "root directory" to the parent directory of the file in the
|
||||
-- current buffer that contains either a ".luarc.json" or a
|
||||
-- ".luarc.jsonc" file. Files that share a root directory will reuse
|
||||
-- the connection to the same LSP server.
|
||||
-- Nested lists indicate equal priority, see |vim.lsp.Config|.
|
||||
root_markers = { { '.luarc.json', '.luarc.jsonc' }, '.git' },
|
||||
|
||||
-- Specific settings to send to the server. The schema for this is
|
||||
-- defined by the server. For example the schema for lua-language-server
|
||||
-- can be found here https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json
|
||||
settings = {
|
||||
Lua = {
|
||||
runtime = {
|
||||
version = 'LuaJIT',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- Specific settings to send to the server. The schema for this is
|
||||
-- defined by the server. For example the schema for lua-language-server
|
||||
-- can be found here https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json
|
||||
settings = {
|
||||
Lua = {
|
||||
runtime = {
|
||||
version = 'LuaJIT',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<
|
||||
3. Use |vim.lsp.enable()| to enable a configuration.
|
||||
Example: >lua
|
||||
vim.lsp.enable('luals')
|
||||
<
|
||||
4. Restart Nvim, or use ":edit" to reload the buffer.
|
||||
4. Open a code file matching one of the `filetypes` specified in the config.
|
||||
Note: Depending on the LSP server, you may need to ensure your project has
|
||||
a |lsp-root_markers| file so the workspace can be recognized.
|
||||
|
||||
5. Check that LSP is active ("attached") for the buffer: >vim
|
||||
:checkhealth vim.lsp
|
||||
@@ -77,6 +80,18 @@ listed below, if (1) the language server supports the functionality and (2)
|
||||
the options are empty or were set by the builtin runtime (ftplugin) files. The
|
||||
options are not restored when the LSP client is stopped or detached.
|
||||
|
||||
GLOBAL DEFAULTS
|
||||
*grr* *gra* *grn* *gri* *grt* *i_CTRL-S*
|
||||
These GLOBAL keymaps are created unconditionally when Nvim starts:
|
||||
- "grn" is mapped in Normal mode to |vim.lsp.buf.rename()|
|
||||
- "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
|
||||
- "grr" is mapped in Normal mode to |vim.lsp.buf.references()|
|
||||
- "gri" is mapped in Normal mode to |vim.lsp.buf.implementation()|
|
||||
- "grt" is mapped in Normal mode to |vim.lsp.buf.type_definition()|
|
||||
- "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()|
|
||||
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
|
||||
|
||||
BUFFER-LOCAL DEFAULTS
|
||||
- 'omnifunc' is set to |vim.lsp.omnifunc()|, use |i_CTRL-X_CTRL-O| to trigger
|
||||
completion.
|
||||
- 'tagfunc' is set to |vim.lsp.tagfunc()|. This enables features like
|
||||
@@ -88,21 +103,11 @@ options are not restored when the LSP client is stopped or detached.
|
||||
- |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or
|
||||
a custom keymap for `K` exists.
|
||||
|
||||
*grr* *gra* *grn* *gri* *i_CTRL-S*
|
||||
Some keymaps are created unconditionally when Nvim starts:
|
||||
- "grn" is mapped in Normal mode to |vim.lsp.buf.rename()|
|
||||
- "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
|
||||
- "grr" is mapped in Normal mode to |vim.lsp.buf.references()|
|
||||
- "gri" is mapped in Normal mode to |vim.lsp.buf.implementation()|
|
||||
- "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()|
|
||||
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
|
||||
DISABLING DEFAULTS *lsp-defaults-disable*
|
||||
You can remove GLOBAL keymaps at any time using |vim.keymap.del()| or
|
||||
|:unmap|. See also |gr-default|.
|
||||
|
||||
If not wanted, these keymaps can be removed at any time using
|
||||
|vim.keymap.del()| or |:unmap| (see also |gr-default|).
|
||||
|
||||
*lsp-defaults-disable*
|
||||
To override or delete any of the above defaults, set or unset the options on
|
||||
|LspAttach|: >lua
|
||||
To remove or override BUFFER-LOCAL defaults, define a |LspAttach| handler: >lua
|
||||
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
callback = function(args)
|
||||
@@ -130,7 +135,7 @@ following (in increasing priority):
|
||||
|
||||
1. Configuration defined for the `'*'` name.
|
||||
2. Configuration from the result of merging all tables returned by
|
||||
`lsp/<name>.lua` files in 'runtimepath' for a server of name `name`.
|
||||
`lsp/<config>.lua` files in 'runtimepath' for the config named `<config>`.
|
||||
3. Configurations defined anywhere else.
|
||||
|
||||
Note: The merge semantics of configurations follow the behaviour of
|
||||
@@ -251,8 +256,14 @@ FAQ *lsp-faq*
|
||||
" (async = false is the default for format)
|
||||
autocmd BufWritePre *.rs lua vim.lsp.buf.format({ async = false })
|
||||
<
|
||||
|
||||
- Q: How to avoid my own lsp/ folder being overridden?
|
||||
- A: Place your configs under "after/lsp/". Files in "after/lsp/" are loaded
|
||||
after those in "nvim/lsp/", so your settings will take precedence over
|
||||
the defaults provided by nvim-lspconfig. See also: |after-directory|
|
||||
|
||||
*lsp-vs-treesitter*
|
||||
- Q: How do LSP and Treesitter compare?
|
||||
- Q: How do LSP, Treesitter and Ctags compare?
|
||||
- A: LSP requires a client and language server. The language server uses
|
||||
semantic analysis to understand code at a project level. This provides
|
||||
language servers with the ability to rename across files, find
|
||||
@@ -264,6 +275,11 @@ FAQ *lsp-faq*
|
||||
like syntax highlighting, simple goto-definitions, scope analysis and
|
||||
more.
|
||||
|
||||
A |ctags|-like program can generate a |tags| file that allows Nvim to
|
||||
jump to definitions, provide simple completions via |i_CTRL-X_CTRL-]|
|
||||
command. It is not as featureful and doesn't have semantic understanding,
|
||||
but it is fast, lightweight and useful for navigating polyglot projects.
|
||||
|
||||
================================================================================
|
||||
LSP API *lsp-api*
|
||||
|
||||
@@ -705,8 +721,10 @@ Lua module: vim.lsp *lsp-core*
|
||||
|
||||
|
||||
Fields: ~
|
||||
• {cmd}? (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
|
||||
See `cmd` in |vim.lsp.ClientConfig|.
|
||||
• {cmd}? (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient`)
|
||||
See `cmd` in |vim.lsp.ClientConfig|. See also
|
||||
`reuse_client` to dynamically decide (per-buffer)
|
||||
when `cmd` should be re-invoked.
|
||||
• {filetypes}? (`string[]`) Filetypes the client will attach to, if
|
||||
activated by `vim.lsp.enable()`. If not provided, the
|
||||
client will attach to all filetypes.
|
||||
@@ -716,46 +734,40 @@ Lua module: vim.lsp *lsp-core*
|
||||
implementation re-uses a client if name and root_dir
|
||||
matches.
|
||||
• {root_dir}? (`string|fun(bufnr: integer, on_dir:fun(root_dir?:string))`)
|
||||
*lsp-root_dir()* Directory where the LSP server will
|
||||
base its workspaceFolders, rootUri, and rootPath on
|
||||
initialization. The function form receives a buffer
|
||||
number and `on_dir` callback which it must call to
|
||||
provide root_dir, or LSP will not be activated for
|
||||
the buffer. Thus a `root_dir()` function can
|
||||
dynamically decide per-buffer whether to activate (or
|
||||
skip) LSP. See example at |vim.lsp.enable()|.
|
||||
• {root_markers}? (`(string|string[])[]`) Directory markers (.e.g.
|
||||
'.git/') where the LSP server will base its
|
||||
*lsp-root_dir()* Decides the workspace root: the
|
||||
directory where the LSP server will base its
|
||||
workspaceFolders, rootUri, and rootPath on
|
||||
initialization. Unused if `root_dir` is provided.
|
||||
|
||||
The list order decides the priority. To indicate
|
||||
initialization. The function form must call the
|
||||
`on_dir` callback to provide the root dir, or LSP
|
||||
will not be activated for the buffer. Thus a
|
||||
`root_dir()` function can dynamically decide
|
||||
per-buffer whether to activate (or skip) LSP. See
|
||||
example at |vim.lsp.enable()|.
|
||||
• {root_markers}? (`(string|string[])[]`) *lsp-root_markers*
|
||||
Filename(s) (".git/", "package.json", …) used to
|
||||
decide the workspace root. Unused if `root_dir` is
|
||||
defined. The list order decides priority. To indicate
|
||||
"equal priority", specify names in a nested list
|
||||
(`{ { 'a', 'b' }, ... }`) Each entry in this list is
|
||||
a set of one or more markers. For each set, Nvim will
|
||||
search upwards for each marker contained in the set.
|
||||
If a marker is found, the directory which contains
|
||||
that marker is used as the root directory. If no
|
||||
markers from the set are found, the process is
|
||||
repeated with the next set in the list.
|
||||
`{ { 'a.txt', 'b.lua' }, ... }`.
|
||||
|
||||
Example: >lua
|
||||
For each item, Nvim will search upwards (from the
|
||||
buffer file) for that marker, or list of markers;
|
||||
search stops at the first directory containing that
|
||||
marker, and the directory is used as the root dir
|
||||
(workspace folder).
|
||||
|
||||
Example: Find the first ancestor directory containing
|
||||
file or directory "stylua.toml"; if not found, find
|
||||
the first ancestor containing ".git": >lua
|
||||
root_markers = { 'stylua.toml', '.git' }
|
||||
<
|
||||
|
||||
Find the first parent directory containing the file
|
||||
`stylua.toml`. If not found, find the first parent
|
||||
directory containing the file or directory `.git`.
|
||||
|
||||
Example: >lua
|
||||
Example: Find the first ancestor directory containing
|
||||
EITHER "stylua.toml" or ".luarc.json"; if not found,
|
||||
find the first ancestor containing ".git": >lua
|
||||
root_markers = { { 'stylua.toml', '.luarc.json' }, '.git' }
|
||||
<
|
||||
|
||||
Find the first parent directory containing EITHER
|
||||
`stylua.toml` or `.luarc.json`. If not found, find
|
||||
the first parent directory containing the file or
|
||||
directory `.git`.
|
||||
|
||||
|
||||
buf_attach_client({bufnr}, {client_id}) *vim.lsp.buf_attach_client()*
|
||||
Implements the `textDocument/did…` notifications required to track a
|
||||
@@ -918,6 +930,12 @@ enable({name}, {enable}) *vim.lsp.enable()*
|
||||
vim.lsp.enable({'luals', 'pyright'})
|
||||
<
|
||||
|
||||
Example: *lsp-restart* Passing `false` stops and detaches the client(s).
|
||||
Thus you can "restart" LSP by disabling and re-enabling a given config: >lua
|
||||
vim.lsp.enable('clangd', false)
|
||||
vim.lsp.enable('clangd', true)
|
||||
<
|
||||
|
||||
Example: To dynamically decide whether LSP is activated, define a
|
||||
|lsp-root_dir()| function which calls `on_dir()` only when you want that
|
||||
config to activate: >lua
|
||||
@@ -932,7 +950,8 @@ enable({name}, {enable}) *vim.lsp.enable()*
|
||||
|
||||
Parameters: ~
|
||||
• {name} (`string|string[]`) Name(s) of client(s) to enable.
|
||||
• {enable} (`boolean?`) `true|nil` to enable, `false` to disable.
|
||||
• {enable} (`boolean?`) `true|nil` to enable, `false` to disable
|
||||
(actively stops and detaches clients as needed)
|
||||
|
||||
foldclose({kind}, {winid}) *vim.lsp.foldclose()*
|
||||
Close all {kind} of folds in the the window with {winid}.
|
||||
@@ -1045,6 +1064,9 @@ get_log_path() *vim.lsp.get_log_path()*
|
||||
is_enabled({name}) *vim.lsp.is_enabled()*
|
||||
Checks if the given LSP config is enabled (globally, not per-buffer).
|
||||
|
||||
Unlike `vim.lsp.config['…']`, this does not have the side-effect of
|
||||
resolving the config.
|
||||
|
||||
Parameters: ~
|
||||
• {name} (`string`) Config name
|
||||
|
||||
@@ -1294,16 +1316,16 @@ Lua module: vim.lsp.client *lsp-client*
|
||||
• Note: To send an empty dictionary use
|
||||
|vim.empty_dict()|, else it will be encoded
|
||||
as an array.
|
||||
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
|
||||
command string[] that launches the language
|
||||
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient`)
|
||||
Command `string[]` that launches the language
|
||||
server (treated as in |jobstart()|, must be
|
||||
absolute or on `$PATH`, shell constructs like
|
||||
"~" are not expanded), or function that creates
|
||||
an RPC client. Function receives a
|
||||
`dispatchers` table and returns a table with
|
||||
member functions `request`, `notify`,
|
||||
`is_closing` and `terminate`. See
|
||||
|vim.lsp.rpc.request()|,
|
||||
`dispatchers` table and the resolved `config`,
|
||||
and must return a table with member functions
|
||||
`request`, `notify`, `is_closing` and
|
||||
`terminate`. See |vim.lsp.rpc.request()|,
|
||||
|vim.lsp.rpc.notify()|. For TCP there is a
|
||||
builtin RPC client factory:
|
||||
|vim.lsp.rpc.connect()|
|
||||
@@ -1322,11 +1344,12 @@ Lua module: vim.lsp.client *lsp-client*
|
||||
command name, and the value is a function which
|
||||
is called if any LSP action (code action, code
|
||||
lenses, …) triggers the command.
|
||||
• {detached}? (`boolean`, default: true) Daemonize the server
|
||||
process so that it runs in a separate process
|
||||
group from Nvim. Nvim will shutdown the process
|
||||
on exit, but if Nvim fails to exit cleanly this
|
||||
could leave behind orphaned server processes.
|
||||
• {detached}? (`boolean`, default: `true`) Daemonize the
|
||||
server process so that it runs in a separate
|
||||
process group from Nvim. Nvim will shutdown the
|
||||
process on exit, but if Nvim fails to exit
|
||||
cleanly this could leave behind orphaned server
|
||||
processes.
|
||||
• {flags}? (`table`) A table with flags for the client.
|
||||
The current (experimental) flags are:
|
||||
• {allow_incremental_sync}? (`boolean`,
|
||||
@@ -1351,8 +1374,8 @@ Lua module: vim.lsp.client *lsp-client*
|
||||
initialization request as
|
||||
`initializationOptions`. See `initialize` in
|
||||
the LSP spec.
|
||||
• {name}? (`string`) (default: client-id) Name in logs
|
||||
and user messages.
|
||||
• {name}? (`string`, default: client-id) Name in logs and
|
||||
user messages.
|
||||
• {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) Called "position
|
||||
encoding" in LSP spec. The encoding that the
|
||||
LSP server expects, used for communication. Not
|
||||
@@ -1402,7 +1425,7 @@ Lua module: vim.lsp.client *lsp-client*
|
||||
this list. Can be `null` if the client supports
|
||||
workspace folders but none are configured. See
|
||||
`workspaceFolders` in LSP spec.
|
||||
• {workspace_required}? (`boolean`) (default false) Server requires a
|
||||
• {workspace_required}? (`boolean`, default: `false`) Server requires a
|
||||
workspace (no "single file" support). Note:
|
||||
Without a workspace, cross-file features
|
||||
(navigation, hover) may or may not work
|
||||
|
@@ -10,19 +10,18 @@
|
||||
==============================================================================
|
||||
Introduction *lua-guide*
|
||||
|
||||
This guide will go through the basics of using Lua in Nvim. It is not meant
|
||||
to be a comprehensive encyclopedia of all available features, nor will it
|
||||
detail all intricacies. Think of it as a survival kit -- the bare minimum
|
||||
needed to know to comfortably get started on using Lua in Nvim.
|
||||
|
||||
An important thing to note is that this isn't a guide to the Lua language
|
||||
itself. Rather, this is a guide on how to configure and modify Nvim through
|
||||
the Lua language and the functions we provide to help with this. Take a look
|
||||
at |luaref| and |lua-concepts| if you'd like to learn more about Lua itself.
|
||||
Similarly, this guide assumes some familiarity with the basics of Nvim
|
||||
This guide introduces the basics of everyday usage of Lua to configure and
|
||||
operate Nvim. It assumes some familiarity with the (non-Lua) basics of Nvim
|
||||
(commands, options, mappings, autocommands), which are covered in the
|
||||
|user-manual|.
|
||||
|
||||
This is not a comprehensive encyclopedia of all available features. Think of
|
||||
it as a survival kit: the bare minimum needed to comfortably get started on
|
||||
using Lua in Nvim.
|
||||
|
||||
See |lua-plugin| for guidance on developing Lua plugins.
|
||||
See |luaref| and |lua-concepts| for details on the Lua programming language.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Some words on the API *lua-guide-api*
|
||||
|
||||
|
306
runtime/doc/lua-plugin.txt
Normal file
306
runtime/doc/lua-plugin.txt
Normal file
@@ -0,0 +1,306 @@
|
||||
*lua-plugin.txt* Nvim
|
||||
|
||||
NVIM REFERENCE MANUAL
|
||||
|
||||
Guide to developing Lua plugins for Nvim
|
||||
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
Introduction *lua-plugin*
|
||||
|
||||
This document provides guidance for developing Nvim (Lua) plugins:
|
||||
|
||||
See |lua-guide| for guidance on using Lua to configure and operate Nvim.
|
||||
See |luaref| and |lua-concepts| for details on the Lua programming language.
|
||||
|
||||
==============================================================================
|
||||
Creating your first plugin *lua-plugin-new*
|
||||
|
||||
Any Vimscript or Lua code file that lives in the right directory,
|
||||
automatically is a "plugin". There's no maniest or "registration" required.
|
||||
|
||||
You can try it right now:
|
||||
|
||||
1. Visit your config directory: >
|
||||
:exe 'edit' stdpath('config')
|
||||
<
|
||||
2. Create a `plugin/foo.lua` file in there.
|
||||
3. Add something to it, like: >lua
|
||||
vim.print('Hello World')
|
||||
<
|
||||
4. Start `nvim` and notice that it prints "Hello World" in the messages area.
|
||||
Check `:messages` if you don't see it.
|
||||
|
||||
Besides `plugin/foo.lua`, which is always run at startup, you can define Lua
|
||||
modules in the `lua/` directory. Those modules aren't loaded until your
|
||||
`plugin/foo.lua`, the user, calls `require(…)`.
|
||||
|
||||
==============================================================================
|
||||
Type safety *lua-plugin-type-safety*
|
||||
|
||||
Lua, as a dynamically typed language, is great for configuration. It provides
|
||||
virtually immediate feedback.
|
||||
But for larger projects, this can be a double-edged sword, leaving your plugin
|
||||
susceptible to unexpected bugs at the wrong time.
|
||||
|
||||
You can leverage LuaCATS or "emmylua" annotations https://luals.github.io/wiki/annotations/
|
||||
along with lua-language-server ("LuaLS") https://luals.github.io/ to catch
|
||||
potential bugs in your CI before your plugin's users do. The Nvim codebase
|
||||
uses these annotations extensively.
|
||||
|
||||
TOOLS
|
||||
|
||||
- lua-typecheck-action https://github.com/marketplace/actions/lua-typecheck-action
|
||||
- lua-language-server https://luals.github.io
|
||||
|
||||
==============================================================================
|
||||
Keymaps *lua-plugin-keymaps*
|
||||
|
||||
Avoid creating excessive keymaps automatically. Doing so can conflict with
|
||||
user |mapping|s.
|
||||
|
||||
NOTE: An example for uncontroversial keymaps are buffer-local |mapping|s for
|
||||
specific file types or floating windows, or <Plug> mappings.
|
||||
|
||||
A common approach to allow keymap configuration is to define a declarative DSL
|
||||
https://en.wikipedia.org/wiki/Domain-specific_language via a `setup` function.
|
||||
|
||||
However, doing so means that
|
||||
|
||||
- You will have to implement and document it yourself.
|
||||
- Users will likely face inconsistencies if another plugin has a slightly
|
||||
different DSL.
|
||||
- |init.lua| scripts that call such a `setup` function may throw an error if
|
||||
the plugin is not installed or disabled.
|
||||
|
||||
As an alternative, you can provide |<Plug>| mappings to allow users to define
|
||||
their own keymaps with |vim.keymap.set()|.
|
||||
|
||||
- This requires one line of code in user configs.
|
||||
- Even if your plugin is not installed or disabled, creating the keymap won't
|
||||
throw an error.
|
||||
|
||||
Another option is to simply expose a Lua function or |user-commands|.
|
||||
|
||||
Some benefits of |<Plug>| mappings are that you can
|
||||
|
||||
- Enforce options like `expr = true`.
|
||||
- Use |vim.keymap|'s built-in mode handling to expose functionality only for
|
||||
specific |map-modes|.
|
||||
- Handle different |map-modes| differently with a single mapping, without
|
||||
adding mode checks to the underlying implementation.
|
||||
- Detect user-defined mappings through |hasmapto()| before creating defaults.
|
||||
|
||||
Some benefits of exposing a Lua function are:
|
||||
|
||||
- Extensibility, if the function takes an options table as an argument.
|
||||
- A cleaner UX, if there are many options and enumerating all combinations
|
||||
of options would result in a lot of |<Plug>| mappings.
|
||||
|
||||
NOTE: If your function takes an options table, users may still benefit
|
||||
from |<Plug>| mappings for the most common combinations.
|
||||
|
||||
KEYMAP EXAMPLE
|
||||
|
||||
In your plugin:
|
||||
>lua
|
||||
vim.keymap.set('n', '<Plug>(SayHello)', function()
|
||||
print('Hello from normal mode')
|
||||
end, { noremap = true })
|
||||
|
||||
vim.keymap.set('v', '<Plug>(SayHello)', function()
|
||||
print('Hello from visual mode')
|
||||
end, { noremap = true })
|
||||
<
|
||||
In the user's config:
|
||||
>lua
|
||||
vim.keymap.set({'n', 'v'}, '<leader>h', '<Plug>(SayHello)')
|
||||
<
|
||||
==============================================================================
|
||||
Initialization *lua-plugin-init*
|
||||
|
||||
Newcomers to Lua plugin development will often put all initialization logic in
|
||||
a single `setup` function, which takes a table of options.
|
||||
If you do this, users will be forced to call this function in order to use
|
||||
your plugin, even if they are happy with the default configuration.
|
||||
|
||||
Strictly separated configuration and smart initialization allow your plugin to
|
||||
work out of the box.
|
||||
|
||||
NOTE: A well designed plugin has minimal impact on startup time. See also
|
||||
|lua-plugin-lazy|.
|
||||
|
||||
Common approaches to a strictly separated configuration are:
|
||||
|
||||
- A Lua function, e.g. `setup(opts)` or `configure(opts)`, which only overrides the
|
||||
default configuration and does not contain any initialization logic.
|
||||
- A Vimscript compatible table (e.g. in the |vim.g| or |vim.b| namespace) that your
|
||||
plugin reads from and validates at initialization time.
|
||||
See also |lua-vim-variables|.
|
||||
|
||||
Typically, automatic initialization logic is done in a |plugin| or |ftplugin|
|
||||
script. See also |'runtimepath'|.
|
||||
|
||||
==============================================================================
|
||||
Lazy loading *lua-plugin-lazy*
|
||||
|
||||
Some users like to micro-manage "lazy loading" of plugins by explicitly
|
||||
configuring which commands and key mappings load the plugin.
|
||||
|
||||
Your plugin should not depend on every user micro-managing their configuration
|
||||
in such a way. Nvim has a mechanism for every plugin to do its own implicit
|
||||
lazy-loading (in Vimscript it's called |autoload|), via `autoload/`
|
||||
(Vimscript) and `lua/` (Lua). Plugin authors can provide "lazy loading" by
|
||||
providing a `plugin/<name>.lua` file which defines their commands and
|
||||
keymappings. This file should be small, and should not eagerly `require()` the
|
||||
rest of your plugin. Commands and mappings should do the `require()`.
|
||||
|
||||
Guidance:
|
||||
|
||||
- Plugins should arrange their "lazy" behavior once, instead of expecting every user to micromanage it.
|
||||
- Keep `plugin/<name>.lua` small, avoid eagerly calling `require()` on modules
|
||||
until a command or mapping is actually used.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Defer require() calls *lua-plugin-defer-require*
|
||||
|
||||
`plugin/<name>.lua` scripts (|plugin|) are eagerly run at startup; this is
|
||||
intentional, so that plugins can setup the (minimal) commands and keymappings
|
||||
that users will use to invoke the plugin. This also means these "plugin/"
|
||||
files should NOT eagerly `require` Lua modules.
|
||||
|
||||
For example, instead of:
|
||||
>lua
|
||||
local foo = require('foo')
|
||||
vim.api.nvim_create_user_command('MyCommand', function()
|
||||
foo.do_something()
|
||||
end, { -- ... })
|
||||
<
|
||||
which calls `require('foo')` as soon as the module is loaded, you can
|
||||
lazy-load it by moving the `require` into the command's implementation:
|
||||
>lua
|
||||
vim.api.nvim_create_user_command('MyCommand', function()
|
||||
local foo = require('foo')
|
||||
foo.do_something()
|
||||
end, {
|
||||
-- ...
|
||||
})
|
||||
<
|
||||
Likewise, if a plugin uses a Lua module as an entrypoint, it should
|
||||
defer `require` calls too.
|
||||
|
||||
NOTE: For a Vimscript alternative to `require`, see |autoload|.
|
||||
|
||||
NOTE: If you are worried about eagerly creating user commands, autocommands or
|
||||
keymaps at startup: Plugin managers that provide abstractions for lazy-loading
|
||||
plugins on such events do the same amount of work. There is no performance
|
||||
benefit for users to define lazy-loading entrypoints in their configuration
|
||||
instead of plugins defining it in `plugin/<name>.lua`.
|
||||
|
||||
NOTE: You can use |--startuptime| to |profile| the impact a plugin has on
|
||||
startup time.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Filetype-specific functionality *lua-plugin-filetype*
|
||||
|
||||
Consider making use of 'filetype' for any functionality that is specific to
|
||||
a filetype, by putting the initialization logic in a `ftplugin/{filetype}.lua`
|
||||
script.
|
||||
|
||||
FILETYPE EXAMPLE
|
||||
|
||||
A plugin tailored to Rust development might have initialization in
|
||||
`ftplugin/rust.lua`:
|
||||
>lua
|
||||
if not vim.g.loaded_my_rust_plugin then
|
||||
-- Initialize
|
||||
end
|
||||
-- NOTE: Using `vim.g.loaded_` prevents the plugin from initializing twice
|
||||
-- and allows users to prevent plugins from loading
|
||||
-- (in both Lua and Vimscript).
|
||||
vim.g.loaded_my_rust_plugin = true
|
||||
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
-- do something specific to this buffer,
|
||||
-- e.g. add a |<Plug>| mapping or create a command
|
||||
vim.keymap.set('n', '<Plug>(MyPluginBufferAction)', function()
|
||||
print('Hello')
|
||||
end, { noremap = true, buffer = bufnr, })
|
||||
<
|
||||
==============================================================================
|
||||
Configuration *lua-plugin-config*
|
||||
|
||||
Once you have merged the default configuration with the user's config, you
|
||||
should validate configs.
|
||||
|
||||
Validations could include:
|
||||
|
||||
- Correct types, see |vim.validate()|
|
||||
- Unknown fields in the user config (e.g. due to typos).
|
||||
This can be tricky to implement, and may be better suited for a |health|
|
||||
check, to reduce overhead.
|
||||
|
||||
==============================================================================
|
||||
Troubleshooting *lua-plugin-troubleshooting*
|
||||
|
||||
HEALTH
|
||||
|
||||
Nvim's "health" framework gives plugins a simple way to report status checks
|
||||
to users. See |health-dev| for an example.
|
||||
|
||||
Basically, this just means your plugin will have a `lua/{plugin}/health.lua`
|
||||
file. |:checkhealth| will automatically find this file when it runs.
|
||||
|
||||
Some things to validate:
|
||||
|
||||
- User configuration
|
||||
- Proper initialization
|
||||
- Presence of Lua dependencies (e.g. other plugins)
|
||||
- Presence of external dependencies
|
||||
|
||||
MINIMAL CONFIG TEMPLATE
|
||||
|
||||
It can be useful to provide a template for a minimal configuration, along with
|
||||
a guide on how to use it to reproduce issues.
|
||||
|
||||
==============================================================================
|
||||
Versioning and releases *lua-plugin-versioning*
|
||||
|
||||
Consider:
|
||||
|
||||
- Use |vim.deprecate()| or a `---@deprecate` annotation when you need to
|
||||
communicate a (future) breaking change or discourged practice.
|
||||
- Using SemVer https://semver.org/ tags and releases to properly communicate
|
||||
bug fixes, new features, and breaking changes.
|
||||
- Automating versioning and releases in CI.
|
||||
- Publishing to luarocks https://luarocks.org, especially if your plugin
|
||||
has dependencies or components that need to be built; or if it could be a
|
||||
dependency for another plugin.
|
||||
|
||||
FURTHER READING
|
||||
|
||||
- Luarocks ❤️ Nvim https://github.com/nvim-neorocks/sample-luarocks-plugin
|
||||
|
||||
VERSIONING TOOLS
|
||||
|
||||
- luarocks-tag-release
|
||||
https://github.com/marketplace/actions/luarocks-tag-release
|
||||
- release-please-action
|
||||
https://github.com/marketplace/actions/release-please-action
|
||||
- semantic-release
|
||||
https://github.com/semantic-release/semantic-release
|
||||
|
||||
==============================================================================
|
||||
Documentation *lua-plugin-doc*
|
||||
|
||||
Provide vimdoc (see |help-writing|), so that users can read your plugin's
|
||||
documentation in Nvim, by entering `:h {plugin}` in |command-mode|.
|
||||
|
||||
DOCUMENTATION TOOLS
|
||||
|
||||
- panvimdoc https://github.com/kdheepak/panvimdoc
|
||||
|
||||
|
||||
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
|
@@ -1466,20 +1466,21 @@ Lua module: vim *lua-vim*
|
||||
vim.cmd({command}) *vim.cmd()*
|
||||
Executes Vimscript (|Ex-commands|).
|
||||
|
||||
Note that `vim.cmd` can be indexed with a command name to return a
|
||||
callable function to the command.
|
||||
Can be indexed with a command name to get a function, thus you can write
|
||||
`vim.cmd.echo(…)` instead of `vim.cmd{cmd='echo',…}`.
|
||||
|
||||
Example: >lua
|
||||
Examples: >lua
|
||||
-- Single command:
|
||||
vim.cmd('echo 42')
|
||||
-- Multiline script:
|
||||
vim.cmd([[
|
||||
augroup My_group
|
||||
augroup my.group
|
||||
autocmd!
|
||||
autocmd FileType c setlocal cindent
|
||||
augroup END
|
||||
]])
|
||||
|
||||
-- Ex command :echo "foo"
|
||||
-- Note string literals need to be double quoted.
|
||||
-- Ex command :echo "foo". Note: string literals must be double-quoted.
|
||||
vim.cmd('echo "foo"')
|
||||
vim.cmd { cmd = 'echo', args = { '"foo"' } }
|
||||
vim.cmd.echo({ args = { '"foo"' } })
|
||||
@@ -1487,22 +1488,20 @@ vim.cmd({command}) *vim.cmd()*
|
||||
|
||||
-- Ex command :write! myfile.txt
|
||||
vim.cmd('write! myfile.txt')
|
||||
vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true }
|
||||
vim.cmd.write { args = { "myfile.txt" }, bang = true }
|
||||
vim.cmd.write { "myfile.txt", bang = true }
|
||||
vim.cmd { cmd = 'write', args = { 'myfile.txt' }, bang = true }
|
||||
vim.cmd.write { args = { 'myfile.txt' }, bang = true }
|
||||
vim.cmd.write { 'myfile.txt', bang = true }
|
||||
|
||||
-- Ex command :colorscheme blue
|
||||
vim.cmd('colorscheme blue')
|
||||
vim.cmd.colorscheme('blue')
|
||||
-- Ex command :vertical resize +2
|
||||
vim.cmd.resize({ '+2', mods = { vertical = true } })
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {command} (`string|table`) Command(s) to execute. If a string,
|
||||
executes multiple lines of Vimscript at once. In this case,
|
||||
it is an alias to |nvim_exec2()|, where `opts.output` is
|
||||
set to false. Thus it works identical to |:source|. If a
|
||||
table, executes a single command. In this case, it is an
|
||||
alias to |nvim_cmd()| where `opts` is empty.
|
||||
• {command} (`string|table`) Command(s) to execute.
|
||||
• The string form supports multiline Vimscript (alias to
|
||||
|nvim_exec2()|, behaves like |:source|).
|
||||
• The table form executes a single command (alias to
|
||||
|nvim_cmd()|).
|
||||
|
||||
See also: ~
|
||||
• |ex-cmd-index|
|
||||
@@ -1779,7 +1778,9 @@ vim.system({cmd}, {opts}, {on_exit}) *vim.system()*
|
||||
the new process. Inherits the current environment with
|
||||
`NVIM` set to |v:servername|.
|
||||
• clear_env: (boolean) `env` defines the job environment
|
||||
exactly, instead of merging current environment.
|
||||
exactly, instead of merging current environment. Note: if
|
||||
`env` is `nil`, the current environment is used but
|
||||
without `NVIM` set.
|
||||
• stdin: (string|string[]|boolean) If `true`, then a pipe
|
||||
to stdin is opened and can be written to via the
|
||||
`write()` method to SystemObj. If string or string[] then
|
||||
@@ -2940,11 +2941,13 @@ vim.fs.dir({path}, {opts}) *vim.fs.dir()*
|
||||
iterate over. The path is first normalized
|
||||
|vim.fs.normalize()|.
|
||||
• {opts} (`table?`) Optional keyword arguments:
|
||||
• depth: integer|nil How deep the traverse (default 1)
|
||||
• skip: (fun(dir_name: string): boolean)|nil Predicate to
|
||||
• {depth}? (`integer`, default: `1`) How deep the traverse.
|
||||
• {skip}? (`fun(dir_name: string): boolean`) Predicate to
|
||||
control traversal. Return false to stop searching the
|
||||
current directory. Only useful when depth > 1
|
||||
• follow: boolean|nil Follow symbolic links. (default: false)
|
||||
current directory. Only useful when depth > 1 Return an
|
||||
iterator over the items located in {path}
|
||||
• {follow}? (`boolean`, default: `false`) Follow symbolic
|
||||
links.
|
||||
|
||||
Return: ~
|
||||
(`Iterator`) over items in {path}. Each iteration yields two values:
|
||||
@@ -3006,7 +3009,7 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
|
||||
|
||||
The function should return `true` if the given item is
|
||||
considered a match.
|
||||
• {opts} (`table`) Optional keyword arguments:
|
||||
• {opts} (`table?`) Optional keyword arguments:
|
||||
• {path}? (`string`) Path to begin searching from. If
|
||||
omitted, the |current-directory| is used.
|
||||
• {upward}? (`boolean`, default: `false`) Search upward
|
||||
@@ -3154,7 +3157,7 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
|
||||
If the buffer is unnamed (has no backing file) or has a non-empty
|
||||
'buftype' then the search begins from Nvim's |current-directory|.
|
||||
|
||||
Example: >lua
|
||||
Examples: >lua
|
||||
-- Find the root of a Python project, starting from file 'main.py'
|
||||
vim.fs.root(vim.fs.joinpath(vim.env.PWD, 'main.py'), {'pyproject.toml', 'setup.py' })
|
||||
|
||||
@@ -3165,6 +3168,10 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
|
||||
vim.fs.root(0, function(name, path)
|
||||
return name:match('%.csproj$') ~= nil
|
||||
end)
|
||||
|
||||
-- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
|
||||
-- not found, find the first ancestor containing ".git":
|
||||
vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' })
|
||||
<
|
||||
|
||||
Attributes: ~
|
||||
@@ -3174,10 +3181,13 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
|
||||
• {source} (`integer|string`) Buffer number (0 for current buffer) or
|
||||
file path (absolute or relative to the |current-directory|)
|
||||
to begin the search from.
|
||||
• {marker} (`string|string[]|fun(name: string, path: string): boolean`)
|
||||
A marker, or list of markers, to search for. If a function,
|
||||
the function is called for each evaluated item and should
|
||||
return true if {name} and {path} are a match.
|
||||
• {marker} (`(string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean`)
|
||||
Filename, function, or list thereof, that decides how to
|
||||
find the root. To indicate "equal priority", specify items
|
||||
in a nested list `{ { 'a.txt', 'b.lua' }, … }`. A function
|
||||
item must return true if `name` and `path` are a match. Each
|
||||
item (which may itself be a nested list) is evaluated
|
||||
in-order against all ancestors, until a match is found.
|
||||
|
||||
Return: ~
|
||||
(`string?`) Directory path containing one of the given markers, or nil
|
||||
|
@@ -188,6 +188,7 @@ DEFAULTS
|
||||
• |gri| in Normal mode maps to |vim.lsp.buf.implementation()|
|
||||
• |gO| in Normal mode maps to |vim.lsp.buf.document_symbol()|
|
||||
• |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|
|
||||
• |grt| in Normal mode maps to |vim.lsp.buf.type_definition()|
|
||||
• CTRL-S in Insert and Select mode maps to |vim.lsp.buf.signature_help()|
|
||||
• Mouse |popup-menu| includes an "Open in web browser" item when you right-click
|
||||
on a URL.
|
||||
@@ -283,6 +284,8 @@ LSP
|
||||
its parameters.
|
||||
• |vim.lsp.Config| gained `workspace_required`.
|
||||
• `root_markers` in |vim.lsp.Config| can now be ordered by priority.
|
||||
• The function form of `cmd` in a vim.lsp.Config or vim.lsp.ClientConfig
|
||||
receives the resolved config as the second arg: `cmd(dispatchers, config)`.
|
||||
|
||||
LUA
|
||||
|
||||
@@ -305,6 +308,7 @@ LUA
|
||||
• |vim.hl.range()| now has a optional `timeout` field which allows for multiple
|
||||
timed highlights.
|
||||
• |vim.text.indent()| indents/dedents text.
|
||||
• |vim.fs.root()| can define "equal priority" via nested lists.
|
||||
|
||||
OPTIONS
|
||||
|
||||
@@ -352,6 +356,11 @@ PLUGINS
|
||||
• Customize :checkhealth by handling a `FileType checkhealth` event.
|
||||
|health-usage|
|
||||
|
||||
• Simplify Python provider setup to a single step: `uv tool install pynvim`
|
||||
Nvim will detect the plugin's location without user configuration, even if
|
||||
unrelated Python virtual environments are activated.
|
||||
|provider-python|
|
||||
|
||||
STARTUP
|
||||
|
||||
• |-es| ("script mode") disables shada by default.
|
||||
|
@@ -11,15 +11,43 @@ not a clone: compatibility with Vim (especially editor and Vimscript features,
|
||||
except |Vim9script|) is maintained where possible. See |vim-differences| for
|
||||
the complete reference.
|
||||
|
||||
If you already use Vim, see |nvim-from-vim| for a quickstart. If you just
|
||||
installed Nvim and have never used it before, watch this 10-minute
|
||||
video: https://youtu.be/TQn2hJeHQbM .
|
||||
- If you already use Vim, see |nvim-from-vim| for a quickstart.
|
||||
- If you have never used Vim or Nvim before, see below.
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
What now? *nvim-quickstart*
|
||||
|
||||
To learn how to use Vim in 30 minutes, try the tutorial: >vim
|
||||
|
||||
:Tutor<Enter>
|
||||
<
|
||||
Type |gO| to see the table of contents.
|
||||
Or watch this 10-minute video: https://youtu.be/TQn2hJeHQbM .
|
||||
|
||||
To customize Nvim, you will need a config file. Create your |init.lua| by
|
||||
copying the "example_init.lua" file: >vim
|
||||
|
||||
:exe 'edit' stdpath('config') .. '/init.lua'
|
||||
:read $VIMRUNTIME/example_init.lua
|
||||
<
|
||||
See |lua-guide| for practical notes on using Lua to configure Nvim.
|
||||
|
||||
"IDE" features in Nvim are provided by |LSP|.
|
||||
|
||||
If you are just trying out Nvim for a few minutes, and want to see the
|
||||
extremes of what it can do, try one of these popular "extension packs" or
|
||||
"distributions" (Note: Nvim is not affiliated with these projects, and does
|
||||
not support them):
|
||||
|
||||
- *lazyvim* https://www.lazyvim.org/
|
||||
- *nvchad* https://nvchad.com/
|
||||
- *kickstart* https://github.com/nvim-lua/kickstart.nvim
|
||||
- Not recommended; use `$VIMRUNTIME/example_init.lua` instead.
|
||||
|
||||
However, we recommend (eventually) taking time to learn Nvim from its stock
|
||||
configuration, and incrementally setting options and adding plugins to your
|
||||
|config| as you discover a need.
|
||||
|
||||
==============================================================================
|
||||
Transitioning from Vim *nvim-from-vim*
|
||||
@@ -72,31 +100,5 @@ the same Nvim configuration on all of your machines, by creating
|
||||
~/AppData/Local/nvim/init.vim containing just this line: >vim
|
||||
source ~/.config/nvim/init.vim
|
||||
|
||||
==============================================================================
|
||||
What next? *nvim-quickstart*
|
||||
|
||||
If you want to use Lua to configure Nvim, you can copy an example
|
||||
configuration to your |init.lua|
|
||||
>vim
|
||||
:exe 'edit' stdpath('config') .. '/init.lua'
|
||||
:read $VIMRUNTIME/example_init.lua
|
||||
<
|
||||
See |lua-guide| for practical notes on using Lua to configure Nvim.
|
||||
|
||||
"IDE" features in Nvim are provided by Language Server Protocol. See |lsp|
|
||||
|
||||
If you are just trying out Nvim for a few minutes, and want to see the
|
||||
extremes of what it can do, try one of these popular "extension packs" or
|
||||
"distributions" (Note: Nvim is not affiliated with these projects, and does
|
||||
not support them):
|
||||
|
||||
- *kickstart* https://github.com/nvim-lua/kickstart.nvim
|
||||
- *lazyvim* https://www.lazyvim.org/
|
||||
- *nvchad* https://nvchad.com/
|
||||
|
||||
However, in general, we recommend (eventually) taking time to learn Nvim from
|
||||
its stock configuration, and incrementally setting options and adding plugins
|
||||
to your |config| as you find an explicit need to do so.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:et:ft=help:norl:
|
||||
|
@@ -2357,6 +2357,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
in the |trust| list. Use |:trust| to manage trusted files. See also
|
||||
|vim.secure.read()|.
|
||||
|
||||
To get its own location, Lua exrc files can use |debug.getinfo()|.
|
||||
|
||||
Compare 'exrc' to |editorconfig|:
|
||||
- 'exrc' can execute any code; editorconfig only specifies settings.
|
||||
- 'exrc' is Nvim-specific; editorconfig works in other editors.
|
||||
@@ -5010,9 +5012,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
the end of line the line break still isn't included.
|
||||
When "exclusive" is used, cursor position in visual mode will be
|
||||
adjusted for inclusive motions |inclusive-motion-selection-exclusive|.
|
||||
Note that when "exclusive" is used and selecting from the end
|
||||
backwards, you cannot include the last character of a line, when
|
||||
starting in Normal mode and 'virtualedit' empty.
|
||||
|
||||
Note:
|
||||
- When "exclusive" is used and selecting from the end backwards, you
|
||||
cannot include the last character of a line, when starting in Normal
|
||||
mode and 'virtualedit' empty.
|
||||
- when "exclusive" is used with a single character visual selection,
|
||||
Vim will behave as if the 'selection' is inclusive (in other words,
|
||||
you cannot visually select an empty region).
|
||||
|
||||
*'selectmode'* *'slm'*
|
||||
'selectmode' 'slm' string (default "")
|
||||
|
@@ -36,21 +36,18 @@ itself).
|
||||
|
||||
For Python 3 plugins:
|
||||
1. Make sure Python 3.9+ is available in your $PATH.
|
||||
2. Install the module (try "python" if "python3" is missing): >bash
|
||||
python3 -m pip install --user --upgrade pynvim
|
||||
2. Install either uv (https://docs.astral.sh/uv/) or pipx
|
||||
(https://pipx.pypa.io/stable/).
|
||||
3. Install the module: >bash
|
||||
uv tool install --upgrade pynvim
|
||||
# or:
|
||||
pipx install --upgrade pynvim
|
||||
|
||||
The pip `--upgrade` flag ensures that you get the latest version even if
|
||||
The `--upgrade` flag ensures that you get the latest version even if
|
||||
a previous version was already installed.
|
||||
|
||||
See also |python-virtualenv|.
|
||||
|
||||
Note: The old "neovim" module was renamed to "pynvim".
|
||||
https://github.com/neovim/neovim/wiki/Following-HEAD#20181118
|
||||
If you run into problems, uninstall _both_ then install "pynvim" again: >bash
|
||||
python -m pip uninstall neovim pynvim
|
||||
python -m pip install --user --upgrade pynvim
|
||||
|
||||
|
||||
PYTHON PROVIDER CONFIGURATION ~
|
||||
*g:python3_host_prog*
|
||||
Command to start Python 3 (executable, not directory). Setting this makes
|
||||
@@ -65,20 +62,18 @@ To disable Python 3 support: >vim
|
||||
|
||||
PYTHON VIRTUALENVS ~
|
||||
*python-virtualenv*
|
||||
If you plan to use per-project virtualenvs often, you should assign one
|
||||
virtualenv for Nvim and hard-code the interpreter path via
|
||||
|g:python3_host_prog| so that the "pynvim" package is not required
|
||||
for each virtualenv.
|
||||
|
||||
Example using pyenv: >bash
|
||||
pyenv install 3.4.4
|
||||
pyenv virtualenv 3.4.4 py3nvim
|
||||
pyenv activate py3nvim
|
||||
python3 -m pip install pynvim
|
||||
pyenv which python # Note the path
|
||||
The last command reports the interpreter path, add it to your init.vim: >vim
|
||||
let g:python3_host_prog = '/path/to/py3nvim/bin/python'
|
||||
Using pynvim 0.6.0+ installed via uv or pipx, Nvim will automatically detect
|
||||
pynvim even if other Python virtual environments are activated (technical
|
||||
note: via the "pynvim-python" global python tool). For older pynvim (or older
|
||||
Neovim), where detection involved finding the first Python interpreter and
|
||||
checking if it could import pynvim, automatic detection would fail when
|
||||
another virtual environment is active. Upgrading to the latest pynvim is the
|
||||
recommended solution to this; but if that's not an option, then you can set
|
||||
the variable |g:python3_host_prog| in `init.vim` to point to the full path to
|
||||
the Python interpreter where `pynvim` is installed, e.g.: >vim
|
||||
|
||||
let g:python3_host_prog = '/path/to/pynvim-venv/bin/python'
|
||||
<
|
||||
See also: https://github.com/zchee/deoplete-jedi/wiki/Setting-up-Python-for-Neovim
|
||||
|
||||
==============================================================================
|
||||
|
@@ -573,7 +573,10 @@ parent tree. The language injection query allows you to specify these
|
||||
“injections” using the following captures:
|
||||
|
||||
• `@injection.content` - indicates that the captured node should have its
|
||||
contents re-parsed using another language.
|
||||
contents re-parsed using another language. If there are multiple
|
||||
`@injection.content` captures in one pattern, all ranges will be
|
||||
collected and parsed as one tree. This allows query authors to create
|
||||
"scoped" injections with injection query quantifiers.
|
||||
• `@injection.language` - indicates that the captured node’s text may
|
||||
contain the name of a language that should be used to re-parse the
|
||||
`@injection.content`.
|
||||
|
@@ -25,9 +25,9 @@ Table of contents: |usr_toc.txt|
|
||||
==============================================================================
|
||||
*02.1* Running Vim for the First Time
|
||||
|
||||
To start Vim, enter this command: >
|
||||
To start Nvim, enter this command: >
|
||||
|
||||
gvim file.txt
|
||||
nvim file.txt
|
||||
|
||||
On Unix you can type this at any command prompt. If you are running Microsoft
|
||||
Windows, open a Command Prompt and enter the command. In either case, Vim
|
||||
@@ -50,20 +50,6 @@ screen, a message line indicates the file is named file.txt and shows that you
|
||||
are creating a new file. The message information is temporary and other
|
||||
information overwrites it.
|
||||
|
||||
|
||||
THE VIM COMMAND
|
||||
|
||||
The gvim command causes the editor to create a new window for editing. If you
|
||||
use this command: >
|
||||
|
||||
vim file.txt
|
||||
|
||||
the editing occurs inside your command window. In other words, if you are
|
||||
running inside an xterm, the editor uses your xterm window. If you are using
|
||||
the command prompt under Microsoft Windows, the editing occurs inside this
|
||||
window. The text in the window will look the same for both versions, but with
|
||||
gvim you have extra features, like a menu bar. More about that later.
|
||||
|
||||
==============================================================================
|
||||
*02.2* Inserting text
|
||||
|
||||
@@ -580,7 +566,7 @@ Summary: *help-summary* >
|
||||
:help quote:
|
||||
|
||||
13) Vim Script is available at >
|
||||
:help eval.txt
|
||||
:help vimeval.txt
|
||||
< Certain aspects of the language are available at :h expr-X where "X" is a
|
||||
single letter. E.g. >
|
||||
:help expr-!
|
||||
@@ -660,10 +646,13 @@ Summary: *help-summary* >
|
||||
command switch of Vim use: >
|
||||
:help -f
|
||||
|
||||
24) Optional features always start with "+". To find out about the
|
||||
conceal feature use: >
|
||||
:help +conceal
|
||||
|
||||
24) Lua language and Nvim's Lua standard library are available at >vim
|
||||
:help lua.txt
|
||||
< Guide to using Lua in Nvim is available at >vim
|
||||
:help lua-guide.txt
|
||||
< Lua 5.1 reference manual is available at >vim
|
||||
:help luaref.txt
|
||||
<
|
||||
25) Documentation for included filetype specific functionality is usually
|
||||
available in the form ft-<filetype>-<functionality>. So >
|
||||
:help ft-c-syntax
|
||||
|
@@ -134,7 +134,8 @@ To remove only the "How-to disable mouse" menu item (and its separator): >vim
|
||||
DEFAULT MAPPINGS
|
||||
*default-mappings*
|
||||
Nvim creates the following default mappings at |startup|. You can disable any
|
||||
of these in your config by simply removing the mapping, e.g. ":unmap Y".
|
||||
of these in your config by simply removing the mapping, e.g. ":unmap Y". If
|
||||
you never want any default mappings, call |:mapclear| early in your config.
|
||||
|
||||
- Y |Y-default|
|
||||
- <C-U> |i_CTRL-U-default|
|
||||
@@ -152,6 +153,7 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
|
||||
- |grr|
|
||||
- |gra|
|
||||
- |gri|
|
||||
- |grt|
|
||||
- |gO|
|
||||
- <C-S> |i_CTRL-S|
|
||||
- ]d |]d-default|
|
||||
@@ -855,9 +857,8 @@ Startup:
|
||||
Test functions:
|
||||
- test_alloc_fail()
|
||||
- test_autochdir()
|
||||
- test_disable_char_avail()
|
||||
- test_feedinput()
|
||||
- test_garbagecollect_soon
|
||||
- test_garbagecollect_soon()
|
||||
- test_getvalue()
|
||||
- test_ignore_error()
|
||||
- test_null_blob()
|
||||
@@ -875,6 +876,8 @@ Test functions:
|
||||
- test_setmouse()
|
||||
- test_settime()
|
||||
- test_srand_seed()
|
||||
- test_unknown()
|
||||
- test_void()
|
||||
|
||||
TUI:
|
||||
*t_xx* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI*
|
||||
|
@@ -1,10 +1,10 @@
|
||||
*eval.txt* Nvim
|
||||
*vimeval.txt* Nvim
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
|
||||
|
||||
Expression evaluation *vimscript* *expression* *expr* *E15* *eval*
|
||||
Expression evaluation *vimscript* *expression* *expr* *E15* *eval* *eval.txt*
|
||||
|
||||
Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|.
|
||||
|
@@ -1,10 +1,10 @@
|
||||
*builtin.txt* Nvim
|
||||
*vimfn.txt* Nvim
|
||||
|
||||
|
||||
NVIM REFERENCE MANUAL
|
||||
|
||||
|
||||
Builtin functions *vimscript-functions* *builtin-functions*
|
||||
Vimscript functions *vimscript-functions* *builtin-functions* *builtin.txt*
|
||||
|
||||
For functions grouped by what they are used for see |function-list|.
|
||||
|
||||
@@ -2040,7 +2040,8 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
|
||||
<SID> "<SNR>123_" where "123" is the
|
||||
current script ID |<SID>|
|
||||
<script> sourced script file, or script file
|
||||
where the current function was defined
|
||||
where the current function was defined.
|
||||
Use |debug.getinfo()| in Lua scripts.
|
||||
<stack> call stack
|
||||
<cword> word under the cursor
|
||||
<cWORD> WORD under the cursor
|
||||
@@ -4093,6 +4094,10 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()*
|
||||
- It is evaluated in current window context, which makes a
|
||||
difference if the buffer is displayed in a window with
|
||||
different 'virtualedit' or 'list' values.
|
||||
- When specifying an exclusive selection and {pos1} and {pos2}
|
||||
are equal, the returned list contains a single character as
|
||||
if selection is inclusive, to match the behavior of an empty
|
||||
exclusive selection in Visual mode.
|
||||
|
||||
Examples: >vim
|
||||
xnoremap <CR>
|
@@ -3,6 +3,7 @@
|
||||
" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com>
|
||||
" Last Change: 2024 Apr 21
|
||||
" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
|
||||
" 2025 Aug 29 by Vim project, add try/catch around json_decode(), #18141
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -52,13 +53,19 @@ function! s:CollectPathsFromConfig() abort
|
||||
endif
|
||||
endif
|
||||
|
||||
let paths_from_config = config_json
|
||||
try
|
||||
let paths_from_config = config_json
|
||||
\ ->readfile()
|
||||
\ ->filter({ _, val -> val =~ '^\s*[\[\]{}"0-9]' })
|
||||
\ ->join()
|
||||
\ ->json_decode()
|
||||
\ ->get('compilerOptions', {})
|
||||
\ ->get('paths', {})
|
||||
catch /^Vim\%((\a\+)\)\=:E491:/ " invalid json
|
||||
let paths_from_config = {}
|
||||
catch /^Vim\%((\a\+)\)\=:E474:/ " invalid json in Nvim
|
||||
let paths_from_config = {}
|
||||
endtry
|
||||
|
||||
if !empty(paths_from_config)
|
||||
let b:astro_paths = paths_from_config
|
||||
|
@@ -1,5 +1,5 @@
|
||||
vim.keymap.set('n', 'gO', function()
|
||||
require('vim.treesitter._headings').show_toc()
|
||||
require('vim.treesitter._headings').show_toc(6)
|
||||
end, { buffer = 0, silent = true, desc = 'Show an Outline of the current buffer' })
|
||||
|
||||
vim.keymap.set('n', ']]', function()
|
||||
|
@@ -1,7 +1,8 @@
|
||||
" Vim filetype plugin file
|
||||
" Language: gpg(1) configuration file
|
||||
" Maintainer: This runtime file is looking for a new maintainer.
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
|
||||
" Latest Revision: 2025-07-22 (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -17,7 +18,7 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 GpgKeywordPrg
|
||||
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+--' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'gpg'
|
||||
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+--' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'gpg'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:GpgKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer GpgKeywordPrg'
|
||||
|
@@ -5,7 +5,9 @@
|
||||
" Contributor: Dorai Sitaram <ds26@gte.com>
|
||||
" C.D. MacEachern <craig.daniel.maceachern@gmail.com>
|
||||
" Phạm Bình An <phambinhanctb2004@gmail.com>
|
||||
" Last Change: 2025 Feb 27
|
||||
" @konfekt
|
||||
" Last Change: 2025 Apr 04
|
||||
" 2025 May 06 by Vim Project update 'path' setting #17267
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -28,6 +30,7 @@ set cpo&vim
|
||||
setlocal comments=:---,:--
|
||||
setlocal commentstring=--\ %s
|
||||
setlocal formatoptions-=t formatoptions+=croql
|
||||
setlocal path-=. " Lua doesn't support importing module in path related to current file like JS
|
||||
|
||||
let &l:define = '\<function\|\<local\%(\s\+function\)\='
|
||||
|
||||
@@ -35,7 +38,7 @@ let &l:include = '\<\%(\%(do\|load\)file\|require\)\s*('
|
||||
setlocal includeexpr=s:LuaInclude(v:fname)
|
||||
setlocal suffixesadd=.lua
|
||||
|
||||
let b:undo_ftplugin = "setl cms< com< def< fo< inc< inex< sua<"
|
||||
let b:undo_ftplugin = "setl cms< com< def< fo< inc< inex< sua< pa<"
|
||||
|
||||
if exists("loaded_matchit") && !exists("b:match_words")
|
||||
let b:match_ignorecase = 0
|
||||
|
@@ -2,7 +2,7 @@
|
||||
" Language: modules.conf(5) configuration file
|
||||
" Maintainer: This runtime file is looking for a new maintainer.
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Latest Revision: 2024-09-20 (remove erroneous endif)
|
||||
" Latest Revision: 2025-07-22 (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -19,7 +19,7 @@ setlocal formatoptions-=t formatoptions+=croql
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 ModconfKeywordPrg
|
||||
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'modprobe.d'
|
||||
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'modprobe.d'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:ModconfKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ModconfKeywordPrg'
|
||||
|
@@ -1,7 +1,8 @@
|
||||
" Vim filetype plugin file
|
||||
" Language: mutt RC File
|
||||
" Maintainer: This runtime file is looking for a new maintainer.
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
|
||||
" Latest Revision: 2025-07-22 (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -20,7 +21,7 @@ let &l:include = '^\s*source\>'
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 MuttrcKeywordPrg
|
||||
\ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'muttrc'
|
||||
\ silent exe 'hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'muttrc'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:MuttrcKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer MuttrcKeywordPrg'
|
||||
|
@@ -5,6 +5,7 @@
|
||||
" 2024 Jan 14 by Vim Project (browsefilter)
|
||||
" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
|
||||
" 2024 Sep 19 by Konfekt (simplify keywordprg #15696)
|
||||
" 2025 Jul 22 by phanium (use :hor term #17822)
|
||||
|
||||
" Only do this when not done yet for this buffer
|
||||
if exists("b:did_ftplugin") | finish | endif
|
||||
@@ -51,7 +52,7 @@ endif
|
||||
|
||||
if exists('s:pwsh_cmd')
|
||||
if exists(':terminal') == 2
|
||||
command! -buffer -nargs=1 GetHelp silent exe 'term ' . s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full "<args>"' . (executable('less') ? ' | less' : '')
|
||||
command! -buffer -nargs=1 GetHelp silent exe 'hor term ' . s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full "<args>"' . (executable('less') ? ' | less' : '')
|
||||
else
|
||||
command! -buffer -nargs=1 GetHelp echo system(s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full <args>')
|
||||
endif
|
||||
|
@@ -3,6 +3,7 @@
|
||||
" Maintainer: Doug Kearns <dougkearns@gmail.com>
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Last Change: 2024 Sep 19 (simplify keywordprg #15696)
|
||||
" 2024 Jul 22 by Vim project (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -36,7 +37,7 @@ endif
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 ReadlineKeywordPrg
|
||||
\ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . '3 readline'
|
||||
\ silent exe 'hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . '3 readline'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:ReadlineKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ReadlineKeywordPrg'
|
||||
|
@@ -7,6 +7,7 @@
|
||||
" Last Change: 2024 Sep 19 by Vim Project (compiler shellcheck)
|
||||
" 2024 Dec 29 by Vim Project (improve setting shellcheck compiler)
|
||||
" 2025 Mar 09 by Vim Project (set b:match_skip)
|
||||
" 2025 Jul 22 by phanium (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -53,7 +54,7 @@ let s:is_kornshell = get(b:, "is_kornshell", get(g:, "is_kornshell", 0))
|
||||
|
||||
if s:is_bash
|
||||
if exists(':terminal') == 2
|
||||
command! -buffer -nargs=1 ShKeywordPrg silent exe ':term bash -c "help "<args>" 2>/dev/null || man "<args>""'
|
||||
command! -buffer -nargs=1 ShKeywordPrg silent exe ':hor term bash -c "help "<args>" 2>/dev/null || man "<args>""'
|
||||
else
|
||||
command! -buffer -nargs=1 ShKeywordPrg echo system('bash -c "help <args>" 2>/dev/null || MANPAGER= man "<args>"')
|
||||
endif
|
||||
|
@@ -2,7 +2,7 @@
|
||||
" Language: OpenSSH client configuration file
|
||||
" Maintainer: This runtime file is looking for a new maintainer.
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
|
||||
" Latest Revision: 2025-07-22 (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -17,7 +17,7 @@ let b:undo_ftplugin = 'setlocal com< cms< fo<'
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 SshconfigKeywordPrg
|
||||
\ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '$', '\') . ''' --hilite-search" man ' . 'ssh_config'
|
||||
\ silent exe 'hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '$', '\') . ''' --hilite-search" man ' . 'ssh_config'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:SshconfigKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SshconfigKeywordPrg'
|
||||
|
@@ -2,7 +2,7 @@
|
||||
" Language: sudoers(5) configuration files
|
||||
" Maintainer: This runtime file is looking for a new maintainer.
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
|
||||
" Latest Revision: 2025-07-22 (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -18,7 +18,7 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 SudoersKeywordPrg
|
||||
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('\b' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'sudoers'
|
||||
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('\b' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'sudoers'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:SudoersKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SudoersKeywordPrg'
|
||||
|
@@ -2,7 +2,7 @@
|
||||
" Language: udev(8) rules file
|
||||
" Maintainer: This runtime file is looking for a new maintainer.
|
||||
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
|
||||
" Latest Revision: 2024-09-19 (simplify keywordprg #15696)
|
||||
" Latest Revision: 2025-07-22 (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -18,7 +18,7 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
|
||||
|
||||
if has('unix') && executable('less') && exists(':terminal') == 2
|
||||
command -buffer -nargs=1 UdevrulesKeywordPrg
|
||||
\ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'udev'
|
||||
\ silent exe ':hor term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'udev'
|
||||
setlocal iskeyword+=-
|
||||
setlocal keywordprg=:UdevrulesKeywordPrg
|
||||
let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer UdevrulesKeywordPrg'
|
||||
|
@@ -5,6 +5,8 @@
|
||||
" Latest Revision: 2024 Sep 19
|
||||
" License: Vim (see :h license)
|
||||
" Repository: https://github.com/chrisbra/vim-zsh
|
||||
" Last Change:
|
||||
" 2025 Jul 23 by Vim Project (use :hor term #17822)
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -20,7 +22,7 @@ let b:undo_ftplugin = "setl com< cms< fo< "
|
||||
|
||||
if executable('zsh') && &shell !~# '/\%(nologin\|false\)$'
|
||||
if exists(':terminal') == 2
|
||||
command! -buffer -nargs=1 ZshKeywordPrg silent exe ':term zsh -c "autoload -Uz run-help; run-help <args>"'
|
||||
command! -buffer -nargs=1 ZshKeywordPrg silent exe ':hor term zsh -c "autoload -Uz run-help; run-help <args>"'
|
||||
else
|
||||
command! -buffer -nargs=1 ZshKeywordPrg echo system('MANPAGER= zsh -c "autoload -Uz run-help; run-help <args> 2>/dev/null"')
|
||||
endif
|
||||
|
@@ -3,6 +3,7 @@
|
||||
" Maintainer: See https://github.com/HerringtonDarkholme/yats.vim
|
||||
" Last Change: 2019 Oct 18
|
||||
" 2023 Aug 28 by Vim Project (undo_indent)
|
||||
" 2025 Jun 05 by Vim Project (remove Fixedgq() formatexp, #17452)
|
||||
" Acknowledgement: Based off of vim-ruby maintained by Nikolai Weibull http://vim-ruby.rubyforge.org
|
||||
|
||||
" 0. Initialization {{{1
|
||||
@@ -18,10 +19,9 @@ setlocal nosmartindent
|
||||
|
||||
" Now, set up our indentation expression and keys that trigger it.
|
||||
setlocal indentexpr=GetTypescriptIndent()
|
||||
setlocal formatexpr=Fixedgq(v:lnum,v:count)
|
||||
setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e
|
||||
|
||||
let b:undo_indent = "setlocal formatexpr< indentexpr< indentkeys< smartindent<"
|
||||
let b:undo_indent = "setlocal indentexpr< indentkeys< smartindent<"
|
||||
|
||||
" Only define the function once.
|
||||
if exists("*GetTypescriptIndent")
|
||||
@@ -443,64 +443,3 @@ endfunction
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
||||
function! Fixedgq(lnum, count)
|
||||
let l:tw = &tw ? &tw : 80
|
||||
|
||||
let l:count = a:count
|
||||
let l:first_char = indent(a:lnum) + 1
|
||||
|
||||
if mode() == 'i' " gq was not pressed, but tw was set
|
||||
return 1
|
||||
endif
|
||||
|
||||
" This gq is only meant to do code with strings, not comments
|
||||
if s:IsLineComment(a:lnum, l:first_char) || s:IsInMultilineComment(a:lnum, l:first_char)
|
||||
return 1
|
||||
endif
|
||||
|
||||
if len(getline(a:lnum)) < l:tw && l:count == 1 " No need for gq
|
||||
return 1
|
||||
endif
|
||||
|
||||
" Put all the lines on one line and do normal splitting after that
|
||||
if l:count > 1
|
||||
while l:count > 1
|
||||
let l:count -= 1
|
||||
normal J
|
||||
endwhile
|
||||
endif
|
||||
|
||||
let l:winview = winsaveview()
|
||||
|
||||
call cursor(a:lnum, l:tw + 1)
|
||||
let orig_breakpoint = searchpairpos(' ', '', '\.', 'bcW', '', a:lnum)
|
||||
call cursor(a:lnum, l:tw + 1)
|
||||
let breakpoint = searchpairpos(' ', '', '\.', 'bcW', s:skip_expr, a:lnum)
|
||||
|
||||
" No need for special treatment, normal gq handles edgecases better
|
||||
if breakpoint[1] == orig_breakpoint[1]
|
||||
call winrestview(l:winview)
|
||||
return 1
|
||||
endif
|
||||
|
||||
" Try breaking after string
|
||||
if breakpoint[1] <= indent(a:lnum)
|
||||
call cursor(a:lnum, l:tw + 1)
|
||||
let breakpoint = searchpairpos('\.', '', ' ', 'cW', s:skip_expr, a:lnum)
|
||||
endif
|
||||
|
||||
|
||||
if breakpoint[1] != 0
|
||||
call feedkeys("r\<CR>")
|
||||
else
|
||||
let l:count = l:count - 1
|
||||
endif
|
||||
|
||||
" run gq on new lines
|
||||
if l:count == 1
|
||||
call feedkeys("gqq")
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
@@ -245,7 +245,7 @@ local function parse_line(line)
|
||||
end
|
||||
|
||||
--- @type string?
|
||||
local glob = (line:match('%b[]') or ''):match('^%s*%[(.*)%]%s*$')
|
||||
local glob = line:match('^%s*%[(.*)%]%s*$')
|
||||
if glob then
|
||||
return glob
|
||||
end
|
||||
|
86
runtime/lua/nvim/tutor.lua
Normal file
86
runtime/lua/nvim/tutor.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
---@class nvim.TutorMetadata
|
||||
---@field expect table<string, string|-1>
|
||||
|
||||
---@alias nvim.TutorExtmarks table<string, string>
|
||||
|
||||
---@type nvim.TutorExtmarks?
|
||||
vim.b.tutor_extmarks = vim.b.tutor_extmarks
|
||||
|
||||
---@type nvim.TutorMetadata?
|
||||
vim.b.tutor_metadata = vim.b.tutor_metadata
|
||||
|
||||
local sign_text_correct = '✓'
|
||||
local sign_text_incorrect = '✗'
|
||||
local tutor_mark_ns = vim.api.nvim_create_namespace('nvim.tutor.mark')
|
||||
local tutor_hl_ns = vim.api.nvim_create_namespace('nvim.tutor.hl')
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param line integer 1-based
|
||||
local function check_line(line)
|
||||
if vim.b.tutor_metadata and vim.b.tutor_metadata.expect and vim.b.tutor_extmarks then
|
||||
local ctext = vim.fn.getline(line)
|
||||
|
||||
---@type vim.api.keyset.get_extmark_item[]
|
||||
local extmarks = vim
|
||||
.iter(vim.api.nvim_buf_get_extmarks(
|
||||
0,
|
||||
tutor_mark_ns,
|
||||
{ line - 1, 0 },
|
||||
{ line - 1, -1 }, -- the extmark can move to col > 0 if users insert text there
|
||||
{ details = true }
|
||||
))
|
||||
:filter(function(extmark)
|
||||
return not extmark[4].invalid
|
||||
end)
|
||||
:totable()
|
||||
|
||||
for _, extmark in ipairs(extmarks) do
|
||||
local mark_id = extmark[1]
|
||||
local expct = vim.b.tutor_extmarks[tostring(mark_id)]
|
||||
local expect = vim.b.tutor_metadata.expect[expct]
|
||||
local is_correct = expect == -1 or ctext == expect
|
||||
|
||||
vim.api.nvim_buf_set_extmark(0, tutor_mark_ns, line - 1, 0, {
|
||||
id = mark_id,
|
||||
sign_text = is_correct and sign_text_correct or sign_text_incorrect,
|
||||
sign_hl_group = is_correct and 'tutorOK' or 'tutorX',
|
||||
invalidate = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.apply_marks()
|
||||
vim.cmd [[hi! link tutorExpect Special]]
|
||||
if vim.b.tutor_metadata and vim.b.tutor_metadata.expect then
|
||||
vim.b.tutor_extmarks = {}
|
||||
for expct, _ in pairs(vim.b.tutor_metadata.expect) do
|
||||
---@diagnostic disable-next-line: assign-type-mismatch
|
||||
local lnum = tonumber(expct) ---@type integer
|
||||
vim.api.nvim_buf_set_extmark(0, tutor_hl_ns, lnum - 1, 0, {
|
||||
line_hl_group = 'tutorExpect',
|
||||
invalidate = true,
|
||||
})
|
||||
|
||||
local mark_id = vim.api.nvim_buf_set_extmark(0, tutor_mark_ns, lnum - 1, 0, {})
|
||||
|
||||
-- Cannot edit field of a Vimscript dictionary from Lua directly, see `:h lua-vim-variables`
|
||||
---@type nvim.TutorExtmarks
|
||||
local tutor_extmarks = vim.b.tutor_extmarks
|
||||
tutor_extmarks[tostring(mark_id)] = expct
|
||||
vim.b.tutor_extmarks = tutor_extmarks
|
||||
|
||||
check_line(lnum)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.apply_marks_on_changed()
|
||||
if vim.b.tutor_metadata and vim.b.tutor_metadata.expect and vim.b.tutor_extmarks then
|
||||
local lnum = vim.fn.line('.')
|
||||
check_line(lnum)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@@ -191,7 +191,7 @@ do
|
||||
--- client is attached. If no client is attached, or if a server does not support a capability, an
|
||||
--- error message is displayed rather than exhibiting different behavior.
|
||||
---
|
||||
--- See |grr|, |grn|, |gra|, |gri|, |gO|, |i_CTRL-S|.
|
||||
--- See |grr|, |grn|, |gra|, |gri|, |grt| |gO|, |i_CTRL-S|.
|
||||
do
|
||||
vim.keymap.set('n', 'grn', function()
|
||||
vim.lsp.buf.rename()
|
||||
@@ -209,6 +209,10 @@ do
|
||||
vim.lsp.buf.implementation()
|
||||
end, { desc = 'vim.lsp.buf.implementation()' })
|
||||
|
||||
vim.keymap.set('n', 'grt', function()
|
||||
vim.lsp.buf.type_definition()
|
||||
end, { desc = 'vim.lsp.buf.type_definition()' })
|
||||
|
||||
vim.keymap.set('n', 'gO', function()
|
||||
vim.lsp.buf.document_symbol()
|
||||
end, { desc = 'vim.lsp.buf.document_symbol()' })
|
||||
|
@@ -106,7 +106,7 @@ local utfs = {
|
||||
--- - env: table<string,string> Set environment variables for the new process. Inherits the
|
||||
--- current environment with `NVIM` set to |v:servername|.
|
||||
--- - clear_env: (boolean) `env` defines the job environment exactly, instead of merging current
|
||||
--- environment.
|
||||
--- environment. Note: if `env` is `nil`, the current environment is used but without `NVIM` set.
|
||||
--- - stdin: (string|string[]|boolean) If `true`, then a pipe to stdin is opened and can be written
|
||||
--- to via the `write()` method to SystemObj. If string or string[] then will be written to stdin
|
||||
--- and closed. Defaults to `false`.
|
||||
@@ -399,22 +399,23 @@ local VIM_CMD_ARG_MAX = 20
|
||||
|
||||
--- Executes Vimscript (|Ex-commands|).
|
||||
---
|
||||
--- Note that `vim.cmd` can be indexed with a command name to return a callable function to the
|
||||
--- command.
|
||||
--- Can be indexed with a command name to get a function, thus you can write `vim.cmd.echo(…)`
|
||||
--- instead of `vim.cmd{cmd='echo',…}`.
|
||||
---
|
||||
--- Example:
|
||||
--- Examples:
|
||||
---
|
||||
--- ```lua
|
||||
--- -- Single command:
|
||||
--- vim.cmd('echo 42')
|
||||
--- -- Multiline script:
|
||||
--- vim.cmd([[
|
||||
--- augroup My_group
|
||||
--- augroup my.group
|
||||
--- autocmd!
|
||||
--- autocmd FileType c setlocal cindent
|
||||
--- augroup END
|
||||
--- ]])
|
||||
---
|
||||
--- -- Ex command :echo "foo"
|
||||
--- -- Note string literals need to be double quoted.
|
||||
--- -- Ex command :echo "foo". Note: string literals must be double-quoted.
|
||||
--- vim.cmd('echo "foo"')
|
||||
--- vim.cmd { cmd = 'echo', args = { '"foo"' } }
|
||||
--- vim.cmd.echo({ args = { '"foo"' } })
|
||||
@@ -422,22 +423,19 @@ local VIM_CMD_ARG_MAX = 20
|
||||
---
|
||||
--- -- Ex command :write! myfile.txt
|
||||
--- vim.cmd('write! myfile.txt')
|
||||
--- vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true }
|
||||
--- vim.cmd.write { args = { "myfile.txt" }, bang = true }
|
||||
--- vim.cmd.write { "myfile.txt", bang = true }
|
||||
--- vim.cmd { cmd = 'write', args = { 'myfile.txt' }, bang = true }
|
||||
--- vim.cmd.write { args = { 'myfile.txt' }, bang = true }
|
||||
--- vim.cmd.write { 'myfile.txt', bang = true }
|
||||
---
|
||||
--- -- Ex command :colorscheme blue
|
||||
--- vim.cmd('colorscheme blue')
|
||||
--- vim.cmd.colorscheme('blue')
|
||||
--- -- Ex command :vertical resize +2
|
||||
--- vim.cmd.resize({ '+2', mods = { vertical = true } })
|
||||
--- ```
|
||||
---
|
||||
---@diagnostic disable-next-line: undefined-doc-param
|
||||
---@param command string|table Command(s) to execute.
|
||||
--- If a string, executes multiple lines of Vimscript at once. In this
|
||||
--- case, it is an alias to |nvim_exec2()|, where `opts.output` is set
|
||||
--- to false. Thus it works identical to |:source|.
|
||||
--- If a table, executes a single command. In this case, it is an alias
|
||||
--- to |nvim_cmd()| where `opts` is empty.
|
||||
--- - The string form supports multiline Vimscript (alias to |nvim_exec2()|, behaves
|
||||
--- like |:source|).
|
||||
--- - The table form executes a single command (alias to |nvim_cmd()|).
|
||||
---@see |ex-cmd-index|
|
||||
vim.cmd = setmetatable({}, {
|
||||
__call = function(_, command)
|
||||
|
@@ -200,7 +200,9 @@ function vim.show_pos(bufnr, row, col, filter)
|
||||
capture,
|
||||
string.format(
|
||||
'priority: %d language: %s',
|
||||
capture.metadata.priority or vim.hl.priorities.treesitter,
|
||||
capture.metadata.priority
|
||||
or (capture.metadata[capture.id] and capture.metadata[capture.id].priority)
|
||||
or vim.hl.priorities.treesitter,
|
||||
capture.lang
|
||||
)
|
||||
)
|
||||
|
8
runtime/lua/vim/_meta/api.lua
generated
8
runtime/lua/vim/_meta/api.lua
generated
@@ -1662,10 +1662,7 @@ function vim.api.nvim_notify(msg, log_level, opts) end
|
||||
---
|
||||
--- ```lua
|
||||
--- vim.api.nvim_create_user_command('TermHl', function()
|
||||
--- local b = vim.api.nvim_create_buf(false, true)
|
||||
--- local chan = vim.api.nvim_open_term(b, {})
|
||||
--- vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
|
||||
--- vim.api.nvim_win_set_buf(0, b)
|
||||
--- vim.api.nvim_open_term(0, {})
|
||||
--- end, { desc = 'Highlights ANSI termcodes in curbuf' })
|
||||
--- ```
|
||||
---
|
||||
@@ -1843,7 +1840,8 @@ function vim.api.nvim_open_term(buffer, opts) end
|
||||
--- the call.
|
||||
--- - fixed: If true when anchor is NW or SW, the float window
|
||||
--- would be kept fixed even if the window would be truncated.
|
||||
--- - hide: If true the floating window will be hidden.
|
||||
--- - hide: If true the floating window will be hidden and the cursor will be invisible when
|
||||
--- focused on it.
|
||||
--- - vertical: Split vertically `:vertical`.
|
||||
--- - split: Split direction: "left", "right", "above", "below".
|
||||
--- @return integer # |window-ID|, or 0 on error
|
||||
|
33
runtime/lua/vim/_meta/options.lua
generated
33
runtime/lua/vim/_meta/options.lua
generated
@@ -655,8 +655,8 @@ vim.bo.bl = vim.bo.buflisted
|
||||
--- "acwrite" implies that the buffer name is not related to a file, like
|
||||
--- "nofile", but it will be written. Thus, in contrast to "nofile" and
|
||||
--- "nowrite", ":w" does work and a modified buffer can't be abandoned
|
||||
--- without saving. For writing there must be matching `BufWriteCmd|,
|
||||
--- |FileWriteCmd` or `FileAppendCmd` autocommands.
|
||||
--- without saving. For writing there must be matching `BufWriteCmd`,
|
||||
--- `FileWriteCmd` or `FileAppendCmd` autocommands.
|
||||
---
|
||||
--- @type ''|'acwrite'|'help'|'nofile'|'nowrite'|'quickfix'|'terminal'|'prompt'
|
||||
vim.o.buftype = ""
|
||||
@@ -2015,6 +2015,8 @@ vim.bo.et = vim.bo.expandtab
|
||||
--- in the `trust` list. Use `:trust` to manage trusted files. See also
|
||||
--- `vim.secure.read()`.
|
||||
---
|
||||
--- To get its own location, Lua exrc files can use `debug.getinfo()`.
|
||||
---
|
||||
--- Compare 'exrc' to `editorconfig`:
|
||||
--- - 'exrc' can execute any code; editorconfig only specifies settings.
|
||||
--- - 'exrc' is Nvim-specific; editorconfig works in other editors.
|
||||
@@ -3160,8 +3162,8 @@ vim.o.ims = vim.o.imsearch
|
||||
vim.bo.imsearch = vim.o.imsearch
|
||||
vim.bo.ims = vim.bo.imsearch
|
||||
|
||||
--- When nonempty, shows the effects of `:substitute`, `:smagic|,
|
||||
--- |:snomagic` and user commands with the `:command-preview` flag as you
|
||||
--- When nonempty, shows the effects of `:substitute`, `:smagic`,
|
||||
--- `:snomagic` and user commands with the `:command-preview` flag as you
|
||||
--- type.
|
||||
---
|
||||
--- Possible values:
|
||||
@@ -3500,8 +3502,8 @@ vim.go.js = vim.go.joinspaces
|
||||
--- when navigating backwards in the jumplist and then
|
||||
--- jumping to a location. `jumplist-stack`
|
||||
---
|
||||
--- view When moving through the jumplist, `changelist|,
|
||||
--- |alternate-file` or using `mark-motions` try to
|
||||
--- view When moving through the jumplist, `changelist`,
|
||||
--- `alternate-file` or using `mark-motions` try to
|
||||
--- restore the `mark-view` in which the action occurred.
|
||||
---
|
||||
--- clean Remove unloaded buffers from the jumplist.
|
||||
@@ -5248,9 +5250,14 @@ vim.go.sect = vim.go.sections
|
||||
--- the end of line the line break still isn't included.
|
||||
--- When "exclusive" is used, cursor position in visual mode will be
|
||||
--- adjusted for inclusive motions `inclusive-motion-selection-exclusive`.
|
||||
--- Note that when "exclusive" is used and selecting from the end
|
||||
--- backwards, you cannot include the last character of a line, when
|
||||
--- starting in Normal mode and 'virtualedit' empty.
|
||||
---
|
||||
--- Note:
|
||||
--- - When "exclusive" is used and selecting from the end backwards, you
|
||||
--- cannot include the last character of a line, when starting in Normal
|
||||
--- mode and 'virtualedit' empty.
|
||||
--- - when "exclusive" is used with a single character visual selection,
|
||||
--- Vim will behave as if the 'selection' is inclusive (in other words,
|
||||
--- you cannot visually select an empty region).
|
||||
---
|
||||
--- @type 'inclusive'|'exclusive'|'old'
|
||||
vim.o.selection = "inclusive"
|
||||
@@ -5636,8 +5643,8 @@ vim.go.ssl = vim.go.shellslash
|
||||
--- and the 'shell' command does not need to support redirection.
|
||||
--- The advantage of using a temp file is that the file type and encoding
|
||||
--- can be detected.
|
||||
--- The `FilterReadPre`, `FilterReadPost` and `FilterWritePre|,
|
||||
--- |FilterWritePost` autocommands event are not triggered when
|
||||
--- The `FilterReadPre`, `FilterReadPost` and `FilterWritePre`,
|
||||
--- `FilterWritePost` autocommands event are not triggered when
|
||||
--- 'shelltemp' is off.
|
||||
--- `system()` does not respect this option, it always uses pipes.
|
||||
---
|
||||
@@ -6207,8 +6214,8 @@ vim.bo.spo = vim.bo.spelloptions
|
||||
---
|
||||
--- expr:{expr} Evaluate expression {expr}. Use a function to avoid
|
||||
--- trouble with spaces. Best is to call a function
|
||||
--- without arguments, see `expr-option-function|.
|
||||
--- |v:val` holds the badly spelled word. The expression
|
||||
--- without arguments, see `expr-option-function`.
|
||||
--- `v:val` holds the badly spelled word. The expression
|
||||
--- must evaluate to a List of Lists, each with a
|
||||
--- suggestion and a score.
|
||||
--- Example:
|
||||
|
7
runtime/lua/vim/_meta/vimfn.lua
generated
7
runtime/lua/vim/_meta/vimfn.lua
generated
@@ -1801,7 +1801,8 @@ function vim.fn.exp(expr) end
|
||||
--- <SID> "<SNR>123_" where "123" is the
|
||||
--- current script ID |<SID>|
|
||||
--- <script> sourced script file, or script file
|
||||
--- where the current function was defined
|
||||
--- where the current function was defined.
|
||||
--- Use |debug.getinfo()| in Lua scripts.
|
||||
--- <stack> call stack
|
||||
--- <cword> word under the cursor
|
||||
--- <cWORD> WORD under the cursor
|
||||
@@ -3692,6 +3693,10 @@ function vim.fn.getreginfo(regname) end
|
||||
--- - It is evaluated in current window context, which makes a
|
||||
--- difference if the buffer is displayed in a window with
|
||||
--- different 'virtualedit' or 'list' values.
|
||||
--- - When specifying an exclusive selection and {pos1} and {pos2}
|
||||
--- are equal, the returned list contains a single character as
|
||||
--- if selection is inclusive, to match the behavior of an empty
|
||||
--- exclusive selection in Visual mode.
|
||||
---
|
||||
--- Examples: >vim
|
||||
--- xnoremap <CR>
|
||||
|
@@ -210,12 +210,15 @@ end
|
||||
--- @param clear_env? boolean
|
||||
--- @return string[]?
|
||||
local function setup_env(env, clear_env)
|
||||
if clear_env then
|
||||
return env
|
||||
if not env and clear_env then
|
||||
return
|
||||
end
|
||||
|
||||
--- @type table<string,string|number>
|
||||
env = vim.tbl_extend('force', base_env(), env or {})
|
||||
env = env or {}
|
||||
if not clear_env then
|
||||
--- @type table<string,string|number>
|
||||
env = vim.tbl_extend('force', base_env(), env)
|
||||
end
|
||||
|
||||
local renv = {} --- @type string[]
|
||||
for k, v in pairs(env) do
|
||||
|
@@ -1442,6 +1442,7 @@ M.handlers.signs = {
|
||||
vim.validate('bufnr', bufnr, 'number')
|
||||
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
|
||||
vim.validate('opts', opts, 'table', true)
|
||||
vim.validate('opts.signs', (opts and opts or {}).signs, 'table', true)
|
||||
|
||||
bufnr = vim._resolve_bufnr(bufnr)
|
||||
opts = opts or {}
|
||||
@@ -2619,7 +2620,9 @@ function M.toqflist(diagnostics)
|
||||
end_lnum = v.end_lnum and (v.end_lnum + 1) or nil,
|
||||
end_col = v.end_col and (v.end_col + 1) or nil,
|
||||
text = v.message,
|
||||
nr = tonumber(v.code),
|
||||
type = errlist_type_map[v.severity] or 'E',
|
||||
valid = 1,
|
||||
}
|
||||
table.insert(list, item)
|
||||
end
|
||||
@@ -2651,7 +2654,8 @@ function M.fromqflist(list)
|
||||
local col = math.max(0, item.col - 1)
|
||||
local end_lnum = item.end_lnum > 0 and (item.end_lnum - 1) or lnum
|
||||
local end_col = item.end_col > 0 and (item.end_col - 1) or col
|
||||
local severity = item.type ~= '' and M.severity[item.type] or M.severity.ERROR
|
||||
local code = item.nr > 0 and item.nr or nil
|
||||
local severity = item.type ~= '' and M.severity[item.type:upper()] or M.severity.ERROR
|
||||
diagnostics[#diagnostics + 1] = {
|
||||
bufnr = item.bufnr,
|
||||
lnum = lnum,
|
||||
@@ -2660,6 +2664,7 @@ function M.fromqflist(list)
|
||||
end_col = end_col,
|
||||
severity = severity,
|
||||
message = item.text,
|
||||
code = code,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@@ -124,6 +124,23 @@ function M.joinpath(...)
|
||||
return (path:gsub('//+', '/'))
|
||||
end
|
||||
|
||||
--- @class vim.fs.dir.Opts
|
||||
--- @inlinedoc
|
||||
---
|
||||
--- How deep the traverse.
|
||||
--- (default: `1`)
|
||||
--- @field depth? integer
|
||||
---
|
||||
--- Predicate to control traversal.
|
||||
--- Return false to stop searching the current directory.
|
||||
--- Only useful when depth > 1
|
||||
--- Return an iterator over the items located in {path}
|
||||
--- @field skip? (fun(dir_name: string): boolean)
|
||||
---
|
||||
--- Follow symbolic links.
|
||||
--- (default: `false`)
|
||||
--- @field follow? boolean
|
||||
|
||||
---@alias Iterator fun(): string?, string?
|
||||
|
||||
--- Return an iterator over the items located in {path}
|
||||
@@ -131,13 +148,7 @@ end
|
||||
---@since 10
|
||||
---@param path (string) An absolute or relative path to the directory to iterate
|
||||
--- over. The path is first normalized |vim.fs.normalize()|.
|
||||
--- @param opts table|nil Optional keyword arguments:
|
||||
--- - depth: integer|nil How deep the traverse (default 1)
|
||||
--- - skip: (fun(dir_name: string): boolean)|nil Predicate
|
||||
--- to control traversal. Return false to stop searching the current directory.
|
||||
--- Only useful when depth > 1
|
||||
--- - follow: boolean|nil Follow symbolic links. (default: false)
|
||||
---
|
||||
---@param opts? vim.fs.dir.Opts Optional keyword arguments:
|
||||
---@return Iterator over items in {path}. Each iteration yields two values: "name" and "type".
|
||||
--- "name" is the basename of the item relative to {path}.
|
||||
--- "type" is one of the following:
|
||||
@@ -256,7 +267,7 @@ end
|
||||
---
|
||||
--- The function should return `true` if the given item is considered a match.
|
||||
---
|
||||
---@param opts vim.fs.find.Opts Optional keyword arguments:
|
||||
---@param opts? vim.fs.find.Opts Optional keyword arguments:
|
||||
---@return (string[]) # Normalized paths |vim.fs.normalize()| of all matching items
|
||||
function M.find(names, opts)
|
||||
opts = opts or {}
|
||||
@@ -375,7 +386,7 @@ end
|
||||
--- If the buffer is unnamed (has no backing file) or has a non-empty 'buftype' then the search
|
||||
--- begins from Nvim's |current-directory|.
|
||||
---
|
||||
--- Example:
|
||||
--- Examples:
|
||||
---
|
||||
--- ```lua
|
||||
--- -- Find the root of a Python project, starting from file 'main.py'
|
||||
@@ -388,14 +399,21 @@ end
|
||||
--- vim.fs.root(0, function(name, path)
|
||||
--- return name:match('%.csproj$') ~= nil
|
||||
--- end)
|
||||
---
|
||||
--- -- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
|
||||
--- -- not found, find the first ancestor containing ".git":
|
||||
--- vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' })
|
||||
--- ```
|
||||
---
|
||||
--- @since 12
|
||||
--- @param source integer|string Buffer number (0 for current buffer) or file path (absolute or
|
||||
--- relative to the |current-directory|) to begin the search from.
|
||||
--- @param marker (string|string[]|fun(name: string, path: string): boolean) A marker, or list
|
||||
--- of markers, to search for. If a function, the function is called for each
|
||||
--- evaluated item and should return true if {name} and {path} are a match.
|
||||
--- @param marker (string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean
|
||||
--- Filename, function, or list thereof, that decides how to find the root. To
|
||||
--- indicate "equal priority", specify items in a nested list `{ { 'a.txt', 'b.lua' }, … }`.
|
||||
--- A function item must return true if `name` and `path` are a match. Each item
|
||||
--- (which may itself be a nested list) is evaluated in-order against all ancestors,
|
||||
--- until a match is found.
|
||||
--- @return string? # Directory path containing one of the given markers, or nil if no directory was
|
||||
--- found.
|
||||
function M.root(source, marker)
|
||||
@@ -415,16 +433,19 @@ function M.root(source, marker)
|
||||
error('invalid type for argument "source": expected string or buffer number')
|
||||
end
|
||||
|
||||
local paths = M.find(marker, {
|
||||
upward = true,
|
||||
path = vim.fn.fnamemodify(path, ':p:h'),
|
||||
})
|
||||
local markers = type(marker) == 'table' and marker or { marker }
|
||||
for _, mark in ipairs(markers) do
|
||||
local paths = M.find(mark, {
|
||||
upward = true,
|
||||
path = vim.fn.fnamemodify(path, ':p:h'),
|
||||
})
|
||||
|
||||
if #paths == 0 then
|
||||
return nil
|
||||
if #paths ~= 0 then
|
||||
return vim.fs.dirname(paths[1])
|
||||
end
|
||||
end
|
||||
|
||||
return vim.fs.dirname(paths[1])
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Split a Windows path into a prefix and a body, such that the body can be processed like a POSIX
|
||||
|
@@ -389,15 +389,17 @@ function M._check(mods, plugin_names)
|
||||
and type(vim.g.health) == 'table'
|
||||
and vim.tbl_get(vim.g.health, 'style') == 'float'
|
||||
then
|
||||
local max_height = math.floor(vim.o.lines * 0.8)
|
||||
local available_lines = vim.o.lines - 12
|
||||
local max_height = math.min(math.floor(vim.o.lines * 0.8), available_lines)
|
||||
local max_width = 80
|
||||
local float_winid
|
||||
bufnr, float_winid = vim.lsp.util.open_floating_preview({}, '', {
|
||||
height = max_height,
|
||||
width = max_width,
|
||||
offset_x = math.floor((vim.o.columns - max_width) / 2),
|
||||
offset_y = math.floor((vim.o.lines - max_height) / 2) - 1,
|
||||
offset_y = math.floor((available_lines - max_height) / 2),
|
||||
relative = 'editor',
|
||||
close_events = {},
|
||||
})
|
||||
vim.api.nvim_set_current_win(float_winid)
|
||||
vim.bo[bufnr].modifiable = true
|
||||
|
@@ -87,9 +87,9 @@ local function check_config()
|
||||
health.error(
|
||||
'Locale does not support UTF-8. Unicode characters may not display correctly.'
|
||||
.. ('\n$LANG=%s $LC_ALL=%s $LC_CTYPE=%s'):format(
|
||||
vim.env.LANG,
|
||||
vim.env.LC_ALL,
|
||||
vim.env.LC_CTYPE
|
||||
vim.env.LANG or '',
|
||||
vim.env.LC_ALL or '',
|
||||
vim.env.LC_CTYPE or ''
|
||||
),
|
||||
{
|
||||
'If using tmux, try the -u option.',
|
||||
@@ -318,9 +318,11 @@ local function check_tmux()
|
||||
'$TERM differs from the tmux `default-terminal` setting. Colors might look wrong.',
|
||||
{ '$TERM may have been set by some rc (.bashrc, .zshrc, ...).' }
|
||||
)
|
||||
elseif not vim.regex([[\v(tmux-256color|screen-256color)]]):match_str(vim.env.TERM) then
|
||||
elseif
|
||||
not vim.regex([[\v(tmux-256color|tmux-direct|screen-256color)]]):match_str(vim.env.TERM)
|
||||
then
|
||||
health.error(
|
||||
'$TERM should be "screen-256color" or "tmux-256color" in tmux. Colors might look wrong.',
|
||||
'$TERM should be "screen-256color", "tmux-256color", or "tmux-direct" in tmux. Colors might look wrong.',
|
||||
{
|
||||
'Set default-terminal in ~/.tmux.conf:\nset-option -g default-terminal "screen-256color"',
|
||||
suggest_faq,
|
||||
|
@@ -957,6 +957,9 @@ end
|
||||
|
||||
---@private
|
||||
function ArrayIter:last()
|
||||
if self._head >= self._tail then
|
||||
return nil
|
||||
end
|
||||
local inc = self._head < self._tail and 1 or -1
|
||||
local v = self._table[self._tail - inc]
|
||||
self._head = self._tail
|
||||
|
@@ -275,7 +275,8 @@ end
|
||||
--- @class vim.lsp.Config : vim.lsp.ClientConfig
|
||||
---
|
||||
--- See `cmd` in [vim.lsp.ClientConfig].
|
||||
--- @field cmd? string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
|
||||
--- See also `reuse_client` to dynamically decide (per-buffer) when `cmd` should be re-invoked.
|
||||
--- @field cmd? string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient
|
||||
---
|
||||
--- Filetypes the client will attach to, if activated by `vim.lsp.enable()`. If not provided, the
|
||||
--- client will attach to all filetypes.
|
||||
@@ -285,43 +286,35 @@ end
|
||||
--- implementation re-uses a client if name and root_dir matches.
|
||||
--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
|
||||
---
|
||||
--- [lsp-root_dir()]() Directory where the LSP server will base its workspaceFolders, rootUri, and
|
||||
--- rootPath on initialization. The function form receives a buffer number and `on_dir` callback
|
||||
--- which it must call to provide root_dir, or LSP will not be activated for the buffer. Thus
|
||||
--- a `root_dir()` function can dynamically decide per-buffer whether to activate (or skip) LSP. See
|
||||
--- example at |vim.lsp.enable()|.
|
||||
--- [lsp-root_dir()]()
|
||||
--- Decides the workspace root: the directory where the LSP server will base its workspaceFolders,
|
||||
--- rootUri, and rootPath on initialization. The function form must call the `on_dir` callback to
|
||||
--- provide the root dir, or LSP will not be activated for the buffer. Thus a `root_dir()` function
|
||||
--- can dynamically decide per-buffer whether to activate (or skip) LSP.
|
||||
--- See example at |vim.lsp.enable()|.
|
||||
--- @field root_dir? string|fun(bufnr: integer, on_dir:fun(root_dir?:string))
|
||||
---
|
||||
--- Directory markers (.e.g. '.git/') where the LSP server will base its workspaceFolders,
|
||||
--- rootUri, and rootPath on initialization. Unused if `root_dir` is provided.
|
||||
--- [lsp-root_markers]()
|
||||
--- Filename(s) (".git/", "package.json", …) used to decide the workspace root. Unused if `root_dir`
|
||||
--- is defined. The list order decides priority. To indicate "equal priority", specify names in
|
||||
--- a nested list `{ { 'a.txt', 'b.lua' }, ... }`.
|
||||
---
|
||||
--- The list order decides the priority. To indicate "equal priority", specify names in a nested list (`{ { 'a', 'b' }, ... }`)
|
||||
--- Each entry in this list is a set of one or more markers. For each set, Nvim
|
||||
--- will search upwards for each marker contained in the set. If a marker is
|
||||
--- found, the directory which contains that marker is used as the root
|
||||
--- directory. If no markers from the set are found, the process is repeated
|
||||
--- with the next set in the list.
|
||||
---
|
||||
--- Example:
|
||||
--- For each item, Nvim will search upwards (from the buffer file) for that marker, or list of
|
||||
--- markers; search stops at the first directory containing that marker, and the directory is used
|
||||
--- as the root dir (workspace folder).
|
||||
---
|
||||
--- Example: Find the first ancestor directory containing file or directory "stylua.toml"; if not
|
||||
--- found, find the first ancestor containing ".git":
|
||||
--- ```lua
|
||||
--- root_markers = { 'stylua.toml', '.git' }
|
||||
--- ```
|
||||
---
|
||||
--- Find the first parent directory containing the file `stylua.toml`. If not
|
||||
--- found, find the first parent directory containing the file or directory
|
||||
--- `.git`.
|
||||
---
|
||||
--- Example:
|
||||
---
|
||||
--- Example: Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
|
||||
--- not found, find the first ancestor containing ".git":
|
||||
--- ```lua
|
||||
--- root_markers = { { 'stylua.toml', '.luarc.json' }, '.git' }
|
||||
--- ```
|
||||
---
|
||||
--- Find the first parent directory containing EITHER `stylua.toml` or
|
||||
--- `.luarc.json`. If not found, find the first parent directory containing the
|
||||
--- file or directory `.git`.
|
||||
---
|
||||
--- @field root_markers? (string|string[])[]
|
||||
|
||||
--- Update the configuration for an LSP client.
|
||||
@@ -531,7 +524,9 @@ local function lsp_enable_callback(bufnr)
|
||||
-- Stop any clients that no longer apply to this buffer.
|
||||
local clients = lsp.get_clients({ bufnr = bufnr, _uninitialized = true })
|
||||
for _, client in ipairs(clients) do
|
||||
if lsp.config[client.name] and not can_start(bufnr, client.name, lsp.config[client.name]) then
|
||||
if
|
||||
lsp.is_enabled(client.name) and not can_start(bufnr, client.name, lsp.config[client.name])
|
||||
then
|
||||
lsp.buf_detach_client(bufnr, client.id)
|
||||
end
|
||||
end
|
||||
@@ -569,6 +564,14 @@ end
|
||||
--- vim.lsp.enable({'luals', 'pyright'})
|
||||
--- ```
|
||||
---
|
||||
--- Example: [lsp-restart]() Passing `false` stops and detaches the client(s). Thus you can
|
||||
--- "restart" LSP by disabling and re-enabling a given config:
|
||||
---
|
||||
--- ```lua
|
||||
--- vim.lsp.enable('clangd', false)
|
||||
--- vim.lsp.enable('clangd', true)
|
||||
--- ```
|
||||
---
|
||||
--- Example: To _dynamically_ decide whether LSP is activated, define a |lsp-root_dir()| function
|
||||
--- which calls `on_dir()` only when you want that config to activate:
|
||||
---
|
||||
@@ -583,7 +586,8 @@ end
|
||||
--- ```
|
||||
---
|
||||
--- @param name string|string[] Name(s) of client(s) to enable.
|
||||
--- @param enable? boolean `true|nil` to enable, `false` to disable.
|
||||
--- @param enable? boolean `true|nil` to enable, `false` to disable (actively stops and detaches
|
||||
--- clients as needed)
|
||||
function lsp.enable(name, enable)
|
||||
validate('name', name, { 'string', 'table' })
|
||||
|
||||
@@ -628,6 +632,8 @@ end
|
||||
|
||||
--- Checks if the given LSP config is enabled (globally, not per-buffer).
|
||||
---
|
||||
--- Unlike `vim.lsp.config['…']`, this does not have the side-effect of resolving the config.
|
||||
---
|
||||
--- @param name string Config name
|
||||
--- @return boolean
|
||||
function lsp.is_enabled(name)
|
||||
@@ -703,13 +709,7 @@ function lsp.start(config, opts)
|
||||
validate('root_markers', opts._root_markers, 'table')
|
||||
config = vim.deepcopy(config)
|
||||
|
||||
for _, marker in ipairs(opts._root_markers) do
|
||||
local root = vim.fs.root(bufnr, marker)
|
||||
if root ~= nil then
|
||||
config.root_dir = root
|
||||
break
|
||||
end
|
||||
end
|
||||
config.root_dir = vim.fs.root(bufnr, opts._root_markers)
|
||||
end
|
||||
|
||||
if
|
||||
@@ -1289,7 +1289,9 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
|
||||
local function _cancel_all_requests()
|
||||
for client_id, request_id in pairs(client_request_ids) do
|
||||
local client = all_clients[client_id]
|
||||
client:cancel_request(request_id)
|
||||
if client.requests[request_id] then
|
||||
client:cancel_request(request_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@@ -3,6 +3,13 @@ local log = require('vim.lsp.log')
|
||||
local ms = require('vim.lsp.protocol').Methods
|
||||
local api = vim.api
|
||||
|
||||
---@type table<lsp.FoldingRangeKind, true>
|
||||
local supported_fold_kinds = {
|
||||
['comment'] = true,
|
||||
['imports'] = true,
|
||||
['region'] = true,
|
||||
}
|
||||
|
||||
local M = {}
|
||||
|
||||
---@class (private) vim.lsp.folding_range.BufState
|
||||
@@ -39,7 +46,7 @@ local function renew(bufnr)
|
||||
---@type table<integer, string?>
|
||||
local row_text = {}
|
||||
|
||||
for _, ranges in pairs(bufstate.client_ranges) do
|
||||
for client_id, ranges in pairs(bufstate.client_ranges) do
|
||||
for _, range in ipairs(ranges) do
|
||||
local start_row = range.startLine
|
||||
local end_row = range.endLine
|
||||
@@ -49,9 +56,14 @@ local function renew(bufnr)
|
||||
|
||||
local kind = range.kind
|
||||
if kind then
|
||||
local kinds = row_kinds[start_row] or {}
|
||||
kinds[kind] = true
|
||||
row_kinds[start_row] = kinds
|
||||
-- Ignore unsupported fold kinds.
|
||||
if supported_fold_kinds[kind] then
|
||||
local kinds = row_kinds[start_row] or {}
|
||||
kinds[kind] = true
|
||||
row_kinds[start_row] = kinds
|
||||
else
|
||||
log.info(('Unknown fold kind "%s" from client %d'):format(kind, client_id))
|
||||
end
|
||||
end
|
||||
|
||||
for row = start_row, end_row do
|
||||
|
@@ -71,7 +71,7 @@ function M.hover(config)
|
||||
|
||||
if vim.tbl_isempty(results1) then
|
||||
if config.silent ~= true then
|
||||
vim.notify('No information available')
|
||||
vim.notify('No information available', vim.log.levels.INFO)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -352,6 +352,7 @@ function M.signature_help(config)
|
||||
|
||||
config = config and vim.deepcopy(config) or {}
|
||||
config.focus_id = method
|
||||
local user_title = config.title
|
||||
|
||||
lsp.buf_request_all(0, method, client_positional_params(), function(results, ctx)
|
||||
if api.nvim_get_current_buf() ~= ctx.bufnr then
|
||||
@@ -363,7 +364,7 @@ function M.signature_help(config)
|
||||
|
||||
if not next(signatures) then
|
||||
if config.silent ~= true then
|
||||
print('No signature help available')
|
||||
vim.notify('No signature help available', vim.log.levels.INFO)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -386,17 +387,19 @@ function M.signature_help(config)
|
||||
return
|
||||
end
|
||||
|
||||
local sfx = total > 1
|
||||
and string.format(' (%d/%d)%s', idx, total, can_cycle and ' (<C-s> to cycle)' or '')
|
||||
or ''
|
||||
local title = string.format('Signature Help: %s%s', client.name, sfx)
|
||||
if config.border then
|
||||
config.title = title
|
||||
else
|
||||
table.insert(lines, 1, '# ' .. title)
|
||||
if hl then
|
||||
hl[1] = hl[1] + 1
|
||||
hl[3] = hl[3] + 1
|
||||
-- Show title only if there are multiple clients or multiple signatures.
|
||||
if total > 1 then
|
||||
local sfx = total > 1
|
||||
and string.format(' (%d/%d)%s', idx, total, can_cycle and ' (<C-s> to cycle)' or '')
|
||||
or ''
|
||||
config.title = user_title or string.format('Signature Help: %s%s', client.name, sfx)
|
||||
-- If no border is set, render title inside the window.
|
||||
if not (config.border or vim.o.winborder ~= '') then
|
||||
table.insert(lines, 1, '# ' .. config.title)
|
||||
if hl then
|
||||
hl[1] = hl[1] + 1
|
||||
hl[3] = hl[3] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -440,7 +443,7 @@ end
|
||||
---
|
||||
---@see vim.lsp.protocol.CompletionTriggerKind
|
||||
function M.completion(context)
|
||||
vim.depends('vim.lsp.buf.completion', 'vim.lsp.completion.trigger', '0.12')
|
||||
vim.deprecate('vim.lsp.buf.completion', 'vim.lsp.completion.trigger', '0.12')
|
||||
return lsp.buf_request(
|
||||
0,
|
||||
ms.textDocument_completion,
|
||||
@@ -970,7 +973,7 @@ function M.add_workspace_folder(workspace_folder)
|
||||
return
|
||||
end
|
||||
if vim.fn.isdirectory(workspace_folder) == 0 then
|
||||
print(workspace_folder, ' is not a valid directory')
|
||||
vim.notify(workspace_folder .. ' is not a valid directory')
|
||||
return
|
||||
end
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
@@ -994,7 +997,7 @@ function M.remove_workspace_folder(workspace_folder)
|
||||
for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do
|
||||
client:_remove_workspace_folder(workspace_folder)
|
||||
end
|
||||
print(workspace_folder, 'is not currently part of the workspace')
|
||||
vim.notify(workspace_folder .. 'is not currently part of the workspace')
|
||||
end
|
||||
|
||||
--- Lists all symbols in the current workspace in the quickfix window.
|
||||
|
@@ -43,14 +43,13 @@ local validate = vim.validate
|
||||
--- array.
|
||||
--- @field capabilities? lsp.ClientCapabilities
|
||||
---
|
||||
--- command string[] that launches the language
|
||||
--- server (treated as in |jobstart()|, must be absolute or on `$PATH`, shell constructs like
|
||||
--- "~" are not expanded), or function that creates an RPC client. Function receives
|
||||
--- a `dispatchers` table and returns a table with member functions `request`, `notify`,
|
||||
--- `is_closing` and `terminate`.
|
||||
--- Command `string[]` that launches the language server (treated as in |jobstart()|, must be
|
||||
--- absolute or on `$PATH`, shell constructs like "~" are not expanded), or function that creates an
|
||||
--- RPC client. Function receives a `dispatchers` table and the resolved `config`, and must return
|
||||
--- a table with member functions `request`, `notify`, `is_closing` and `terminate`.
|
||||
--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
|
||||
--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
|
||||
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
|
||||
--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
|
||||
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient
|
||||
---
|
||||
--- Directory to launch the `cmd` process. Not related to `root_dir`.
|
||||
--- (default: cwd)
|
||||
@@ -73,7 +72,7 @@ local validate = vim.validate
|
||||
--- Daemonize the server process so that it runs in a separate process group from Nvim.
|
||||
--- Nvim will shutdown the process on exit, but if Nvim fails to exit cleanly this could leave
|
||||
--- behind orphaned server processes.
|
||||
--- (default: true)
|
||||
--- (default: `true`)
|
||||
--- @field detached? boolean
|
||||
---
|
||||
--- A table with flags for the client. The current (experimental) flags are:
|
||||
@@ -89,7 +88,8 @@ local validate = vim.validate
|
||||
--- the LSP spec.
|
||||
--- @field init_options? lsp.LSPObject
|
||||
---
|
||||
--- (default: client-id) Name in logs and user messages.
|
||||
--- Name in logs and user messages.
|
||||
--- (default: client-id)
|
||||
--- @field name? string
|
||||
---
|
||||
--- Called "position encoding" in LSP spec. The encoding that the LSP server expects, used for
|
||||
@@ -132,9 +132,10 @@ local validate = vim.validate
|
||||
--- supports workspace folders but none are configured. See `workspaceFolders` in LSP spec.
|
||||
--- @field workspace_folders? lsp.WorkspaceFolder[]
|
||||
---
|
||||
--- (default false) Server requires a workspace (no "single file" support). Note: Without
|
||||
--- Server requires a workspace (no "single file" support). Note: Without
|
||||
--- a workspace, cross-file features (navigation, hover) may or may not work depending on the
|
||||
--- language server, even if the server doesn't require a workspace.
|
||||
--- (default: `false`)
|
||||
--- @field workspace_required? boolean
|
||||
|
||||
--- @class vim.lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}>
|
||||
@@ -454,7 +455,7 @@ function Client.create(config)
|
||||
-- Start the RPC client.
|
||||
local config_cmd = config.cmd
|
||||
if type(config_cmd) == 'function' then
|
||||
self.rpc = config_cmd(dispatchers)
|
||||
self.rpc = config_cmd(dispatchers, config)
|
||||
else
|
||||
self.rpc = lsp.rpc.start(config_cmd, dispatchers, {
|
||||
cwd = config.cmd_cwd,
|
||||
|
@@ -198,7 +198,7 @@ local function check_enabled_configs()
|
||||
local v_str --- @type string?
|
||||
if k == 'name' then
|
||||
v_str = nil
|
||||
elseif k == 'filetypes' or k == 'root_markers' then
|
||||
elseif k == 'filetypes' then
|
||||
v_str = table.concat(v, ', ')
|
||||
elseif type(v) == 'function' then
|
||||
v_str = func_tostring(v)
|
||||
|
@@ -162,14 +162,13 @@ local constants = {
|
||||
MethodNotFound = -32601,
|
||||
InvalidParams = -32602,
|
||||
InternalError = -32603,
|
||||
serverErrorStart = -32099,
|
||||
serverErrorEnd = -32000,
|
||||
ServerNotInitialized = -32002,
|
||||
UnknownErrorCode = -32001,
|
||||
-- Defined by the protocol.
|
||||
RequestCancelled = -32800,
|
||||
ContentModified = -32801,
|
||||
ServerCancelled = -32802,
|
||||
RequestFailed = -32803,
|
||||
},
|
||||
|
||||
-- Describes the content type that a client supports in various
|
||||
@@ -329,6 +328,7 @@ end
|
||||
--- capabilities.
|
||||
--- @return lsp.ClientCapabilities
|
||||
function protocol.make_client_capabilities()
|
||||
---@type lsp.ClientCapabilities
|
||||
return {
|
||||
general = {
|
||||
positionEncodings = {
|
||||
@@ -340,6 +340,9 @@ function protocol.make_client_capabilities()
|
||||
textDocument = {
|
||||
diagnostic = {
|
||||
dynamicRegistration = false,
|
||||
tagSupport = {
|
||||
valueSet = get_value_set(constants.DiagnosticTag),
|
||||
},
|
||||
},
|
||||
inlayHint = {
|
||||
dynamicRegistration = true,
|
||||
@@ -436,6 +439,9 @@ function protocol.make_client_capabilities()
|
||||
foldingRange = {
|
||||
dynamicRegistration = false,
|
||||
lineFoldingOnly = true,
|
||||
foldingRangeKind = {
|
||||
valueSet = { 'comment', 'imports', 'region' },
|
||||
},
|
||||
foldingRange = {
|
||||
collapsedText = true,
|
||||
},
|
||||
|
@@ -745,6 +745,10 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers
|
||||
if type(doc) == 'string' then
|
||||
signature.documentation = { kind = 'plaintext', value = doc }
|
||||
end
|
||||
-- Add delimiter if there is documentation to display
|
||||
if signature.documentation.value ~= '' then
|
||||
contents[#contents + 1] = '---'
|
||||
end
|
||||
M.convert_input_to_markdown_lines(signature.documentation, contents)
|
||||
end
|
||||
if signature.parameters and #signature.parameters > 0 then
|
||||
@@ -861,7 +865,7 @@ function M.make_floating_popup_options(width, height, opts)
|
||||
col = 1
|
||||
end
|
||||
|
||||
local title = (opts.border and opts.title) and opts.title or nil
|
||||
local title = ((opts.border or vim.o.winborder ~= '') and opts.title) and opts.title or nil
|
||||
local title_pos --- @type 'left'|'center'|'right'?
|
||||
|
||||
if title then
|
||||
@@ -1340,26 +1344,34 @@ end
|
||||
---
|
||||
---@param events table list of events
|
||||
---@param winnr integer window id of preview window
|
||||
---@param bufnrs table list of buffers where the preview window will remain visible
|
||||
---@param floating_bufnr integer floating preview buffer
|
||||
---@param bufnr integer buffer that opened the floating preview buffer
|
||||
---@see autocmd-events
|
||||
local function close_preview_autocmd(events, winnr, bufnrs)
|
||||
local function close_preview_autocmd(events, winnr, floating_bufnr, bufnr)
|
||||
local augroup = api.nvim_create_augroup('nvim.preview_window_' .. winnr, {
|
||||
clear = true,
|
||||
})
|
||||
|
||||
-- close the preview window when entered a buffer that is not
|
||||
-- the floating window buffer or the buffer that spawned it
|
||||
api.nvim_create_autocmd('BufEnter', {
|
||||
api.nvim_create_autocmd('BufLeave', {
|
||||
group = augroup,
|
||||
buffer = bufnr,
|
||||
callback = function()
|
||||
close_preview_window(winnr, bufnrs)
|
||||
vim.schedule(function()
|
||||
-- When jumping to the quickfix window from the preview window,
|
||||
-- do not close the preview window.
|
||||
if api.nvim_get_option_value('filetype', { buf = 0 }) ~= 'qf' then
|
||||
close_preview_window(winnr, { floating_bufnr, bufnr })
|
||||
end
|
||||
end)
|
||||
end,
|
||||
})
|
||||
|
||||
if #events > 0 then
|
||||
api.nvim_create_autocmd(events, {
|
||||
group = augroup,
|
||||
buffer = bufnrs[2],
|
||||
buffer = bufnr,
|
||||
callback = function()
|
||||
close_preview_window(winnr)
|
||||
end,
|
||||
@@ -1606,7 +1618,7 @@ function M.open_floating_preview(contents, syntax, opts)
|
||||
'<cmd>bdelete<cr>',
|
||||
{ silent = true, noremap = true, nowait = true }
|
||||
)
|
||||
close_preview_autocmd(opts.close_events, floating_winnr, { floating_bufnr, bufnr })
|
||||
close_preview_autocmd(opts.close_events, floating_winnr, floating_bufnr, bufnr)
|
||||
|
||||
-- save focus_id
|
||||
if opts.focus_id then
|
||||
|
@@ -724,10 +724,9 @@ local function python()
|
||||
local message = 'Detected pip upgrade failure: Python executable can import "pynvim" but not "neovim": '
|
||||
.. pynvim_exe
|
||||
local advice = {
|
||||
'Use that Python version to reinstall "pynvim" and optionally "neovim".',
|
||||
'Use that Python version to uninstall any "pynvim" or "neovim", e.g.:',
|
||||
pynvim_exe .. ' -m pip uninstall pynvim neovim',
|
||||
pynvim_exe .. ' -m pip install pynvim',
|
||||
pynvim_exe .. ' -m pip install neovim # only if needed by third-party software',
|
||||
'Then see :help provider-python for "pynvim" installation steps.',
|
||||
}
|
||||
health.error(message, advice)
|
||||
end
|
||||
@@ -753,7 +752,7 @@ local function python()
|
||||
if is_bad_response(current) then
|
||||
health.error(
|
||||
'pynvim is not installed.\nError: ' .. current,
|
||||
'Run in shell: ' .. python_exe .. ' -m pip install pynvim'
|
||||
'See :help provider-python for "pynvim" installation steps.'
|
||||
)
|
||||
end
|
||||
|
||||
|
@@ -83,6 +83,10 @@ function M.detect_by_module(module)
|
||||
return vim.fn.exepath(vim.fn.expand(python_exe, true)), nil
|
||||
end
|
||||
|
||||
if vim.fn.executable('pynvim-python') == 1 then
|
||||
return 'pynvim-python'
|
||||
end
|
||||
|
||||
local errors = {}
|
||||
for _, exe in ipairs(python_candidates) do
|
||||
local error = check_for_module(exe, module)
|
||||
|
@@ -119,7 +119,7 @@ local Tabstop = {}
|
||||
function Tabstop.new(index, bufnr, range, choices)
|
||||
local extmark_id = vim.api.nvim_buf_set_extmark(bufnr, snippet_ns, range[1], range[2], {
|
||||
right_gravity = true,
|
||||
end_right_gravity = true,
|
||||
end_right_gravity = false,
|
||||
end_line = range[3],
|
||||
end_col = range[4],
|
||||
hl_group = hl_group,
|
||||
@@ -170,7 +170,7 @@ function Tabstop:set_right_gravity(right_gravity)
|
||||
local range = self:get_range()
|
||||
self.extmark_id = vim.api.nvim_buf_set_extmark(self.bufnr, snippet_ns, range[1], range[2], {
|
||||
right_gravity = right_gravity,
|
||||
end_right_gravity = true,
|
||||
end_right_gravity = not right_gravity,
|
||||
end_line = range[3],
|
||||
end_col = range[4],
|
||||
hl_group = hl_group,
|
||||
@@ -257,10 +257,21 @@ local M = { session = nil }
|
||||
local function display_choices(tabstop)
|
||||
assert(tabstop.choices, 'Tabstop has no choices')
|
||||
|
||||
local text = tabstop:get_text()
|
||||
local found_text = false
|
||||
|
||||
local start_col = tabstop:get_range()[2] + 1
|
||||
local matches = {} --- @type table[]
|
||||
for _, choice in ipairs(tabstop.choices) do
|
||||
matches[#matches + 1] = { word = choice }
|
||||
if choice ~= text then
|
||||
matches[#matches + 1] = { word = choice }
|
||||
else
|
||||
found_text = true
|
||||
end
|
||||
end
|
||||
|
||||
if found_text then
|
||||
table.insert(matches, 1, text)
|
||||
end
|
||||
|
||||
vim.defer_fn(function()
|
||||
@@ -298,6 +309,7 @@ local function select_tabstop(tabstop)
|
||||
vim.cmd.startinsert({ bang = range[4] >= #vim.api.nvim_get_current_line() })
|
||||
end
|
||||
if tabstop.choices then
|
||||
vim.fn.cursor(range[3] + 1, range[4] + 1)
|
||||
display_choices(tabstop)
|
||||
end
|
||||
else
|
||||
|
@@ -83,8 +83,9 @@ local get_headings = function(bufnr)
|
||||
return headings
|
||||
end
|
||||
|
||||
--- @param qf_height? integer height of loclist window
|
||||
--- Shows an Outline (table of contents) of the current buffer, in the loclist.
|
||||
function M.show_toc()
|
||||
function M.show_toc(qf_height)
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(bufnr)
|
||||
local headings = get_headings(bufnr)
|
||||
@@ -102,7 +103,7 @@ function M.show_toc()
|
||||
end
|
||||
vim.fn.setloclist(0, headings, ' ')
|
||||
vim.fn.setloclist(0, {}, 'a', { title = 'Table of contents' })
|
||||
vim.cmd.lopen()
|
||||
vim.cmd.lopen({ count = qf_height })
|
||||
vim.w.qf_toc = bufname
|
||||
-- reload syntax file after setting qf_toc variable
|
||||
vim.bo.filetype = 'qf'
|
||||
|
@@ -26,6 +26,7 @@ function TSTree:root() end
|
||||
---@param end_col_old integer
|
||||
---@param end_row_new integer
|
||||
---@param end_col_new integer
|
||||
---@return TSTree
|
||||
---@nodoc
|
||||
function TSTree:edit(start_byte, end_byte_old, end_byte_new, start_row, start_col, end_row_old, end_col_old, end_row_new, end_col_new) end
|
||||
|
||||
|
@@ -23,23 +23,24 @@ function M.check()
|
||||
---@class ParserEntry
|
||||
---@field name string
|
||||
---@field path string
|
||||
---@field index integer runtime path index (unique)
|
||||
|
||||
local sorted_parsers = {} ---@type ParserEntry[]
|
||||
|
||||
for _, parser in ipairs(parsers) do
|
||||
for i, parser in ipairs(parsers) do
|
||||
local parsername = vim.fn.fnamemodify(parser, ':t:r')
|
||||
table.insert(sorted_parsers, { name = parsername, path = parser })
|
||||
table.insert(sorted_parsers, { name = parsername, path = parser, index = i })
|
||||
end
|
||||
|
||||
table.sort(sorted_parsers, function(a, b)
|
||||
if a.name == b.name then
|
||||
return a.path < b.path
|
||||
return a.index < b.index -- if names are the same sort by rtpath index (unique)
|
||||
else
|
||||
return a.name < b.name
|
||||
end
|
||||
end)
|
||||
|
||||
for _, parser in ipairs(sorted_parsers) do
|
||||
for i, parser in ipairs(sorted_parsers) do
|
||||
local is_loadable, err_or_nil = pcall(ts.language.add, parser.name)
|
||||
|
||||
if not is_loadable then
|
||||
@@ -51,10 +52,15 @@ function M.check()
|
||||
err_or_nil or '?'
|
||||
)
|
||||
)
|
||||
elseif i > 1 and sorted_parsers[i - 1].name == parser.name then
|
||||
-- Sorted by runtime path order (load order), thus, if the previous parser has the same name,
|
||||
-- the current parser will not be loaded and `ts.language.inspect(parser.name)` with have
|
||||
-- incorrect information.
|
||||
health.ok(string.format('Parser: %-20s (not loaded), path: %s', parser.name, parser.path))
|
||||
else
|
||||
local lang = ts.language.inspect(parser.name)
|
||||
health.ok(
|
||||
string.format('Parser: %-20s ABI: %d, path: %s', parser.name, lang.abi_version, parser.path)
|
||||
string.format('Parser: %-25s ABI: %d, path: %s', parser.name, lang.abi_version, parser.path)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@@ -52,26 +52,30 @@ function TSHighlighterQuery:query()
|
||||
return self._query
|
||||
end
|
||||
|
||||
---@alias MarkInfo { start_line: integer, start_col: integer, opts: vim.api.keyset.set_extmark }
|
||||
|
||||
---@class (private) vim.treesitter.highlighter.State
|
||||
---@field tstree TSTree
|
||||
---@field next_row integer
|
||||
---@field iter vim.treesitter.highlighter.Iter?
|
||||
---@field highlighter_query vim.treesitter.highlighter.Query
|
||||
---@field prev_marks MarkInfo[]
|
||||
|
||||
---@nodoc
|
||||
---@class vim.treesitter.highlighter
|
||||
---@field active table<integer,vim.treesitter.highlighter>
|
||||
---@field bufnr integer
|
||||
---@field private orig_spelloptions string
|
||||
--- A map of highlight states.
|
||||
--- A map from window ID to highlight states.
|
||||
--- This state is kept during rendering across each line update.
|
||||
---@field private _highlight_states vim.treesitter.highlighter.State[]
|
||||
---@field private _highlight_states table<integer, vim.treesitter.highlighter.State[]>
|
||||
---@field private _queries table<string,vim.treesitter.highlighter.Query>
|
||||
---@field _conceal_line boolean?
|
||||
---@field _conceal_checked table<integer, boolean>
|
||||
---@field tree vim.treesitter.LanguageTree
|
||||
---@field private redraw_count integer
|
||||
---@field parsing boolean true if we are parsing asynchronously
|
||||
--- A map from window ID to whether we are currently parsing that window asynchronously
|
||||
---@field parsing table<integer, boolean>
|
||||
local TSHighlighter = {
|
||||
active = {},
|
||||
}
|
||||
@@ -132,6 +136,7 @@ function TSHighlighter.new(tree, opts)
|
||||
self._conceal_checked = {}
|
||||
self._queries = {}
|
||||
self._highlight_states = {}
|
||||
self.parsing = {}
|
||||
|
||||
-- Queries for a specific language can be overridden by a custom
|
||||
-- string query... if one is not provided it will be looked up by file.
|
||||
@@ -177,19 +182,23 @@ function TSHighlighter:destroy()
|
||||
vim.b[self.bufnr].ts_highlight = nil
|
||||
api.nvim_buf_clear_namespace(self.bufnr, ns, 0, -1)
|
||||
if vim.g.syntax_on == 1 then
|
||||
api.nvim_exec_autocmds(
|
||||
'FileType',
|
||||
{ group = 'syntaxset', buffer = self.bufnr, modeline = false }
|
||||
)
|
||||
-- FileType autocmds commonly assume curbuf is the target buffer, so nvim_buf_call.
|
||||
api.nvim_buf_call(self.bufnr, function()
|
||||
api.nvim_exec_autocmds(
|
||||
'FileType',
|
||||
{ group = 'syntaxset', buffer = self.bufnr, modeline = false }
|
||||
)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param win integer
|
||||
---@param srow integer
|
||||
---@param erow integer exclusive
|
||||
---@private
|
||||
function TSHighlighter:prepare_highlight_states(srow, erow)
|
||||
self._highlight_states = {}
|
||||
function TSHighlighter:prepare_highlight_states(win, srow, erow)
|
||||
self._highlight_states[win] = {}
|
||||
|
||||
self.tree:for_each_tree(function(tstree, tree)
|
||||
if not tstree then
|
||||
@@ -212,19 +221,21 @@ function TSHighlighter:prepare_highlight_states(srow, erow)
|
||||
|
||||
-- _highlight_states should be a list so that the highlights are added in the same order as
|
||||
-- for_each_tree traversal. This ensures that parents' highlight don't override children's.
|
||||
table.insert(self._highlight_states, {
|
||||
table.insert(self._highlight_states[win], {
|
||||
tstree = tstree,
|
||||
next_row = 0,
|
||||
iter = nil,
|
||||
highlighter_query = hl_query,
|
||||
prev_marks = {},
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
---@param win integer
|
||||
---@param fn fun(state: vim.treesitter.highlighter.State)
|
||||
---@package
|
||||
function TSHighlighter:for_each_highlight_state(fn)
|
||||
for _, state in ipairs(self._highlight_states) do
|
||||
function TSHighlighter:for_each_highlight_state(win, fn)
|
||||
for _, state in ipairs(self._highlight_states[win] or {}) do
|
||||
fn(state)
|
||||
end
|
||||
end
|
||||
@@ -307,14 +318,44 @@ local function get_spell(capture_name)
|
||||
return nil, 0
|
||||
end
|
||||
|
||||
---Adds the mark to the buffer, clipped by the line.
|
||||
---Queues the remainder if the mark continues after the line.
|
||||
---@param m MarkInfo
|
||||
---@param buf integer
|
||||
---@param line integer
|
||||
---@param next_marks MarkInfo[]
|
||||
local function add_mark(m, buf, line, next_marks)
|
||||
local cur_start_l = m.start_line
|
||||
local cur_start_c = m.start_col
|
||||
if cur_start_l < line then
|
||||
cur_start_l = line
|
||||
cur_start_c = 0
|
||||
end
|
||||
|
||||
local cur_opts = m.opts
|
||||
if cur_opts.end_line >= line + 1 then
|
||||
cur_opts = vim.deepcopy(cur_opts, true)
|
||||
cur_opts.end_line = line + 1
|
||||
cur_opts.end_col = 0
|
||||
table.insert(next_marks, m)
|
||||
end
|
||||
|
||||
local empty = cur_opts.end_line < cur_start_l
|
||||
or (cur_opts.end_line == cur_start_l and cur_opts.end_col <= cur_start_c)
|
||||
if cur_start_l <= line and not empty then
|
||||
api.nvim_buf_set_extmark(buf, ns, cur_start_l, cur_start_c, cur_opts)
|
||||
end
|
||||
end
|
||||
|
||||
---@param self vim.treesitter.highlighter
|
||||
---@param win integer
|
||||
---@param buf integer
|
||||
---@param line integer
|
||||
---@param on_spell boolean
|
||||
---@param on_conceal boolean
|
||||
local function on_line_impl(self, buf, line, on_spell, on_conceal)
|
||||
local function on_line_impl(self, win, buf, line, on_spell, on_conceal)
|
||||
self._conceal_checked[line] = true
|
||||
self:for_each_highlight_state(function(state)
|
||||
self:for_each_highlight_state(win, function(state)
|
||||
local root_node = state.tstree:root()
|
||||
local root_start_row, _, root_end_row, _ = root_node:range()
|
||||
|
||||
@@ -323,6 +364,12 @@ local function on_line_impl(self, buf, line, on_spell, on_conceal)
|
||||
return
|
||||
end
|
||||
|
||||
local next_marks = {}
|
||||
|
||||
for _, mark in ipairs(state.prev_marks) do
|
||||
add_mark(mark, buf, line, next_marks)
|
||||
end
|
||||
|
||||
if state.iter == nil or state.next_row < line then
|
||||
-- Mainly used to skip over folds
|
||||
|
||||
@@ -362,7 +409,7 @@ local function on_line_impl(self, buf, line, on_spell, on_conceal)
|
||||
local url = get_url(match, buf, capture, metadata)
|
||||
|
||||
if hl and end_row >= line and not on_conceal and (not on_spell or spell ~= nil) then
|
||||
api.nvim_buf_set_extmark(buf, ns, start_row, start_col, {
|
||||
local opts = {
|
||||
end_line = end_row,
|
||||
end_col = end_col,
|
||||
hl_group = hl,
|
||||
@@ -371,7 +418,9 @@ local function on_line_impl(self, buf, line, on_spell, on_conceal)
|
||||
conceal = conceal,
|
||||
spell = spell,
|
||||
url = url,
|
||||
})
|
||||
}
|
||||
local mark = { start_line = start_row, start_col = start_col, opts = opts }
|
||||
add_mark(mark, buf, line, next_marks)
|
||||
end
|
||||
|
||||
if
|
||||
@@ -390,27 +439,30 @@ local function on_line_impl(self, buf, line, on_spell, on_conceal)
|
||||
state.next_row = start_row
|
||||
end
|
||||
end
|
||||
|
||||
state.prev_marks = next_marks
|
||||
end)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param _win integer
|
||||
---@param win integer
|
||||
---@param buf integer
|
||||
---@param line integer
|
||||
function TSHighlighter._on_line(_, _win, buf, line, _)
|
||||
function TSHighlighter._on_line(_, win, buf, line, _)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then
|
||||
return
|
||||
end
|
||||
|
||||
on_line_impl(self, buf, line, false, false)
|
||||
on_line_impl(self, win, buf, line, false, false)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param win integer
|
||||
---@param buf integer
|
||||
---@param srow integer
|
||||
---@param erow integer
|
||||
function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
|
||||
function TSHighlighter._on_spell_nav(_, win, buf, srow, _, erow, _)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then
|
||||
return
|
||||
@@ -418,30 +470,31 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
|
||||
|
||||
-- Do not affect potentially populated highlight state. Here we just want a temporary
|
||||
-- empty state so the C code can detect whether the region should be spell checked.
|
||||
local highlight_states = self._highlight_states
|
||||
self:prepare_highlight_states(srow, erow)
|
||||
local highlight_states = self._highlight_states[win]
|
||||
self:prepare_highlight_states(win, srow, erow)
|
||||
|
||||
for row = srow, erow do
|
||||
on_line_impl(self, buf, row, true, false)
|
||||
on_line_impl(self, win, buf, row, true, false)
|
||||
end
|
||||
self._highlight_states = highlight_states
|
||||
self._highlight_states[win] = highlight_states
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param win integer
|
||||
---@param buf integer
|
||||
---@param row integer
|
||||
function TSHighlighter._on_conceal_line(_, _, buf, row)
|
||||
function TSHighlighter._on_conceal_line(_, win, buf, row)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self or not self._conceal_line or self._conceal_checked[row] then
|
||||
return
|
||||
end
|
||||
|
||||
-- Do not affect potentially populated highlight state.
|
||||
local highlight_states = self._highlight_states
|
||||
local highlight_states = self._highlight_states[win]
|
||||
self.tree:parse({ row, row })
|
||||
self:prepare_highlight_states(row, row)
|
||||
on_line_impl(self, buf, row, false, true)
|
||||
self._highlight_states = highlight_states
|
||||
self:prepare_highlight_states(win, row, row)
|
||||
on_line_impl(self, win, buf, row, false, true)
|
||||
self._highlight_states[win] = highlight_states
|
||||
end
|
||||
|
||||
---@private
|
||||
@@ -466,33 +519,33 @@ function TSHighlighter._on_win(_, win, buf, topline, botline)
|
||||
if not self then
|
||||
return false
|
||||
end
|
||||
self.parsing = self.parsing
|
||||
self.parsing[win] = self.parsing[win]
|
||||
or nil
|
||||
== self.tree:parse({ topline, botline + 1 }, function(_, trees)
|
||||
if trees and self.parsing then
|
||||
self.parsing = false
|
||||
api.nvim__redraw({ win = win, valid = false, flush = false })
|
||||
if trees and self.parsing[win] then
|
||||
self.parsing[win] = false
|
||||
if api.nvim_win_is_valid(win) then
|
||||
api.nvim__redraw({ win = win, valid = false, flush = false })
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not self.parsing then
|
||||
if not self.parsing[win] then
|
||||
self.redraw_count = self.redraw_count + 1
|
||||
self:prepare_highlight_states(topline, botline)
|
||||
self:prepare_highlight_states(win, topline, botline)
|
||||
else
|
||||
self:for_each_highlight_state(function(state)
|
||||
self:for_each_highlight_state(win, function(state)
|
||||
-- TODO(ribru17): Inefficient. Eventually all marks should be applied in on_buf, and all
|
||||
-- non-folded ranges of each open window should be merged, and iterators should only be
|
||||
-- created over those regions. This would also fix #31777.
|
||||
--
|
||||
-- Currently this is not possible because the parser discards previously parsed injection
|
||||
-- trees upon parsing a different region.
|
||||
--
|
||||
-- It would also be nice if rather than re-querying extmarks for old trees, we could tell the
|
||||
-- decoration provider to not clear previous ephemeral marks for this redraw cycle.
|
||||
state.iter = nil
|
||||
state.next_row = 0
|
||||
end)
|
||||
end
|
||||
return #self._highlight_states > 0
|
||||
local hl_states = self._highlight_states[win] or {}
|
||||
return #hl_states > 0
|
||||
end
|
||||
|
||||
api.nvim_set_decoration_provider(ns, {
|
||||
|
@@ -956,7 +956,9 @@ function LanguageTree:_get_injection(match, metadata)
|
||||
local ft = vim.filetype.match({ filename = text })
|
||||
lang = ft and resolve_lang(ft)
|
||||
elseif name == 'injection.content' then
|
||||
ranges = get_node_ranges(node, self._source, metadata[id], include_children)
|
||||
for _, range in ipairs(get_node_ranges(node, self._source, metadata[id], include_children)) do
|
||||
ranges[#ranges + 1] = range
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1080,8 +1082,8 @@ function LanguageTree:_edit(
|
||||
end_row_new,
|
||||
end_col_new
|
||||
)
|
||||
for _, tree in pairs(self._trees) do
|
||||
tree:edit(
|
||||
for i, tree in pairs(self._trees) do
|
||||
self._trees[i] = tree:edit(
|
||||
start_byte,
|
||||
end_byte_old,
|
||||
end_byte_new,
|
||||
|
@@ -979,8 +979,7 @@ function Query:iter_captures(node, source, start, stop, opts)
|
||||
|
||||
start, stop = value_or_node_range(start, stop, node)
|
||||
|
||||
-- Copy the tree to ensure it is valid during the entire lifetime of the iterator
|
||||
local tree = node:tree():copy()
|
||||
local tree = node:tree()
|
||||
local cursor = vim._create_ts_querycursor(node, self.query, start, stop, opts)
|
||||
|
||||
-- For faster checks that a match is not in the cache.
|
||||
@@ -1079,8 +1078,7 @@ function Query:iter_matches(node, source, start, stop, opts)
|
||||
|
||||
start, stop = value_or_node_range(start, stop, node)
|
||||
|
||||
-- Copy the tree to ensure it is valid during the entire lifetime of the iterator
|
||||
local tree = node:tree():copy()
|
||||
local tree = node:tree()
|
||||
local cursor = vim._create_ts_querycursor(node, self.query, start, stop, opts)
|
||||
|
||||
local function iter()
|
||||
|
@@ -238,8 +238,8 @@ function VersionRange:has(version)
|
||||
version = setmetatable(vim.deepcopy(version, true), Version)
|
||||
end
|
||||
if version then
|
||||
if version.prerelease ~= self.from.prerelease then
|
||||
return false
|
||||
if self.from == self.to then
|
||||
return version == self.from
|
||||
end
|
||||
return version >= self.from and (self.to == nil or version < self.to)
|
||||
end
|
||||
@@ -310,9 +310,7 @@ function M.range(spec) -- Adapted from https://github.com/folke/lazy.nvim
|
||||
local from = semver --- @type vim.Version?
|
||||
local to = vim.deepcopy(semver, true) --- @type vim.Version?
|
||||
---@diagnostic disable: need-check-nil
|
||||
if mods == '' or mods == '=' then
|
||||
to.patch = to.patch + 1
|
||||
elseif mods == '<' then
|
||||
if mods == '<' then
|
||||
from = M._version({})
|
||||
elseif mods == '<=' then
|
||||
from = M._version({})
|
||||
|
@@ -26,6 +26,8 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release date="2025-08-31" version="0.11.4"/>
|
||||
<release date="2025-07-12" version="0.11.3"/>
|
||||
<release date="2025-05-30" version="0.11.2"/>
|
||||
<release date="2025-04-26" version="0.11.1"/>
|
||||
<release date="2025-03-26" version="0.11.0"/>
|
||||
|
@@ -127,6 +127,7 @@
|
||||
"eval"
|
||||
"sign"
|
||||
"abort"
|
||||
"substitute"
|
||||
] @keyword
|
||||
|
||||
(map_statement
|
||||
@@ -252,6 +253,9 @@
|
||||
(heredoc
|
||||
(parameter) @keyword)
|
||||
|
||||
(script
|
||||
(parameter) @keyword)
|
||||
|
||||
[
|
||||
(marker_definition)
|
||||
(endmarker)
|
||||
@@ -313,6 +317,9 @@
|
||||
(binary_operation
|
||||
"." @operator)
|
||||
|
||||
(lua_statement
|
||||
"=" @keyword)
|
||||
|
||||
; Punctuation
|
||||
[
|
||||
"("
|
||||
|
@@ -14,8 +14,8 @@ syn keyword DiagnosticError ERROR[:]
|
||||
syn keyword DiagnosticWarn WARNING[:]
|
||||
syn keyword DiagnosticOk OK[:]
|
||||
" Note: hs=e starts higlighting on the title line (instead of the "===" line).
|
||||
syn match helpSectionDelim /^======*\n.*$/hs=e
|
||||
highlight helpSectionDelim gui=reverse cterm=reverse
|
||||
syn match healthHeadingChar "=" conceal cchar= contained containedin=helpSectionDelim
|
||||
syn match healthSectionDelim /^======*\n.*$/hs=e
|
||||
highlight default healthSectionDelim gui=reverse cterm=reverse
|
||||
syn match healthHeadingChar "=" conceal cchar= contained containedin=healthSectionDelim
|
||||
|
||||
let b:current_syntax = "checkhealth"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
" Vim syntax file
|
||||
" Language: Vim help file
|
||||
" Maintainer: The Vim Project <https://github.com/vim/vim>
|
||||
" Last Change: 2024 Oct 16
|
||||
" Last Change: 2024 Dec 15
|
||||
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
|
||||
" Quit when a (custom) syntax file was already loaded
|
||||
@@ -12,15 +12,36 @@ endif
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
if !exists('g:help_example_languages')
|
||||
let g:help_example_languages = #{ vim: 'vim' }
|
||||
endif
|
||||
|
||||
syn match helpHeadline "^[A-Z.][-A-Z0-9 .,()_']*?\=\ze\(\s\+\*\|$\)"
|
||||
syn match helpSectionDelim "^===.*===$"
|
||||
syn match helpSectionDelim "^---.*--$"
|
||||
" Nvim: support language annotation in codeblocks
|
||||
|
||||
if has("conceal")
|
||||
syn region helpExample matchgroup=helpIgnore start=" >[a-z0-9]*$" start="^>[a-z0-9]*$" end="^[^ \t]"me=e-1 end="^<" concealends
|
||||
syn region helpExample matchgroup=helpIgnore
|
||||
\ start="\%(^\| \)>[a-z0-9]*$" end="^[^ \t]"me=e-1 end="^<" concealends
|
||||
else
|
||||
syn region helpExample matchgroup=helpIgnore start=" >[a-z0-9]*$" start="^>[a-z0-9]*$" end="^[^ \t]"me=e-1 end="^<"
|
||||
syn region helpExample matchgroup=helpIgnore
|
||||
\ start="\%(^\| \)>[a-z0-9]*$" end="^[^ \t]"me=e-1 end="^<"
|
||||
endif
|
||||
|
||||
for [s:lang, s:syntax] in g:help_example_languages->items()
|
||||
unlet! b:current_syntax
|
||||
" silent! to prevent E403
|
||||
execute 'silent! syn include' $'@helpExampleHighlight_{s:lang}'
|
||||
\ $'syntax/{s:syntax}.vim'
|
||||
|
||||
execute $'syn region helpExampleHighlight_{s:lang} matchgroup=helpIgnore'
|
||||
\ $'start=/\%(^\| \)>{s:lang}$/'
|
||||
\ 'end=/^[^ \t]/me=e-1 end=/^</'
|
||||
\ (has("conceal") ? 'concealends' : '')
|
||||
\ $'contains=@helpExampleHighlight_{s:lang} keepend'
|
||||
endfor
|
||||
unlet! s:lang s:syntax
|
||||
|
||||
syn match helpHyperTextJump "\\\@<!|[#-)!+-~]\+|" contains=helpBar
|
||||
syn match helpHyperTextEntry "\*[#-)!+-~]\+\*\s"he=e-1 contains=helpStar
|
||||
syn match helpHyperTextEntry "\*[#-)!+-~]\+\*$" contains=helpStar
|
||||
|
@@ -19,7 +19,7 @@ syn match qfError "error" contained
|
||||
syn cluster qfType contains=qfError
|
||||
|
||||
" Hide file name and line number for help outline (TOC).
|
||||
if has_key(w:, 'qf_toc') || get(w:, 'quickfix_title') =~# '\<TOC$'
|
||||
if has_key(w:, 'qf_toc') || get(w:, 'quickfix_title') =~# '\<TOC$\|\<Table of contents\>'
|
||||
setlocal conceallevel=3 concealcursor=nc
|
||||
syn match Ignore "^[^|]*|[^|]*| " conceal
|
||||
endif
|
||||
|
3
runtime/syntax/tutor.lua
Normal file
3
runtime/syntax/tutor.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
vim.cmd [[
|
||||
syntax match tutorExpect /^--->.*$/
|
||||
]]
|
@@ -1,5 +1,7 @@
|
||||
# Welcome to the Neovim Tutorial
|
||||
|
||||
# Chapter 1
|
||||
|
||||
Neovim is a very powerful editor that has many commands, too many to explain in
|
||||
a tutorial such as this. This tutorial is designed to describe enough of the
|
||||
commands that you will be able to easily use Neovim as an all-purpose editor.
|
||||
@@ -302,7 +304,7 @@ it would be easier to simply type two d's to delete a line.
|
||||
|
||||
3. Now move to the fourth line.
|
||||
|
||||
4. Type `2dd`{normal} to delete two lines, then press `u`{normal} twice to undo all three lines.
|
||||
4. Type `2dd`{normal} to delete two lines.
|
||||
|
||||
1) Roses are red,
|
||||
2) Mud is fun,
|
||||
@@ -366,7 +368,7 @@ Fiix the errors oon thhis line and reeplace them witth undo.
|
||||
|
||||
** Type `p`{normal} to put previously deleted text after the cursor. **
|
||||
|
||||
1. Move the cursor to the first ✓ line below.
|
||||
1. Move the cursor to the first `--->` line below.
|
||||
|
||||
2. Type `dd`{normal} to delete the line and store it in a Neovim register.
|
||||
|
||||
@@ -376,10 +378,10 @@ Fiix the errors oon thhis line and reeplace them witth undo.
|
||||
|
||||
5. Repeat steps 2 through 4 to put all the lines in correct order.
|
||||
|
||||
d) Can you learn too?
|
||||
b) Violets are blue,
|
||||
c) Intelligence is learned,
|
||||
a) Roses are red,
|
||||
---> d) Can you learn too?
|
||||
---> b) Violets are blue,
|
||||
---> c) Intelligence is learned,
|
||||
---> a) Roses are red,
|
||||
|
||||
NOTE: You can also put the text before the cursor with `P`{normal} (capital P).
|
||||
|
||||
@@ -978,6 +980,9 @@ Run `:help nvim-quickstart`{vim} for more information on extending Nvim.
|
||||
|
||||
# CONCLUSION
|
||||
|
||||
This concludes Chapter 1 of the Vim Tutor. Consider continuing with
|
||||
[Chapter 2](@tutor:vim-02-beginner).
|
||||
|
||||
This was intended to give a brief overview of the Neovim editor, just enough to
|
||||
allow you to use it fairly easily. It is far from complete as Neovim has
|
||||
many many more commands. Consult the help often.
|
||||
|
@@ -1,44 +1,40 @@
|
||||
{
|
||||
"expect": {
|
||||
"103": "The cow jumped over the moon.",
|
||||
"125": "There is some text missing from this line.",
|
||||
"126": "There is some text missing from this line.",
|
||||
"145": "There is some text missing from this line.",
|
||||
"146": "There is some text missing from this line.",
|
||||
"147": "There is also some text missing here.",
|
||||
"148": "There is also some text missing here.",
|
||||
"216": "There are some words that don't belong in this sentence.",
|
||||
"232": "Somebody typed the end of this line twice.",
|
||||
"271": -1,
|
||||
"290": "This line of words is cleaned up.",
|
||||
"307": "1) Roses are red,",
|
||||
"308": "3) Violets are blue,",
|
||||
"309": "6) Sugar is sweet",
|
||||
"310": "7) And so are you.",
|
||||
"311": "7) And so are you.",
|
||||
"312": "7) And so are you.",
|
||||
"313": "7) And so are you.",
|
||||
"333": "Fix the errors on this line and replace them with undo.",
|
||||
"379": -1,
|
||||
"380": -1,
|
||||
"381": -1,
|
||||
"382": -1,
|
||||
"398": "When this line was typed in, someone pressed some wrong keys!",
|
||||
"399": "When this line was typed in, someone pressed some wrong keys!",
|
||||
"419": "This line has a few words that need changing using the change operator.",
|
||||
"420": "This line has a few words that need changing using the change operator.",
|
||||
"440": "The end of this line needs to be corrected using the c$ command.",
|
||||
"441": "The end of this line needs to be corrected using the c$ command.",
|
||||
"504": -1,
|
||||
"523": -1,
|
||||
"546": "Usually the best time to see the flowers is in the spring.",
|
||||
"741": -1,
|
||||
"746": -1,
|
||||
"762": "This line will allow you to practice appending text to a line.",
|
||||
"763": "This line will allow you to practice appending text to a line.",
|
||||
"783": "Adding 123 to 456 gives you 579.",
|
||||
"784": "Adding 123 to 456 gives you 579.",
|
||||
"810": "a) This is the first item.",
|
||||
"811": "b) This is the second item."
|
||||
"105": "The cow jumped over the moon.",
|
||||
"127": "There is some text missing from this line.",
|
||||
"128": "There is some text missing from this line.",
|
||||
"147": "There is some text missing from this line.",
|
||||
"148": "There is some text missing from this line.",
|
||||
"149": "There is also some text missing here.",
|
||||
"150": "There is also some text missing here.",
|
||||
"218": "There are some words that don't belong in this sentence.",
|
||||
"234": "Somebody typed the end of this line twice.",
|
||||
"273": -1,
|
||||
"292": "This line of words is cleaned up.",
|
||||
"309": "1) Roses are red,",
|
||||
"310": "",
|
||||
"311": "3) Violets are blue,",
|
||||
"312": "",
|
||||
"313": "",
|
||||
"314": "6) Sugar is sweet",
|
||||
"315": "7) And so are you.",
|
||||
"335": "Fix the errors on this line and replace them with undo.",
|
||||
"400": "When this line was typed in, someone pressed some wrong keys!",
|
||||
"401": "When this line was typed in, someone pressed some wrong keys!",
|
||||
"421": "This line has a few words that need changing using the change operator.",
|
||||
"422": "This line has a few words that need changing using the change operator.",
|
||||
"442": "The end of this line needs to be corrected using the c$ command.",
|
||||
"443": "The end of this line needs to be corrected using the c$ command.",
|
||||
"506": -1,
|
||||
"525": -1,
|
||||
"548": "Usually the best time to see the flowers is in the spring.",
|
||||
"743": -1,
|
||||
"748": -1,
|
||||
"764": "This line will allow you to practice appending text to a line.",
|
||||
"765": "This line will allow you to practice appending text to a line.",
|
||||
"785": "Adding 123 to 456 gives you 579.",
|
||||
"786": "Adding 123 to 456 gives you 579.",
|
||||
"812": "a) This is the first item.",
|
||||
"813": "b) This is the second item."
|
||||
}
|
||||
}
|
||||
|
194
runtime/tutor/en/vim-02-beginner.tutor
Normal file
194
runtime/tutor/en/vim-02-beginner.tutor
Normal file
@@ -0,0 +1,194 @@
|
||||
# Welcome to the Neovim Tutorial
|
||||
|
||||
# Chapter 2
|
||||
|
||||
Hic Sunt Dracones: if this is your first exposure to vim and you
|
||||
intended to avail yourself of the introductory chapter, kindly type
|
||||
on the command line of the Vim editor
|
||||
~~~ cmd
|
||||
:Tutor vim-01-beginner
|
||||
~~~
|
||||
Or just open the [first chapter](@tutor:vim-01-beginner) of the tutor at the link.
|
||||
|
||||
The approximate time required to complete this chapter is 8-10 minutes,
|
||||
depending upon how much time is spent with experimentation.
|
||||
|
||||
|
||||
# Lesson 2.1.1: THE NAMED REGISTERS
|
||||
|
||||
** Store two yanked words concurrently and then paste them **
|
||||
|
||||
1. Move the cursor to the line below marked ✓
|
||||
|
||||
2. Navigate to any point on the word 'Edward' and type `"ayiw`{normal}
|
||||
|
||||
**MNEMONIC**: *into register(") named (a) (y)ank (i)nner (w)ord*
|
||||
|
||||
3. Navigate forward to the word 'cookie' (`fk`{normal} or `2fc`{normal}
|
||||
or `$2b`{normal} or `/co`{normal} `<ENTER>`{normal}) and type `"byiw`{normal}
|
||||
|
||||
4. Navigate to any point on the word 'Vince' and type `ciw<CTRL-r>a<ESC>`{normal}
|
||||
|
||||
**MNEMONIC**: *(c)hange (i)nner (w)ord with <contents of (r)egister> named (a)*
|
||||
|
||||
5. Navigate to any point on the word 'cake' and type `ciw<CTRL-r>b<ESC>`{normal}
|
||||
|
||||
a) Edward will henceforth be in charge of the cookie rations
|
||||
b) In this capacity, Vince will have sole cake discretionary powers
|
||||
|
||||
NOTE: Delete also works into registers, i.e. `"sdiw`{normal} will delete
|
||||
the word under the cursor into register s.
|
||||
|
||||
REFERENCE: [Registers](registers)
|
||||
[Named Registers](quotea)
|
||||
[Motion](text-objects)
|
||||
[CTRL-R](i_CTRL-R)
|
||||
|
||||
|
||||
# Lesson 2.1.2: THE EXPRESSION REGISTER
|
||||
|
||||
** Insert the results of calculations on the fly **
|
||||
|
||||
1. Move the cursor to the line below marked ✗
|
||||
|
||||
2. Navigate to any point on the supplied number
|
||||
|
||||
3. Type `ciw<CTRL-r>=`{normal}60\*60\*24 `<ENTER>`{normal}
|
||||
|
||||
4. On the next line, enter insert mode and add today's date with
|
||||
`<CTRL-r>=`{normal}`system('date')`{vim} `<ENTER>`{normal}
|
||||
|
||||
NOTE: All calls to system are OS dependent, e.g. on Windows use
|
||||
`system('date /t')`{vim} or `:r!date /t`{vim}
|
||||
|
||||
I have forgotten the exact number of seconds in a day, is it 84600?
|
||||
Today's date is:
|
||||
|
||||
NOTE: the same can be achieved with `:pu=`{normal}`system('date')`{vim}
|
||||
or, with fewer keystrokes `:r!date`{vim}
|
||||
|
||||
REFERENCE: [Expression Register](quote=)
|
||||
|
||||
|
||||
# Lesson 2.1.3: THE NUMBERED REGISTERS
|
||||
|
||||
** Press `yy`{normal} and `dd`{normal} to witness their effect on the registers **
|
||||
|
||||
1. Move the cursor to the line below marked ✓
|
||||
|
||||
2. yank the zeroth line, then inspect registers with `:reg`{vim} `<ENTER>`{normal}
|
||||
|
||||
3. delete line 0. with `"cdd`{normal}, then inspect registers
|
||||
(Where do you expect line 0 to be?)
|
||||
|
||||
4. continue deleting each successive line, inspecting `:reg`{vim} as you go
|
||||
|
||||
NOTE: You should notice that old full-line deletions move down the list
|
||||
as new full-line deletions are added
|
||||
|
||||
5. Now (p)aste the following registers in order; c, 7, 4, 8, 2. i.e. `"7p`{normal}
|
||||
|
||||
0. This
|
||||
9. wobble
|
||||
8. secret
|
||||
7. is
|
||||
6. on
|
||||
5. axis
|
||||
4. a
|
||||
3. war
|
||||
2. message
|
||||
1. tribute
|
||||
|
||||
|
||||
NOTE: Whole line deletions (`dd`{normal}) are much longer lived in the
|
||||
numbered registers than whole line yanks, or deletions involving
|
||||
smaller movements
|
||||
|
||||
REFERENCE: [Numbered Registers](quote0)
|
||||
|
||||
|
||||
# Lesson 2.1.4: THE BEAUTY OF MARKS
|
||||
|
||||
** Code monkey arithmetic avoidance **
|
||||
|
||||
NOTE: a common conundrum when coding is moving around large chunks of code.
|
||||
The following technique helps avoid number line calculations associated
|
||||
with operations like `"a147d`{normal} or `:945,1091d a`{vim} or even worse
|
||||
using `i<CTRL-r>=`{normal}1091-945 `<ENTER>`{normal} first
|
||||
|
||||
1. Move the cursor to the line below marked ✓
|
||||
|
||||
2. Go to the first line of the function and mark it with `ma`{normal}
|
||||
|
||||
NOTE: exact position on line is NOT important!
|
||||
|
||||
3. Navigate to the end of the line and then the end of the code block
|
||||
with `$%`{normal}
|
||||
|
||||
4. Delete the block into register a with `"ad'a`{normal}
|
||||
|
||||
**MNEMONIC**: *into register(") named (a) put the (d)eletion from the cursor to
|
||||
the LINE containing mark(') (a)*
|
||||
|
||||
5. Paste the block between BBB and CCC `"ap`{normal}
|
||||
|
||||
NOTE: practice this operation multiple times to become fluent `ma$%"ad'a`{normal}
|
||||
|
||||
~~~ cmd
|
||||
AAA
|
||||
function itGotRealBigRealFast() {
|
||||
if ( somethingIsTrue ) {
|
||||
doIt()
|
||||
}
|
||||
// the taxonomy of our function has changed and it
|
||||
// no longer makes alphabetical sense in its current position
|
||||
|
||||
// imagine hundreds of lines of code
|
||||
|
||||
// naively you could navigate to the start and end and record or
|
||||
// remember each line number
|
||||
}
|
||||
BBB
|
||||
CCC
|
||||
~~~
|
||||
|
||||
NOTE: marks and registers do not share a namespace, therefore register a is
|
||||
completely independent of mark a. This is not true of registers and
|
||||
macros.
|
||||
|
||||
REFERENCE: [Marks](marks)
|
||||
[Mark Motions](mark-motions) (difference between ' and \`)
|
||||
|
||||
|
||||
# Lesson 2.1 SUMMARY
|
||||
|
||||
1. To store (yank, delete) text into, and retrieve (paste) from, a total of
|
||||
26 registers (a-z)
|
||||
2. Yank a whole word from anywhere within a word: `yiw`{normal}
|
||||
3. Change a whole word from anywhere within a word: `ciw`{normal}
|
||||
4. Insert text directly from registers in insert mode: `<CTRL-r>a`{normal}
|
||||
|
||||
5. Insert the results of simple arithmetic operations:
|
||||
`<CTRL-r>=`{normal}60\*60 `<ENTER>`{normal} in insert mode
|
||||
6. Insert the results of system calls:
|
||||
`<CTRL-r>=`{normal}`system('ls -1')`{vim} in insert mode
|
||||
|
||||
7. Inspect registers with `:reg`{vim}
|
||||
8. Learn the final destination of whole line deletions: `dd`{normal} in
|
||||
the numbered registers, i.e. descending from register 1 - 9. Appreciate
|
||||
that whole line deletions are preserved in the numbered registers longer
|
||||
than any other operation
|
||||
9. Learn the final destination of all yanks in the numbered registers and
|
||||
how ephemeral they are
|
||||
|
||||
10. Place marks from command mode `m[a-zA-Z0-9]`{normal}
|
||||
11. Move line-wise to a mark with `'`{normal}
|
||||
|
||||
|
||||
# CONCLUSION
|
||||
|
||||
This concludes chapter two of the Vim Tutor. It is a work in progress.
|
||||
|
||||
This chapter was written by Paul D. Parker.
|
||||
|
||||
Modified for vim-tutor-mode by Restorer.
|
10
runtime/tutor/en/vim-02-beginner.tutor.json
Normal file
10
runtime/tutor/en/vim-02-beginner.tutor.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"expect": {
|
||||
"36": -1,
|
||||
"37": "b) In this capacity, Edward will have sole cookie discretionary powers",
|
||||
"64": "I have forgotten the exact number of seconds in a day, is it 86400",
|
||||
"65": -1,
|
||||
"91": -1,
|
||||
"138": -1
|
||||
}
|
||||
}
|
@@ -368,7 +368,7 @@ This is just a line with words you can move around in.
|
||||
|
||||
** 最後に削除された行をカーソルの後に貼り付ける(Put)には `p`{normal} をタイプします。 **
|
||||
|
||||
1. ✓ と示された以下の最初の行にカーソルを移動しましょう。
|
||||
1. `--->` と示された以下の最初の行にカーソルを移動しましょう。
|
||||
|
||||
2. `dd`{normal} とタイプして行を削除し、Neovim のレジスタに格納しましょう。
|
||||
|
||||
@@ -378,10 +378,10 @@ This is just a line with words you can move around in.
|
||||
|
||||
5. 順番が正しくなる様にステップ 2 から 4 を繰り返しましょう。
|
||||
|
||||
d) 貴方も学ぶことができるか?
|
||||
b) 菫は青く
|
||||
c) 知恵とは学ぶもの
|
||||
a) 薔薇は赤く
|
||||
---> d) 貴方も学ぶことができるか?
|
||||
---> b) 菫は青く
|
||||
---> c) 知恵とは学ぶもの
|
||||
---> a) 薔薇は赤く
|
||||
|
||||
NOTE: `P`{normal} (大文字 P)とタイプすることで、カーソルの前に貼り付ける事もできます。
|
||||
|
||||
|
@@ -11,18 +11,14 @@
|
||||
"233": "誰かがこの行の最後を2度タイプしました。",
|
||||
"272": -1,
|
||||
"291": "この行の単語は綺麗になった。",
|
||||
"308": -1,
|
||||
"309": -1,
|
||||
"310": -1,
|
||||
"311": -1,
|
||||
"312": -1,
|
||||
"313": -1,
|
||||
"314": -1,
|
||||
"308": "1) 薔薇は赤く",
|
||||
"309": "",
|
||||
"310": "3) 菫は青く",
|
||||
"311": "",
|
||||
"312": "",
|
||||
"313": "6) 砂糖は甘く",
|
||||
"314": "7) そして貴方も",
|
||||
"335": "この行の間違いを修正し、後でそれらの修正を取り消します。",
|
||||
"381": -1,
|
||||
"382": -1,
|
||||
"383": -1,
|
||||
"384": -1,
|
||||
"400": "この行を入力した時に、その人は幾つか間違ったキーを押しました!",
|
||||
"401": "この行を入力した時に、その人は幾つか間違ったキーを押しました!",
|
||||
"421": "This line has a few words that need changing using the change operator.",
|
||||
|
@@ -1,35 +1,35 @@
|
||||
{
|
||||
"expect": {
|
||||
"63": "This is text with **important information**",
|
||||
"64": "This is text with **important information**",
|
||||
"71": "TODO: Document '&variable'",
|
||||
"72": "TODO: Document '&variable'",
|
||||
"78": "# This is a level 1 header",
|
||||
"79": "# This is a level 1 header",
|
||||
"80": "### This is a level 3 header",
|
||||
"81": "### This is a level 3 header",
|
||||
"82": "# This is a header with a label {*label*}",
|
||||
"83": "# This is a header with a label {*label*}",
|
||||
"108": "A link to help for the ['breakindent']('breakindent') option",
|
||||
"109": "A link to help for the ['breakindent']('breakindent') option",
|
||||
"123": "A link to the [Links](*links*) section",
|
||||
"124": "A link to the [Links](*links*) section",
|
||||
"139": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
|
||||
"140": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
|
||||
"157": "~~~ viml",
|
||||
"158": "echom 'the value of &number is'.string(&number)",
|
||||
"159": "~~~",
|
||||
"161": "~~~ viml",
|
||||
"162": "echom 'the value of &number is'.string(&number)",
|
||||
"163": "~~~",
|
||||
"188": "~~~ normal",
|
||||
"189": "d2w",
|
||||
"190": "~~~",
|
||||
"192": "~~~ normal",
|
||||
"193": "d2w",
|
||||
"194": "~~~",
|
||||
"206": "`d2w`{normal}",
|
||||
"207": "`d2w`{normal}",
|
||||
"244": -1
|
||||
"56": "This is text with **important information**",
|
||||
"57": "This is text with **important information**",
|
||||
"64": "TODO: Document '&variable'",
|
||||
"65": "TODO: Document '&variable'",
|
||||
"71": "# This is a level 1 header",
|
||||
"72": "# This is a level 1 header",
|
||||
"73": "### This is a level 3 header",
|
||||
"74": "### This is a level 3 header",
|
||||
"75": "# This is a header with a label {*label*}",
|
||||
"76": "# This is a header with a label {*label*}",
|
||||
"101": "A link to help for the ['breakindent']('breakindent') option",
|
||||
"102": "A link to help for the ['breakindent']('breakindent') option",
|
||||
"116": "A link to the [Links](*links*) section",
|
||||
"117": "A link to the [Links](*links*) section",
|
||||
"132": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
|
||||
"133": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
|
||||
"150": "~~~ viml",
|
||||
"151": "echom 'the value of &number is'.string(&number)",
|
||||
"152": "~~~",
|
||||
"154": "~~~ viml",
|
||||
"155": "echom 'the value of &number is'.string(&number)",
|
||||
"156": "~~~",
|
||||
"181": "~~~ normal",
|
||||
"182": "d2w",
|
||||
"183": "~~~",
|
||||
"185": "~~~ normal",
|
||||
"186": "d2w",
|
||||
"187": "~~~",
|
||||
"199": "`d2w`{normal}",
|
||||
"200": "`d2w`{normal}",
|
||||
"237": -1
|
||||
}
|
||||
}
|
||||
|
967
runtime/tutor/zh/vim-01-beginner.tutor
Normal file
967
runtime/tutor/zh/vim-01-beginner.tutor
Normal file
@@ -0,0 +1,967 @@
|
||||
# 欢迎来到 Neovim 教程
|
||||
|
||||
# 第 1 章
|
||||
|
||||
Neovim 是一个功能非常强大的编辑器,它的命令多到无法在这篇教程里一一讲解。本教程
|
||||
旨在介绍足够多的基本命令,让你能轻松地将 Neovim 作为通用编辑器来使用。
|
||||
|
||||
请务必记住,本教程是为“在实践中学习”而设计的。这意味着你需要亲手完成这些练习才能
|
||||
真正掌握它们。如果你只看不练,很快就会忘记最重要的内容!
|
||||
|
||||
现在,请确保你的大写锁定键(Caps-Lock)是关闭状态,然后多次按下 `j`{normal} 键,
|
||||
直到光标移动到第 0 课完全充满屏幕为止。
|
||||
|
||||
# 第 0 课
|
||||
|
||||
NOTE: 课程中的命令会修改本文,但这些更改不会被保存。不用担心会搞乱什么;只要记住
|
||||
按 [<Esc>](<Esc>) 键,再按 [u](u) 键,就可以撤销最近的更改。
|
||||
|
||||
本教程是交互式的,有几件事你需要知道。
|
||||
- 在 [这样的](holy-grail ) 链接上按 [<Enter>](<Enter>) 键可以打开链接的帮助文档。
|
||||
- 或者,你也可以在任意单词上按 [K](K) 键来查找它的文档!
|
||||
- 你可以用 `:q`{vim} `<Enter>`{normal} 来关闭这个帮助窗口。
|
||||
|
||||
当左边出现 ✗ 标志时,你需要去修改文本。当你正确地完成修改后,左边的 ✗ 标志就会变
|
||||
成 ✓。我想你已经能体会到 Neovim 的强大之处了。
|
||||
|
||||
其他时候,你会被提示运行一个命令(稍后会对此进行解释):
|
||||
|
||||
`:help`{vim} `<Enter>`{normal}
|
||||
|
||||
或者按下一系列按键:
|
||||
~~~ normal
|
||||
<Esc>0f<Space>d3wP$P
|
||||
~~~
|
||||
尖括号(<>)里的文本(如 `<Enter>`{normal})代表你需要按下的键,而不是要输入的文本。
|
||||
|
||||
现在,移动到下一课(使用 `j`{normal} 键向下滚动)。
|
||||
|
||||
# 第 1.1 课:移动光标
|
||||
|
||||
** 按 `h`、`j`、`k`、`l` 键来移动光标,如下所示。 **
|
||||
|
||||
↑
|
||||
k 提示:`h`{normal} 键在左边,向左移动。
|
||||
← h l → `l`{normal} 键在右边,向右移动。
|
||||
j `j`{normal} 键看起来像一个向下的箭头。
|
||||
↓
|
||||
|
||||
1. 在屏幕上四处移动光标,直到你习惯这种操作。
|
||||
|
||||
2. 按住向下键(`j`{normal})直到光标开始连续向下移动。
|
||||
现在你知道如何移动到下一课了。
|
||||
|
||||
3. 使用下移键,移动到第 1.2 课。
|
||||
|
||||
NOTE: 如果你不确定自己输入了什么,随时可以按 <Esc> 键回到普通模式(Normal mode)。
|
||||
然后重新输入你想要的命令。
|
||||
|
||||
NOTE: 键盘上的方向键通常也能用。但一旦你习惯了,使用 hjkl 可以让你移动得更快。
|
||||
|
||||
# 第 1.2 课:退出 Neovim
|
||||
|
||||
!! NOTE: 在执行以下任何步骤之前,请先阅读完本课的全部内容 !!
|
||||
|
||||
1. 按下 <Esc> 键(确保你处于普通模式)。
|
||||
|
||||
2. 输入:
|
||||
|
||||
`:q!`{vim} `<Enter>`{normal}
|
||||
|
||||
这个命令会退出编辑器,并“丢弃”你所做的所有更改。
|
||||
|
||||
3. 重新打开 Neovim,并通过执行带你进入本教程的命令回到这里。这个命令也许是:
|
||||
|
||||
`:Tutor`{vim} `<Enter>`{normal}
|
||||
|
||||
4. 如果你已经记住了这些步骤并充满信心,请执行第 1 到 3 步来退出并重新进入编辑器。
|
||||
|
||||
NOTE: [:q!](:q) `<Enter>`{normal} 会丢弃你做的任何更改。在接下来的几课中,你将学习如何
|
||||
将更改保存到文件中。
|
||||
|
||||
5. 向下移动光标到第 1.3 课。
|
||||
|
||||
# 第 1.3 课:文本编辑——删除(Deletion)
|
||||
|
||||
** 按 `x`{normal} 键可以删除光标下的单个字符。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的那一行。
|
||||
|
||||
2. 为了修正错误,请将光标移动到需要被删除的字符上。
|
||||
|
||||
3. 按下 [x 键](x) 来删除那个多余的字符。
|
||||
|
||||
4. 重复第 2 到 4 步,直到句子正确为止。
|
||||
|
||||
The ccow jumpedd ovverr thhe mooon.
|
||||
The cow jumped over the moon.
|
||||
|
||||
5. 现在句子已经正确了,请继续学习第 1.4 课。
|
||||
|
||||
NOTE: 在学习本教程时,不必试图记住所有内容,你的 Neovim 词汇量会随着使用而增长。
|
||||
可以考虑定期回到本教程进行复习。
|
||||
|
||||
# 第 1.4 课:文本编辑——插入(Insertion)
|
||||
|
||||
** 按 `i`{normal} 键可以插入文本。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的第一行。
|
||||
|
||||
2. 为了让第一行和第二行变得一样,请将光标移动到需要插入文本位置“之后”的那个字符上。
|
||||
|
||||
3. 按下 `i`{normal} 键,然后输入需要补充的内容。
|
||||
|
||||
4. 每个错误修正后,按 `<Esc>`{normal} 键回到普通模式。
|
||||
重复第 2 到 4 步来修正整个句子。
|
||||
|
||||
There is text misng this .
|
||||
There is some text missing from this line.
|
||||
|
||||
5. 当你熟练掌握插入文本后,请继续学习第 1.5 课。
|
||||
|
||||
# 第 1.5 课:文本编辑——追加(Appending)
|
||||
|
||||
** 按 `A`{normal} 键可以在行末追加文本。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的第一行。
|
||||
光标在该行的哪个字符上并不重要。
|
||||
|
||||
2. 按下 [A](A) 键,然后输入需要补充的内容。
|
||||
|
||||
3. 文本追加完成后,按 `<Esc>`{normal} 键回到普通模式。
|
||||
|
||||
4. 将光标移动到标有 ✗ 的第二行,并重复第 2 和第 3 步来修正这个句子。
|
||||
|
||||
There is some text missing from th
|
||||
There is some text missing from this line.
|
||||
There is also some text miss
|
||||
There is also some text missing here.
|
||||
|
||||
5. 当你熟练掌握追加文本后,请继续学习第 1.6 课。
|
||||
|
||||
# 第 1.6 课:编辑文件
|
||||
|
||||
** 使用 `:wq`{vim} 来写入(保存)文件并退出。 **
|
||||
|
||||
!! NOTE: 在执行以下任何步骤之前,请先阅读完本课的全部内容 !!
|
||||
|
||||
1. 像第 1.2 课那样退出本教程:`:q!`{vim}
|
||||
或者,如果你能打开另一个终端,就在那个终端里执行以下操作。
|
||||
|
||||
2. 在 shell 提示符下输入这个命令:
|
||||
~~~ sh
|
||||
$ nvim tutor
|
||||
~~~
|
||||
'nvim' 是启动 Neovim 编辑器的命令,'tutor' 是你希望编辑的文件名。
|
||||
请使用一个可以被修改的文件。
|
||||
|
||||
3. 像在前面课程中学到的那样,插入和删除一些文本。
|
||||
|
||||
4. 保存更改并退出 Neovim:
|
||||
~~~ cmd
|
||||
:wq
|
||||
~~~
|
||||
注意,你需要按 `<Enter>` 键来执行该命令。
|
||||
|
||||
5. 如果你在第 1 步退出了本教程,请重启教程并移动到下面的总结部分。
|
||||
|
||||
6. 在阅读并理解了以上步骤后,亲手操作一遍。
|
||||
|
||||
# 第 1 课总结
|
||||
|
||||
1. 移动光标可以使用方向键,也可以使用 hjkl 键。
|
||||
h (左) j (下) k (上) l (右)
|
||||
|
||||
2. 从 shell 提示符启动 Neovim,输入:
|
||||
~~~ sh
|
||||
$ nvim 文件名
|
||||
~~~
|
||||
3. 退出 Neovim,输入:`<Esc>`{normal} `:q!`{vim} `<Enter>`{normal} 放弃所有更改。
|
||||
或者输入:`<Esc>`{normal} `:wq`{vim} `<Enter>`{normal} 保存所有更改。
|
||||
|
||||
4. 删除光标下的字符,输入:`x`{normal}
|
||||
|
||||
5. 插入或追加文本,输入:
|
||||
`i`{normal} 插入文本 `<Esc>`{normal} 在光标前插入。
|
||||
`A`{normal} 追加文本 `<Esc>`{normal} 在当前行末尾追加。
|
||||
|
||||
NOTE: 按 `<Esc>`{normal} 键会让你进入普通模式,或者取消一个不想继续输入的、未完成的命令。
|
||||
|
||||
现在,请继续学习第 2 课。
|
||||
|
||||
# 第 2.1 课:删除类命令(Deletion)
|
||||
|
||||
** 输入 `dw`{normal} 来删除一个单词(word)。 **
|
||||
|
||||
1. 按 `<Esc>`{normal} 键确保你处于普通模式。
|
||||
|
||||
2. 将光标移动到下面标有 ✗ 的那一行。
|
||||
|
||||
3. 将光标移动到需要被删除的单词的开头。
|
||||
|
||||
4. 输入 [d](d)[w](w) 让这个单词消失。
|
||||
|
||||
There are a some words fun that don't belong paper in this sentence.
|
||||
There are some words that don't belong in this sentence.
|
||||
|
||||
5. 重复第 3 和第 4 步,直到句子正确,然后继续学习第 2.2 课。
|
||||
|
||||
# 第 2.2 课:更多删除类命令
|
||||
|
||||
** 输入 `d$`{normal} 来删除从光标到行尾的内容。 **
|
||||
|
||||
1. 按 `<Esc>`{normal} 键确保你处于普通模式。
|
||||
|
||||
2. 将光标移动到下面标有 ✗ 的那一行。
|
||||
|
||||
3. 将光标移动到正确句子的末尾(在第一个 . 之后)。
|
||||
|
||||
4. 输入 `d$`{normal} 来删除到行尾的所有内容。
|
||||
|
||||
Somebody typed the end of this line twice. end of this line twice.
|
||||
|
||||
5. 继续学习第 2.3 课,来理解这背后的原理。
|
||||
|
||||
# 第 2.3 课:关于操作符(operator)和移动(motion)
|
||||
|
||||
许多修改文本的命令都由一个 [操作符](operator) 和一个 [移动](navigation) 组成。
|
||||
使用 [d](d) 删除操作符的命令格式如下:
|
||||
|
||||
d 移动
|
||||
|
||||
其中:
|
||||
d - 是删除操作符。
|
||||
移动 - 是操作符将要作用的范围(如下所列)。
|
||||
|
||||
一些常用的移动:
|
||||
[w](w) - 到下一个单词的开头,但不包括其第一个字符。
|
||||
[e](e) - 到当前单词的末尾,并包括最后一个字符。
|
||||
[$]($) - 到当前行的末尾,并包括最后一个字符。
|
||||
|
||||
因此,输入 `de`{normal} 将会删除从光标到当前单词末尾的内容。
|
||||
|
||||
NOTE: 在普通模式下,不带操作符、只按下移动键,将会像预期的那样移动光标。
|
||||
|
||||
# 第 2.4 课:为移动增加计数
|
||||
|
||||
** 在移动命令前输入一个数字,可以将其重复执行那么多次。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✓ 的那行的开头。
|
||||
|
||||
2. 输入 `2w`{normal},光标会向前移动两个单词。
|
||||
|
||||
3. 输入 `3e`{normal},光标会移动到前方第三个单词的末尾。
|
||||
|
||||
4. 输入 `0`{normal}([零](0))可以移动到行首。
|
||||
|
||||
5. 用不同的数字重复第 2 和第 3 步。
|
||||
|
||||
This is just a line with words you can move around in.
|
||||
|
||||
6. 继续学习第 2.5 课。
|
||||
|
||||
# 第 2.5 课:使用计数删除更多内容
|
||||
|
||||
** 在操作符和移动之间加上一个数字,可以将其重复执行那么多次。 **
|
||||
|
||||
在前面提到的“删除操作符 + 移动”组合中,你可以在移动前插入一个计数来删除更多内容:
|
||||
d 数字 移动
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的那一行中第一个全大写单词上。
|
||||
|
||||
2. 输入 `d2w`{normal} 来删除两个全大写单词。
|
||||
|
||||
3. 重复第 1 和第 2 步,但使用不同的计数,用一个命令删除剩余连续的全大写单词。
|
||||
|
||||
This ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
|
||||
|
||||
# 第 2.6 课:行操作
|
||||
|
||||
** 输入 `dd`{normal} 来删除一整行。 **
|
||||
|
||||
由于删除整行的操作非常频繁,Vi 的设计者们决定,输入两个 d 来删除一行会更方便。
|
||||
|
||||
1. 将光标移动到下面短语的第 2 行。
|
||||
|
||||
2. 输入 [dd](dd) 来删除该行。
|
||||
|
||||
3. 现在移动到第 4 行。
|
||||
|
||||
4. 输入 `2dd`{normal} 来删除两行。
|
||||
|
||||
1) Roses are red,
|
||||
2) Mud is fun,
|
||||
3) Violets are blue,
|
||||
4) I have a car,
|
||||
5) Clocks tell time,
|
||||
6) Sugar is sweet
|
||||
7) And so are you.
|
||||
|
||||
# 第 2.7 课:撤销命令(Undo)
|
||||
|
||||
** 按 `u`{normal} 撤销上一个命令,按 `U`{normal} 恢复一整行。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的那一行,并把它放在第一个错误上。
|
||||
|
||||
2. 输入 `x`{normal} 来删除第一个多余的字符。
|
||||
|
||||
3. 现在输入 `u`{normal} 来撤销上一次执行的命令。
|
||||
|
||||
4. 这次,使用 `x`{normal} 命令修正该行所有的错误。
|
||||
|
||||
5. 现在输入大写的 `U`{normal},将该行恢复到它最初始的状态。
|
||||
|
||||
6. 现在多次输入 `u`{normal},来撤销 `U`{normal} 以及之前的命令。
|
||||
|
||||
7. 现在多次输入 `<C-r>`{normal}(Ctrl + R),来重做(redo)那些被撤销的命令。
|
||||
|
||||
Fiix the errors oon thhis line and reeplace them witth undo.
|
||||
Fix the errors on this line and replace them with undo.
|
||||
|
||||
8. 这些都是非常有用的命令。现在请继续学习第 2 课的总结。
|
||||
|
||||
# 第 2 课总结
|
||||
|
||||
1. 删除从光标到下一个单词开头的内容,输入: `dw`{normal}
|
||||
|
||||
2. 删除从光标到行尾的内容,输入: `d$`{normal}
|
||||
|
||||
3. 删除一整行,输入: `dd`{normal}
|
||||
|
||||
4. 重复一个移动,在它前面加上数字: `2w`{normal}
|
||||
|
||||
5. 修改类命令的格式是:
|
||||
|
||||
操作符 [数字] 移动
|
||||
|
||||
其中:
|
||||
|
||||
操作符 - 是要做什么,比如 [d](d) 代表删除。
|
||||
[数字] - 是一个可选的计数,用来重复移动。
|
||||
移动 - 定义了操作符要作用的文本范围,例如:
|
||||
[w](w)(单词),
|
||||
[$]($)(到行尾),等等。
|
||||
|
||||
6. 移动到行首,使用零:[0](0)
|
||||
|
||||
7. 撤销之前的操作,输入: `u`{normal}(小写 u)
|
||||
撤销对一整行的所有更改,输入: `U`{normal}(大写 U)
|
||||
重做被撤销的操作,输入: `<C-r>`{normal}
|
||||
|
||||
# 第 3.1 课:粘贴命令(Put)
|
||||
|
||||
** 输入 `p`{normal} 可以将之前删除的文本粘贴到光标之后。 **
|
||||
|
||||
1. 将光标移动到下面第一个标有 `--->` 的行。
|
||||
|
||||
2. 输入 `dd`{normal} 来删除该行,并将其存入 Neovim 的一个寄存器中。
|
||||
|
||||
3. 将光标移动到 c) 行,也就是被删除那一行的“上一行”。
|
||||
|
||||
4. 输入 `p`{normal},将之前删除的行粘贴到光标下方。
|
||||
|
||||
5. 重复第 2 到 4 步,将所有行按正确的顺序(abcd)排列。
|
||||
|
||||
---> d) Can you learn too?
|
||||
---> b) Violets are blue,
|
||||
---> c) Intelligence is learned,
|
||||
---> a) Roses are red,
|
||||
|
||||
NOTE: 你也可以用 `P`{normal}(大写 P)将文本粘贴到光标之前。
|
||||
|
||||
# 第 3.2 课:替换命令(Replace)
|
||||
|
||||
** 输入 `rx`{normal} 可以将光标下的字符替换为 x。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的第一行。
|
||||
|
||||
2. 将光标移动到第一个错误字符上。
|
||||
|
||||
3. 输入 `r`{normal},然后输入正确的字符。
|
||||
|
||||
4. 重复第 2 和第 3 步,直到第一行和第二行完全一样。
|
||||
|
||||
Whan this lime was tuoed in, someone presswd some wrojg keys!
|
||||
When this line was typed in, someone pressed some wrong keys!
|
||||
|
||||
5. 现在请继续学习第 3.3 课。
|
||||
|
||||
NOTE: 请记住,你应该通过实践来学习,而不是死记硬背。
|
||||
|
||||
# 第 3.3 课:更改操作符(Change)
|
||||
|
||||
** 要更改到单词末尾,输入 `ce`{normal}。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的第一行。
|
||||
|
||||
2. 将光标放在 "lubw" 的 "u" 上。
|
||||
|
||||
3. 输入 `ce`{normal},然后输入正确的单词(在这种情况是输入 "ine")。
|
||||
|
||||
4. 按下 `<Esc>`{normal},然后移动到下一个需要修改的字符。
|
||||
|
||||
5. 重复第 3 和第 4 步,直到第一句和第二句完全一样。
|
||||
|
||||
This lubw has a few wptfd that mrrf changing usf the change operator.
|
||||
This line has a few words that need changing using the change operator.
|
||||
|
||||
请注意,[c](c)e 会删除单词并让你进入插入模式(Insert mode)。
|
||||
|
||||
# 第 3.4 课:使用 `c`{normal} 进行更多更改
|
||||
|
||||
** 更改操作符可以和删除操作符使用相同的移动。 **
|
||||
|
||||
1. 更改操作符的工作方式和删除操作符一样。格式是:
|
||||
|
||||
c [数字] 移动
|
||||
|
||||
2. 移动也是一样的,比如 `w`{normal}(单词)和 `$`{normal}(到行尾)。
|
||||
|
||||
3. 移动到下面标有 ✗ 的第一行。
|
||||
|
||||
4. 将光标移动到第一个错误处。
|
||||
|
||||
5. 输入 `c$`{normal},然后输入该行余下正确的内容(参照第二行),最后按 `<Esc>`{normal}。
|
||||
|
||||
The end of this line needs some help to make it like the second.
|
||||
The end of this line needs to be corrected using the c$ command.
|
||||
|
||||
NOTE: 在输入时,你可以使用退格键(Backspace)来修正错误。
|
||||
|
||||
# 第 3 课总结
|
||||
|
||||
1. 要粘贴刚刚删除的文本,输入 [p](p)。这会把删除的文本放在光标“之后”
|
||||
(如果删除的是一整行,它会被粘贴到光标所在行的下一行)。
|
||||
|
||||
2. 要替换光标下的单个字符,输入 [r](r) 然后输入你想要的那个字符。
|
||||
|
||||
3. [更改操作符](c) 允许你更改从光标开始到一个移动命令结束位置的文本。
|
||||
输入 `ce`{normal} 来更改到单词末尾,`c$`{normal} 来更改到行尾,等等。
|
||||
|
||||
4. 更改命令的格式是:
|
||||
|
||||
c [数字] 移动
|
||||
|
||||
现在请继续学习下一课。
|
||||
|
||||
# 第 4.1 课:光标位置和文件状态
|
||||
|
||||
** 输入 `<C-g>`{normal} 来显示你在文件中的位置和文件状态。
|
||||
输入 `{count}G`{normal} 来移动到文件中的第 {count} 行。 **
|
||||
|
||||
NOTE: 在执行任何步骤之前,请先阅读完本课的全部内容!!
|
||||
|
||||
1. 按住 `<Ctrl>`{normal} 键并按下 `g`{normal}。我们称这个操作为 `<C-g>`{normal}。
|
||||
屏幕底部会出现一条消息,包含文件名和你在文件中的位置。
|
||||
请记住行号,第 3 步会用到。
|
||||
|
||||
NOTE: 你可能会在屏幕右下角看到光标位置。这是因为设置了 ['ruler']('ruler') 选项。
|
||||
|
||||
2. 按 [G](G) 移动到文件的末尾。
|
||||
输入 [gg](gg) 移动到文件的开头。
|
||||
|
||||
3. 输入你之前记住的行号,然后按 `G`{normal}。这会让你回到你第一次按 `<C-g>`{normal} 时所在的行。
|
||||
|
||||
4. 如果你觉得没问题,就执行第 1 到 3 步。
|
||||
|
||||
# 第 4.2 课:搜索命令
|
||||
|
||||
** 输入 `/`{normal} 后面跟一个短语,来搜索这个短语。 **
|
||||
|
||||
1. 在普通模式下,输入 `/`{normal} 字符。注意它和光标会出现在屏幕底部,
|
||||
就像 `:`{normal} 命令一样。
|
||||
|
||||
2. 现在输入 errroor `<Enter>`{normal}。这是你想要搜索的词。
|
||||
|
||||
3. 要再次搜索同一个短语,只需输入 [n](n)。
|
||||
要反向搜索同一个短语,输入 [N](N)。
|
||||
|
||||
4. 要反向搜索一个短语,使用 [?](?) 而不是 `/`{normal}。
|
||||
|
||||
5. 要回到你之前的位置,按 `<C-o>`{normal}。(按住 `<Ctrl>`{normal} 键的同时按字母 `o`{normal})。
|
||||
重复按可以回到更早的位置。`<C-i>`{normal} 则会前进。
|
||||
|
||||
"errroor" is not the way to spell error; errroor is an error.
|
||||
|
||||
NOTE: 当搜索到达文件末尾时,它会从头开始继续搜索,除非 ['wrapscan']('wrapscan') 选项被关闭了。
|
||||
|
||||
# 第 4.3 课:括号匹配搜索
|
||||
|
||||
** 输入 `%`{normal} 来查找匹配的 ), ], }。 **
|
||||
|
||||
1. 将光标放在下面标有 ✓ 的那一行中的任意一个 (, [, { 上。
|
||||
|
||||
2. 现在输入 [%](%) 字符。
|
||||
|
||||
3. 光标会移动到与之匹配的括号上。
|
||||
|
||||
4. 再次输入 `%`{normal},光标会移回另一半匹配的括号。
|
||||
|
||||
5. 将光标移动到另一个 (, ), [, ], {, } 上,看看 `%`{normal} 的效果。
|
||||
|
||||
This ( is a test line with ('s, ['s, ] and {'s } in it. ))
|
||||
|
||||
NOTE: 这在调试程序中不匹配的括号时非常有用!
|
||||
|
||||
# 第 4.4 课:替换命令(Substitute)
|
||||
|
||||
** 输入 `:s/old/new/g` 来用 "new" 替换 "old"。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的那一行。
|
||||
|
||||
2. 输入
|
||||
~~~ cmd
|
||||
:s/thee/the/
|
||||
~~~
|
||||
NOTE: [:s](:s) 命令只改变了行中第一个匹配的 "thee"。
|
||||
|
||||
3. 现在输入
|
||||
~~~ cmd
|
||||
:s/thee/the/g
|
||||
~~~
|
||||
加上 g [标志](:s_flags) 意味着在行内进行全局替换,也就是改变该行中所有出现的 "thee"。
|
||||
|
||||
Usually thee best time to see thee flowers is in thee spring.
|
||||
|
||||
4. 要在两行之间替换一个字符串的所有出现,输入
|
||||
~~~ cmd
|
||||
:#,#s/old/new/g
|
||||
~~~
|
||||
其中 # 是要进行替换的行号范围(例如,`1,3` 表示从第 1 行到第 3 行,包含这两行)。
|
||||
|
||||
输入
|
||||
~~~ cmd
|
||||
:%s/old/new/g
|
||||
~~~
|
||||
可以在整个文件中进行替换。
|
||||
|
||||
输入
|
||||
~~~ cmd
|
||||
:%s/old/new/gc
|
||||
~~~
|
||||
可以在整个文件中查找所有出现,并对每一次替换进行确认。
|
||||
|
||||
NOTE: 你也可以先用可视模式(Visual mode)选中你想替换的行。这在后面的课程中会详细解释。
|
||||
|
||||
# 第 4 课总结
|
||||
|
||||
1. `<C-g>`{normal} 显示你的位置和文件状态。
|
||||
`G`{normal} 移动到文件末尾。
|
||||
数字 `G`{normal} 移动到指定的行号。
|
||||
`gg`{normal} 移动到第一行。
|
||||
|
||||
2. 输入 `/`{normal} 后跟一个短语,会“向前”搜索该短语。
|
||||
输入 `?`{normal} 后跟一个短语,会“向后”搜索该短语。
|
||||
搜索后,输入 `n`{normal} 查找下一个(同方向),或 `N`{normal} 查找下一个(反方向)。
|
||||
`<C-o>`{normal} 带你回到旧的光标位置,`<C-i>`{normal} 则去往新的位置。
|
||||
|
||||
3. 当光标在 (, ), [, ], {, } 上时,输入 `%`{normal} 会跳转到其匹配的另一半。
|
||||
|
||||
4. 将行内第一个 old 替换为 new,输入
|
||||
~~~ cmd
|
||||
:s/old/new
|
||||
~~~
|
||||
将行内所有 old 替换为 new,输入
|
||||
~~~ cmd
|
||||
:s/old/new/g
|
||||
~~~
|
||||
在两行 # 之间进行替换,输入
|
||||
~~~ cmd
|
||||
:#,#s/old/new/g
|
||||
~~~
|
||||
在整个文件中进行替换,输入
|
||||
~~~ cmd
|
||||
:%s/old/new/g
|
||||
~~~
|
||||
每次替换前进行确认,添加 'c' 标志
|
||||
~~~ cmd
|
||||
:%s/old/new/gc
|
||||
~~~
|
||||
|
||||
# 第 5.1 课:如何执行外部命令
|
||||
|
||||
** 输入 `:!`{vim} 后面跟一个外部命令,来执行该命令。 **
|
||||
|
||||
1. 输入你熟悉的命令 `:`{normal},让光标定位到屏幕底部。这允许你输入一个
|
||||
命令行命令。
|
||||
|
||||
2. 现在输入 [!](!cmd)(感叹号)字符。这允许你执行任何外部的 shell 命令。
|
||||
|
||||
3. 举个例子,在 "!" 后面输入 "ls",然后按 `<Enter>`{normal}。
|
||||
这会显示你的目录列表,就像你在 shell 提示符下一样。
|
||||
|
||||
NOTE: 你可以用这种方式执行任何外部命令,并且可以带参数。
|
||||
|
||||
NOTE: 所有 `:`{vim} 命令都在你按下 `<Enter>`{normal} 后执行。
|
||||
|
||||
# 第 5.2 课:更多关于写入文件的知识
|
||||
|
||||
** 要保存对文本的更改,输入 `:w`{vim} 文件名。 **
|
||||
|
||||
1. 输入 `:!{unix:(ls),win:(dir)}`{vim} 来获取你的目录列表。
|
||||
你已经知道在这之后必须按 `<Enter>`{normal}。
|
||||
|
||||
2. 选择一个还不存在的文件名,比如 TEST。
|
||||
|
||||
3. 现在输入:
|
||||
~~~ cmd
|
||||
:w TEST
|
||||
~~~
|
||||
(这里的 TEST 是你选择的文件名。)
|
||||
|
||||
4. 这会将当前文件以 TEST 的名字保存。
|
||||
要验证这一点,再次输入 `:!{unix:(ls),win:(dir)}`{vim} 来查看你的目录。
|
||||
|
||||
NOTE: 如果你退出 Neovim,然后用 `nvim TEST` 再次启动它,这个文件将会是你保存时教程
|
||||
内容的一个精确副本。
|
||||
|
||||
5. 现在通过输入以下命令来删除该文件:
|
||||
~~~ cmd
|
||||
:!{unix:(rm),win:(del)} TEST
|
||||
~~~
|
||||
|
||||
# 第 5.3 课:选择要写入的文本
|
||||
|
||||
** 要保存文件的一部分,输入 `v`{normal} 移动 `:w 文件名`{vim}。 **
|
||||
|
||||
1. 将光标移动到这一行。
|
||||
|
||||
2. 按下 [v](v) 并将光标移动到下面的第五项。注意文本被高亮了。
|
||||
|
||||
3. 按下 `:`{normal} 字符。在屏幕底部会出现:
|
||||
|
||||
`:'<,'>`{vim}
|
||||
|
||||
4. 输入
|
||||
|
||||
`w TEST`{vim}
|
||||
|
||||
这里的 TEST 是一个还不存在的文件名。在按 `<Enter>`{normal} 之前,
|
||||
确认你看到的是:
|
||||
|
||||
`:'<,'>w TEST`{vim}
|
||||
|
||||
5. Neovim 会将被选中的行写入文件 TEST。使用 `:!{unix:(ls),win:(dir)}`{vim} 来查看它。
|
||||
先不要删除它!我们将在下一课用到它。
|
||||
|
||||
NOTE: 按下 [v](v) 会启动 [可视选择(Visual selection)](visual-mode)。你可以移动光标来扩大或缩小选择范围。
|
||||
然后你可以使用一个操作符来对选中的文本
|
||||
做些什么。例如,`d`{normal} 会删除选中的文本。
|
||||
|
||||
# 第 5.4 课:读取和合并文件
|
||||
|
||||
** 要读取一个文件的内容,输入 `:r 文件名`{vim}。 **
|
||||
|
||||
1. 将光标放在这一行的正上方。
|
||||
|
||||
NOTE: 执行第 2 步后,你会看到第 5.3 课的文本。然后向下移动
|
||||
才能再次看到本课内容。完成后按 `u`{normal} 撤销。
|
||||
|
||||
2. 现在使用以下命令读取你的 TEST 文件:
|
||||
|
||||
`:r TEST`{vim}
|
||||
|
||||
这里的 TEST 是你之前使用的文件名。
|
||||
你读取的文件内容会被放在光标所在行的下方。
|
||||
|
||||
3. 要验证文件是否被读取,向上移动光标,你会注意到现在有两份第 5.3 课的内容,
|
||||
一份是原始的,一份是读取进来的。
|
||||
|
||||
NOTE: 你也可以读取一个外部命令的输出。例如:
|
||||
|
||||
`:r !{unix:(ls),win:(dir)}`{vim}
|
||||
|
||||
会读取 `ls` 命令的输出,并将其放在光标下方。
|
||||
|
||||
# 第 5 课总结
|
||||
|
||||
1. [:!command](:!cmd) 执行一个外部命令。
|
||||
|
||||
一些有用的例子:
|
||||
`:!{unix:(ls ),win:(dir)}`{vim} - 显示目录列表
|
||||
`:!{unix:(rm ),win:(del)} 文件`{vim} - 删除文件
|
||||
|
||||
2. [:w](:w) 文件名 将当前 Neovim 文件以“文件名”这个名字写入磁盘。
|
||||
|
||||
3. [v](v) 移动 :w 文件名 将可视模式选中的行保存到文件“文件名”中。
|
||||
|
||||
4. [:r](:r) 文件名 读取磁盘文件“文件名”的内容,并将其放在光标位置的下方。
|
||||
|
||||
5. {unix:([:r !ls](:r!) ),win:([:r !dir](:r!))} 读取 {unix:(ls),win:(dir)} 命令的输出,并将其放在光标位置的下方。
|
||||
|
||||
# 第 6.1 课:开启新行命令(Open)
|
||||
|
||||
** 输入 `o`{normal} 可以在光标下方开启一个新行,并进入插入模式。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✓ 的那一行。
|
||||
|
||||
2. 输入小写字母 `o`{normal},在光标“下方”[开启](o)一个新行,并让你进入插入模式。
|
||||
|
||||
3. 现在输入一些文本,然后按 `<Esc>`{normal} 退出插入模式。完成后请删除你开启的行。
|
||||
|
||||
After typing `o`{normal} the cursor is placed on the open line in Insert mode.
|
||||
|
||||
4. 要在光标“上方”开启一个新行,只需输入[大写 O](O),而不是小写 `o`{normal}。
|
||||
在下面这行上试试。完成后请删除你开启的行。
|
||||
|
||||
Open up a line above this by typing O while the cursor is on this line.
|
||||
|
||||
# 第 6.2 课:追加命令(Append)
|
||||
|
||||
** 输入 `a`{normal} 可以在光标“之后”插入文本。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的那行的开头。
|
||||
|
||||
2. 按 `e`{normal} 直到光标移动到 "li" 的末尾。
|
||||
|
||||
3. 输入小写字母 `a`{normal},在光标“之后”[追加](a)文本。
|
||||
|
||||
4. 参照下一行,补全这个单词。按 `<Esc>`{normal} 退出插入模式。
|
||||
|
||||
5. 使用 `e`{normal} 移动到下一个不完整的单词,并重复第 3 和第 4 步。
|
||||
|
||||
This li will allow you to pract appendi text to a line.
|
||||
This line will allow you to practice appending text to a line.
|
||||
|
||||
NOTE: [a](a)、[i](i) 和 [A](A) 都会进入同一个插入模式,唯一的区别是字符被插入的位置不同。
|
||||
|
||||
# 第 6.3 课:另一种替换方式
|
||||
|
||||
** 输入大写 `R`{normal} 可以替换多个字符。 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的第一行。将光标移动到第一个 "xxx" 的开头。
|
||||
|
||||
2. 现在按下 `R`{normal}([大写 R](R))并输入第二行中对应的数字,用它来替换 "xxx"。
|
||||
|
||||
3. 按下 `<Esc>`{normal} 离开[替换模式(Replace mode)](mode-replace)。注意该行余下的部分保持不变。
|
||||
|
||||
4. 重复以上步骤来替换剩下的 "xxx"。
|
||||
|
||||
Adding 123 to xxx gives you xxx.
|
||||
Adding 123 to 456 gives you 579.
|
||||
|
||||
NOTE: 替换模式很像插入模式,但你输入的每个字符都会替换掉一个已有的字符。
|
||||
|
||||
# 第 6.4 课:复制和粘贴文本
|
||||
|
||||
** 使用 `y`{normal} 操作符来复制(yank)文本,用 `p`{normal} 来粘贴(put)它。 **
|
||||
|
||||
1. 去到下面标有 ✓ 的那一行,并将光标放在 "a)" 之后。
|
||||
|
||||
2. 用 `v`{normal} 启动可视模式,并将光标移动到 "first" 之前。
|
||||
|
||||
3. 输入 `y`{normal} 来 [复制(yank)](yank) 高亮的文本。
|
||||
|
||||
4. 将光标移动到下一行的末尾:`j$`{normal}
|
||||
|
||||
5. 输入 `p`{normal} 来 [粘贴(put)](put) 文本。
|
||||
|
||||
6. 按下 `a`{normal} 然后输入 "second"。按 `<Esc>`{normal} 离开
|
||||
插入模式。
|
||||
|
||||
7. 使用可视模式选中 "item.",用 `y`{normal} 复制它,用 `j$`{normal} 移动到
|
||||
下一行的末尾,然后用 `p`{normal} 在那里粘贴文本。
|
||||
|
||||
a) This is the first item.
|
||||
b)
|
||||
|
||||
NOTE: 你可以把 `y`{normal} 当作一个操作符来使用:`yw`{normal} 会复制一个单词。
|
||||
|
||||
NOTE: 你可以用 `P`{normal} 在光标前粘贴,而不是在光标后。
|
||||
|
||||
# 第 6.5 课:设置选项(Set)
|
||||
|
||||
** 设置一个选项,让搜索和替换命令忽略大小写。 **
|
||||
|
||||
Neovim 中有许多设置,你可以配置它们来满足你的需求。
|
||||
|
||||
1. 通过输入 `/ignore` 来搜索 'ignore'。
|
||||
多按几次 `n`{normal} 来重复搜索。
|
||||
|
||||
2. 通过输入以下命令来设置 'ic'(Ignore case,即忽略大小写) 选项:
|
||||
~~~ cmd
|
||||
:set ic
|
||||
~~~
|
||||
3. 现在再次按 `n`{normal} 搜索 'ignore'。
|
||||
注意 Ignore 和 IGNORE 现在也能被找到了。
|
||||
|
||||
4. 设置 'hlsearch' 和 'incsearch' 选项:
|
||||
~~~ cmd
|
||||
:set hls is
|
||||
~~~
|
||||
5. 现在再次输入搜索命令,看看会发生什么:/ignore <Enter>
|
||||
|
||||
6. 要禁用忽略大小写,输入:
|
||||
~~~ cmd
|
||||
:set noic
|
||||
~~~
|
||||
7. 要反转一个设置的值,在它前面加上 "inv":
|
||||
~~~ cmd
|
||||
:set invic
|
||||
~~~
|
||||
NOTE: 要移除匹配项的高亮,输入:
|
||||
~~~ cmd
|
||||
:nohlsearch
|
||||
~~~
|
||||
NOTE: 如果你只想在某一次搜索命令中忽略大小写,在短语中使用 [\c](/\c):
|
||||
/ignore\c <Enter>
|
||||
|
||||
# 第 6 课总结
|
||||
|
||||
1. 输入 `o`{normal} 在光标“下方”开启一个新行并进入插入模式。
|
||||
输入 `O`{normal} 在光标“上方”开启一个新行。
|
||||
|
||||
2. 输入 `a`{normal} 在光标“之后”插入文本。
|
||||
输入 `A`{normal} 在行尾之后插入文本。
|
||||
|
||||
3. `e`{normal} 命令移动到一个单词的末尾。
|
||||
|
||||
4. `y`{normal} 操作符复制文本,`p`{normal} 粘贴它。
|
||||
|
||||
5. 输入大写 `R`{normal} 会进入替换模式,直到按下 `<Esc>`{normal}。
|
||||
|
||||
6. 输入 "[:set](:set) xxx" 可以设置选项 "xxx"。一些有用的选项是:
|
||||
|
||||
'ic' 'ignorecase' 搜索时忽略大小写
|
||||
'is' 'incsearch' 实时显示搜索短语的部分匹配
|
||||
'hls' 'hlsearch' 高亮所有匹配的短语
|
||||
|
||||
你可以使用长选项名或短选项名。
|
||||
|
||||
7. 在选项前加上 "no" 来关闭一个选项:
|
||||
~~~ cmd
|
||||
:set noic
|
||||
~~~
|
||||
8. 在选项前加上 "inv" 来反转一个选项的值:
|
||||
~~~ cmd
|
||||
:set invic
|
||||
~~~
|
||||
# 第 7.1 课:获取帮助
|
||||
|
||||
** 使用在线帮助系统。 **
|
||||
|
||||
Neovim 有一个全面的在线帮助系统。
|
||||
|
||||
要开始使用,试试下面两种方法之一:
|
||||
|
||||
- 按下 `<F1>`{normal} 键(如果你有的话)
|
||||
- 输入 `:help`{vim}
|
||||
|
||||
阅读帮助窗口中的文本,了解帮助系统是如何工作的。
|
||||
输入 `<C-w><C-w>`{normal} 可以在窗口之间跳转。
|
||||
输入 `:q`{vim} 关闭帮助窗口。
|
||||
|
||||
你几乎可以找到任何主题的帮助,只需给 ":help" 命令传递一个参数。
|
||||
试试这些(别忘了按 <Enter>):
|
||||
~~~ cmd
|
||||
:help w
|
||||
:help c_CTRL-D
|
||||
:help insert-index
|
||||
:help user-manual
|
||||
~~~
|
||||
|
||||
# 第 7.2 课:补全功能
|
||||
|
||||
** 使用 `<C-d>`{normal} 和 `<Tab>`{normal} 进行命令行补全。 **
|
||||
|
||||
1. 列出当前目录的内容:`:!{unix:(ls),win:(dir)}`{vim}
|
||||
|
||||
2. 输入一个命令的开头:`:e`{vim}
|
||||
|
||||
3. 按下 `<C-d>`{normal},Neovim 会显示一个以 "e" 开头的命令列表。
|
||||
|
||||
4. 按下 `<Tab>`{normal},Neovim 会显示一个包含可能补全项的菜单
|
||||
(或者如果输入的命令是唯一的,则直接补全,例如 ":ed`<Tab>`{normal}" 会被补全为 ":edit")。
|
||||
|
||||
5. 使用 `<Tab>`{normal} 或 `<C-n>`{normal} 移动到下一个匹配项。或者
|
||||
使用 `<S-Tab>`{normal} 或 `<C-p>`{normal} 移动到上一个匹配项。
|
||||
|
||||
6. 选择 `edit`{vim} 条目。现在你可以看到 `edit`{vim} 这个词已经被自动插入到命令行了。
|
||||
|
||||
7. 现在加上一个空格和一个已存在文件名的开头:`:edit FIL`{vim}
|
||||
|
||||
8. 按下 `<Tab>`{normal}。Vim 会显示一个补全菜单,列出以 `FIL` 开头的文件名。
|
||||
|
||||
NOTE: 补全功能对许多命令都有效。它对 `:help`{vim} 命令尤其有用。
|
||||
|
||||
# 第 7.3 课:配置 NVIM
|
||||
|
||||
Neovim 是一个高度可配置的编辑器。你可以根据自己的需求进行定制。要开始使用更多功能,
|
||||
可以创建一个 vimrc 文件,如果你想用 Lua,文件名可以是 "init.lua",如果你想用
|
||||
Vimscript,文件名可以是 "init.vim"。在本课中,我们将使用 "init.lua"。
|
||||
|
||||
1. 开始编辑 "init.lua" 文件。
|
||||
|
||||
`:exe 'edit' stdpath('config')..'/init.lua'`{vim}
|
||||
|
||||
2. 将 Lua 的示例配置复制到你的 "init.lua" 文件中。
|
||||
|
||||
`:read $VIMRUNTIME/example_init.lua`{vim}
|
||||
|
||||
3. 写入文件(这也会创建任何缺失的父目录):
|
||||
|
||||
`:w ++p`{vim}
|
||||
|
||||
4. 下次你启动 Neovim 时,可以用以下命令快速打开这个 vimrc 文件:
|
||||
|
||||
`:e $MYVIMRC`{vim}
|
||||
|
||||
# 第 7 课总结
|
||||
|
||||
1. 输入 `:help`{vim}
|
||||
或按下 `<F1>`{normal} 或 `<Help>`{normal} 来打开一个帮助窗口。
|
||||
|
||||
2. 输入 `:help 主题`{vim} 来查找关于“主题”的帮助。
|
||||
|
||||
3. 输入 `<C-w><C-w>`{normal} 来跳转到另一个窗口。
|
||||
|
||||
4. 输入 `:q`{vim} 来关闭帮助窗口。
|
||||
|
||||
5. 在命令模式下,按 `<C-d>`{normal} 查看可能的补全。按 `<Tab>`{normal} 使用补全菜单并选择一个匹配项。
|
||||
|
||||
6. 创建你的配置文件来保存你的偏好设置。你可以用 `:e $MYVIMRC`{vim} 再次访问它。
|
||||
|
||||
# 接下来呢?
|
||||
|
||||
运行 `:help nvim-quickstart`{vim} 获取更多关于扩展 Nvim 的信息。
|
||||
|
||||
# 结语
|
||||
|
||||
这就是 Vim 教程第一章的全部内容。你可以继续学习[第二章](@tutor:vim-02-beginner)。
|
||||
|
||||
本教程旨在简要介绍 Neovim 编辑器,内容刚好足够让你能比较轻松地使用它。它远非完
|
||||
整,因为 Neovim 还有许许多多其他的命令。请经常查阅帮助文档。网上也有无数优秀的
|
||||
教程和视频可供学习。这里有一些推荐:
|
||||
|
||||
- *Learn Vim Progressively*:
|
||||
https://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
|
||||
- *Learning Vim in 2014*:
|
||||
https://benmccormick.org/learning-vim-in-2014/
|
||||
- *Vimcasts*:
|
||||
http://vimcasts.org/
|
||||
- *Vim Video-Tutorials by Derek Wyatt*:
|
||||
http://derekwyatt.org/vim/tutorials/
|
||||
- *Learn Vimscript the Hard Way*:
|
||||
https://learnvimscriptthehardway.stevelosh.com/
|
||||
- *7 Habits of Effective Text Editing*:
|
||||
https://www.moolenaar.net/habits.html
|
||||
- *vim-galore*:
|
||||
https://github.com/mhinz/vim-galore
|
||||
|
||||
如果你更喜欢书籍,Drew Neil 的 *Practical Vim* 经常被推荐
|
||||
(其续作 *Modern Vim* 包含了 Neovim 的特有内容)。
|
||||
|
||||
本教程由 Michael C. Pierce 和 Robert K. Ware(科罗拉多矿业大学)编写,采用了
|
||||
Charles Smith(科罗拉多州立大学)提供的想法。电子邮件: bware@mines.colorado.edu。
|
||||
|
||||
由 Bram Moolenaar 为 Vim 修改。
|
||||
由 Felipe Morales 为 vim-tutor-mode 修改。
|
||||
由 Rory Nesbitt 为 Neovim 修改。
|
||||
|
||||
Neovim Tutor 简体中文翻译版由 PilgrimLyieu <pilgrimlyieu@outlook.com> 译制并校对。
|
||||
|
||||
变更记录:
|
||||
- 2025-07-06 PilgrimLyieu <pilgrimlyieu@outlook.com>
|
||||
译制并校对
|
||||
|
||||
// vim: nowrap
|
43
runtime/tutor/zh/vim-01-beginner.tutor.json
Normal file
43
runtime/tutor/zh/vim-01-beginner.tutor.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"expect": {
|
||||
"96": "The cow jumped over the moon.",
|
||||
"97": "The cow jumped over the moon.",
|
||||
"117": "There is some text missing from this line.",
|
||||
"118": "There is some text missing from this line.",
|
||||
"135": "There is some text missing from this line.",
|
||||
"136": "There is some text missing from this line.",
|
||||
"137": "There is also some text missing here.",
|
||||
"138": "There is also some text missing here.",
|
||||
"204": "There are some words that don't belong in this sentence.",
|
||||
"205": "There are some words that don't belong in this sentence.",
|
||||
"221": "Somebody typed the end of this line twice.",
|
||||
"259": -1,
|
||||
"276": "This line of words is cleaned up.",
|
||||
"292": "1) Roses are red,",
|
||||
"293": "",
|
||||
"294": "3) Violets are blue,",
|
||||
"295": "",
|
||||
"296": "",
|
||||
"297": "6) Sugar is sweet",
|
||||
"298": "7) And so are you.",
|
||||
"318": "Fix the errors on this line and replace them with undo.",
|
||||
"319": "Fix the errors on this line and replace them with undo.",
|
||||
"384": "When this line was typed in, someone pressed some wrong keys!",
|
||||
"385": "When this line was typed in, someone pressed some wrong keys!",
|
||||
"405": "This line has a few words that need changing using the change operator.",
|
||||
"406": "This line has a few words that need changing using the change operator.",
|
||||
"426": "The end of this line needs to be corrected using the c$ command.",
|
||||
"427": "The end of this line needs to be corrected using the c$ command.",
|
||||
"484": -1,
|
||||
"502": -1,
|
||||
"524": "Usually the best time to see the flowers is in the spring.",
|
||||
"702": -1,
|
||||
"707": -1,
|
||||
"723": "This line will allow you to practice appending text to a line.",
|
||||
"724": "This line will allow you to practice appending text to a line.",
|
||||
"740": "Adding 123 to 456 gives you 579.",
|
||||
"741": "Adding 123 to 456 gives you 579.",
|
||||
"765": "a) This is the first item.",
|
||||
"766": "b) This is the second item."
|
||||
}
|
||||
}
|
189
runtime/tutor/zh/vim-02-beginner.tutor
Normal file
189
runtime/tutor/zh/vim-02-beginner.tutor
Normal file
@@ -0,0 +1,189 @@
|
||||
# 欢迎来到 Neovim 教程
|
||||
|
||||
# 第 2 章
|
||||
|
||||
此处有龙(拉丁语 Hic Sunt Dracones,表示有危险):如果这是您第一次接触 vim,并
|
||||
且您希望从入门章节开始,请在 Vim 编辑器的命令行中输入:
|
||||
~~~ cmd
|
||||
:Tutor vim-01-beginner
|
||||
~~~
|
||||
或者直接点击链接打开教程的[第一章](@tutor:vim-01-beginner)。
|
||||
|
||||
完成本章大约需要 8-10 分钟,具体取决于您在实践探索上花费的时间。
|
||||
|
||||
|
||||
# 第 2.1.1 课:命名寄存器
|
||||
|
||||
** 同时复制两个单词,然后分别粘贴它们 **
|
||||
|
||||
1. 将光标移动到下面标有 ✓ 的那一行。
|
||||
|
||||
2. 导航到 'Edward' 单词的任意位置,然后输入 `"ayiw`{normal}
|
||||
|
||||
**助记**:*将 (i)nner (w)ord(内部单词)(y)ank(复制)到名为 (a) 的寄存器(")中*
|
||||
|
||||
3. 向前导航到 'cookie' 单词(可以使用 `fk`{normal} 或 `2fc`{normal}
|
||||
或 `$2b`{normal} 或 `/co`{normal} `<Enter>`{normal}),然后输入 `"byiw`{normal}
|
||||
|
||||
4. 导航到 'Vince' 单词的任意位置,然后输入 `ciw<CTRL-r>a<ESC>`{normal}
|
||||
|
||||
**助记**:*用名为 (a) 的寄存器(<contents of (r)egister>)的内容 (c)hange (i)
|
||||
nner (w)ord(修改内部单词)*
|
||||
|
||||
5. 导航到 'cake' 单词的任意位置,然后输入 `ciw<CTRL-r>b<ESC>`{normal}
|
||||
|
||||
a) Edward will henceforth be in charge of the cookie rations
|
||||
b) In this capacity, Vince will have sole cake discretionary powers
|
||||
|
||||
NOTE: 删除操作同样可以存入寄存器,例如 `"sdiw`{normal} 会将被光标下的单词删除并存入寄存器 s。
|
||||
|
||||
参考:[寄存器](registers)
|
||||
[命名寄存器](quotea)
|
||||
[移动与文本对象](text-objects)
|
||||
[CTRL-R](i_CTRL-R)
|
||||
|
||||
|
||||
# 第 2.1.2 课:表达式寄存器
|
||||
|
||||
** 即时插入计算结果 **
|
||||
|
||||
1. 将光标移动到下面标有 ✗ 的那一行。
|
||||
|
||||
2. 导航到所给数字的任意位置。
|
||||
|
||||
3. 输入 `ciw<CTRL-r>=`{normal}60\*60\*24 `<Enter>`{normal}
|
||||
|
||||
4. 在下一行,进入插入模式,并使用
|
||||
`<CTRL-r>=`{normal}`system('date')`{vim} `<Enter>`{normal} 来添加今天的日期。
|
||||
|
||||
NOTE: 所有对 `system` 的调用都依赖于操作系统,例如在 Windows 上应使用
|
||||
`system('date /t')`{vim} 或 `:r!date /t`{vim}
|
||||
|
||||
I have forgotten the exact number of seconds in a day, is it 84600?
|
||||
Today's date is:
|
||||
|
||||
NOTE: 同样效果也可以通过 `:pu=`{normal}`system('date')`{vim} 实现,
|
||||
或者用更少的按键 `:r!date`{vim}
|
||||
|
||||
参考:[表达式寄存器](quote=)
|
||||
|
||||
|
||||
# 第 2.1.3 课:数字寄存器
|
||||
|
||||
** 按下 `yy`{normal} 和 `dd`{normal} 来观察它们对寄存器的影响 **
|
||||
|
||||
1. 将光标移动到下面标有 ✓ 的那一行。
|
||||
|
||||
2. 复制(yank)第 0 行,然后用 `:reg`{vim} `<Enter>`{normal} 查看寄存器。
|
||||
|
||||
3. 用 `"cdd`{normal} 删除第 0 行,然后再次查看寄存器。
|
||||
(你觉得第 0 行的内容会出现在哪里?)
|
||||
|
||||
4. 继续删除后续的每一行,并在每次删除后用 `:reg`{vim} 查看寄存器。
|
||||
|
||||
NOTE: 你应该会发现,当新的整行删除内容被添加进来时,之前删除的内容会在寄存器列
|
||||
表中依次下移。
|
||||
|
||||
5. 现在,按顺序 (p)aste(粘贴)以下寄存器中的内容:c, 7, 4, 8, 2。例如,使用 `"7p`{normal}
|
||||
|
||||
0. This
|
||||
9. wobble
|
||||
8. secret
|
||||
7. is
|
||||
6. on
|
||||
5. axis
|
||||
4. a
|
||||
3. war
|
||||
2. message
|
||||
1. tribute
|
||||
|
||||
|
||||
NOTE: 在数字寄存器中,整行删除(`dd`{normal})的内容比整行复制或涉及更小范围移动
|
||||
的删除操作“存活”得更久。
|
||||
|
||||
参考:[数字寄存器](quote0)
|
||||
|
||||
|
||||
# 第 2.1.4 课:标记之美
|
||||
|
||||
** 避免“码农式”的行号计算 **
|
||||
|
||||
NOTE: 在写代码时,一个常见的难题是移动大块的代码。
|
||||
下面的技巧可以帮助你避免进行行号计算,比如 `"a147d`{normal} 或 `:945,1091d a`{vim},
|
||||
甚至是更麻烦的先用 `i<CTRL-r>=`{normal}1091-945 `<Enter>`{normal} 计算行数。
|
||||
|
||||
1. 将光标移动到下面标有 ✓ 的那一行。
|
||||
|
||||
2. 跳转到函数的第一行,并用 `ma`{normal} 将其标记为 a。
|
||||
|
||||
NOTE: 光标在该行的确切位置并不重要!
|
||||
|
||||
3. 使用 `$%`{normal} 导航到行尾,然后再到代码块的末尾。
|
||||
|
||||
4. 使用 `"ad'a`{normal} 将该代码块删除并存入寄存器 a。
|
||||
|
||||
**助记**:*将从光标位置到包含标记(')(a) 的那一行的内容 (d)elete(删除)到名为 (a) 的寄存器(")中*
|
||||
|
||||
5. 在 BBB 和 CCC 之间用 `"ap`{normal} 粘贴该代码块。
|
||||
|
||||
NOTE: 多次练习这个操作以达到熟练:`ma$%"ad'a`{normal}
|
||||
|
||||
~~~ cmd
|
||||
AAA
|
||||
function itGotRealBigRealFast() {
|
||||
if ( somethingIsTrue ) {
|
||||
doIt()
|
||||
}
|
||||
// the taxonomy of our function has changed and it
|
||||
// no longer makes alphabetical sense in its current position
|
||||
|
||||
// imagine hundreds of lines of code
|
||||
|
||||
// naively you could navigate to the start and end and record or
|
||||
// remember each line number
|
||||
}
|
||||
BBB
|
||||
CCC
|
||||
~~~
|
||||
|
||||
NOTE: 标记和寄存器不共享命名空间,因此寄存器 a 和标记 a 是完全独立的。
|
||||
但寄存器和宏并非如此。
|
||||
|
||||
参考:[标记](marks)
|
||||
[标记移动](mark-motions)(' 和 \` 的区别)
|
||||
|
||||
|
||||
# 第 2.1 课总结
|
||||
|
||||
1. 将文本 存储(复制、删除)到 26 个寄存器(a-z)中,并从中提取(粘贴)出来。
|
||||
2. 从单词内的任意位置复制整个单词:`yiw`{normal}
|
||||
3. 从单词内的任意位置更改整个单词:`ciw`{normal}
|
||||
4. 在插入模式下直接从寄存器插入文本:`<CTRL-r>a`{normal}
|
||||
|
||||
5. 插入简单算术运算的结果:
|
||||
在插入模式下使用 `<CTRL-r>=`{normal}60\*60 `<Enter>`{normal}
|
||||
6. 插入系统调用的结果:
|
||||
在插入模式下使用 `<CTRL-r>=`{normal}`system('ls -1')`{vim}
|
||||
|
||||
7. 使用 `:reg`{vim} 查看寄存器。
|
||||
8. 了解整行删除 (`dd`{normal}) 的最终去向:在数字寄存器中,即从寄存器 1 到 9
|
||||
依次向下存放。要理解整行删除的内容在数字寄存器中比任何其他操作都保存得更久。
|
||||
9. 了解所有复制操作在数字寄存器中的最终去向,以及它们是多么“短暂易逝”。
|
||||
|
||||
10. 在普通模式下设置标记:`m[a-zA-Z0-9]`{normal}
|
||||
11. 按行移动到标记位置:`'`{normal}
|
||||
|
||||
|
||||
# 结语
|
||||
|
||||
Neovim 教程第二章到此结束。本教程仍在不断完善中。
|
||||
|
||||
本章由 Paul D. Parker 编写。
|
||||
|
||||
由 Restorer 为 vim-tutor-mode 修改。
|
||||
|
||||
简体中文翻译版由 PilgrimLyieu <pilgrimlyieu@outlook.com> 译制并校对。
|
||||
|
||||
变更记录:
|
||||
- 2025-07-07 PilgrimLyieu <pilgrimlyieu@outlook.com>
|
||||
译制并校对
|
10
runtime/tutor/zh/vim-02-beginner.tutor.json
Normal file
10
runtime/tutor/zh/vim-02-beginner.tutor.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"expect": {
|
||||
"35": -1,
|
||||
"36": "b) In this capacity, Edward will have sole cookie discretionary powers",
|
||||
"62": "I have forgotten the exact number of seconds in a day, is it 86400",
|
||||
"63": -1,
|
||||
"89": -1,
|
||||
"132": -1
|
||||
}
|
||||
}
|
@@ -293,6 +293,10 @@ preprocess_patch() {
|
||||
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/option\.h/\1\/option_vars.h/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
||||
# Rename runtime/doc/eval.txt to runtime/doc/vimeval.txt
|
||||
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/eval\.txt/\1\/vimeval.txt/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
||||
# Rename version*.txt to news.txt
|
||||
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/version[0-9]+\.txt/\1\/news.txt/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
2
src/cjson/lua_cjson.c
vendored
2
src/cjson/lua_cjson.c
vendored
@@ -82,7 +82,7 @@
|
||||
#define DEFAULT_ENCODE_INVALID_NUMBERS 0
|
||||
#define DEFAULT_DECODE_INVALID_NUMBERS 1
|
||||
#define DEFAULT_ENCODE_KEEP_BUFFER 1
|
||||
#define DEFAULT_ENCODE_NUMBER_PRECISION 14
|
||||
#define DEFAULT_ENCODE_NUMBER_PRECISION 16
|
||||
#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 0
|
||||
#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
|
||||
#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
|
||||
|
@@ -359,11 +359,11 @@ local function norm_text(x, special)
|
||||
x = x:gsub([=[%|?(nvim_[^.()| ]+)%(?%)?%|?]=], 'vim.api.%1')
|
||||
-- TODO: Remove backticks when LuaLS resolves: https://github.com/LuaLS/lua-language-server/issues/2889
|
||||
-- "|foo|" => "`:help foo`"
|
||||
x = x:gsub([=[|([^ ]+)|]=], '`:help %1`')
|
||||
x = x:gsub([=[|([^%s|]+)|]=], '`:help %1`')
|
||||
end
|
||||
|
||||
return (
|
||||
x:gsub('|([^ ]+)|', '`%1`')
|
||||
x:gsub('|([^%s|]+)|', '`%1`')
|
||||
:gsub('\n*>lua', '\n\n```lua')
|
||||
:gsub('\n*>vim', '\n\n```vim')
|
||||
:gsub('\n+<$', '\n```')
|
||||
@@ -949,17 +949,17 @@ local CONFIG = {
|
||||
render = render_api_keyset_meta,
|
||||
},
|
||||
{
|
||||
path = 'runtime/doc/builtin.txt',
|
||||
path = 'runtime/doc/vimfn.txt',
|
||||
funcs = get_eval_meta,
|
||||
render = render_eval_doc,
|
||||
header = {
|
||||
'*builtin.txt* Nvim',
|
||||
'*vimfn.txt* Nvim',
|
||||
'',
|
||||
'',
|
||||
'\t\t NVIM REFERENCE MANUAL',
|
||||
'',
|
||||
'',
|
||||
'Builtin functions\t\t*vimscript-functions* *builtin-functions*',
|
||||
'Vimscript functions\t*vimscript-functions* *builtin-functions* *builtin.txt*',
|
||||
'',
|
||||
'For functions grouped by what they are used for see |function-list|.',
|
||||
'',
|
||||
|
@@ -92,7 +92,7 @@ local redirects = {
|
||||
|
||||
-- TODO: These known invalid |links| require an update to the relevant docs.
|
||||
local exclude_invalid = {
|
||||
["'string'"] = 'eval.txt',
|
||||
["'string'"] = 'vimeval.txt',
|
||||
Query = 'treesitter.txt',
|
||||
matchit = 'vim_diff.txt',
|
||||
['set!'] = 'treesitter.txt',
|
||||
|
@@ -742,7 +742,11 @@ endif()
|
||||
|
||||
target_sources(nlua0 PUBLIC ${NLUA0_SOURCES})
|
||||
|
||||
if(STATIC_BUILD)
|
||||
target_link_options(nvim_bin PRIVATE -static-libgcc -static-libstdc++ -static)
|
||||
endif()
|
||||
target_link_libraries(nvim_bin PRIVATE main_lib PUBLIC libuv)
|
||||
|
||||
install_helper(TARGETS nvim_bin)
|
||||
if(MSVC)
|
||||
install(FILES $<TARGET_PDB_FILE:nvim_bin> DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
|
||||
@@ -975,7 +979,7 @@ add_target(doc-eval
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/eval.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua
|
||||
${NVIM_RUNTIME_DIR}/doc/builtin.txt
|
||||
${NVIM_RUNTIME_DIR}/doc/vimfn.txt
|
||||
)
|
||||
|
||||
add_custom_target(doc)
|
||||
|
@@ -636,6 +636,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
|
||||
|
||||
garray_T capture_local;
|
||||
const int save_msg_silent = msg_silent;
|
||||
const bool save_redir_off = redir_off;
|
||||
garray_T * const save_capture_ga = capture_ga;
|
||||
const int save_msg_col = msg_col;
|
||||
|
||||
@@ -647,6 +648,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
|
||||
TRY_WRAP(err, {
|
||||
if (opts->output) {
|
||||
msg_silent++;
|
||||
redir_off = false;
|
||||
msg_col = 0; // prevent leading spaces
|
||||
}
|
||||
|
||||
@@ -657,6 +659,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
|
||||
if (opts->output) {
|
||||
capture_ga = save_capture_ga;
|
||||
msg_silent = save_msg_silent;
|
||||
redir_off = save_redir_off;
|
||||
// Put msg_col back where it was, since nothing should have been written.
|
||||
msg_col = save_msg_col;
|
||||
}
|
||||
@@ -1073,6 +1076,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
|
||||
goto err;
|
||||
});
|
||||
|
||||
argt |= EX_RANGE;
|
||||
if (addr_type_arg != ADDR_LINES) {
|
||||
argt |= EX_ZEROR;
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ Object nvim_execute_lua(String code, Array args, Arena *arena, Error *err)
|
||||
FUNC_API_DEPRECATED_SINCE(7)
|
||||
FUNC_API_REMOTE_ONLY
|
||||
{
|
||||
return nlua_exec(code, args, kRetObject, arena, err);
|
||||
return nlua_exec(code, NULL, args, kRetObject, arena, err);
|
||||
}
|
||||
|
||||
/// Gets the buffer number
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user