mirror of
https://github.com/neovim/neovim.git
synced 2025-09-03 18:08:16 +00:00
Compare commits
14 Commits
38073747ae
...
c381eb052b
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c381eb052b | ||
![]() |
b4d21f141c | ||
![]() |
4f374bf938 | ||
![]() |
c4c69c5012 | ||
![]() |
a5e7ccc329 | ||
![]() |
28ab656122 | ||
![]() |
8a12a01466 | ||
![]() |
4cda52a5d1 | ||
![]() |
d8a8825679 | ||
![]() |
6888f65be1 | ||
![]() |
06df337617 | ||
![]() |
8fc1db043a | ||
![]() |
d4f789fd78 | ||
![]() |
3c601d02dc |
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
|
||||
}
|
||||
}
|
||||
|
13
.github/workflows/notes.md
vendored
13
.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).
|
||||
|
||||
|
34
.github/workflows/release.yml
vendored
34
.github/workflows/release.yml
vendored
@@ -132,27 +132,44 @@ jobs:
|
||||
|
||||
windows:
|
||||
needs: setup
|
||||
runs-on: windows-2022
|
||||
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@v5
|
||||
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:
|
||||
@@ -196,10 +213,11 @@ jobs:
|
||||
- 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"
|
||||
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/*
|
||||
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/*
|
||||
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/*
|
||||
|
@@ -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).
|
||||
|
@@ -2229,6 +2229,16 @@ is_enabled({filter}) *vim.lsp.inlay_hint.is_enabled()*
|
||||
==============================================================================
|
||||
Lua module: vim.lsp.inline_completion *lsp-inline_completion*
|
||||
|
||||
*vim.lsp.inline_completion.Item*
|
||||
|
||||
Fields: ~
|
||||
• {client_id} (`integer`) Client ID
|
||||
• {insert_text} (`string|lsp.StringValue`) The text to be inserted, can
|
||||
be a snippet.
|
||||
• {range}? (`vim.Range`) Which range it be applied.
|
||||
• {command}? (`lsp.Command`) Corresponding server command.
|
||||
|
||||
|
||||
enable({enable}, {filter}) *vim.lsp.inline_completion.enable()*
|
||||
Enables or disables inline completion for the {filter}ed scope, inline
|
||||
completion will automatically be refreshed when you are in insert mode.
|
||||
@@ -2246,9 +2256,9 @@ enable({enable}, {filter}) *vim.lsp.inline_completion.enable()*
|
||||
for all.
|
||||
|
||||
get({opts}) *vim.lsp.inline_completion.get()*
|
||||
Apply the currently displayed completion candidate to the buffer.
|
||||
Accept the currently displayed completion candidate to the buffer.
|
||||
|
||||
It returns false when no candidate can be applied, so you can use the
|
||||
It returns false when no candidate can be accepted, so you can use the
|
||||
return value to implement a fallback: >lua
|
||||
vim.keymap.set('i', '<Tab>', function()
|
||||
if not vim.lsp.inline_completion.get() then
|
||||
@@ -2265,6 +2275,10 @@ get({opts}) *vim.lsp.inline_completion.get()*
|
||||
• {opts} (`table?`) A table with the following fields:
|
||||
• {bufnr}? (`integer`, default: 0) Buffer handle, or 0 for
|
||||
current.
|
||||
• {on_accept}? (`fun(item: vim.lsp.inline_completion.Item)`)
|
||||
Accept handler, called with the accepted item. If not
|
||||
provided, the default handler is used, which applies changes
|
||||
to the buffer based on the completion item.
|
||||
|
||||
Return: ~
|
||||
(`boolean`) `true` if a completion was applied, else `false`.
|
||||
|
@@ -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*
|
||||
|
||||
|
309
runtime/doc/lua-plugin.txt
Normal file
309
runtime/doc/lua-plugin.txt
Normal file
@@ -0,0 +1,309 @@
|
||||
*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*
|
||||
|
||||
While developing a plugin, you can use the |:restart| command to see the
|
||||
result of code changes in your plugin.
|
||||
|
||||
HEALTH
|
||||
|
||||
Nvim's "health" framework gives plugins a simple way to report status checks
|
||||
to users. See |health-dev| for an example.
|
||||
|
||||
Basically, this just means your plugin will have a `lua/{plugin}/health.lua`
|
||||
file. |:checkhealth| will automatically find this file when it runs.
|
||||
|
||||
Some things to validate:
|
||||
|
||||
- User configuration
|
||||
- Proper initialization
|
||||
- Presence of Lua dependencies (e.g. other plugins)
|
||||
- Presence of external dependencies
|
||||
|
||||
MINIMAL CONFIG TEMPLATE
|
||||
|
||||
It can be useful to provide a template for a minimal configuration, along with
|
||||
a guide on how to use it to reproduce issues.
|
||||
|
||||
==============================================================================
|
||||
Versioning and releases *lua-plugin-versioning*
|
||||
|
||||
Consider:
|
||||
|
||||
- Use |vim.deprecate()| or a `---@deprecate` annotation when you need to
|
||||
communicate a (future) breaking change or 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:
|
@@ -843,32 +843,29 @@ vim.ui_detach({ns}) *vim.ui_detach()*
|
||||
• {ns} (`integer`) Namespace ID
|
||||
|
||||
vim.wait({time}, {callback}, {interval}, {fast_only}) *vim.wait()*
|
||||
Wait for {time} in milliseconds until {callback} returns `true`.
|
||||
Waits up to `time` milliseconds, until `callback` returns `true`
|
||||
(success). Executes `callback` immediately, then at intervals of
|
||||
approximately `interval` milliseconds (default 200). Returns all
|
||||
`callback` results on success.
|
||||
|
||||
Executes {callback} immediately and at approximately {interval}
|
||||
milliseconds (default 200). Nvim still processes other events during this
|
||||
time.
|
||||
|
||||
Cannot be called while in an |api-fast| event.
|
||||
Nvim processes other events while waiting. Cannot be called during an
|
||||
|api-fast| event.
|
||||
|
||||
Examples: >lua
|
||||
---
|
||||
-- Wait for 100 ms, allowing other events to process
|
||||
vim.wait(100, function() end)
|
||||
-- Wait for 100 ms, allowing other events to process.
|
||||
vim.wait(100)
|
||||
|
||||
---
|
||||
-- Wait for 100 ms or until global variable set.
|
||||
vim.wait(100, function() return vim.g.waiting_for_var end)
|
||||
-- Wait up to 1000 ms or until `vim.g.foo` is true, at intervals of ~500 ms.
|
||||
vim.wait(1000, function() return vim.g.foo end, 500)
|
||||
|
||||
---
|
||||
-- Wait for 1 second or until global variable set, checking every ~500 ms
|
||||
vim.wait(1000, function() return vim.g.waiting_for_var end, 500)
|
||||
-- Wait up to 100 ms or until `vim.g.foo` is true, and get the callback results.
|
||||
local ok, rv1, rv2, rv3 = vim.wait(100, function()
|
||||
return vim.g.foo, 'a', 42, { ok = { 'yes' } }
|
||||
end)
|
||||
|
||||
---
|
||||
-- Schedule a function to set a value in 100ms
|
||||
-- Schedule a function to set a value in 100ms. This would wait 10s if blocked, but actually
|
||||
-- only waits 100ms because `vim.wait` processes other events while waiting.
|
||||
vim.defer_fn(function() vim.g.timer_result = true end, 100)
|
||||
|
||||
-- Would wait ten seconds if results blocked. Actually only waits 100 ms
|
||||
if vim.wait(10000, function() return vim.g.timer_result end) then
|
||||
print('Only waiting a little bit of time!')
|
||||
end
|
||||
@@ -886,10 +883,10 @@ vim.wait({time}, {callback}, {interval}, {fast_only}) *vim.wait()*
|
||||
Return (multiple): ~
|
||||
(`boolean`)
|
||||
(`-1|-2?`)
|
||||
• If {callback} returns `true` during the {time}: `true, nil`
|
||||
• If {callback} never returns `true` during the {time}: `false, -1`
|
||||
• If {callback} is interrupted during the {time}: `false, -2`
|
||||
• If {callback} errors, the error is raised.
|
||||
• If callback returns `true` before timeout: `true, nil, ...`
|
||||
• On timeout: `false, -1`
|
||||
• On interrupt: `false, -2`
|
||||
• On error: the error is raised.
|
||||
|
||||
|
||||
==============================================================================
|
||||
|
@@ -186,7 +186,7 @@ The following new APIs or features were added.
|
||||
Additionally |TSNode:range()| now takes an optional {include_bytes} argument.
|
||||
|
||||
• Treesitter injection queries now use the format described at
|
||||
https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection .
|
||||
https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#language-injection .
|
||||
Support for the previous format will be removed in a future release.
|
||||
|
||||
• Added |nvim_get_hl()| for getting highlight group definitions in a format
|
||||
|
@@ -204,6 +204,7 @@ HIGHLIGHTS
|
||||
• |hl-DiffTextAdd| highlights added text within a changed line.
|
||||
• |hl-StderrMsg| |hl-StdoutMsg|
|
||||
• |hl-SnippetTabstopActive| highlights the currently active tabstop.
|
||||
• |hl-OkMsg| highlights success messages.
|
||||
|
||||
LSP
|
||||
|
||||
@@ -247,6 +248,7 @@ LSP
|
||||
|
||||
LUA
|
||||
|
||||
• |vim.wait()| returns the callback results.
|
||||
• Lua type annotations for `vim.uv`.
|
||||
• |vim.hl.range()| now allows multiple timed highlights.
|
||||
• |vim.tbl_extend()| and |vim.tbl_deep_extend()| now accept a function behavior argument.
|
||||
|
@@ -5263,6 +5263,8 @@ EndOfBuffer Filler lines (~) after the last line in the buffer.
|
||||
By default, this is highlighted like |hl-NonText|.
|
||||
*hl-TermCursor*
|
||||
TermCursor Cursor in a focused terminal.
|
||||
*hl-OkMsg*
|
||||
OkMsg Success messages on the command line.
|
||||
*hl-ErrorMsg*
|
||||
ErrorMsg Error messages on the command line.
|
||||
*hl-StderrMsg*
|
||||
|
@@ -551,7 +551,7 @@ TREESITTER LANGUAGE INJECTIONS *treesitter-language-injections*
|
||||
<
|
||||
|
||||
Note the following information is adapted from:
|
||||
https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
|
||||
https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#language-injection
|
||||
|
||||
Some source files contain code written in multiple different languages.
|
||||
Examples include:
|
||||
|
@@ -179,34 +179,30 @@ function vim.iconv(str, from, to, opts) end
|
||||
--- @param fn fun()
|
||||
function vim.schedule(fn) end
|
||||
|
||||
--- Wait for {time} in milliseconds until {callback} returns `true`.
|
||||
--- Waits up to `time` milliseconds, until `callback` returns `true` (success). Executes
|
||||
--- `callback` immediately, then at intervals of approximately `interval` milliseconds (default
|
||||
--- 200). Returns all `callback` results on success.
|
||||
---
|
||||
--- Executes {callback} immediately and at approximately {interval}
|
||||
--- milliseconds (default 200). Nvim still processes other events during
|
||||
--- this time.
|
||||
---
|
||||
--- Cannot be called while in an |api-fast| event.
|
||||
--- Nvim processes other events while waiting.
|
||||
--- Cannot be called during an |api-fast| event.
|
||||
---
|
||||
--- Examples:
|
||||
---
|
||||
--- ```lua
|
||||
--- ---
|
||||
--- -- Wait for 100 ms, allowing other events to process
|
||||
--- vim.wait(100, function() end)
|
||||
--- -- Wait for 100 ms, allowing other events to process.
|
||||
--- vim.wait(100)
|
||||
---
|
||||
--- ---
|
||||
--- -- Wait for 100 ms or until global variable set.
|
||||
--- vim.wait(100, function() return vim.g.waiting_for_var end)
|
||||
--- -- Wait up to 1000 ms or until `vim.g.foo` is true, at intervals of ~500 ms.
|
||||
--- vim.wait(1000, function() return vim.g.foo end, 500)
|
||||
---
|
||||
--- ---
|
||||
--- -- Wait for 1 second or until global variable set, checking every ~500 ms
|
||||
--- vim.wait(1000, function() return vim.g.waiting_for_var end, 500)
|
||||
--- -- Wait up to 100 ms or until `vim.g.foo` is true, and get the callback results.
|
||||
--- local ok, rv1, rv2, rv3 = vim.wait(100, function()
|
||||
--- return vim.g.foo, 'a', 42, { ok = { 'yes' } }
|
||||
--- end)
|
||||
---
|
||||
--- ---
|
||||
--- -- Schedule a function to set a value in 100ms
|
||||
--- -- Schedule a function to set a value in 100ms. This would wait 10s if blocked, but actually
|
||||
--- -- only waits 100ms because `vim.wait` processes other events while waiting.
|
||||
--- vim.defer_fn(function() vim.g.timer_result = true end, 100)
|
||||
---
|
||||
--- -- Would wait ten seconds if results blocked. Actually only waits 100 ms
|
||||
--- if vim.wait(10000, function() return vim.g.timer_result end) then
|
||||
--- print('Only waiting a little bit of time!')
|
||||
--- end
|
||||
@@ -216,11 +212,11 @@ function vim.schedule(fn) end
|
||||
--- @param callback? fun(): boolean Optional callback. Waits until {callback} returns true
|
||||
--- @param interval? integer (Approximate) number of milliseconds to wait between polls
|
||||
--- @param fast_only? boolean If true, only |api-fast| events will be processed.
|
||||
--- @return boolean, nil|-1|-2
|
||||
--- - If {callback} returns `true` during the {time}: `true, nil`
|
||||
--- - If {callback} never returns `true` during the {time}: `false, -1`
|
||||
--- - If {callback} is interrupted during the {time}: `false, -2`
|
||||
--- - If {callback} errors, the error is raised.
|
||||
--- @return boolean, nil|-1|-2, ...
|
||||
--- - If callback returns `true` before timeout: `true, nil, ...`
|
||||
--- - On timeout: `false, -1`
|
||||
--- - On interrupt: `false, -2`
|
||||
--- - On error: the error is raised.
|
||||
function vim.wait(time, callback, interval, fast_only) end
|
||||
|
||||
--- Subscribe to |ui-events|, similar to |nvim_ui_attach()| but receive events in a Lua callback.
|
||||
|
@@ -2236,6 +2236,7 @@ local pattern = {
|
||||
},
|
||||
['/%.'] = {
|
||||
['/%.aws/credentials$'] = 'confini',
|
||||
['/%.aws/cli/alias$'] = 'confini',
|
||||
['/%.gitconfig%.d/'] = starsetf('gitconfig'),
|
||||
['/%.gnupg/gpg%.conf$'] = 'gpg',
|
||||
['/%.gnupg/options$'] = 'gpg',
|
||||
@@ -2244,6 +2245,7 @@ local pattern = {
|
||||
['/%.pinforc$'] = 'pinfo',
|
||||
['/%.cargo/credentials$'] = 'toml',
|
||||
['/%.init/.*%.override$'] = 'upstart',
|
||||
['/%.kube/kuberc$'] = 'yaml',
|
||||
},
|
||||
['calendar/'] = {
|
||||
['/%.calendar/'] = starsetf('calendar'),
|
||||
|
@@ -11,11 +11,11 @@ local M = {}
|
||||
|
||||
local namespace = api.nvim_create_namespace('nvim.lsp.inline_completion')
|
||||
|
||||
---@class (private) vim.lsp.inline_completion.CurrentItem
|
||||
---@field index integer The index among all items form all clients.
|
||||
---@class vim.lsp.inline_completion.Item
|
||||
---@field _index integer The index among all items form all clients.
|
||||
---@field client_id integer Client ID
|
||||
---@field insert_text string|lsp.StringValue The text to be inserted, can be a snippet.
|
||||
---@field filter_text? string
|
||||
---@field _filter_text? string
|
||||
---@field range? vim.Range Which range it be applied.
|
||||
---@field command? lsp.Command Corresponding server command.
|
||||
|
||||
@@ -25,7 +25,7 @@ local namespace = api.nvim_create_namespace('nvim.lsp.inline_completion')
|
||||
---@class (private) vim.lsp.inline_completion.Completor : vim.lsp.Capability
|
||||
---@field active table<integer, vim.lsp.inline_completion.Completor?>
|
||||
---@field timer? uv.uv_timer_t Timer for debouncing automatic requests
|
||||
---@field current? vim.lsp.inline_completion.CurrentItem Currently selected item
|
||||
---@field current? vim.lsp.inline_completion.Item Currently selected item
|
||||
---@field client_state table<integer, vim.lsp.inline_completion.ClientState>
|
||||
local Completor = {
|
||||
name = 'inline_completion',
|
||||
@@ -146,11 +146,11 @@ function Completor:select(index, show_index)
|
||||
local client = assert(vim.lsp.get_client_by_id(client_id))
|
||||
local range = item.range and vim.range.lsp(self.bufnr, item.range, client.offset_encoding)
|
||||
self.current = {
|
||||
index = index,
|
||||
_index = index,
|
||||
client_id = client_id,
|
||||
insert_text = item.insertText,
|
||||
range = range,
|
||||
filter_text = item.filterText,
|
||||
_filter_text = item.filterText,
|
||||
command = item.command,
|
||||
}
|
||||
|
||||
@@ -281,19 +281,14 @@ function Completor:abort()
|
||||
self.current = nil
|
||||
end
|
||||
|
||||
--- Apply the current completion item to the buffer.
|
||||
--- Accept the current completion item to the buffer.
|
||||
---
|
||||
---@package
|
||||
function Completor:apply()
|
||||
local current = self.current
|
||||
self:abort()
|
||||
if not current then
|
||||
return
|
||||
end
|
||||
|
||||
local insert_text = current.insert_text
|
||||
---@param item vim.lsp.inline_completion.Item
|
||||
function Completor:accept(item)
|
||||
local insert_text = item.insert_text
|
||||
if type(insert_text) == 'string' then
|
||||
local range = current.range
|
||||
local range = item.range
|
||||
if range then
|
||||
local lines = vim.split(insert_text, '\n')
|
||||
api.nvim_buf_set_text(
|
||||
@@ -304,7 +299,7 @@ function Completor:apply()
|
||||
range.end_.col,
|
||||
lines
|
||||
)
|
||||
local pos = range.start:to_cursor()
|
||||
local pos = item.range.start:to_cursor()
|
||||
api.nvim_win_set_cursor(vim.fn.bufwinid(self.bufnr), {
|
||||
pos[1] + #lines - 1,
|
||||
(#lines == 1 and pos[2] or 0) + #lines[#lines],
|
||||
@@ -317,9 +312,9 @@ function Completor:apply()
|
||||
end
|
||||
|
||||
-- Execute the command *after* inserting this completion.
|
||||
if current.command then
|
||||
local client = assert(vim.lsp.get_client_by_id(current.client_id))
|
||||
client:exec_cmd(current.command, { bufnr = self.bufnr })
|
||||
if item.command then
|
||||
local client = assert(vim.lsp.get_client_by_id(item.client_id))
|
||||
client:exec_cmd(item.command, { bufnr = self.bufnr })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -381,7 +376,7 @@ function M.select(opts)
|
||||
end
|
||||
|
||||
local n = completor:count_items()
|
||||
local index = current.index + count
|
||||
local index = current._index + count
|
||||
if wrap then
|
||||
index = (index - 1) % n + 1
|
||||
else
|
||||
@@ -396,10 +391,15 @@ end
|
||||
--- Buffer handle, or 0 for current.
|
||||
--- (default: 0)
|
||||
---@field bufnr? integer
|
||||
|
||||
--- Apply the currently displayed completion candidate to the buffer.
|
||||
---
|
||||
--- It returns false when no candidate can be applied,
|
||||
--- Accept handler, called with the accepted item.
|
||||
--- If not provided, the default handler is used,
|
||||
--- which applies changes to the buffer based on the completion item.
|
||||
---@field on_accept? fun(item: vim.lsp.inline_completion.Item)
|
||||
|
||||
--- Accept the currently displayed completion candidate to the buffer.
|
||||
---
|
||||
--- It returns false when no candidate can be accepted,
|
||||
--- so you can use the return value to implement a fallback:
|
||||
---
|
||||
--- ```lua
|
||||
@@ -420,11 +420,23 @@ function M.get(opts)
|
||||
opts = opts or {}
|
||||
|
||||
local bufnr = vim._resolve_bufnr(opts.bufnr)
|
||||
local on_accept = opts.on_accept
|
||||
|
||||
local completor = Completor.active[bufnr]
|
||||
if completor and completor.current then
|
||||
-- Schedule apply to allow `get()` can be mapped with `<expr>`.
|
||||
vim.schedule(function()
|
||||
completor:apply()
|
||||
local item = completor.current
|
||||
completor:abort()
|
||||
if not item then
|
||||
return
|
||||
end
|
||||
|
||||
if on_accept then
|
||||
on_accept(item)
|
||||
else
|
||||
completor:accept(item)
|
||||
end
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
@@ -988,7 +988,7 @@ end
|
||||
|
||||
---@private
|
||||
--- Extract injections according to:
|
||||
--- https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
|
||||
--- https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#language-injection
|
||||
---@param match table<integer,TSNode[]>
|
||||
---@param metadata vim.treesitter.query.TSMetadata
|
||||
---@return string?, boolean, Range6[]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
|
||||
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
|
||||
" Repository: https://github.com/zzzyxwvut/java-vim.git
|
||||
" Last Change: 2025 Aug 07
|
||||
" Last Change: 2025 Aug 30
|
||||
|
||||
" Please check ":help java.vim" for comments on some of the options
|
||||
" available.
|
||||
@@ -447,6 +447,11 @@ if !exists("g:java_ignore_javadoc") && (s:with_html || s:with_markdown) && g:mai
|
||||
unlet g:html_syntax_folding
|
||||
endif
|
||||
|
||||
if !empty(get(g:, 'markdown_fenced_languages', []))
|
||||
let s:markdown_fenced_languages_copy = g:markdown_fenced_languages
|
||||
unlet g:markdown_fenced_languages
|
||||
endif
|
||||
|
||||
syntax include @javaMarkdown syntax/markdown.vim
|
||||
|
||||
try
|
||||
@@ -464,6 +469,11 @@ if !exists("g:java_ignore_javadoc") && (s:with_html || s:with_markdown) && g:mai
|
||||
finally
|
||||
unlet! b:current_syntax
|
||||
|
||||
if exists("s:markdown_fenced_languages_copy")
|
||||
let g:markdown_fenced_languages = s:markdown_fenced_languages_copy
|
||||
unlet s:markdown_fenced_languages_copy
|
||||
endif
|
||||
|
||||
if exists("s:html_syntax_folding_copy")
|
||||
let g:html_syntax_folding = s:html_syntax_folding_copy
|
||||
unlet s:html_syntax_folding_copy
|
||||
|
@@ -796,6 +796,7 @@ Union(Integer, String) nvim_echo(ArrayOf(Tuple(String, *HLGroupID)) chunks, Bool
|
||||
}
|
||||
|
||||
bool is_progress = strequal(kind, "progress");
|
||||
bool needs_clear = !history;
|
||||
|
||||
VALIDATE(is_progress
|
||||
|| (opts->status.size == 0 && opts->title.size == 0 && opts->percent == 0
|
||||
@@ -822,7 +823,7 @@ Union(Integer, String) nvim_echo(ArrayOf(Tuple(String, *HLGroupID)) chunks, Bool
|
||||
MessageData msg_data = { .title = opts->title, .status = opts->status,
|
||||
.percent = opts->percent, .data = opts->data };
|
||||
|
||||
id = msg_multihl(opts->id, hl_msg, kind, history, opts->err, &msg_data);
|
||||
id = msg_multihl(opts->id, hl_msg, kind, history, opts->err, &msg_data, &needs_clear);
|
||||
|
||||
if (opts->verbose) {
|
||||
verbose_leave();
|
||||
@@ -833,8 +834,8 @@ Union(Integer, String) nvim_echo(ArrayOf(Tuple(String, *HLGroupID)) chunks, Bool
|
||||
do_autocmd_progress(id, hl_msg, &msg_data);
|
||||
}
|
||||
|
||||
if (history) {
|
||||
// history takes ownership
|
||||
if (!needs_clear) {
|
||||
// history takes ownership of `hl_msg`
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@@ -7360,7 +7360,7 @@ ssize_t find_cmdline_var(const char *src, size_t *usedlen)
|
||||
char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump,
|
||||
const char **errormsg, int *escaped, bool empty_is_error)
|
||||
{
|
||||
char *result;
|
||||
char *result = "";
|
||||
char *resultbuf = NULL;
|
||||
size_t resultlen;
|
||||
int valid = VALID_HEAD | VALID_PATH; // Assume valid result.
|
||||
@@ -7576,7 +7576,6 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum
|
||||
default:
|
||||
// should not happen
|
||||
*errormsg = "";
|
||||
result = ""; // avoid gcc warning
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -84,6 +84,7 @@ EXTERN const char *hlf_names[] INIT( = {
|
||||
[HLF_BFOOTER] = "FloatFooter",
|
||||
[HLF_TS] = "StatusLineTerm",
|
||||
[HLF_TSNC] = "StatusLineTermNC",
|
||||
[HLF_OK] = "OkMsg",
|
||||
});
|
||||
|
||||
EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
|
||||
|
@@ -132,6 +132,7 @@ typedef enum {
|
||||
HLF_TSNC, ///< status line for non-current terminal window
|
||||
HLF_SE, ///< stderr messages (from shell)
|
||||
HLF_SO, ///< stdout messages (from shell)
|
||||
HLF_OK, ///< OK message
|
||||
HLF_COUNT, ///< MUST be the last one
|
||||
} hlf_T;
|
||||
|
||||
|
@@ -375,6 +375,7 @@ static const char *highlight_init_light[] = {
|
||||
"MoreMsg guifg=NvimDarkCyan ctermfg=6",
|
||||
"NonText guifg=NvimLightGrey4",
|
||||
"NormalFloat guibg=NvimLightGrey1",
|
||||
"OkMsg guifg=NvimDarkGreen ctermfg=2",
|
||||
"Pmenu guibg=NvimLightGrey3 cterm=reverse",
|
||||
"PmenuThumb guibg=NvimLightGrey4",
|
||||
"Question guifg=NvimDarkCyan ctermfg=6",
|
||||
@@ -459,6 +460,7 @@ static const char *highlight_init_dark[] = {
|
||||
"MoreMsg guifg=NvimLightCyan ctermfg=14",
|
||||
"NonText guifg=NvimDarkGrey4",
|
||||
"NormalFloat guibg=NvimDarkGrey1",
|
||||
"OkMsg guifg=NvimLightGreen ctermfg=10",
|
||||
"Pmenu guibg=NvimDarkGrey3 cterm=reverse",
|
||||
"PmenuThumb guibg=NvimDarkGrey4",
|
||||
"Question guifg=NvimLightCyan ctermfg=14",
|
||||
|
@@ -175,11 +175,18 @@ int nlua_pcall(lua_State *lstate, int nargs, int nresults)
|
||||
lua_getfield(lstate, -1, "traceback");
|
||||
lua_remove(lstate, -2);
|
||||
lua_insert(lstate, -2 - nargs);
|
||||
int pre_top = lua_gettop(lstate);
|
||||
int status = lua_pcall(lstate, nargs, nresults, -2 - nargs);
|
||||
if (status) {
|
||||
lua_remove(lstate, -2);
|
||||
} else {
|
||||
lua_remove(lstate, -1 - nresults);
|
||||
if (nresults == LUA_MULTRET) {
|
||||
int new_top = lua_gettop(lstate);
|
||||
int actual_nres = new_top - pre_top + nargs + 1;
|
||||
lua_remove(lstate, -1 - actual_nres);
|
||||
} else {
|
||||
lua_remove(lstate, -1 - nresults);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -415,16 +422,28 @@ static void dummy_timer_close_cb(TimeWatcher *tw, void *data)
|
||||
xfree(tw);
|
||||
}
|
||||
|
||||
static bool nlua_wait_condition(lua_State *lstate, int *status, bool *callback_result)
|
||||
static bool nlua_wait_condition(lua_State *lstate, int *status, bool *callback_result,
|
||||
int *nresults)
|
||||
{
|
||||
int top = lua_gettop(lstate);
|
||||
lua_pushvalue(lstate, 2);
|
||||
*status = nlua_pcall(lstate, 0, 1);
|
||||
*status = nlua_pcall(lstate, 0, LUA_MULTRET);
|
||||
if (*status) {
|
||||
return true; // break on error, but keep error on stack
|
||||
}
|
||||
*callback_result = lua_toboolean(lstate, -1);
|
||||
lua_pop(lstate, 1);
|
||||
return *callback_result; // break if true
|
||||
*nresults = lua_gettop(lstate) - top;
|
||||
if (*nresults == 0) {
|
||||
*callback_result = false;
|
||||
return false;
|
||||
}
|
||||
*callback_result = lua_toboolean(lstate, top + 1);
|
||||
if (!*callback_result) {
|
||||
lua_settop(lstate, top);
|
||||
return false;
|
||||
}
|
||||
lua_remove(lstate, top + 1);
|
||||
(*nresults)--;
|
||||
return true; // break if true
|
||||
}
|
||||
|
||||
/// "vim.wait(timeout, condition[, interval])" function
|
||||
@@ -454,8 +473,7 @@ static int nlua_wait(lua_State *lstate)
|
||||
}
|
||||
|
||||
if (!is_function) {
|
||||
lua_pushliteral(lstate,
|
||||
"vim.wait: if passed, condition must be a function");
|
||||
lua_pushliteral(lstate, "vim.wait: callback must be callable");
|
||||
return lua_error(lstate);
|
||||
}
|
||||
}
|
||||
@@ -488,6 +506,7 @@ static int nlua_wait(lua_State *lstate)
|
||||
|
||||
int pcall_status = 0;
|
||||
bool callback_result = false;
|
||||
int nresults = 0;
|
||||
|
||||
// Flush screen updates before blocking.
|
||||
ui_flush();
|
||||
@@ -497,7 +516,8 @@ static int nlua_wait(lua_State *lstate)
|
||||
(int)timeout,
|
||||
got_int || (is_function ? nlua_wait_condition(lstate,
|
||||
&pcall_status,
|
||||
&callback_result)
|
||||
&callback_result,
|
||||
&nresults)
|
||||
: false));
|
||||
|
||||
// Stop dummy timer
|
||||
@@ -508,18 +528,26 @@ static int nlua_wait(lua_State *lstate)
|
||||
return lua_error(lstate);
|
||||
} else if (callback_result) {
|
||||
lua_pushboolean(lstate, 1);
|
||||
lua_pushnil(lstate);
|
||||
if (nresults == 0) {
|
||||
lua_pushnil(lstate);
|
||||
nresults = 1;
|
||||
} else {
|
||||
lua_insert(lstate, -1 - nresults);
|
||||
}
|
||||
return nresults + 1;
|
||||
} else if (got_int) {
|
||||
got_int = false;
|
||||
vgetc();
|
||||
lua_pushboolean(lstate, 0);
|
||||
lua_pushinteger(lstate, -2);
|
||||
return 2;
|
||||
} else {
|
||||
lua_pushboolean(lstate, 0);
|
||||
lua_pushinteger(lstate, -1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 2;
|
||||
abort();
|
||||
}
|
||||
|
||||
static nlua_ref_state_t *nlua_new_ref_state(lua_State *lstate, bool is_thread)
|
||||
@@ -966,7 +994,8 @@ static void nlua_print_event(void **argv)
|
||||
HlMessage msg = KV_INITIAL_VALUE;
|
||||
HlMessageChunk chunk = { { .data = argv[0], .size = (size_t)(intptr_t)argv[1] - 1 }, 0 };
|
||||
kv_push(msg, chunk);
|
||||
msg_multihl(INTEGER_OBJ(0), msg, "lua_print", true, false, NULL);
|
||||
bool needs_clear = false;
|
||||
msg_multihl(INTEGER_OBJ(0), msg, "lua_print", true, false, NULL, &needs_clear);
|
||||
}
|
||||
|
||||
/// Print as a Vim message
|
||||
|
@@ -292,14 +292,61 @@ void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_
|
||||
// Avoid starting a new message for each chunk and adding message to history in msg_keep().
|
||||
static bool is_multihl = false;
|
||||
|
||||
/// Format a progress message, adding title and percent if given.
|
||||
///
|
||||
/// @param hl_msg Message chunks
|
||||
/// @param msg_data Additional data for progress messages
|
||||
static HlMessage format_progress_message(HlMessage hl_msg, MessageData *msg_data)
|
||||
{
|
||||
HlMessage updated_msg = KV_INITIAL_VALUE;
|
||||
// progress messages are special. displayed as "title: percent% msg"
|
||||
if (msg_data->title.size != 0) {
|
||||
// this block draws the "title:" before the progress-message
|
||||
int hl_id = 0;
|
||||
if (msg_data->status.data == NULL) {
|
||||
hl_id = 0;
|
||||
} else if (strequal(msg_data->status.data, "success")) {
|
||||
hl_id = syn_check_group("OkMsg", STRLEN_LITERAL("OkMsg"));
|
||||
} else if (strequal(msg_data->status.data, "failed")) {
|
||||
hl_id = syn_check_group("ErrorMsg", STRLEN_LITERAL("ErrorMsg"));
|
||||
} else if (strequal(msg_data->status.data, "running")) {
|
||||
hl_id = syn_check_group("MoreMsg", STRLEN_LITERAL("MoreMsg"));
|
||||
} else if (strequal(msg_data->status.data, "cancel")) {
|
||||
hl_id = syn_check_group("WarningMsg", STRLEN_LITERAL("WarningMsg"));
|
||||
}
|
||||
kv_push(updated_msg,
|
||||
((HlMessageChunk){ .text = copy_string(msg_data->title, NULL), .hl_id = hl_id }));
|
||||
kv_push(updated_msg, ((HlMessageChunk){ .text = cstr_to_string(": "), .hl_id = 0 }));
|
||||
}
|
||||
if (msg_data->percent > 0) {
|
||||
char percent_buf[10];
|
||||
vim_snprintf(percent_buf, sizeof(percent_buf), "%3ld%% ", (long)msg_data->percent);
|
||||
String percent = cstr_to_string(percent_buf);
|
||||
int hl_id = syn_check_group("WarningMsg", STRLEN_LITERAL("WarningMsg"));
|
||||
kv_push(updated_msg, ((HlMessageChunk){ .text = percent, .hl_id = hl_id }));
|
||||
}
|
||||
|
||||
if (kv_size(updated_msg) != 0) {
|
||||
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
|
||||
kv_push(updated_msg,
|
||||
((HlMessageChunk){ .text = copy_string(kv_A(hl_msg, i).text, NULL),
|
||||
.hl_id = kv_A(hl_msg, i).hl_id }));
|
||||
}
|
||||
return updated_msg;
|
||||
} else {
|
||||
return hl_msg;
|
||||
}
|
||||
}
|
||||
|
||||
/// Print message chunks, each with their own highlight ID.
|
||||
///
|
||||
/// @param hl_msg Message chunks
|
||||
/// @param kind Message kind (can be NULL to avoid setting kind)
|
||||
/// @param history Whether to add message to history
|
||||
/// @param err Whether to print message as an error
|
||||
/// @param msg_data Additional data for progress messages
|
||||
MsgID msg_multihl(MsgID id, HlMessage hl_msg, const char *kind, bool history, bool err,
|
||||
MessageData *msg_data)
|
||||
MessageData *msg_data, bool *needs_msg_clear)
|
||||
{
|
||||
no_wait_return++;
|
||||
msg_start();
|
||||
@@ -311,7 +358,6 @@ MsgID msg_multihl(MsgID id, HlMessage hl_msg, const char *kind, bool history, bo
|
||||
}
|
||||
is_multihl = true;
|
||||
msg_ext_skip_flush = true;
|
||||
bool is_progress = strequal(kind, "progress");
|
||||
|
||||
// provide a new id if not given
|
||||
if (id.type == kObjectTypeNil) {
|
||||
@@ -323,12 +369,13 @@ MsgID msg_multihl(MsgID id, HlMessage hl_msg, const char *kind, bool history, bo
|
||||
}
|
||||
}
|
||||
|
||||
// progress message are special displayed as "title: msg...percent%"
|
||||
if (is_progress && msg_data && msg_data->title.size != 0) {
|
||||
// this block draws the "title:" before the progress-message
|
||||
String title = cstr_as_string(concat_str(msg_data->title.data, ": "));
|
||||
msg_multiline(title, 0, true, false, &need_clear);
|
||||
api_free_string(title);
|
||||
// progress message are special displayed as "title: percent% msg"
|
||||
if (strequal(kind, "progress") && msg_data) {
|
||||
HlMessage formated_message = format_progress_message(hl_msg, msg_data);
|
||||
if (formated_message.items != hl_msg.items) {
|
||||
*needs_msg_clear = true;
|
||||
hl_msg = formated_message;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
|
||||
@@ -341,12 +388,6 @@ MsgID msg_multihl(MsgID id, HlMessage hl_msg, const char *kind, bool history, bo
|
||||
assert(!ui_has(kUIMessages) || kind == NULL || msg_ext_kind == kind);
|
||||
}
|
||||
|
||||
if (is_progress && msg_data && msg_data->percent > 0) {
|
||||
// this block draws the "...percent%" before the progress-message
|
||||
char percent_buf[10];
|
||||
vim_snprintf(percent_buf, sizeof(percent_buf), "...%ld%%", (long)msg_data->percent);
|
||||
msg_multiline(cstr_as_string(percent_buf), 0, true, false, &need_clear);
|
||||
}
|
||||
if (history && kv_size(hl_msg)) {
|
||||
msg_hist_add_multihl(id, hl_msg, false, msg_data);
|
||||
}
|
||||
@@ -1265,7 +1306,8 @@ void ex_messages(exarg_T *eap)
|
||||
}
|
||||
if (redirecting() || !ui_has(kUIMessages)) {
|
||||
msg_silent += ui_has(kUIMessages);
|
||||
msg_multihl(INTEGER_OBJ(0), p->msg, p->kind, false, false, NULL);
|
||||
bool needs_clear = false;
|
||||
msg_multihl(INTEGER_OBJ(0), p->msg, p->kind, false, false, NULL, &needs_clear);
|
||||
msg_silent -= ui_has(kUIMessages);
|
||||
}
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ static const int included_patches[] = {
|
||||
2423,
|
||||
2422,
|
||||
2421,
|
||||
// 2420,
|
||||
2420,
|
||||
2419,
|
||||
// 2418,
|
||||
2417,
|
||||
@@ -147,7 +147,7 @@ static const int included_patches[] = {
|
||||
2337,
|
||||
2336,
|
||||
2335,
|
||||
// 2334,
|
||||
2334,
|
||||
2333,
|
||||
2332,
|
||||
2331,
|
||||
@@ -174,14 +174,14 @@ static const int included_patches[] = {
|
||||
2310,
|
||||
2309,
|
||||
2308,
|
||||
// 2307,
|
||||
2307,
|
||||
2306,
|
||||
2305,
|
||||
2304,
|
||||
2303,
|
||||
2302,
|
||||
2301,
|
||||
// 2300,
|
||||
2300,
|
||||
2299,
|
||||
2298,
|
||||
2297,
|
||||
@@ -193,9 +193,9 @@ static const int included_patches[] = {
|
||||
2291,
|
||||
2290,
|
||||
2289,
|
||||
// 2288,
|
||||
// 2287,
|
||||
// 2286,
|
||||
2288,
|
||||
2287,
|
||||
2286,
|
||||
2285,
|
||||
2284,
|
||||
2283,
|
||||
@@ -204,7 +204,7 @@ static const int included_patches[] = {
|
||||
2280,
|
||||
// 2279,
|
||||
2278,
|
||||
// 2277,
|
||||
2277,
|
||||
2276,
|
||||
2275,
|
||||
2274,
|
||||
@@ -241,7 +241,7 @@ static const int included_patches[] = {
|
||||
2243,
|
||||
2242,
|
||||
// 2241,
|
||||
// 2240,
|
||||
2240,
|
||||
2239,
|
||||
2238,
|
||||
2237,
|
||||
@@ -268,10 +268,10 @@ static const int included_patches[] = {
|
||||
2216,
|
||||
2215,
|
||||
2214,
|
||||
// 2213,
|
||||
2213,
|
||||
2212,
|
||||
2211,
|
||||
// 2210,
|
||||
2210,
|
||||
2209,
|
||||
// 2208,
|
||||
2207,
|
||||
@@ -317,7 +317,7 @@ static const int included_patches[] = {
|
||||
2167,
|
||||
2166,
|
||||
2165,
|
||||
// 2164,
|
||||
2164,
|
||||
2163,
|
||||
2162,
|
||||
2161,
|
||||
@@ -367,12 +367,12 @@ static const int included_patches[] = {
|
||||
2117,
|
||||
2116,
|
||||
2115,
|
||||
// 2114,
|
||||
2114,
|
||||
2113,
|
||||
2112,
|
||||
2111,
|
||||
// 2110,
|
||||
// 2109,
|
||||
2110,
|
||||
2109,
|
||||
2108,
|
||||
2107,
|
||||
2106,
|
||||
@@ -449,7 +449,7 @@ static const int included_patches[] = {
|
||||
2035,
|
||||
2034,
|
||||
2033,
|
||||
// 2032,
|
||||
2032,
|
||||
2031,
|
||||
2030,
|
||||
2029,
|
||||
@@ -472,7 +472,7 @@ static const int included_patches[] = {
|
||||
2012,
|
||||
2011,
|
||||
2010,
|
||||
// 2009,
|
||||
2009,
|
||||
2008,
|
||||
2007,
|
||||
2006,
|
||||
@@ -483,8 +483,8 @@ static const int included_patches[] = {
|
||||
2001,
|
||||
2000,
|
||||
// 1999,
|
||||
// 1998,
|
||||
// 1997,
|
||||
1998,
|
||||
1997,
|
||||
// 1996,
|
||||
1995,
|
||||
1994,
|
||||
@@ -518,11 +518,11 @@ static const int included_patches[] = {
|
||||
1966,
|
||||
1965,
|
||||
// 1964,
|
||||
// 1963,
|
||||
1963,
|
||||
1962,
|
||||
1961,
|
||||
1960,
|
||||
// 1959,
|
||||
1959,
|
||||
1958,
|
||||
// 1957,
|
||||
1956,
|
||||
@@ -536,7 +536,7 @@ static const int included_patches[] = {
|
||||
1948,
|
||||
1947,
|
||||
1946,
|
||||
// 1945,
|
||||
1945,
|
||||
// 1944,
|
||||
// 1943,
|
||||
1942,
|
||||
@@ -545,14 +545,14 @@ static const int included_patches[] = {
|
||||
// 1939,
|
||||
1938,
|
||||
1937,
|
||||
// 1936,
|
||||
1936,
|
||||
1935,
|
||||
// 1934,
|
||||
1934,
|
||||
1933,
|
||||
1932,
|
||||
1931,
|
||||
1930,
|
||||
// 1929,
|
||||
1929,
|
||||
// 1928,
|
||||
1927,
|
||||
1926,
|
||||
@@ -563,8 +563,8 @@ static const int included_patches[] = {
|
||||
1921,
|
||||
// 1920,
|
||||
// 1919,
|
||||
// 1918,
|
||||
// 1917,
|
||||
1918,
|
||||
1917,
|
||||
1916,
|
||||
1915,
|
||||
1914,
|
||||
@@ -574,12 +574,12 @@ static const int included_patches[] = {
|
||||
1910,
|
||||
1909,
|
||||
// 1908,
|
||||
// 1907,
|
||||
1907,
|
||||
// 1906,
|
||||
// 1905,
|
||||
// 1904,
|
||||
1903,
|
||||
// 1902,
|
||||
1902,
|
||||
1901,
|
||||
1900,
|
||||
1899,
|
||||
@@ -607,7 +607,7 @@ static const int included_patches[] = {
|
||||
1877,
|
||||
1876,
|
||||
1875,
|
||||
// 1874,
|
||||
1874,
|
||||
1873,
|
||||
1872,
|
||||
1871,
|
||||
@@ -631,12 +631,12 @@ static const int included_patches[] = {
|
||||
1853,
|
||||
1852,
|
||||
// 1851,
|
||||
// 1850,
|
||||
1850,
|
||||
1849,
|
||||
1848,
|
||||
1847,
|
||||
1846,
|
||||
// 1845,
|
||||
1845,
|
||||
1844,
|
||||
1843,
|
||||
1842,
|
||||
@@ -667,7 +667,7 @@ static const int included_patches[] = {
|
||||
1817,
|
||||
1816,
|
||||
1815,
|
||||
// 1814,
|
||||
1814,
|
||||
// 1813,
|
||||
1812,
|
||||
// 1811,
|
||||
@@ -692,28 +692,28 @@ static const int included_patches[] = {
|
||||
1792,
|
||||
1791,
|
||||
1790,
|
||||
// 1789,
|
||||
1789,
|
||||
1788,
|
||||
// 1787,
|
||||
// 1786,
|
||||
1786,
|
||||
1785,
|
||||
// 1784,
|
||||
1783,
|
||||
1782,
|
||||
1781,
|
||||
1780,
|
||||
// 1779,
|
||||
// 1778,
|
||||
1779,
|
||||
1778,
|
||||
1777,
|
||||
1776,
|
||||
1775,
|
||||
1774,
|
||||
// 1773,
|
||||
1773,
|
||||
1772,
|
||||
1771,
|
||||
// 1770,
|
||||
1769,
|
||||
// 1768,
|
||||
1768,
|
||||
1767,
|
||||
1766,
|
||||
1765,
|
||||
@@ -726,10 +726,10 @@ static const int included_patches[] = {
|
||||
1758,
|
||||
1757,
|
||||
1756,
|
||||
// 1755,
|
||||
// 1754,
|
||||
// 1753,
|
||||
// 1752,
|
||||
1755,
|
||||
1754,
|
||||
1753,
|
||||
1752,
|
||||
// 1751,
|
||||
1750,
|
||||
1749,
|
||||
@@ -748,7 +748,7 @@ static const int included_patches[] = {
|
||||
1736,
|
||||
1735,
|
||||
1734,
|
||||
// 1733,
|
||||
1733,
|
||||
1732,
|
||||
1731,
|
||||
1730,
|
||||
@@ -762,7 +762,7 @@ static const int included_patches[] = {
|
||||
1722,
|
||||
1721,
|
||||
1720,
|
||||
// 1719,
|
||||
1719,
|
||||
// 1718,
|
||||
1717,
|
||||
1716,
|
||||
@@ -772,9 +772,9 @@ static const int included_patches[] = {
|
||||
1712,
|
||||
1711,
|
||||
1710,
|
||||
// 1709,
|
||||
1709,
|
||||
1708,
|
||||
// 1707,
|
||||
1707,
|
||||
1706,
|
||||
1705,
|
||||
1704,
|
||||
@@ -803,9 +803,9 @@ static const int included_patches[] = {
|
||||
1681,
|
||||
1680,
|
||||
1679,
|
||||
// 1678,
|
||||
1678,
|
||||
1677,
|
||||
// 1676,
|
||||
1676,
|
||||
1675,
|
||||
1674,
|
||||
// 1673,
|
||||
@@ -815,8 +815,8 @@ static const int included_patches[] = {
|
||||
1669,
|
||||
1668,
|
||||
1667,
|
||||
// 1666,
|
||||
// 1665,
|
||||
1666,
|
||||
1665,
|
||||
1664,
|
||||
1663,
|
||||
1662,
|
||||
@@ -825,17 +825,17 @@ static const int included_patches[] = {
|
||||
// 1659,
|
||||
1658,
|
||||
1657,
|
||||
// 1656,
|
||||
1656,
|
||||
1655,
|
||||
1654,
|
||||
1653,
|
||||
1652,
|
||||
1651,
|
||||
1650,
|
||||
// 1649,
|
||||
1649,
|
||||
1648,
|
||||
1647,
|
||||
// 1646,
|
||||
1646,
|
||||
1645,
|
||||
1644,
|
||||
1643,
|
||||
@@ -845,7 +845,7 @@ static const int included_patches[] = {
|
||||
1639,
|
||||
1638,
|
||||
1637,
|
||||
// 1636,
|
||||
1636,
|
||||
1635,
|
||||
1634,
|
||||
1633,
|
||||
@@ -859,14 +859,14 @@ static const int included_patches[] = {
|
||||
1625,
|
||||
1624,
|
||||
1623,
|
||||
// 1622,
|
||||
1622,
|
||||
1621,
|
||||
// 1620,
|
||||
1620,
|
||||
1619,
|
||||
1618,
|
||||
// 1617,
|
||||
1617,
|
||||
1616,
|
||||
// 1615,
|
||||
1615,
|
||||
1614,
|
||||
1613,
|
||||
// 1612,
|
||||
@@ -879,13 +879,13 @@ static const int included_patches[] = {
|
||||
1605,
|
||||
1604,
|
||||
1603,
|
||||
// 1602,
|
||||
1602,
|
||||
1601,
|
||||
// 1600,
|
||||
1599,
|
||||
1598,
|
||||
// 1597,
|
||||
// 1596,
|
||||
1596,
|
||||
1595,
|
||||
1594,
|
||||
1593,
|
||||
@@ -919,7 +919,7 @@ static const int included_patches[] = {
|
||||
1565,
|
||||
1564,
|
||||
1563,
|
||||
// 1562,
|
||||
1562,
|
||||
// 1561,
|
||||
// 1560,
|
||||
// 1559,
|
||||
@@ -931,7 +931,7 @@ static const int included_patches[] = {
|
||||
// 1553,
|
||||
1552,
|
||||
1551,
|
||||
// 1550,
|
||||
1550,
|
||||
1549,
|
||||
// 1548,
|
||||
1547,
|
||||
@@ -954,7 +954,7 @@ static const int included_patches[] = {
|
||||
1530,
|
||||
1529,
|
||||
1528,
|
||||
// 1527,
|
||||
1527,
|
||||
1526,
|
||||
// 1525,
|
||||
1524,
|
||||
@@ -1398,7 +1398,7 @@ static const int included_patches[] = {
|
||||
1086,
|
||||
1085,
|
||||
1084,
|
||||
// 1083,
|
||||
1083,
|
||||
1082,
|
||||
1081,
|
||||
1080,
|
||||
|
@@ -2096,6 +2096,31 @@ stack traceback:
|
||||
exec_lua [[vim.wait(100, function() return true end)]]
|
||||
end)
|
||||
|
||||
it('returns all (multiple) callback results', function()
|
||||
eq({ true, false }, exec_lua [[return { vim.wait(200, function() return true, false end) }]])
|
||||
eq(
|
||||
{ true, 'a', 42, { ok = { 'yes' } } },
|
||||
exec_lua [[
|
||||
local ok, rv1, rv2, rv3 = vim.wait(200, function()
|
||||
return true, 'a', 42, { ok = { 'yes' } }
|
||||
end)
|
||||
|
||||
return { ok, rv1, rv2, rv3 }
|
||||
]]
|
||||
)
|
||||
end)
|
||||
|
||||
it('does not return callback results on timeout', function()
|
||||
eq(
|
||||
{ false, -1 },
|
||||
exec_lua [[
|
||||
return { vim.wait(1, function()
|
||||
return false, 'a', 42, { ok = { 'yes' } }
|
||||
end) }
|
||||
]]
|
||||
)
|
||||
end)
|
||||
|
||||
it('waits the expected time if false', function()
|
||||
eq(
|
||||
{ time = true, wait_result = { false, -1 } },
|
||||
@@ -2184,38 +2209,36 @@ stack traceback:
|
||||
eq({ false, '[string "<nvim>"]:1: As Expected' }, { result[1], remove_trace(result[2]) })
|
||||
end)
|
||||
|
||||
it('if callback is passed, it must be a function', function()
|
||||
it('callback must be a function', function()
|
||||
eq(
|
||||
{ false, 'vim.wait: if passed, condition must be a function' },
|
||||
exec_lua [[
|
||||
return {pcall(function() vim.wait(1000, 13) end)}
|
||||
]]
|
||||
{ false, 'vim.wait: callback must be callable' },
|
||||
exec_lua [[return {pcall(function() vim.wait(1000, 13) end)}]]
|
||||
)
|
||||
end)
|
||||
|
||||
it('allows waiting with no callback, explicit', function()
|
||||
it('waits if callback arg is nil', function()
|
||||
eq(
|
||||
true,
|
||||
exec_lua [[
|
||||
local start_time = vim.uv.hrtime()
|
||||
vim.wait(50, nil)
|
||||
vim.wait(50, nil) -- select('#', ...) == 1
|
||||
return vim.uv.hrtime() - start_time > 25000
|
||||
]]
|
||||
)
|
||||
end)
|
||||
|
||||
it('allows waiting with no callback, implicit', function()
|
||||
it('waits if callback arg is omitted', function()
|
||||
eq(
|
||||
true,
|
||||
exec_lua [[
|
||||
local start_time = vim.uv.hrtime()
|
||||
vim.wait(50)
|
||||
vim.wait(50) -- select('#', ...) == 0
|
||||
return vim.uv.hrtime() - start_time > 25000
|
||||
]]
|
||||
)
|
||||
end)
|
||||
|
||||
it('calls callbacks exactly once if they return true immediately', function()
|
||||
it('invokes callback exactly once if it returns true immediately', function()
|
||||
eq(
|
||||
true,
|
||||
exec_lua [[
|
||||
|
@@ -4,6 +4,7 @@ local t_lsp = require('test.functional.plugin.lsp.testutil')
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local dedent = t.dedent
|
||||
local eq = t.eq
|
||||
|
||||
local api = n.api
|
||||
local exec_lua = n.exec_lua
|
||||
@@ -183,6 +184,59 @@ describe('vim.lsp.inline_completion', function()
|
||||
feed('<Esc>')
|
||||
screen:expect({ grid = grid_applied_candidates })
|
||||
end)
|
||||
|
||||
it('accepts on_accept callback', function()
|
||||
feed('i')
|
||||
screen:expect({ grid = grid_with_candidates })
|
||||
local result = exec_lua(function()
|
||||
---@type vim.lsp.inline_completion.Item
|
||||
local result
|
||||
vim.lsp.inline_completion.get({
|
||||
on_accept = function(item)
|
||||
result = item
|
||||
end,
|
||||
})
|
||||
vim.wait(1000, function()
|
||||
return result ~= nil
|
||||
end) -- Wait for async callback.
|
||||
return result
|
||||
end)
|
||||
feed('<Esc>')
|
||||
screen:expect({ grid = grid_without_candidates })
|
||||
eq({
|
||||
_index = 1,
|
||||
client_id = 1,
|
||||
command = {
|
||||
command = 'dummy',
|
||||
title = 'Completion Accepted',
|
||||
},
|
||||
insert_text = dedent([[
|
||||
function fibonacci(n) {
|
||||
if (n <= 0) return 0;
|
||||
if (n === 1) return 1;
|
||||
|
||||
let a = 0, b = 1, c;
|
||||
for (let i = 2; i <= n; i++) {
|
||||
c = a + b;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
return b;
|
||||
}]]),
|
||||
range = {
|
||||
end_ = {
|
||||
buf = 1,
|
||||
col = 20,
|
||||
row = 0,
|
||||
},
|
||||
start = {
|
||||
buf = 1,
|
||||
col = 0,
|
||||
row = 0,
|
||||
},
|
||||
},
|
||||
}, result)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('select()', function()
|
||||
|
@@ -262,7 +262,7 @@ describe('ui/cursor', function()
|
||||
m.attr = { background = Screen.colors.DarkGray }
|
||||
end
|
||||
if m.id_lm then
|
||||
m.id_lm = 75
|
||||
m.id_lm = 76
|
||||
m.attr_lm = {}
|
||||
end
|
||||
end
|
||||
|
@@ -3145,6 +3145,7 @@ describe('progress-message', function()
|
||||
local function setup_autocmd(pattern)
|
||||
exec_lua(function()
|
||||
local grp = vim.api.nvim_create_augroup('ProgressListener', { clear = true })
|
||||
_G.progress_autocmd_result = nil
|
||||
vim.api.nvim_create_autocmd('Progress', {
|
||||
pattern = pattern,
|
||||
group = grp,
|
||||
@@ -3171,6 +3172,7 @@ describe('progress-message', function()
|
||||
screen:add_extra_attr_ids {
|
||||
[100] = { undercurl = true, special = Screen.colors.Red },
|
||||
[101] = { foreground = Screen.colors.Magenta1, bold = true },
|
||||
[102] = { foreground = Screen.colors.NvimDarkGreen },
|
||||
}
|
||||
else
|
||||
screen = Screen.new(40, 5)
|
||||
@@ -3192,19 +3194,23 @@ describe('progress-message', function()
|
||||
|
||||
screen:expect({
|
||||
grid = [[
|
||||
^ |
|
||||
{1:~ }|*4
|
||||
]],
|
||||
^ |
|
||||
{1:~ }|*4
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = { { 'testsuit: test-message...10%' } },
|
||||
content = {
|
||||
{ 'testsuit', 6, 'MoreMsg' },
|
||||
{ ': ' },
|
||||
{ ' 10% ', 19, 'WarningMsg' },
|
||||
{ 'test-message' },
|
||||
},
|
||||
history = true,
|
||||
id = 1,
|
||||
kind = 'progress',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert_progress_autocmd({
|
||||
text = { 'test-message' },
|
||||
percent = 10,
|
||||
@@ -3227,7 +3233,12 @@ describe('progress-message', function()
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = { { 'TestSuit: test-message-updated...50%' } },
|
||||
content = {
|
||||
{ 'TestSuit', 6, 'MoreMsg' },
|
||||
{ ': ' },
|
||||
{ ' 50% ', 19, 'WarningMsg' },
|
||||
{ 'test-message-updated' },
|
||||
},
|
||||
history = true,
|
||||
id = 1,
|
||||
kind = 'progress',
|
||||
@@ -3244,6 +3255,105 @@ describe('progress-message', function()
|
||||
data = {},
|
||||
}, 'Progress autocmd receives progress update')
|
||||
|
||||
-- success status
|
||||
api.nvim_echo(
|
||||
{ { 'test-message (success)' } },
|
||||
true,
|
||||
{ kind = 'progress', title = 'TestSuit', percent = 100, status = 'success' }
|
||||
)
|
||||
screen:expect({
|
||||
grid = [[
|
||||
^ |
|
||||
{1:~ }|*4
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = {
|
||||
{ 'TestSuit', 102, 'OkMsg' },
|
||||
{ ': ' },
|
||||
{ '100% ', 19, 'WarningMsg' },
|
||||
{ 'test-message (success)' },
|
||||
},
|
||||
history = true,
|
||||
id = 2,
|
||||
kind = 'progress',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- failed status
|
||||
api.nvim_echo(
|
||||
{ { 'test-message (success)' } },
|
||||
true,
|
||||
{ kind = 'progress', title = 'TestSuit', percent = 35, status = 'failed' }
|
||||
)
|
||||
screen:expect({
|
||||
grid = [[
|
||||
^ |
|
||||
{1:~ }|*4
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = {
|
||||
{ 'TestSuit', 9, 'ErrorMsg' },
|
||||
{ ': ' },
|
||||
{ ' 35% ', 19, 'WarningMsg' },
|
||||
{ 'test-message (success)' },
|
||||
},
|
||||
history = true,
|
||||
id = 3,
|
||||
kind = 'progress',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- cancel status
|
||||
api.nvim_echo(
|
||||
{ { 'test-message (success)' } },
|
||||
true,
|
||||
{ kind = 'progress', title = 'TestSuit', percent = 30, status = 'cancel' }
|
||||
)
|
||||
screen:expect({
|
||||
grid = [[
|
||||
^ |
|
||||
{1:~ }|*4
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = {
|
||||
{ 'TestSuit', 19, 'WarningMsg' },
|
||||
{ ': ' },
|
||||
{ ' 30% ', 19, 'WarningMsg' },
|
||||
{ 'test-message (success)' },
|
||||
},
|
||||
history = true,
|
||||
id = 4,
|
||||
kind = 'progress',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- without title and percent
|
||||
api.nvim_echo(
|
||||
{ { 'test-message (no-tile or percent)' } },
|
||||
true,
|
||||
{ kind = 'progress', status = 'cancel' }
|
||||
)
|
||||
screen:expect({
|
||||
grid = [[
|
||||
^ |
|
||||
{1:~ }|*4
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = { { 'test-message (no-tile or percent)' } },
|
||||
history = true,
|
||||
id = 5,
|
||||
kind = 'progress',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- progress event can filter by title
|
||||
setup_autocmd('Special Title')
|
||||
api.nvim_echo(
|
||||
@@ -3284,7 +3394,12 @@ describe('progress-message', function()
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = { { 'TestSuit: test-message...10%' } },
|
||||
content = {
|
||||
{ 'TestSuit', 6, 'MoreMsg' },
|
||||
{ ': ' },
|
||||
{ ' 10% ', 19, 'WarningMsg' },
|
||||
{ 'test-message' },
|
||||
},
|
||||
history = true,
|
||||
id = 1,
|
||||
kind = 'progress',
|
||||
@@ -3373,23 +3488,29 @@ describe('progress-message', function()
|
||||
true,
|
||||
{ kind = 'progress', title = 'TestSuit', percent = 10, status = 'running' }
|
||||
)
|
||||
eq('test-message 10', exec_capture('messages'))
|
||||
eq('TestSuit: 10% test-message 10', exec_capture('messages'))
|
||||
|
||||
api.nvim_echo(
|
||||
{ { 'test-message 20' } },
|
||||
true,
|
||||
{ id = id, kind = 'progress', title = 'TestSuit', percent = 20, status = 'running' }
|
||||
)
|
||||
eq('test-message 10\ntest-message 20', exec_capture('messages'))
|
||||
eq('TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20', exec_capture('messages'))
|
||||
|
||||
api.nvim_echo({ { 'middle msg' } }, true, {})
|
||||
eq('test-message 10\ntest-message 20\nmiddle msg', exec_capture('messages'))
|
||||
eq(
|
||||
'TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20\nmiddle msg',
|
||||
exec_capture('messages')
|
||||
)
|
||||
api.nvim_echo(
|
||||
{ { 'test-message 30' } },
|
||||
true,
|
||||
{ id = id, kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
|
||||
)
|
||||
eq('test-message 10\ntest-message 20\nmiddle msg\ntest-message 30', exec_capture('messages'))
|
||||
eq(
|
||||
'TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20\nmiddle msg\nTestSuit: 30% test-message 30',
|
||||
exec_capture('messages')
|
||||
)
|
||||
|
||||
api.nvim_echo(
|
||||
{ { 'test-message 50' } },
|
||||
@@ -3397,7 +3518,7 @@ describe('progress-message', function()
|
||||
{ id = id, kind = 'progress', title = 'TestSuit', percent = 50, status = 'running' }
|
||||
)
|
||||
eq(
|
||||
'test-message 10\ntest-message 20\nmiddle msg\ntest-message 30\ntest-message 50',
|
||||
'TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20\nmiddle msg\nTestSuit: 30% test-message 30\nTestSuit: 50% test-message 50',
|
||||
exec_capture('messages')
|
||||
)
|
||||
end)
|
||||
@@ -3476,7 +3597,12 @@ describe('progress-message', function()
|
||||
]],
|
||||
messages = {
|
||||
{
|
||||
content = { { 'TestSuit: supports str-id...30%' } },
|
||||
content = {
|
||||
{ 'TestSuit', 6, 'MoreMsg' },
|
||||
{ ': ' },
|
||||
{ ' 30% ', 19, 'WarningMsg' },
|
||||
{ 'supports str-id' },
|
||||
},
|
||||
history = true,
|
||||
id = 'str-id',
|
||||
kind = 'progress',
|
||||
@@ -3511,7 +3637,7 @@ describe('progress-message', function()
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*3
|
||||
TestSuit: test-message...10% |
|
||||
{6:TestSuit}: {19: 10% }test-message |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
@@ -192,7 +192,7 @@ func s:GetFilenameChecks() abort
|
||||
\ 'conaryrecipe': ['file.recipe'],
|
||||
\ 'conf': ['auto.master', 'file.conf', 'texdoc.cnf', '.x11vncrc', '.chktexrc', '.ripgreprc', 'ripgreprc', 'file.ctags'],
|
||||
\ 'config': ['/etc/hostname.file', 'any/etc/hostname.file', 'configure.in', 'configure.ac', 'file.at', 'aclocal.m4'],
|
||||
\ 'confini': ['pacman.conf', 'paru.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials', 'file.nmconnection',
|
||||
\ 'confini': ['pacman.conf', 'paru.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials', 'any/.aws/cli/alias', 'file.nmconnection',
|
||||
\ 'any/.gnuradio/grc.conf', 'any/gnuradio/config.conf', 'any/gnuradio/conf.d/modtool.conf'],
|
||||
\ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'],
|
||||
\ 'cook': ['file.cook'],
|
||||
@@ -928,7 +928,7 @@ func s:GetFilenameChecks() abort
|
||||
\ 'xslt': ['file.xsl', 'file.xslt'],
|
||||
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
|
||||
\ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'file.kyaml', 'file.kyml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock',
|
||||
\ '/home/user/.kube/config', '.condarc', 'condarc', 'pixi.lock'],
|
||||
\ '/home/user/.kube/config', '/home/user/.kube/kuberc', '.condarc', 'condarc', 'pixi.lock'],
|
||||
\ 'yang': ['file.yang'],
|
||||
\ 'yuck': ['file.yuck'],
|
||||
\ 'z8a': ['file.z8a'],
|
||||
|
Reference in New Issue
Block a user