mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
Compare commits
50 Commits
a9fc1df93b
...
e69608f69d
Author | SHA1 | Date | |
---|---|---|---|
|
e69608f69d | ||
|
be5cf33836 | ||
|
a060c13f55 | ||
|
758504ec73 | ||
|
4f788f78f8 | ||
|
ca9f6f5694 | ||
|
5e5b004da4 | ||
|
7db83d47b2 | ||
|
d62b3fa623 | ||
|
f1e51528d2 | ||
|
15e77a56b7 | ||
|
af6537bc66 | ||
|
eee52d3427 | ||
|
d6f7fa14c5 | ||
|
5b1b765610 | ||
|
b0e85010fe | ||
|
ba7a52dedc | ||
|
56ae85a33c | ||
|
e39b6d0c52 | ||
|
50cd5ed360 | ||
|
4ddd999f65 | ||
|
095f731af0 | ||
|
01e82eba20 | ||
|
47cd532bf1 | ||
|
1bc7e18aa8 | ||
|
6d86a6fe44 | ||
|
a757195a60 | ||
|
d85f180f26 | ||
|
7bb0dd08db | ||
|
cf140fb25b | ||
|
74e695d227 | ||
|
9d48266bed | ||
|
2cd76a758b | ||
|
17b298b7c8 | ||
|
5ca330859c | ||
|
e35ae6fbc2 | ||
|
bf9e92c81c | ||
|
7367838359 | ||
|
38bb0e1da8 | ||
|
c2433589dc | ||
|
0892c080d1 | ||
|
6f49ed58c3 | ||
|
a9df0c5ce6 | ||
|
28d1640dd6 | ||
|
65b1fd00a7 | ||
|
eca72def1f | ||
|
7421a4d8b5 | ||
|
b7e3003106 | ||
|
226466a469 | ||
|
e45ee5adf8 |
@ -58,6 +58,11 @@ aa4f9c5341f5280f16cce0630ea54b84eef717b3
|
||||
6ff245732a5a8ab821598a38fb0c5805e6bd3779
|
||||
abf758a2977c4e6cab4dfa217f56da853d85851c
|
||||
cb84f5ee530f0f32b92bed5b4ad41344e8b551aa
|
||||
f98b8d2d44d289263b1a3b33b6a7f20644ef671c
|
||||
544ef994df72c3cbe0dca6b856ce2dcbc5169767
|
||||
45fe4d11add933df76a2ea4bf52ce8904f4a778b
|
||||
517f0cc634b985057da5b95cf4ad659ee456a77e
|
||||
04f2f864e270e772c6326cefdf24947f0130e492
|
||||
|
||||
# typos
|
||||
d238b8f6003d34cae7f65ff7585b48a2cd9449fb
|
||||
|
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -8,11 +8,11 @@ body:
|
||||
value: |
|
||||
*Before reporting:*
|
||||
- Confirm the problem is reproducible on [**master**](https://github.com/neovim/neovim/releases/nightly) or [**latest stable**](https://github.com/neovim/neovim/releases/stable) release
|
||||
- run `make distclean` when encountering build issues
|
||||
- search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
|
||||
- check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ)
|
||||
- Run `make distclean` when encountering build issues
|
||||
- Search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug,bug-crash) (including [closed](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aclosed+label%3Abug%2Cbug-crash))
|
||||
- Read the [FAQ](https://neovim.io/doc/user/faq.html) and ["Reporting Problems" in CONTRIBUTING.md](https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#reporting-problems).
|
||||
|
||||
Usage or "How to" questions belong on the [stackoverflow](https://vi.stackexchange.com/) and will be closed.
|
||||
Usage or "How to" questions belong on [stackoverflow](https://vi.stackexchange.com/) and will be closed.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Problem"
|
||||
@ -24,6 +24,7 @@ body:
|
||||
label: "Steps to reproduce"
|
||||
description: |
|
||||
- For build failures: list the exact steps including CMake flags (if any).
|
||||
- If the bug pertains to crashing (or segfault), please include a [stacktrace](https://neovim.io/doc/user/dev_tools.html#dev-tools-backtrace).
|
||||
- For startup or shell-related problems: try `env -i TERM=ansi-256color "$(which nvim)"`.
|
||||
- Use the provided [minimal reproduction template](https://github.com/neovim/neovim/blob/master/contrib/minimal.lua) to create a minimal configuration. After you fill it out with necessary information, run with `nvim --clean -u minimal.lua`.
|
||||
- Please do **not** include a package manager in the reproduction steps.
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting: search [existing issues](https://github.com/neovim/neovim/labels/enhancement) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ).
|
||||
Before requesting: search [existing feature requests](https://github.com/neovim/neovim/labels/enhancement) and check the [FAQ](https://neovim.io/doc/user/faq.html).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
2
.github/ISSUE_TEMPLATE/lsp_bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/lsp_bug_report.yml
vendored
@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
_Before reporting:_ search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions or "Why isn't X language server/feature working?" belong on [stackoverflow](https://vi.stackexchange.com/) and will be closed.
|
||||
_Before reporting:_ search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://neovim.io/doc/user/faq.html). Usage questions or "Why isn't X language server/feature working?" belong on [stackoverflow](https://vi.stackexchange.com/) and will be closed.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
5
.github/workflows/docs.yml
vendored
5
.github/workflows/docs.yml
vendored
@ -7,6 +7,8 @@ on:
|
||||
- 'src/nvim/eval.lua'
|
||||
- 'runtime/lua/**.lua'
|
||||
- 'runtime/doc/**'
|
||||
- 'scripts/gen_vimdoc.py'
|
||||
- 'scripts/gen_help_html.lua'
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
@ -30,3 +32,6 @@ jobs:
|
||||
echo "::error::The doc generation produces the following changes:"
|
||||
git diff --color --exit-code
|
||||
fi
|
||||
|
||||
- name: Validate docs
|
||||
run: make lintdoc
|
||||
|
2
.github/workflows/notes.md
vendored
2
.github/workflows/notes.md
vendored
@ -48,7 +48,7 @@ https://github.com/neovim/neovim-releases.
|
||||
|
||||
### Other
|
||||
|
||||
- Install by [package manager](https://github.com/neovim/neovim/wiki/Installing-Neovim)
|
||||
- Install by [package manager](https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-package)
|
||||
|
||||
## SHA256 Checksums
|
||||
|
||||
|
@ -263,7 +263,7 @@ add_custom_target(lintcommit
|
||||
add_dependencies(lintcommit nvim_bin)
|
||||
|
||||
add_custom_target(lint)
|
||||
add_dependencies(lint lintc lintlua lintsh lintcommit)
|
||||
add_dependencies(lint lintc lintlua lintsh lintcommit lintdoc)
|
||||
|
||||
# Format
|
||||
add_glob_target(
|
||||
|
@ -24,8 +24,8 @@ Reporting problems
|
||||
- If a specific configuration or plugin is necessary to recreate the problem, use the minimal template in `contrib/minimal.lua` with `nvim --clean -u contrib/minimal.lua` after making the necessary changes.
|
||||
- [Bisect](https://neovim.io/doc/user/starting.html#bisect) your config: disable plugins incrementally, to narrow down the cause of the issue.
|
||||
- [Bisect][git-bisect] Neovim's source code to find the cause of a regression, if you can. This is _extremely_ helpful.
|
||||
- When reporting a crash, [include a stacktrace](https://neovim.io/doc/user/faq.html#backtrace-linux).
|
||||
- Use [ASAN/UBSAN](#clang-sanitizers-asan-and-ubsan) to get detailed errors for segfaults and undefined behavior.
|
||||
- When reporting a crash, [include a stacktrace](https://neovim.io/doc/user/dev_tools.html#dev-tools-backtrace).
|
||||
- Use [ASAN/UBSAN](#sanitizers-asan-and-ubsan) to get detailed errors for segfaults and undefined behavior.
|
||||
- Check the logs. `:edit $NVIM_LOG_FILE`
|
||||
- Include `cmake --system-information` for build-related issues.
|
||||
|
||||
@ -265,6 +265,12 @@ Many `:help` docs are autogenerated from (C or Lua) docstrings. To generate the
|
||||
make doc
|
||||
```
|
||||
|
||||
To validate the documentation files, run:
|
||||
|
||||
```bash
|
||||
make lintdoc
|
||||
```
|
||||
|
||||
If you need to modify or debug the documentation flow, these are the main files:
|
||||
- `./scripts/gen_vimdoc.py`:
|
||||
Main doc generator. Drives doxygen to generate xml files, and scrapes those
|
||||
@ -282,6 +288,8 @@ If you need to modify or debug the documentation flow, these are the main files:
|
||||
src/nvim/options.lua => runtime/doc/options.txt
|
||||
```
|
||||
|
||||
- `./scripts/lintdoc.lua`: Validation and linting of documentation files.
|
||||
|
||||
### Lua docstrings
|
||||
|
||||
Use [LuaLS] annotations in Lua docstrings to annotate parameter types, return
|
||||
|
@ -225,6 +225,15 @@ https://github.com/neovim/neovim-backup
|
||||
trying to produce images that work in the broadest number of environments,
|
||||
and therefore want to use older releases.
|
||||
|
||||
### Special labels
|
||||
|
||||
Some github labels are used to trigger certain jobs:
|
||||
|
||||
* `backport release-x.y` - backport to release branch
|
||||
* `ci-s390x` - enable s390x CI
|
||||
* `needs:response` - Close PR after a certain amount of time if author doesn't
|
||||
respond
|
||||
|
||||
See also
|
||||
--------
|
||||
|
||||
|
2
Makefile
2
Makefile
@ -117,7 +117,7 @@ functionaltest-lua: | nvim
|
||||
$(BUILD_TOOL) -C build functionaltest
|
||||
|
||||
FORMAT=formatc formatlua format
|
||||
LINT=lintlua lintsh lintc clang-analyzer lintcommit lint
|
||||
LINT=lintlua lintsh lintc clang-analyzer lintcommit lintdoc lint
|
||||
TEST=functionaltest unittest
|
||||
generated-sources benchmark $(FORMAT) $(LINT) $(TEST) doc: | build/.ran-cmake
|
||||
$(CMAKE) --build build --target $@
|
||||
|
@ -231,7 +231,7 @@ if vim.o.background == 'light' then
|
||||
hi('SpellRare', { sp = 'Magenta', undercurl = true, ctermbg = 'LightMagenta' })
|
||||
hi('TabLine', { bg = 'LightGrey', underline = true, ctermfg = 'Black', ctermbg = 'LightGrey', cterm = { underline = true } })
|
||||
hi('Title', { fg = 'Magenta', bold = true, ctermfg = 'DarkMagenta' })
|
||||
hi('Visual', { bg = 'LightGrey', ctermbg = 'LightGrey' })
|
||||
hi('Visual', { bg = 'LightGrey', ctermfg = 'White', ctermbg = 'DarkGrey' })
|
||||
hi('WarningMsg', { fg = 'Red', ctermfg = 'DarkRed' })
|
||||
hi('Comment', { fg = 'Blue', ctermfg = 'DarkBlue' })
|
||||
hi('Constant', { fg = 'Magenta', ctermfg = 'DarkRed' })
|
||||
@ -270,7 +270,7 @@ else
|
||||
hi('SpellRare', { sp = 'Magenta', undercurl = true, ctermbg = 'Magenta' })
|
||||
hi('TabLine', { bg = 'DarkGrey', underline = true, ctermfg = 'White', ctermbg = 'DarkGrey', cterm = { underline = true } })
|
||||
hi('Title', { fg = 'Magenta', bold = true, ctermfg = 'LightMagenta' })
|
||||
hi('Visual', { bg = 'DarkGrey', ctermbg = 'DarkGrey' })
|
||||
hi('Visual', { bg = '#575757', ctermfg = 'Black', ctermbg = 'Grey' })
|
||||
hi('WarningMsg', { fg = 'Red', ctermfg = 'LightRed' })
|
||||
hi('Comment', { fg = '#80a0ff', ctermfg = 'Cyan' })
|
||||
hi('Constant', { fg = '#ffa0a0', ctermfg = 'Magenta' })
|
||||
|
@ -3336,6 +3336,13 @@ nvim_tabpage_set_var({tabpage}, {name}, {value})
|
||||
• {name} Variable name
|
||||
• {value} Variable value
|
||||
|
||||
nvim_tabpage_set_win({tabpage}, {win}) *nvim_tabpage_set_win()*
|
||||
Sets the current window in a tabpage
|
||||
|
||||
Parameters: ~
|
||||
• {tabpage} Tabpage handle, or 0 for current tabpage
|
||||
• {win} Window handle, must already belong to {tabpage}
|
||||
|
||||
|
||||
==============================================================================
|
||||
Autocmd Functions *api-autocmd*
|
||||
|
4
runtime/doc/builtin.txt
generated
4
runtime/doc/builtin.txt
generated
@ -2079,6 +2079,8 @@ getbufinfo([{dict}]) *getbufinfo()*
|
||||
bufnr Buffer number.
|
||||
changed TRUE if the buffer is modified.
|
||||
changedtick Number of changes made to the buffer.
|
||||
command TRUE if the buffer belongs to the
|
||||
command-line window |cmdwin|.
|
||||
hidden TRUE if the buffer is hidden.
|
||||
lastused Timestamp in seconds, like
|
||||
|localtime()|, when the buffer was
|
||||
@ -2270,7 +2272,7 @@ getcharmod() *getcharmod()*
|
||||
32 mouse double click
|
||||
64 mouse triple click
|
||||
96 mouse quadruple click (== 32 + 64)
|
||||
128 command (Macintosh only)
|
||||
128 command (Mac) or super
|
||||
Only the modifiers that have not been included in the
|
||||
character itself are obtained. Thus Shift-a results in "A"
|
||||
without a modifier. Returns 0 if no modifiers are used.
|
||||
|
@ -687,7 +687,7 @@ To disable this behavior, set the following variable in your vimrc: >
|
||||
QUERY *ft-query-plugin*
|
||||
|
||||
|
||||
Linting of tree-sitter queries for installed parsers using
|
||||
Linting of treesitter queries for installed parsers using
|
||||
|vim.treesitter.query.lint()| is enabled by default on `BufEnter` and
|
||||
`BufWrite`. To change the events that trigger linting, use >lua
|
||||
|
||||
|
@ -253,6 +253,14 @@ arguments separated by " " (space) instead of "\t" (tab).
|
||||
:lua print(_VERSION)
|
||||
< To see the LuaJIT version: >vim
|
||||
:lua =jit.version
|
||||
<
|
||||
:{range}lua
|
||||
Executes buffer lines in {range} as Lua code. Unlike |:source|, this
|
||||
always treats the lines as Lua code.
|
||||
|
||||
Example: select the following code and type ":lua<Enter>" to execute it: >lua
|
||||
print(string.format(
|
||||
'unix time: %s', os.time()))
|
||||
<
|
||||
*:lua-heredoc*
|
||||
:lua << [trim] [{endmarker}]
|
||||
@ -266,10 +274,8 @@ arguments separated by " " (space) instead of "\t" (tab).
|
||||
function! CurrentLineInfo()
|
||||
lua << EOF
|
||||
local linenr = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local curline = vim.api.nvim_buf_get_lines(
|
||||
0, linenr - 1, linenr, false)[1]
|
||||
print(string.format("Current line [%d] has %d bytes",
|
||||
linenr, #curline))
|
||||
local curline = vim.api.nvim_buf_get_lines(0, linenr - 1, linenr, false)[1]
|
||||
print(string.format('Line [%d] has %d bytes', linenr, #curline))
|
||||
EOF
|
||||
endfunction
|
||||
<
|
||||
@ -613,7 +619,7 @@ vim.highlight.on_yank({opts}) *vim.highlight.on_yank()*
|
||||
vim.highlight.priorities *vim.highlight.priorities*
|
||||
Table with default priorities used for highlighting:
|
||||
• `syntax`: `50`, used for standard syntax highlighting
|
||||
• `treesitter`: `100`, used for tree-sitter-based highlighting
|
||||
• `treesitter`: `100`, used for treesitter-based highlighting
|
||||
• `semantic_tokens`: `125`, used for LSP semantic token highlighting
|
||||
• `diagnostics`: `150`, used for code analysis such as diagnostics
|
||||
• `user`: `200`, used for user-triggered highlights such as LSP document
|
||||
|
@ -849,8 +849,15 @@ For the Meta modifier the "T" character is used. For example, to map Meta-b
|
||||
in Insert mode: >
|
||||
:imap <T-b> terrible
|
||||
|
||||
1.12 MAPPING SUPER-KEYS or COMMAND-KEYS *:map-super-keys* *:map-cmd-key*
|
||||
|
||||
1.12 MAPPING AN OPERATOR *:map-operator*
|
||||
The Super / Command modifier is available if the terminal or GUI supports it.
|
||||
The character "D" is used for the Super / Command modifier.
|
||||
|
||||
For example, to map Command-b in Insert mode: >
|
||||
:imap <D-b> barritone
|
||||
|
||||
1.13 MAPPING AN OPERATOR *:map-operator*
|
||||
|
||||
An operator is used before a {motion} command. To define your own operator
|
||||
you must create a mapping that first sets the 'operatorfunc' option and then
|
||||
|
@ -123,7 +123,8 @@ BREAKING CHANGES IN HEAD *news-breaking-dev*
|
||||
The following breaking changes were made during the development cycle to
|
||||
unreleased features on Nvim HEAD.
|
||||
|
||||
• ...
|
||||
• Removed `vim.treesitter.foldtext` as transparent foldtext is now supported
|
||||
https://github.com/neovim/neovim/pull/20750
|
||||
• ...
|
||||
|
||||
==============================================================================
|
||||
@ -223,8 +224,6 @@ The following new APIs and features were added.
|
||||
• |vim.treesitter.query.edit()| allows live editing of treesitter
|
||||
queries.
|
||||
• Improved error messages for query parsing.
|
||||
• |vim.treesitter.foldtext()| applies treesitter highlighting to
|
||||
foldtext.
|
||||
|
||||
• |vim.ui.open()| opens URIs using the system default handler (macOS `open`,
|
||||
Windows `explorer`, Linux `xdg-open`, etc.)
|
||||
@ -305,6 +304,8 @@ The following new APIs and features were added.
|
||||
highlight attribute. The TUI will display URLs using the OSC 8 control
|
||||
sequence, enabling clickable text in supporting terminals.
|
||||
|
||||
• Added |nvim_tabpage_set_win()| to set the current window of a tabpage.
|
||||
|
||||
==============================================================================
|
||||
CHANGED FEATURES *news-changed*
|
||||
|
||||
@ -341,6 +342,9 @@ The following changes to existing APIs or features add new behavior.
|
||||
• |:source| without arguments treats a buffer with its 'filetype' set to "lua"
|
||||
as Lua code regardless of its extension.
|
||||
|
||||
• |:lua| with a |[range]| executes that range in the current buffer as Lua code
|
||||
regardless of its extension.
|
||||
|
||||
• |:checkhealth| buffer now implements |folding|. The initial folding status is
|
||||
defined by the 'foldenable' option.
|
||||
|
||||
|
@ -192,11 +192,11 @@ Using Vim scripts *using-scripts*
|
||||
For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
||||
|
||||
*:so* *:source* *load-vim-script*
|
||||
:[range]so[urce] [file] Runs |Ex| commands or Lua code (".lua" files) from
|
||||
:[range]so[urce] [file] Runs |Ex-commands| or Lua code (".lua" files) from
|
||||
[file].
|
||||
If no [file], the current buffer is used, and it is
|
||||
treated as Lua code if its 'filetype' is "lua" or its
|
||||
file name ends with ".lua".
|
||||
If no [file], the current buffer is used and treated
|
||||
as Lua code if 'filetype' is "lua" or its filename
|
||||
ends with ".lua".
|
||||
Triggers the |SourcePre| autocommand.
|
||||
*:source!*
|
||||
:[range]so[urce]! {file}
|
||||
|
@ -17,7 +17,7 @@ changes. This documentation may also not fully reflect the latest changes.
|
||||
==============================================================================
|
||||
PARSER FILES *treesitter-parsers*
|
||||
|
||||
Parsers are the heart of tree-sitter. They are libraries that tree-sitter will
|
||||
Parsers are the heart of treesitter. They are libraries that treesitter will
|
||||
search for in the `parser` runtime directory. By default, Nvim bundles parsers
|
||||
for C, Lua, Vimscript, Vimdoc and Treesitter query files, but parsers can be
|
||||
installed via a plugin like https://github.com/nvim-treesitter/nvim-treesitter
|
||||
@ -43,7 +43,7 @@ TREESITTER TREES *treesitter-tree*
|
||||
|
||||
A "treesitter tree" represents the parsed contents of a buffer, which can be
|
||||
used to perform further analysis. It is a |userdata| reference to an object
|
||||
held by the tree-sitter library.
|
||||
held by the treesitter library.
|
||||
|
||||
An instance `TSTree` of a treesitter tree supports the following methods.
|
||||
|
||||
@ -59,7 +59,7 @@ TREESITTER NODES *treesitter-node*
|
||||
|
||||
A "treesitter node" represents one specific element of the parsed contents of
|
||||
a buffer, which can be captured by a |Query| for, e.g., highlighting. It is
|
||||
a |userdata| reference to an object held by the tree-sitter library.
|
||||
a |userdata| reference to an object held by the treesitter library.
|
||||
|
||||
An instance `TSNode` of a treesitter node supports the following methods.
|
||||
|
||||
@ -563,7 +563,7 @@ Conceals specified in this way respect 'conceallevel'.
|
||||
*treesitter-highlight-priority*
|
||||
Treesitter uses |nvim_buf_set_extmark()| to set highlights with a default
|
||||
priority of 100. This enables plugins to set a highlighting priority lower or
|
||||
higher than tree-sitter. It is also possible to change the priority of an
|
||||
higher than treesitter. It is also possible to change the priority of an
|
||||
individual query pattern manually by setting its `"priority"` metadata
|
||||
attribute: >query
|
||||
|
||||
@ -624,17 +624,17 @@ associated with patterns:
|
||||
VIM.TREESITTER *lua-treesitter*
|
||||
|
||||
The remainder of this document is a reference manual for the `vim.treesitter`
|
||||
Lua module, which is the main interface for Nvim's tree-sitter integration.
|
||||
Lua module, which is the main interface for Nvim's treesitter integration.
|
||||
Most of the following content is automatically generated from the function
|
||||
documentation.
|
||||
|
||||
|
||||
*vim.treesitter.language_version*
|
||||
The latest parser ABI version that is supported by the bundled tree-sitter
|
||||
The latest parser ABI version that is supported by the bundled treesitter
|
||||
library.
|
||||
|
||||
*vim.treesitter.minimum_language_version*
|
||||
The earliest parser ABI version that is supported by the bundled tree-sitter
|
||||
The earliest parser ABI version that is supported by the bundled treesitter
|
||||
library.
|
||||
|
||||
==============================================================================
|
||||
@ -652,16 +652,6 @@ foldexpr({lnum}) *vim.treesitter.foldexpr()*
|
||||
Return: ~
|
||||
(`string`)
|
||||
|
||||
foldtext() *vim.treesitter.foldtext()*
|
||||
Returns the highlighted content of the first line of the fold or falls
|
||||
back to |foldtext()| if no treesitter parser is found. Can be set directly
|
||||
to 'foldtext': >lua
|
||||
vim.wo.foldtext = 'v:lua.vim.treesitter.foldtext()'
|
||||
<
|
||||
|
||||
Return: ~
|
||||
(`{ [1]: string, [2]: string[] }[]|string`)
|
||||
|
||||
*vim.treesitter.get_captures_at_cursor()*
|
||||
get_captures_at_cursor({winnr})
|
||||
Returns a list of highlight capture names under the cursor
|
||||
|
11
runtime/ftplugin/hurl.vim
Normal file
11
runtime/ftplugin/hurl.vim
Normal file
@ -0,0 +1,11 @@
|
||||
" Vim filetype plugin file
|
||||
" Language: hurl
|
||||
" Maintainer: Melker Ulander <melker.ulander@pm.me>
|
||||
" Last Changed: 2024 01 26
|
||||
|
||||
if exists("b:did_ftplugin") | finish | endif
|
||||
|
||||
let b:did_ftplugin = 1
|
||||
setlocal commentstring=#\ %s
|
||||
|
||||
let b:undo_ftplugin = "setlocal commentstring<"
|
@ -1,5 +1,5 @@
|
||||
-- Neovim filetype plugin file
|
||||
-- Language: Tree-sitter query
|
||||
-- Language: Treesitter query
|
||||
-- Last Change: 2023 Aug 23
|
||||
|
||||
if vim.b.did_ftplugin == 1 then
|
||||
|
@ -49,18 +49,17 @@ setlocal isk+=#
|
||||
" Use :help to lookup the keyword under the cursor with K.
|
||||
setlocal keywordprg=:help
|
||||
|
||||
" if "\n" .. getline(1, 10)->join("\n") =~# '\n\s*vim9\%[script]\>'
|
||||
if "\n" .. join(getline(1, 10), "\n") =~# '\n\s*vim9\%[script]\>'
|
||||
" Set 'comments' to format dashed lists in comments
|
||||
setlocal com=sO:#\ -,mO:#\ \ ,eO:##,:#
|
||||
" Comments starts with # in Vim9 script
|
||||
" Comments starts with # in Vim9 script. We have to guess which one to use.
|
||||
if "\n" .. getline(1, 10)->join("\n") =~# '\n\s*vim9\%[script]\>'
|
||||
setlocal commentstring=#%s
|
||||
else
|
||||
setlocal com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\"
|
||||
" Comments starts with a double quote in legacy script
|
||||
setlocal commentstring=\"%s
|
||||
endif
|
||||
|
||||
" Set 'comments' to format dashed lists in comments, both in Vim9 and legacy
|
||||
" script.
|
||||
setlocal com=sO:#\ -,mO:#\ \ ,eO:##,:#\\\ ,:#,sO:\"\ -,mO:\"\ \ ,eO:\"\",:\"\\\ ,:\"
|
||||
|
||||
|
||||
" Format comments to be up to 78 characters long
|
||||
if &tw == 0
|
||||
|
@ -1,5 +1,5 @@
|
||||
-- Neovim indent file
|
||||
-- Language: Tree-sitter query
|
||||
-- Language: Treesitter query
|
||||
-- Last Change: 2022 Mar 29
|
||||
|
||||
-- it's a lisp!
|
||||
|
@ -23,9 +23,15 @@ local function check_runtime()
|
||||
health.start('Runtime')
|
||||
-- Files from an old installation.
|
||||
local bad_files = {
|
||||
['plugin/man.vim'] = false,
|
||||
['scripts.vim'] = false,
|
||||
['plugin/health.vim'] = false,
|
||||
['autoload/health/nvim.vim'] = false,
|
||||
['autoload/health/provider.vim'] = false,
|
||||
['autoload/man.vim'] = false,
|
||||
['plugin/man.vim'] = false,
|
||||
['queries/help/highlights.scm'] = false,
|
||||
['queries/help/injections.scm'] = false,
|
||||
['scripts.vim'] = false,
|
||||
['syntax/syncolor.vim'] = false,
|
||||
}
|
||||
local bad_files_msg = ''
|
||||
for k, _ in pairs(bad_files) do
|
||||
@ -42,10 +48,10 @@ local function check_runtime()
|
||||
if not ok then
|
||||
health.error(
|
||||
string.format(
|
||||
'$VIMRUNTIME has files from an old installation (this can cause weird behavior):\n%s',
|
||||
'Found old files in $VIMRUNTIME (this can cause weird behavior):\n%s',
|
||||
bad_files_msg
|
||||
),
|
||||
{ 'Delete $VIMRUNTIME (or uninstall Nvim), then reinstall Nvim.' }
|
||||
{ 'Delete the $VIMRUNTIME directory (or uninstall Nvim), then reinstall Nvim.' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -255,7 +255,7 @@ function M.check()
|
||||
'See :help provider-python for more information.',
|
||||
'You may disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim',
|
||||
})
|
||||
elseif pyname ~= '' and python_exe == '' then
|
||||
elseif pyname and pyname ~= '' and python_exe == '' then
|
||||
if not vim.g[host_prog_var] then
|
||||
local message = string.format(
|
||||
'`g:%s` is not set. Searching for %s in the environment.',
|
||||
@ -343,7 +343,7 @@ function M.check()
|
||||
end
|
||||
end
|
||||
|
||||
if python_exe == '' and pyname ~= '' then
|
||||
if pyname and python_exe == '' and pyname ~= '' then
|
||||
-- An error message should have already printed.
|
||||
health.error('`' .. pyname .. '` was not found.')
|
||||
elseif python_exe ~= '' and not check_bin(python_exe) then
|
||||
|
@ -22,7 +22,7 @@ function M.check()
|
||||
|
||||
local ruby_detect_table = require('vim.provider.ruby').detect()
|
||||
local host = ruby_detect_table[1]
|
||||
if host:find('^%s*$') then
|
||||
if (not host) or host:find('^%s*$') then
|
||||
health.warn('`neovim-ruby-host` not found.', {
|
||||
'Run `gem install neovim` to ensure the neovim RubyGem is installed.',
|
||||
'Run `gem environment` to ensure the gem bin directory is in $PATH.',
|
||||
|
34
runtime/lua/vim/_meta/api.lua
generated
34
runtime/lua/vim/_meta/api.lua
generated
@ -320,7 +320,7 @@ function vim.api.nvim_buf_get_commands(buffer, opts) end
|
||||
--- • details: Whether to include the details dict
|
||||
--- • hl_name: Whether to include highlight group name instead
|
||||
--- of id, true if omitted
|
||||
--- @return integer[]
|
||||
--- @return vim.api.keyset.get_extmark_item
|
||||
function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end
|
||||
|
||||
--- Gets `extmarks` in "traversal order" from a `charwise` region defined by
|
||||
@ -376,14 +376,14 @@ function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end
|
||||
--- if their start position is less than `start`
|
||||
--- • type: Filter marks by type: "highlight", "sign",
|
||||
--- "virt_text" and "virt_lines"
|
||||
--- @return any[]
|
||||
--- @return vim.api.keyset.get_extmark_item[]
|
||||
function vim.api.nvim_buf_get_extmarks(buffer, ns_id, start, end_, opts) end
|
||||
|
||||
--- Gets a list of buffer-local `mapping` definitions.
|
||||
---
|
||||
--- @param buffer integer Buffer handle, or 0 for current buffer
|
||||
--- @param mode string Mode short-name ("n", "i", "v", ...)
|
||||
--- @return table<string,any>[]
|
||||
--- @return vim.api.keyset.keymap[]
|
||||
function vim.api.nvim_buf_get_keymap(buffer, mode) end
|
||||
|
||||
--- Gets a line-range from the buffer.
|
||||
@ -1153,7 +1153,7 @@ function vim.api.nvim_get_all_options_info() end
|
||||
--- • buffer: Buffer number or list of buffer numbers for buffer
|
||||
--- local autocommands `autocmd-buflocal`. Cannot be used with
|
||||
--- {pattern}
|
||||
--- @return any[]
|
||||
--- @return vim.api.keyset.get_autocmds.ret[]
|
||||
function vim.api.nvim_get_autocmds(opts) end
|
||||
|
||||
--- Gets information about a channel.
|
||||
@ -1179,7 +1179,7 @@ function vim.api.nvim_get_color_by_name(name) end
|
||||
--- Keys are color names (e.g. "Aqua") and values are 24-bit RGB color values
|
||||
--- (e.g. 65535).
|
||||
---
|
||||
--- @return table<string,any>
|
||||
--- @return table<string,integer>
|
||||
function vim.api.nvim_get_color_map() end
|
||||
|
||||
--- Gets a map of global (non-buffer-local) Ex commands.
|
||||
@ -1229,7 +1229,7 @@ function vim.api.nvim_get_current_win() end
|
||||
--- instead of effective definition `:hi-link`.
|
||||
--- • create: (boolean, default true) When highlight group
|
||||
--- doesn't exist create it.
|
||||
--- @return table<string,any>
|
||||
--- @return vim.api.keyset.hl_info
|
||||
function vim.api.nvim_get_hl(ns_id, opts) end
|
||||
|
||||
--- @deprecated
|
||||
@ -1264,7 +1264,7 @@ function vim.api.nvim_get_hl_ns(opts) end
|
||||
--- Gets a list of global (non-buffer-local) `mapping` definitions.
|
||||
---
|
||||
--- @param mode string Mode short-name ("n", "i", "v", ...)
|
||||
--- @return table<string,any>[]
|
||||
--- @return vim.api.keyset.keymap[]
|
||||
function vim.api.nvim_get_keymap(mode) end
|
||||
|
||||
--- Returns a `(row, col, buffer, buffername)` tuple representing the position
|
||||
@ -1274,18 +1274,18 @@ function vim.api.nvim_get_keymap(mode) end
|
||||
---
|
||||
--- @param name string Mark name
|
||||
--- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use.
|
||||
--- @return any[]
|
||||
--- @return vim.api.keyset.get_mark
|
||||
function vim.api.nvim_get_mark(name, opts) end
|
||||
|
||||
--- Gets the current mode. `mode()` "blocking" is true if Nvim is waiting for
|
||||
--- input.
|
||||
---
|
||||
--- @return table<string,any>
|
||||
--- @return vim.api.keyset.get_mode
|
||||
function vim.api.nvim_get_mode() end
|
||||
|
||||
--- Gets existing, non-anonymous `namespace`s.
|
||||
---
|
||||
--- @return table<string,any>
|
||||
--- @return table<string,integer>
|
||||
function vim.api.nvim_get_namespaces() end
|
||||
|
||||
--- @deprecated
|
||||
@ -1295,7 +1295,7 @@ function vim.api.nvim_get_option(name) end
|
||||
|
||||
--- @deprecated
|
||||
--- @param name string
|
||||
--- @return table<string,any>
|
||||
--- @return vim.api.keyset.get_option_info
|
||||
function vim.api.nvim_get_option_info(name) end
|
||||
|
||||
--- Gets the option information for one option from arbitrary buffer or window
|
||||
@ -1325,7 +1325,7 @@ function vim.api.nvim_get_option_info(name) end
|
||||
--- • win: `window-ID`. Used for getting window local options.
|
||||
--- • buf: Buffer number. Used for getting buffer local options.
|
||||
--- Implies {scope} is "local".
|
||||
--- @return table<string,any>
|
||||
--- @return vim.api.keyset.get_option_info
|
||||
function vim.api.nvim_get_option_info2(name, opts) end
|
||||
|
||||
--- Gets the value of an option. The behavior of this function matches that of
|
||||
@ -1637,7 +1637,7 @@ function vim.api.nvim_out_write(str) end
|
||||
---
|
||||
--- @param str string Command line string to parse. Cannot contain "\n".
|
||||
--- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use.
|
||||
--- @return table<string,any>
|
||||
--- @return vim.api.keyset.parse_cmd
|
||||
function vim.api.nvim_parse_cmd(str, opts) end
|
||||
|
||||
--- Parse a Vimscript expression.
|
||||
@ -1952,6 +1952,12 @@ function vim.api.nvim_tabpage_list_wins(tabpage) end
|
||||
--- @param value any Variable value
|
||||
function vim.api.nvim_tabpage_set_var(tabpage, name, value) end
|
||||
|
||||
--- Sets the current window in a tabpage
|
||||
---
|
||||
--- @param tabpage integer Tabpage handle, or 0 for current tabpage
|
||||
--- @param win integer Window handle, must already belong to {tabpage}
|
||||
function vim.api.nvim_tabpage_set_win(tabpage, win) end
|
||||
|
||||
--- Calls a function with window as temporary current window.
|
||||
---
|
||||
--- @param window integer Window handle, or 0 for current window
|
||||
@ -1985,7 +1991,7 @@ function vim.api.nvim_win_get_buf(window) end
|
||||
--- `relative` is empty for normal windows.
|
||||
---
|
||||
--- @param window integer Window handle, or 0 for current window
|
||||
--- @return table<string,any>
|
||||
--- @return vim.api.keyset.float_config
|
||||
function vim.api.nvim_win_get_config(window) end
|
||||
|
||||
--- Gets the (1,0)-indexed, buffer-relative cursor position for a given window
|
||||
|
1
runtime/lua/vim/_meta/api_keysets.lua
generated
1
runtime/lua/vim/_meta/api_keysets.lua
generated
@ -274,6 +274,7 @@ error('Cannot require a meta file')
|
||||
--- @field ui_watched? boolean
|
||||
--- @field undo_restore? boolean
|
||||
--- @field url? string
|
||||
--- @field _subpriority? integer
|
||||
|
||||
--- @class vim.api.keyset.user_command
|
||||
--- @field addr? any
|
||||
|
167
runtime/lua/vim/_meta/api_keysets_extra.lua
Normal file
167
runtime/lua/vim/_meta/api_keysets_extra.lua
Normal file
@ -0,0 +1,167 @@
|
||||
--- @meta _
|
||||
error('Cannot require a meta file')
|
||||
|
||||
--- Extra types we can't generate keysets for
|
||||
|
||||
--- @class vim.api.keyset.extmark_details
|
||||
--- @field ns_id integer
|
||||
--- @field right_gravity boolean
|
||||
---
|
||||
--- @field end_row? integer
|
||||
--- @field end_col? integer
|
||||
--- @field end_right_gravity? integer
|
||||
---
|
||||
--- @field priority? integer
|
||||
---
|
||||
--- @field undo_restore? false
|
||||
--- @field invalidate? true
|
||||
--- @field invalid? true
|
||||
---
|
||||
--- @field hl_group? string
|
||||
--- @field hl_eol? boolean
|
||||
---
|
||||
--- @field conceal? boolean
|
||||
--- @field spell? boolean
|
||||
--- @field ui_watched? boolean
|
||||
--- @field url? boolean
|
||||
--- @field hl_mode? string
|
||||
---
|
||||
--- @field virt_text? {[1]: string, [2]: string}[]
|
||||
--- @field virt_text_hide? boolean
|
||||
--- @field virt_text_repeat_linebreak? boolean
|
||||
--- @field virt_text_win_col? integer
|
||||
--- @field virt_text_pos? string
|
||||
---
|
||||
--- @field virt_lines? {[1]: string, [2]: string}[][]
|
||||
--- @field virt_lines_above? boolean
|
||||
--- @field virt_lines_leftcol? boolean
|
||||
---
|
||||
--- @field sign_text? string
|
||||
--- @field sign_name? string
|
||||
--- @field sign_hl_group? string
|
||||
--- @field number_hl_group? string
|
||||
--- @field line_hl_group? string
|
||||
--- @field cursorline_hl_group? string
|
||||
|
||||
--- @class vim.api.keyset.get_extmark_item
|
||||
--- @field [1] integer row
|
||||
--- @field [2] integer col
|
||||
--- @field [3] vim.api.keyset.extmark_details?
|
||||
|
||||
--- @class vim.api.keyset.get_mark
|
||||
--- @field [1] integer row
|
||||
--- @field [2] integer col
|
||||
--- @field [3] integer buffer
|
||||
--- @field [4] string buffername
|
||||
|
||||
--- @class vim.api.keyset.get_autocmds.ret
|
||||
--- @field id? integer
|
||||
--- @field group? integer
|
||||
--- @field group_name? integer
|
||||
--- @field desc? string
|
||||
--- @field event? string
|
||||
--- @field command? string
|
||||
--- @field callback? function
|
||||
--- @field once? boolean
|
||||
--- @field pattern? string
|
||||
--- @field buflocal? boolean
|
||||
--- @field buffer? integer
|
||||
|
||||
--- @class vim.api.keyset.command_info
|
||||
--- @field name string
|
||||
--- @field definition string
|
||||
--- @field script_id integer
|
||||
--- @field bang boolean
|
||||
--- @field bar boolean
|
||||
--- @field register boolean
|
||||
--- @field keepscript boolean
|
||||
--- @field preview boolean
|
||||
--- @field nargs string
|
||||
--- @field complete? string
|
||||
--- @field complete_arg? string
|
||||
--- @field count? string
|
||||
--- @field range? string
|
||||
--- @field addr? string
|
||||
|
||||
--- @class vim.api.keyset.hl_info.base
|
||||
--- @field reverse? true
|
||||
--- @field bold? true
|
||||
--- @field italic? true
|
||||
--- @field underline? true
|
||||
--- @field undercurl? true
|
||||
--- @field underdouble? true
|
||||
--- @field underdotted? true
|
||||
--- @field underdashed? true
|
||||
--- @field standout? true
|
||||
--- @field strikethrough? true
|
||||
--- @field altfont? true
|
||||
--- @field nocombine? true
|
||||
|
||||
--- @class vim.api.keyset.hl_info.cterm : vim.api.keyset.hl_info.base
|
||||
--- @field ctermfg? integer
|
||||
--- @field ctermbg? integer
|
||||
--- @field foreground? integer
|
||||
--- @field background? integer
|
||||
|
||||
--- @class vim.api.keyset.hl_info : vim.api.keyset.hl_info.base
|
||||
--- @field fg? integer
|
||||
--- @field bg? integer
|
||||
--- @field sp? integer
|
||||
--- @field default? true
|
||||
--- @field link? string
|
||||
--- @field blend? integer
|
||||
--- @field cterm? vim.api.keyset.hl_info.cterm
|
||||
|
||||
--- @class vim.api.keyset.get_mode
|
||||
--- @field blocking boolean
|
||||
--- @field mode string
|
||||
|
||||
--- @class vim.api.keyset.get_option_info
|
||||
--- @field name string
|
||||
--- @field shortname string
|
||||
--- @field scope 'buf'|'win'|'global'
|
||||
--- @field global_local boolean
|
||||
--- @field commalist boolean
|
||||
--- @field flaglist boolean
|
||||
--- @field was_set boolean
|
||||
--- @field last_set_id integer
|
||||
--- @field last_set_linenr integer
|
||||
--- @field last_set_chan integer
|
||||
--- @field type 'string'|'boolean'|'number'
|
||||
--- @field default string|boolean|integer
|
||||
--- @field allow_duplicates boolean
|
||||
|
||||
--- @class vim.api.keyset.parse_cmd.mods
|
||||
--- @field filter { force: boolean, pattern: string }
|
||||
--- @field silent boolean
|
||||
--- @field emsg_silent boolean
|
||||
--- @field unsilent boolean
|
||||
--- @field sandbox boolean
|
||||
--- @field noautocmd boolean
|
||||
--- @field tab integer
|
||||
--- @field verbose integer
|
||||
--- @field browse boolean
|
||||
--- @field confirm boolean
|
||||
--- @field hide boolean
|
||||
--- @field keepalt boolean
|
||||
--- @field keepjumps boolean
|
||||
--- @field keepmarks boolean
|
||||
--- @field keeppatterns boolean
|
||||
--- @field lockmarks boolean
|
||||
--- @field noswapfile boolean
|
||||
--- @field vertical boolean
|
||||
--- @field horizontal boolean
|
||||
--- @field split ''|'botright'|'topleft'|'belowright'|'aboveleft'
|
||||
|
||||
--- @class vim.api.keyset.parse_cmd
|
||||
--- @field addr 'line'|'arg'|'buf'|'load'|'win'|'tab'|'qf'|'none'|'?'
|
||||
--- @field args string[]
|
||||
--- @field bang boolean
|
||||
--- @field cmd string
|
||||
--- @field magic {bar: boolean, file: boolean}
|
||||
--- @field mods vim.api.keyset.parse_cmd.mods
|
||||
--- @field nargs '0'|'1'|'?'|'+'|'*'
|
||||
--- @field nextcmd string
|
||||
--- @field range? integer[]
|
||||
--- @field count? integer
|
||||
--- @field reg? string
|
4
runtime/lua/vim/_meta/vimfn.lua
generated
4
runtime/lua/vim/_meta/vimfn.lua
generated
@ -2562,6 +2562,8 @@ function vim.fn.getbufinfo(buf) end
|
||||
--- bufnr Buffer number.
|
||||
--- changed TRUE if the buffer is modified.
|
||||
--- changedtick Number of changes made to the buffer.
|
||||
--- command TRUE if the buffer belongs to the
|
||||
--- command-line window |cmdwin|.
|
||||
--- hidden TRUE if the buffer is hidden.
|
||||
--- lastused Timestamp in seconds, like
|
||||
--- |localtime()|, when the buffer was
|
||||
@ -2777,7 +2779,7 @@ function vim.fn.getchar() end
|
||||
--- 32 mouse double click
|
||||
--- 64 mouse triple click
|
||||
--- 96 mouse quadruple click (== 32 + 64)
|
||||
--- 128 command (Macintosh only)
|
||||
--- 128 command (Mac) or super
|
||||
--- Only the modifiers that have not been included in the
|
||||
--- character itself are obtained. Thus Shift-a results in "A"
|
||||
--- without a modifier. Returns 0 if no modifiers are used.
|
||||
|
@ -1909,7 +1909,7 @@ local pattern = {
|
||||
['.*baseq[2-3]/.*%.cfg'] = 'quake',
|
||||
['.*quake[1-3]/.*%.cfg'] = 'quake',
|
||||
['.*id1/.*%.cfg'] = 'quake',
|
||||
['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries (Neovim only)
|
||||
['.*/queries/.*%.scm'] = 'query', -- treesitter queries (Neovim only)
|
||||
['.*,v'] = 'rcs',
|
||||
['%.reminders.*'] = starsetf('remind'),
|
||||
['[rR]akefile.*'] = starsetf('ruby'),
|
||||
|
@ -26,7 +26,7 @@ local M = {}
|
||||
|
||||
--- Table with default priorities used for highlighting:
|
||||
--- - `syntax`: `50`, used for standard syntax highlighting
|
||||
--- - `treesitter`: `100`, used for tree-sitter-based highlighting
|
||||
--- - `treesitter`: `100`, used for treesitter-based highlighting
|
||||
--- - `semantic_tokens`: `125`, used for LSP semantic token highlighting
|
||||
--- - `diagnostics`: `150`, used for code analysis such as diagnostics
|
||||
--- - `user`: `200`, used for user-triggered highlights such as LSP document
|
||||
|
@ -6,7 +6,7 @@ local M = {}
|
||||
|
||||
---@class lsp.inlay_hint.bufstate
|
||||
---@field version? integer
|
||||
---@field client_hint? table<integer, table<integer, lsp.InlayHint[]>> client_id -> (lnum -> hints)
|
||||
---@field client_hints? table<integer, table<integer, lsp.InlayHint[]>> client_id -> (lnum -> hints)
|
||||
---@field applied table<integer, integer> Last version of hints applied to this line
|
||||
---@field enabled boolean Whether inlay hints are enabled for this buffer
|
||||
---@type table<integer, lsp.inlay_hint.bufstate>
|
||||
@ -39,11 +39,11 @@ function M.on_inlayhint(err, result, ctx, _)
|
||||
if not bufstate or not bufstate.enabled then
|
||||
return
|
||||
end
|
||||
if not (bufstate.client_hint and bufstate.version) then
|
||||
bufstate.client_hint = vim.defaulttable()
|
||||
if not (bufstate.client_hints and bufstate.version) then
|
||||
bufstate.client_hints = vim.defaulttable()
|
||||
bufstate.version = ctx.version
|
||||
end
|
||||
local hints_by_client = bufstate.client_hint
|
||||
local hints_by_client = bufstate.client_hints
|
||||
local client = assert(vim.lsp.get_client_by_id(client_id))
|
||||
|
||||
local new_hints_by_lnum = vim.defaulttable()
|
||||
@ -162,7 +162,7 @@ function M.get(filter)
|
||||
end
|
||||
|
||||
local bufstate = bufstates[bufnr]
|
||||
if not (bufstate and bufstate.client_hint) then
|
||||
if not (bufstate and bufstate.client_hints) then
|
||||
return {}
|
||||
end
|
||||
|
||||
@ -185,7 +185,7 @@ function M.get(filter)
|
||||
--- @type vim.lsp.inlay_hint.get.ret[]
|
||||
local hints = {}
|
||||
for _, client in pairs(clients) do
|
||||
local hints_by_lnum = bufstate.client_hint[client.id]
|
||||
local hints_by_lnum = bufstate.client_hints[client.id]
|
||||
if hints_by_lnum then
|
||||
for lnum = range.start.line, range['end'].line do
|
||||
local line_hints = hints_by_lnum[lnum] or {}
|
||||
@ -218,11 +218,11 @@ local function clear(bufnr)
|
||||
return
|
||||
end
|
||||
local bufstate = bufstates[bufnr]
|
||||
local client_lens = (bufstate or {}).client_hint or {}
|
||||
local client_lens = (bufstate or {}).client_hints or {}
|
||||
local client_ids = vim.tbl_keys(client_lens) --- @type integer[]
|
||||
for _, iter_client_id in ipairs(client_ids) do
|
||||
if bufstate then
|
||||
bufstate.client_hint[iter_client_id] = {}
|
||||
bufstate.client_hints[iter_client_id] = {}
|
||||
end
|
||||
end
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
|
||||
@ -319,7 +319,7 @@ api.nvim_set_decoration_provider(namespace, {
|
||||
if bufstate.version ~= util.buf_versions[bufnr] then
|
||||
return
|
||||
end
|
||||
local hints_by_client = assert(bufstate.client_hint)
|
||||
local hints_by_client = assert(bufstate.client_hints)
|
||||
|
||||
for lnum = topline, botline do
|
||||
if bufstate.applied[lnum] ~= bufstate.version then
|
||||
|
@ -517,16 +517,4 @@ function M.foldexpr(lnum)
|
||||
return require('vim.treesitter._fold').foldexpr(lnum)
|
||||
end
|
||||
|
||||
--- Returns the highlighted content of the first line of the fold or falls back to |foldtext()|
|
||||
--- if no treesitter parser is found. Can be set directly to 'foldtext':
|
||||
---
|
||||
--- ```lua
|
||||
--- vim.wo.foldtext = 'v:lua.vim.treesitter.foldtext()'
|
||||
--- ```
|
||||
---
|
||||
---@return { [1]: string, [2]: string[] }[] | string
|
||||
function M.foldtext()
|
||||
return require('vim.treesitter._fold').foldtext()
|
||||
end
|
||||
|
||||
return M
|
||||
|
@ -397,97 +397,4 @@ api.nvim_create_autocmd('OptionSet', {
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
---@package
|
||||
---@return { [1]: string, [2]: string[] }[]|string
|
||||
function M.foldtext()
|
||||
local foldstart = vim.v.foldstart
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
|
||||
---@type boolean, LanguageTree
|
||||
local ok, parser = pcall(ts.get_parser, bufnr)
|
||||
if not ok then
|
||||
return vim.fn.foldtext()
|
||||
end
|
||||
|
||||
local query = ts.query.get(parser:lang(), 'highlights')
|
||||
if not query then
|
||||
return vim.fn.foldtext()
|
||||
end
|
||||
|
||||
local tree = parser:parse({ foldstart - 1, foldstart })[1]
|
||||
|
||||
local line = api.nvim_buf_get_lines(bufnr, foldstart - 1, foldstart, false)[1]
|
||||
if not line then
|
||||
return vim.fn.foldtext()
|
||||
end
|
||||
|
||||
---@type { [1]: string, [2]: string[], range: { [1]: integer, [2]: integer } }[] | { [1]: string, [2]: string[] }[]
|
||||
local result = {}
|
||||
|
||||
local line_pos = 0
|
||||
|
||||
for id, node, metadata in query:iter_captures(tree:root(), 0, foldstart - 1, foldstart) do
|
||||
local name = query.captures[id]
|
||||
local start_row, start_col, end_row, end_col = node:range()
|
||||
|
||||
local priority = tonumber(metadata.priority or vim.highlight.priorities.treesitter)
|
||||
|
||||
if start_row == foldstart - 1 and end_row == foldstart - 1 then
|
||||
-- check for characters ignored by treesitter
|
||||
if start_col > line_pos then
|
||||
table.insert(result, {
|
||||
line:sub(line_pos + 1, start_col),
|
||||
{},
|
||||
range = { line_pos, start_col },
|
||||
})
|
||||
end
|
||||
line_pos = end_col
|
||||
|
||||
local text = line:sub(start_col + 1, end_col)
|
||||
table.insert(result, { text, { { '@' .. name, priority } }, range = { start_col, end_col } })
|
||||
end
|
||||
end
|
||||
|
||||
local i = 1
|
||||
while i <= #result do
|
||||
-- find first capture that is not in current range and apply highlights on the way
|
||||
local j = i + 1
|
||||
while
|
||||
j <= #result
|
||||
and result[j].range[1] >= result[i].range[1]
|
||||
and result[j].range[2] <= result[i].range[2]
|
||||
do
|
||||
for k, v in ipairs(result[i][2]) do
|
||||
if not vim.tbl_contains(result[j][2], v) then
|
||||
table.insert(result[j][2], k, v)
|
||||
end
|
||||
end
|
||||
j = j + 1
|
||||
end
|
||||
|
||||
-- remove the parent capture if it is split into children
|
||||
if j > i + 1 then
|
||||
table.remove(result, i)
|
||||
else
|
||||
-- highlights need to be sorted by priority, on equal prio, the deeper nested capture (earlier
|
||||
-- in list) should be considered higher prio
|
||||
if #result[i][2] > 1 then
|
||||
table.sort(result[i][2], function(a, b)
|
||||
return a[2] < b[2]
|
||||
end)
|
||||
end
|
||||
|
||||
result[i][2] = vim.tbl_map(function(tbl)
|
||||
return tbl[1]
|
||||
end, result[i][2])
|
||||
result[i] = { result[i][1], result[i][2] }
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
return M
|
||||
|
@ -14,7 +14,7 @@ local M = {}
|
||||
local TSTreeView = {}
|
||||
|
||||
---@class TSP.Node
|
||||
---@field node TSNode Tree-sitter node
|
||||
---@field node TSNode Treesitter node
|
||||
---@field field string? Node field
|
||||
---@field depth integer Depth of this node in the tree
|
||||
---@field text string? Text displayed in the inspector for this node. Not computed until the
|
||||
|
@ -1,6 +1,10 @@
|
||||
local tty = vim.iter(vim.api.nvim_list_uis()):any(function(ui)
|
||||
return ui.chan == 1 and ui.stdout_tty
|
||||
end)
|
||||
local tty = false
|
||||
for _, ui in ipairs(vim.api.nvim_list_uis()) do
|
||||
if ui.chan == 1 and ui.stdout_tty then
|
||||
tty = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not tty or vim.g.clipboard ~= nil or vim.o.clipboard ~= '' or not os.getenv('SSH_TTY') then
|
||||
return
|
||||
|
@ -1,9 +1,9 @@
|
||||
" Vim syntax file
|
||||
" Language: ANT build file (xml)
|
||||
" Maintainer: Johannes Zellner <johannes@zellner.org>
|
||||
" Last Change: Tue Apr 27 13:05:59 CEST 2004
|
||||
" Filenames: build.xml
|
||||
" $Id: ant.vim,v 1.1 2004/06/13 18:13:18 vimboss Exp $
|
||||
" Language: ANT build file (xml)
|
||||
" Maintainer: Doug Kearns <dougkearns@gmail.com>
|
||||
" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
|
||||
" Last Change: 2024 Jan 27
|
||||
" Filenames: build.xml
|
||||
|
||||
" Quit when a syntax file was already loaded
|
||||
if exists("b:current_syntax")
|
||||
@ -44,48 +44,48 @@ call AntSyntaxScript('jpython', 'python.vim')
|
||||
|
||||
syn cluster xmlTagHook add=antElement
|
||||
|
||||
syn keyword antElement display WsdlToDotnet addfiles and ant antcall antstructure apply archives arg argument
|
||||
syn keyword antElement display assertions attrib attribute available basename bcc blgenclient bootclasspath
|
||||
syn keyword antElement display borland bottom buildnumber buildpath buildpathelement bunzip2 bzip2 cab
|
||||
syn keyword antElement display catalogpath cc cccheckin cccheckout cclock ccmcheckin ccmcheckintask ccmcheckout
|
||||
syn keyword antElement display ccmcreatetask ccmkattr ccmkbl ccmkdir ccmkelem ccmklabel ccmklbtype
|
||||
syn keyword antElement display ccmreconfigure ccrmtype ccuncheckout ccunlock ccupdate checksum chgrp chmod
|
||||
syn keyword antElement display chown classconstants classes classfileset classpath commandline comment
|
||||
syn keyword antElement display compilerarg compilerclasspath concat concatfilter condition copy copydir
|
||||
syn keyword antElement display copyfile coveragepath csc custom cvs cvschangelog cvspass cvstagdiff cvsversion
|
||||
syn keyword antElement display daemons date defaultexcludes define delete deletecharacters deltree depend
|
||||
syn keyword antElement display depends dependset depth description different dirname dirset disable dname
|
||||
syn keyword antElement display doclet doctitle dtd ear echo echoproperties ejbjar element enable entity entry
|
||||
syn keyword antElement display env equals escapeunicode exclude excludepackage excludesfile exec execon
|
||||
syn keyword antElement display existing expandproperties extdirs extension extensionSet extensionset factory
|
||||
syn keyword antElement display fail filelist filename filepath fileset filesmatch filetokenizer filter
|
||||
syn keyword antElement display filterchain filterreader filters filterset filtersfile fixcrlf footer format
|
||||
syn keyword antElement display from ftp generic genkey get gjdoc grant group gunzip gzip header headfilter http
|
||||
syn keyword antElement display ignoreblank ilasm ildasm import importtypelib include includesfile input iplanet
|
||||
syn keyword antElement display iplanet-ejbc isfalse isreference isset istrue jar jarlib-available
|
||||
syn keyword antElement display jarlib-manifest jarlib-resolve java javac javacc javadoc javadoc2 jboss jdepend
|
||||
syn keyword antElement display jjdoc jjtree jlink jonas jpcoverage jpcovmerge jpcovreport jsharpc jspc
|
||||
syn keyword antElement display junitreport jvmarg lib libfileset linetokenizer link loadfile loadproperties
|
||||
syn keyword antElement display location macrodef mail majority manifest map mapper marker mergefiles message
|
||||
syn keyword antElement display metainf method mimemail mkdir mmetrics modified move mparse none not options or
|
||||
syn keyword antElement display os outputproperty package packageset parallel param patch path pathconvert
|
||||
syn keyword antElement display pathelement patternset permissions prefixlines present presetdef project
|
||||
syn keyword antElement display property propertyfile propertyref propertyset pvcs pvcsproject record reference
|
||||
syn keyword antElement display regexp rename renameext replace replacefilter replaceregex replaceregexp
|
||||
syn keyword antElement display replacestring replacetoken replacetokens replacevalue replyto report resource
|
||||
syn keyword antElement display revoke rmic root rootfileset rpm scp section selector sequential serverdeploy
|
||||
syn keyword antElement display setproxy signjar size sleep socket soscheckin soscheckout sosget soslabel source
|
||||
syn keyword antElement display sourcepath sql src srcfile srcfilelist srcfiles srcfileset sshexec stcheckin
|
||||
syn keyword antElement display stcheckout stlabel stlist stringtokenizer stripjavacomments striplinebreaks
|
||||
syn keyword antElement display striplinecomments style subant substitution support symlink sync sysproperty
|
||||
syn keyword antElement display syspropertyset tabstospaces tag taglet tailfilter tar tarfileset target
|
||||
syn keyword antElement display targetfile targetfilelist targetfileset taskdef tempfile test testlet text title
|
||||
syn keyword antElement display to token tokenfilter touch transaction translate triggers trim tstamp type
|
||||
syn keyword antElement display typedef unjar untar unwar unzip uptodate url user vbc vssadd vsscheckin
|
||||
syn keyword antElement display vsscheckout vsscp vsscreate vssget vsshistory vsslabel waitfor war wasclasspath
|
||||
syn keyword antElement display webapp webinf weblogic weblogictoplink websphere whichresource wlclasspath
|
||||
syn keyword antElement display wljspc wsdltodotnet xmlcatalog xmlproperty xmlvalidate xslt zip zipfileset
|
||||
syn keyword antElement display zipgroupfileset
|
||||
syn keyword antElement WsdlToDotnet addfiles and ant antcall antstructure apply archives arg argument
|
||||
syn keyword antElement assertions attrib attribute available basename bcc blgenclient bootclasspath
|
||||
syn keyword antElement borland bottom buildnumber buildpath buildpathelement bunzip2 bzip2 cab
|
||||
syn keyword antElement catalogpath cc cccheckin cccheckout cclock ccmcheckin ccmcheckintask ccmcheckout
|
||||
syn keyword antElement ccmcreatetask ccmkattr ccmkbl ccmkdir ccmkelem ccmklabel ccmklbtype
|
||||
syn keyword antElement ccmreconfigure ccrmtype ccuncheckout ccunlock ccupdate checksum chgrp chmod
|
||||
syn keyword antElement chown classconstants classes classfileset classpath commandline comment
|
||||
syn keyword antElement compilerarg compilerclasspath concat concatfilter condition copy copydir
|
||||
syn keyword antElement copyfile coveragepath csc custom cvs cvschangelog cvspass cvstagdiff cvsversion
|
||||
syn keyword antElement daemons date defaultexcludes define delete deletecharacters deltree depend
|
||||
syn keyword antElement depends dependset depth description different dirname dirset disable dname
|
||||
syn keyword antElement doclet doctitle dtd ear echo echoproperties ejbjar element enable entity entry
|
||||
syn keyword antElement env equals escapeunicode exclude excludepackage excludesfile exec execon
|
||||
syn keyword antElement existing expandproperties extdirs extension extensionSet extensionset factory
|
||||
syn keyword antElement fail filelist filename filepath fileset filesmatch filetokenizer filter
|
||||
syn keyword antElement filterchain filterreader filters filterset filtersfile fixcrlf footer format
|
||||
syn keyword antElement from ftp generic genkey get gjdoc grant group gunzip gzip header headfilter http
|
||||
syn keyword antElement ignoreblank ilasm ildasm import importtypelib include includesfile input iplanet
|
||||
syn keyword antElement iplanet-ejbc isfalse isreference isset istrue jar jarlib-available
|
||||
syn keyword antElement jarlib-manifest jarlib-resolve java javac javacc javadoc javadoc2 jboss jdepend
|
||||
syn keyword antElement jjdoc jjtree jlink jonas jpcoverage jpcovmerge jpcovreport jsharpc jspc
|
||||
syn keyword antElement junitreport jvmarg lib libfileset linetokenizer link loadfile loadproperties
|
||||
syn keyword antElement location macrodef mail majority manifest map mapper marker mergefiles message
|
||||
syn keyword antElement metainf method mimemail mkdir mmetrics modified move mparse none not options or
|
||||
syn keyword antElement os outputproperty package packageset parallel param patch path pathconvert
|
||||
syn keyword antElement pathelement patternset permissions prefixlines present presetdef project
|
||||
syn keyword antElement property propertyfile propertyref propertyset pvcs pvcsproject record reference
|
||||
syn keyword antElement regexp rename renameext replace replacefilter replaceregex replaceregexp
|
||||
syn keyword antElement replacestring replacetoken replacetokens replacevalue replyto report resource
|
||||
syn keyword antElement revoke rmic root rootfileset rpm scp section selector sequential serverdeploy
|
||||
syn keyword antElement setproxy signjar size sleep socket soscheckin soscheckout sosget soslabel source
|
||||
syn keyword antElement sourcepath sql src srcfile srcfilelist srcfiles srcfileset sshexec stcheckin
|
||||
syn keyword antElement stcheckout stlabel stlist stringtokenizer stripjavacomments striplinebreaks
|
||||
syn keyword antElement striplinecomments style subant substitution support symlink sync sysproperty
|
||||
syn keyword antElement syspropertyset tabstospaces tag taglet tailfilter tar tarfileset target
|
||||
syn keyword antElement targetfile targetfilelist targetfileset taskdef tempfile test testlet text title
|
||||
syn keyword antElement to token tokenfilter touch transaction translate triggers trim tstamp type
|
||||
syn keyword antElement typedef unjar untar unwar unzip uptodate url user vbc vssadd vsscheckin
|
||||
syn keyword antElement vsscheckout vsscp vsscreate vssget vsshistory vsslabel waitfor war wasclasspath
|
||||
syn keyword antElement webapp webinf weblogic weblogictoplink websphere whichresource wlclasspath
|
||||
syn keyword antElement wljspc wsdltodotnet xmlcatalog xmlproperty xmlvalidate xslt zip zipfileset
|
||||
syn keyword antElement zipgroupfileset
|
||||
|
||||
hi def link antElement Statement
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
" Language: Mail file
|
||||
" Previous Maintainer: Felix von Leitner <leitner@math.fu-berlin.de>
|
||||
" Maintainer: GI <a@b.c>, where a='gi1242+vim', b='gmail', c='com'
|
||||
" Last Change: Thu 18 Jan 2024 06:34:38 PM EST
|
||||
" Last Change: Thu 25 Jan 2024 10:34:02 AM EST
|
||||
|
||||
" Quit when a syntax file was already loaded
|
||||
if exists("b:current_syntax")
|
||||
@ -64,7 +64,7 @@ syn match mailURL contains=@NoSpell `\v<(((https?|ftp|gopher)://|(mailto|file|ne
|
||||
syn match mailEmail contains=@NoSpell "\v[_=a-z\./+0-9-]+\@[a-z0-9._-]+\a{2}"
|
||||
|
||||
" Don't spell emojis
|
||||
syn match mailEmoji contains=@NoSpell "\v[\U1f300-\U1f64f\U1f900-\U1f9ff]"
|
||||
syn match mailEmoji contains=@NoSpell "\%#=2\v[\U1f300-\U1f64f\U1f900-\U1f9ff]"
|
||||
|
||||
" Make sure quote markers in regions (header / signature) have correct color
|
||||
syn match mailQuoteExp1 contained "\v^(\> ?)"
|
||||
|
@ -1,5 +1,5 @@
|
||||
-- Neovim syntax file
|
||||
-- Language: Tree-sitter query
|
||||
-- Language: Treesitter query
|
||||
-- Last Change: 2022 Apr 13
|
||||
|
||||
-- it's a lisp!
|
||||
|
@ -204,7 +204,7 @@ syn keyword vimAugroupKey contained aug[roup]
|
||||
|
||||
" Operators: {{{2
|
||||
" =========
|
||||
syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimType,vimRegister,vimContinue,vim9Comment,vimVar
|
||||
syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimType,vimRegister,@vimContinue,vim9Comment,vimVar
|
||||
syn match vimOper "||\|&&\|[-+*/%.!]" skipwhite nextgroup=vimString,vimSpecFile
|
||||
syn match vimOper "\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\|!\~#\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile
|
||||
syn match vimOper "\(\<is\|\<isnot\)[?#]\{0,2}\>" skipwhite nextgroup=vimString,vimSpecFile
|
||||
@ -311,6 +311,12 @@ syn match vimString contained +"[^"]*\\$+ skipnl nextgroup=vimStringCont
|
||||
syn match vimStringCont contained +\(\\\\\|.\)\{-}[^\\]"+
|
||||
syn match vimEscape contained "\\."
|
||||
|
||||
syn region vimString start=+$'+ end=+'+ skip=+''+ oneline contains=vimStringInterpolationBrace,vimStringInterpolationExpr
|
||||
syn region vimString start=+$"+ end=+"+ oneline contains=@vimStringGroup,vimStringInterpolationBrace,vimStringInterpolationExpr
|
||||
syn region vimStringInterpolationExpr matchgroup=vimOperParen start=+{+ end=+}+ oneline contains=vimFunc,vimFuncVar,vimOper,vimNotation,vimOperParen,vimString,vimVar
|
||||
syn match vimStringInterpolationBrace "{{"
|
||||
syn match vimStringInterpolationBrace "}}"
|
||||
|
||||
" Substitutions: {{{2
|
||||
" =============
|
||||
syn cluster vimSubstList contains=vimPatSep,vimPatRegion,vimPatSepErr,vimSubstTwoBS,vimSubstRange,vimNotation
|
||||
@ -476,16 +482,22 @@ syn match vimNormCmds contained ".*$"
|
||||
|
||||
" Syntax: {{{2
|
||||
"=======
|
||||
syn match vimGroupList contained "@\=[^ \t,]*" contains=vimGroupSpecial,vimPatSep
|
||||
syn match vimGroupList contained "@\=[^ \t,]*," nextgroup=vimGroupList contains=vimGroupSpecial,vimPatSep
|
||||
syn match vimGroupList contained "[^[:space:],]\+\%(\s*,\s*[^[:space:],]\+\)*" contains=vimGroupSpecial
|
||||
syn region vimGroupList contained start=/^\s*["#]\\ \|^\s*\\\|[^[:space:],]\+\s*,/ skip=/\s*\n\s*\\\|\s*\n\s*["#]\\ \|^\s*\\\|^\s*["#]\\ / end=/[^[:space:],]\s*$\|[^[:space:],]\ze\s\+\w/ contains=@vimContinue,vimGroupSpecial
|
||||
syn keyword vimGroupSpecial contained ALL ALLBUT CONTAINED TOP
|
||||
|
||||
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimsynerror")
|
||||
syn match vimSynError contained "\i\+"
|
||||
syn match vimSynError contained "\i\+=" nextgroup=vimGroupList
|
||||
endif
|
||||
syn match vimSynContains contained "\<contain\(s\|edin\)=" nextgroup=vimGroupList
|
||||
syn match vimSynKeyContainedin contained "\<containedin=" nextgroup=vimGroupList
|
||||
syn match vimSynNextgroup contained "nextgroup=" nextgroup=vimGroupList
|
||||
syn match vimSynContains contained "\<contain\%(s\|edin\)=" skipwhite skipnl nextgroup=vimGroupList
|
||||
syn match vimSynKeyContainedin contained "\<containedin=" skipwhite skipnl nextgroup=vimGroupList
|
||||
syn match vimSynNextgroup contained "\<nextgroup=" skipwhite skipnl nextgroup=vimGroupList
|
||||
if has("conceal")
|
||||
" no whitespace allowed after '='
|
||||
syn match vimSynCchar contained "\<cchar=" nextgroup=vimSynCcharValue
|
||||
syn match vimSynCcharValue contained "\S"
|
||||
endif
|
||||
|
||||
syn match vimSyntax "\<sy\%[ntax]\>" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment,vim9Comment
|
||||
syn match vimAuSyntax contained "\s+sy\%[ntax]" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment,vim9Comment
|
||||
@ -503,9 +515,9 @@ syn keyword vimSynType contained clear skipwhite nextgroup=vimGroupList
|
||||
|
||||
" Syntax: cluster {{{2
|
||||
syn keyword vimSynType contained cluster skipwhite nextgroup=vimClusterName
|
||||
syn region vimClusterName contained matchgroup=vimGroupName start="\h\w*" skip="\\\\\|\\|" matchgroup=vimSep end="$\||" contains=vimGroupAdd,vimGroupRem,vimSynContains,vimSynError
|
||||
syn match vimGroupAdd contained "add=" nextgroup=vimGroupList
|
||||
syn match vimGroupRem contained "remove=" nextgroup=vimGroupList
|
||||
syn region vimClusterName contained keepend matchgroup=vimGroupName start="\h\w*\>" skip=+\\\\\|\\\|\n\s*\\\|\n\s*"\\ + matchgroup=vimCmdSep end="$\||" contains=@vimContinue,vimGroupAdd,vimGroupRem,vimSynContains,vimSynError
|
||||
syn match vimGroupAdd contained keepend "\<add=" skipwhite skipnl nextgroup=vimGroupList
|
||||
syn match vimGroupRem contained keepend "\<remove=" skipwhite skipnl nextgroup=vimGroupList
|
||||
syn cluster vimFuncBodyList add=vimSynType,vimGroupAdd,vimGroupRem
|
||||
|
||||
" Syntax: foldlevel {{{2
|
||||
@ -525,35 +537,31 @@ syn keyword vimSynType contained include skipwhite nextgroup=vimGroupList
|
||||
syn cluster vimFuncBodyList add=vimSynType
|
||||
|
||||
" Syntax: keyword {{{2
|
||||
syn cluster vimSynKeyGroup contains=vimSynNextgroup,vimSynKeyOpt,vimSynKeyContainedin
|
||||
syn cluster vimSynKeyGroup contains=@vimContinue,vimSynCchar,vimSynNextgroup,vimSynKeyOpt,vimSynKeyContainedin
|
||||
syn keyword vimSynType contained keyword skipwhite nextgroup=vimSynKeyRegion
|
||||
syn region vimSynKeyRegion contained oneline keepend matchgroup=vimGroupName start="\h\w*" skip="\\\\\|\\|" matchgroup=vimSep end="|\|$" contains=@vimSynKeyGroup
|
||||
syn region vimSynKeyRegion contained keepend matchgroup=vimGroupName start="\h\w*\>" skip=+\\\\\|\\|\|\n\s*\\\|\n\s*"\\ + matchgroup=vimCmdSep end="|\|$" contains=@vimSynKeyGroup
|
||||
syn match vimSynKeyOpt contained "\%#=1\<\(conceal\|contained\|transparent\|skipempty\|skipwhite\|skipnl\)\>"
|
||||
syn cluster vimFuncBodyList add=vimSynType
|
||||
|
||||
" Syntax: match {{{2
|
||||
syn cluster vimSynMtchGroup contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation,vim9Comment
|
||||
syn cluster vimSynMtchGroup contains=@vimContinue,vimSynCchar,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation,vimMtchComment
|
||||
syn keyword vimSynType contained match skipwhite nextgroup=vimSynMatchRegion
|
||||
syn region vimSynMatchRegion contained keepend matchgroup=vimGroupName start="\h\w*" matchgroup=vimSep end="|\|$" contains=@vimSynMtchGroup
|
||||
syn region vimSynMatchRegion contained keepend matchgroup=vimGroupName start="\h\w*\>" skip=+\\\\\|\\|\|\n\s*\\\|\n\s*"\\ + matchgroup=vimCmdSep end="|\|$" contains=@vimSynMtchGroup
|
||||
syn match vimSynMtchOpt contained "\%#=1\<\(conceal\|transparent\|contained\|excludenl\|keepend\|skipempty\|skipwhite\|display\|extend\|skipnl\|fold\)\>"
|
||||
if has("conceal")
|
||||
syn match vimSynMtchOpt contained "\<cchar=" nextgroup=vimSynMtchCchar
|
||||
syn match vimSynMtchCchar contained "\S"
|
||||
endif
|
||||
syn cluster vimFuncBodyList add=vimSynMtchGroup
|
||||
|
||||
" Syntax: off and on {{{2
|
||||
syn keyword vimSynType contained enable list manual off on reset
|
||||
|
||||
" Syntax: region {{{2
|
||||
syn cluster vimSynRegPatGroup contains=vimPatSep,vimNotPatSep,vimSynPatRange,vimSynNotPatRange,vimSubstSubstr,vimPatRegion,vimPatSepErr,vimNotation
|
||||
syn cluster vimSynRegGroup contains=vimSynContains,vimSynNextgroup,vimSynRegOpt,vimSynReg,vimSynMtchGrp
|
||||
syn cluster vimSynRegPatGroup contains=@vimContinue,vimPatSep,vimNotPatSep,vimSynPatRange,vimSynNotPatRange,vimSubstSubstr,vimPatRegion,vimPatSepErr,vimNotation
|
||||
syn cluster vimSynRegGroup contains=@vimContinue,vimSynCchar,vimSynContains,vimSynNextgroup,vimSynRegOpt,vimSynReg,vimSynMtchGrp
|
||||
syn keyword vimSynType contained region skipwhite nextgroup=vimSynRegion
|
||||
syn region vimSynRegion contained keepend matchgroup=vimGroupName start="\h\w*" skip="\\\\\|\\|" end="|\|$" contains=@vimSynRegGroup
|
||||
syn region vimSynRegion contained keepend matchgroup=vimGroupName start="\h\w*" skip=+\\\\\|\\\|\n\s*\\\|\n\s*"\\ + end="|\|$" contains=@vimSynRegGroup
|
||||
syn match vimSynRegOpt contained "\%#=1\<\(conceal\(ends\)\=\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|keepend\|oneline\|extend\|skipnl\|fold\)\>"
|
||||
syn match vimSynReg contained "\(start\|skip\|end\)="he=e-1 nextgroup=vimSynRegPat
|
||||
syn match vimSynReg contained "\<\%(start\|skip\|end\)=" nextgroup=vimSynRegPat
|
||||
syn match vimSynMtchGrp contained "matchgroup=" nextgroup=vimGroup,vimHLGroup,vimOnlyHLGroup,nvimHLGroup
|
||||
syn region vimSynRegPat contained extend start="\z([-`~!@#$%^&*_=+;:'",./?]\)" skip="\\\\\|\\\z1" end="\z1" contains=@vimSynRegPatGroup skipwhite nextgroup=vimSynPatMod,vimSynReg
|
||||
syn region vimSynRegPat contained extend start="\z([-`~!@#$%^&*_=+;:'",./?]\)" skip=/\\\\\|\\\z1\|\n\s*\\\|\n\s*"\\ / end="\z1" contains=@vimSynRegPatGroup skipwhite nextgroup=vimSynPatMod,vimSynReg
|
||||
syn match vimSynPatMod contained "\%#=1\(hs\|ms\|me\|hs\|he\|rs\|re\)=[se]\([-+]\d\+\)\="
|
||||
syn match vimSynPatMod contained "\%#=1\(hs\|ms\|me\|hs\|he\|rs\|re\)=[se]\([-+]\d\+\)\=," nextgroup=vimSynPatMod
|
||||
syn match vimSynPatMod contained "lc=\d\+"
|
||||
@ -642,10 +650,14 @@ syn match vimCtrlChar "[--]"
|
||||
|
||||
" Beginners - Patterns that involve ^ {{{2
|
||||
" =========
|
||||
syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle
|
||||
syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle,vimComment
|
||||
syn match vimLineComment +^[ \t:]*"\("[^"]*"\|[^"]\)*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle
|
||||
syn match vim9LineComment +^[ \t:]\+#.*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle
|
||||
syn match vimCommentTitle '"\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vimCommentTitleLeader,vimTodo,@vimCommentGroup
|
||||
syn match vimContinue "^\s*\\"
|
||||
" Note: Look-behind to work around nextgroup skipnl consuming leading whitespace and preventing a match
|
||||
syn match vimContinue "^\s*\zs\\"
|
||||
syn match vimContinueComment '^\s*\zs["#]\\ .*' contained
|
||||
syn cluster vimContinue contains=vimContinue,vimContinueComment
|
||||
syn region vimString start="^\s*\\\z(['"]\)" skip='\\\\\|\\\z1' end="\z1" oneline keepend contains=@vimStringGroup,vimContinue
|
||||
syn match vimCommentTitleLeader '"\s\+'ms=s+1 contained
|
||||
|
||||
@ -889,6 +901,7 @@ if !exists("skip_vim_syntax_inits")
|
||||
hi def link vimCondHL vimCommand
|
||||
hi def link vimConst vimCommand
|
||||
hi def link vimContinue Special
|
||||
hi def link vimContinueComment vimComment
|
||||
hi def link vimCtrlChar SpecialChar
|
||||
hi def link vimEchoHLNone vimGroup
|
||||
hi def link vimEchoHL vimCommand
|
||||
@ -984,6 +997,7 @@ if !exists("skip_vim_syntax_inits")
|
||||
hi def link vimStringCont vimString
|
||||
hi def link vimString String
|
||||
hi def link vimStringEnd vimString
|
||||
hi def link vimStringInterpolationBrace vimEscape
|
||||
hi def link vimSubst1 vimSubst
|
||||
hi def link vimSubstDelim Delimiter
|
||||
hi def link vimSubstFlags Special
|
||||
@ -1004,6 +1018,8 @@ if !exists("skip_vim_syntax_inits")
|
||||
hi def link vimSynFoldMethod Type
|
||||
hi def link vimSynKeyContainedin vimSynContains
|
||||
hi def link vimSynKeyOpt vimSynOption
|
||||
hi def link vimSynCchar vimSynOption
|
||||
hi def link vimSynCcharValue Character
|
||||
hi def link vimSynMtchGrp vimSynOption
|
||||
hi def link vimSynMtchOpt vimSynOption
|
||||
hi def link vimSynNextgroup vimSynOption
|
||||
|
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env -S nvim -l
|
||||
|
||||
-- Generator for various vimdoc and Lua type files
|
||||
|
||||
local DEP_API_METADATA = 'build/api_metadata.mpack'
|
||||
@ -17,6 +19,31 @@ local DEP_API_DOC = 'runtime/doc/api.mpack'
|
||||
--- @field remote boolean
|
||||
--- @field since integer
|
||||
|
||||
local LUA_API_RETURN_OVERRIDES = {
|
||||
nvim_buf_get_command = 'table<string,vim.api.keyset.command_info>',
|
||||
nvim_buf_get_extmark_by_id = 'vim.api.keyset.get_extmark_item',
|
||||
nvim_buf_get_extmarks = 'vim.api.keyset.get_extmark_item[]',
|
||||
nvim_buf_get_keymap = 'vim.api.keyset.keymap[]',
|
||||
nvim_get_autocmds = 'vim.api.keyset.get_autocmds.ret[]',
|
||||
nvim_get_color_map = 'table<string,integer>',
|
||||
nvim_get_command = 'table<string,vim.api.keyset.command_info>',
|
||||
nvim_get_keymap = 'vim.api.keyset.keymap[]',
|
||||
nvim_get_mark = 'vim.api.keyset.get_mark',
|
||||
|
||||
-- Can also return table<string,vim.api.keyset.hl_info>, however we need to
|
||||
-- pick one to get some benefit.
|
||||
-- REVISIT lewrus01 (26/01/24): we can maybe add
|
||||
-- @overload fun(ns: integer, {}): table<string,vim.api.keyset.hl_info>
|
||||
nvim_get_hl = 'vim.api.keyset.hl_info',
|
||||
|
||||
nvim_get_mode = 'vim.api.keyset.get_mode',
|
||||
nvim_get_namespaces = 'table<string,integer>',
|
||||
nvim_get_option_info = 'vim.api.keyset.get_option_info',
|
||||
nvim_get_option_info2 = 'vim.api.keyset.get_option_info',
|
||||
nvim_parse_cmd = 'vim.api.keyset.parse_cmd',
|
||||
nvim_win_get_config = 'vim.api.keyset.float_config',
|
||||
}
|
||||
|
||||
local LUA_META_HEADER = {
|
||||
'--- @meta _',
|
||||
'-- THIS FILE IS GENERATED',
|
||||
@ -289,11 +316,9 @@ local function render_api_meta(_f, fun, write)
|
||||
end
|
||||
end
|
||||
if fun.returns ~= '' then
|
||||
if fun.returns_desc then
|
||||
write('--- @return ' .. fun.returns .. ' : ' .. fun.returns_desc)
|
||||
else
|
||||
write('--- @return ' .. fun.returns)
|
||||
end
|
||||
local ret_desc = fun.returns_desc and ' : ' .. fun.returns_desc or ''
|
||||
local ret = LUA_API_RETURN_OVERRIDES[fun.name] or fun.returns
|
||||
write('--- @return ' .. ret .. ret_desc)
|
||||
end
|
||||
local param_str = table.concat(param_names, ', ')
|
||||
|
||||
|
@ -2,32 +2,38 @@
|
||||
--
|
||||
-- NOTE: :helptags checks for duplicate tags, whereas this script checks _links_ (to tags).
|
||||
--
|
||||
-- USAGE (For CI/local testing purposes): Simply `make lintdoc` or `scripts/lintdoc.lua`, which
|
||||
-- basically does the following:
|
||||
-- 1. :helptags ALL
|
||||
-- 2. nvim -V1 -es +"lua require('scripts.gen_help_html').run_validate()" +q
|
||||
-- 3. nvim -V1 -es +"lua require('scripts.gen_help_html').test_gen()" +q
|
||||
--
|
||||
-- USAGE (GENERATE HTML):
|
||||
-- 1. Run `make helptags` first; this script depends on vim.fn.taglist().
|
||||
-- 2. nvim -V1 -es --clean +"lua require('scripts.gen_help_html').gen('./build/runtime/doc/', 'target/dir/')"
|
||||
-- 1. `:helptags ALL` first; this script depends on vim.fn.taglist().
|
||||
-- 2. nvim -V1 -es --clean +"lua require('scripts.gen_help_html').gen('./runtime/doc', 'target/dir/')" +q
|
||||
-- - Read the docstring at gen().
|
||||
-- 3. cd target/dir/ && jekyll serve --host 0.0.0.0
|
||||
-- 4. Visit http://localhost:4000/…/help.txt.html
|
||||
--
|
||||
-- USAGE (VALIDATE):
|
||||
-- 1. nvim -V1 -es +"lua require('scripts.gen_help_html').validate()"
|
||||
-- 1. nvim -V1 -es +"lua require('scripts.gen_help_html').validate('./runtime/doc')" +q
|
||||
-- - validate() is 10x faster than gen(), so it is used in CI.
|
||||
--
|
||||
-- SELF-TEST MODE:
|
||||
-- 1. nvim -V1 -es +"lua require('scripts.gen_help_html')._test()"
|
||||
-- 1. nvim -V1 -es +"lua require('scripts.gen_help_html')._test()" +q
|
||||
--
|
||||
-- NOTES:
|
||||
-- * gen() and validate() are the primary entrypoints. validate() only exists because gen() is too
|
||||
-- slow (~1 min) to run in per-commit CI.
|
||||
-- * gen() and validate() are the primary (programmatic) entrypoints. validate() only exists
|
||||
-- because gen() is too slow (~1 min) to run in per-commit CI.
|
||||
-- * visit_node() is the core function used by gen() to traverse the document tree and produce HTML.
|
||||
-- * visit_validate() is the core function used by validate().
|
||||
-- * Files in `new_layout` will be generated with a "flow" layout instead of preformatted/fixed-width layout.
|
||||
|
||||
local tagmap = nil
|
||||
local helpfiles = nil
|
||||
local invalid_links = {}
|
||||
local invalid_urls = {}
|
||||
local invalid_spelling = {}
|
||||
local tagmap = nil ---@type table<string, string>
|
||||
local helpfiles = nil ---@type string[]
|
||||
local invalid_links = {} ---@type table<string, any>
|
||||
local invalid_urls = {} ---@type table<string, any>
|
||||
local invalid_spelling = {} ---@type table<string, table<string, string>>
|
||||
local spell_dict = {
|
||||
Neovim = 'Nvim',
|
||||
NeoVim = 'Nvim',
|
||||
@ -36,9 +42,14 @@ local spell_dict = {
|
||||
VimL = 'Vimscript',
|
||||
vimL = 'Vimscript',
|
||||
viml = 'Vimscript',
|
||||
['tree-sitter'] = 'treesitter',
|
||||
['Tree-sitter'] = 'Treesitter',
|
||||
}
|
||||
--- specify the list of keywords to ignore (i.e. allow), or true to disable spell check completely.
|
||||
--- @type table<string, true|string[]>
|
||||
local spell_ignore_files = {
|
||||
['backers.txt'] = 'true',
|
||||
['backers.txt'] = true,
|
||||
['news.txt'] = { 'tree-sitter' }, -- in news, may refer to the upstream "tree-sitter" library
|
||||
}
|
||||
local language = nil
|
||||
|
||||
@ -102,8 +113,9 @@ local function tofile(fname, text)
|
||||
end
|
||||
end
|
||||
|
||||
---@type fun(s: string): string
|
||||
local function html_esc(s)
|
||||
return s:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
|
||||
return (s:gsub('&', '&'):gsub('<', '<'):gsub('>', '>'))
|
||||
end
|
||||
|
||||
local function url_encode(s)
|
||||
@ -118,7 +130,7 @@ local function url_encode(s)
|
||||
end
|
||||
|
||||
local function expandtabs(s)
|
||||
return s:gsub('\t', (' '):rep(8))
|
||||
return s:gsub('\t', (' '):rep(8)) --[[ @as string ]]
|
||||
end
|
||||
|
||||
local function to_titlecase(s)
|
||||
@ -142,6 +154,7 @@ local function is_blank(s)
|
||||
return not not s:find([[^[\t ]*$]])
|
||||
end
|
||||
|
||||
---@type fun(s: string, dir?:0|1|2): string
|
||||
local function trim(s, dir)
|
||||
return vim.fn.trim(s, '\r\t\n ', dir or 0)
|
||||
end
|
||||
@ -150,7 +163,8 @@ end
|
||||
---
|
||||
--- TODO: fix this in the parser instead... https://github.com/neovim/tree-sitter-vimdoc
|
||||
---
|
||||
--- @returns (fixed_url, removed_chars) where `removed_chars` is in the order found in the input.
|
||||
--- @param url string
|
||||
--- @return string, string (fixed_url, removed_chars) where `removed_chars` is in the order found in the input.
|
||||
local function fix_url(url)
|
||||
local removed_chars = ''
|
||||
local fixed_url = url
|
||||
@ -262,6 +276,9 @@ local function trim_indent(s)
|
||||
end
|
||||
|
||||
--- Gets raw buffer text in the node's range (+/- an offset), as a newline-delimited string.
|
||||
---@param node TSNode
|
||||
---@param bufnr integer
|
||||
---@param offset integer
|
||||
local function getbuflinestr(node, bufnr, offset)
|
||||
local line1, _, line2, _ = node:range()
|
||||
line1 = line1 - offset
|
||||
@ -272,8 +289,12 @@ end
|
||||
|
||||
--- Gets the whitespace just before `node` from the raw buffer text.
|
||||
--- Needed for preformatted `old` lines.
|
||||
---@param node TSNode
|
||||
---@param bufnr integer
|
||||
---@return string
|
||||
local function getws(node, bufnr)
|
||||
local line1, c1, line2, _ = node:range()
|
||||
---@type string
|
||||
local raw = vim.fn.getbufline(bufnr, line1 + 1, line2 + 1)[1]
|
||||
local text_before = raw:sub(1, c1)
|
||||
local leading_ws = text_before:match('%s+$') or ''
|
||||
@ -310,9 +331,10 @@ local function ignore_parse_error(fname, s)
|
||||
return s:find("^[`'|*]")
|
||||
end
|
||||
|
||||
---@param node TSNode
|
||||
local function has_ancestor(node, ancestor_name)
|
||||
local p = node
|
||||
while true do
|
||||
local p = node ---@type TSNode?
|
||||
while p do
|
||||
p = p:parent()
|
||||
if not p or p:type() == 'help_file' then
|
||||
break
|
||||
@ -324,6 +346,7 @@ local function has_ancestor(node, ancestor_name)
|
||||
end
|
||||
|
||||
--- Gets the first matching child node matching `name`.
|
||||
---@param node TSNode
|
||||
local function first(node, name)
|
||||
for c, _ in node:iter_children() do
|
||||
if c:named() and c:type() == name then
|
||||
@ -357,6 +380,11 @@ local function validate_url(text, fname)
|
||||
end
|
||||
|
||||
--- Traverses the tree at `root` and checks that |tag| links point to valid helptags.
|
||||
---@param root TSNode
|
||||
---@param level integer
|
||||
---@param lang_tree TSTree
|
||||
---@param opt table
|
||||
---@param stats table
|
||||
local function visit_validate(root, level, lang_tree, opt, stats)
|
||||
level = level or 0
|
||||
local node_name = (root.named and root:named()) and root:type() or nil
|
||||
@ -391,9 +419,18 @@ local function visit_validate(root, level, lang_tree, opt, stats)
|
||||
then
|
||||
local text_nopunct = vim.fn.trim(text, '.,', 0) -- Ignore some punctuation.
|
||||
local fname_basename = assert(vim.fs.basename(opt.fname))
|
||||
if spell_dict[text_nopunct] and not spell_ignore_files[fname_basename] then
|
||||
invalid_spelling[text_nopunct] = invalid_spelling[text_nopunct] or {}
|
||||
invalid_spelling[text_nopunct][fname_basename] = node_text(root:parent())
|
||||
if spell_dict[text_nopunct] then
|
||||
local should_ignore = (
|
||||
spell_ignore_files[fname_basename] == true
|
||||
or vim.tbl_contains(
|
||||
(spell_ignore_files[fname_basename] or {}) --[[ @as string[] ]],
|
||||
text_nopunct
|
||||
)
|
||||
)
|
||||
if not should_ignore then
|
||||
invalid_spelling[text_nopunct] = invalid_spelling[text_nopunct] or {}
|
||||
invalid_spelling[text_nopunct][fname_basename] = node_text(root:parent())
|
||||
end
|
||||
end
|
||||
elseif node_name == 'url' then
|
||||
local fixed_url, _ = fix_url(trim(text))
|
||||
@ -405,6 +442,8 @@ end
|
||||
|
||||
-- Fix tab alignment issues caused by concealed characters like |, `, * in tags
|
||||
-- and code blocks.
|
||||
---@param text string
|
||||
---@param next_node_text string
|
||||
local function fix_tab_after_conceal(text, next_node_text)
|
||||
-- Vim tabs take into account the two concealed characters even though they
|
||||
-- are invisible, so we need to add back in the two spaces if this is
|
||||
@ -415,7 +454,18 @@ local function fix_tab_after_conceal(text, next_node_text)
|
||||
return text
|
||||
end
|
||||
|
||||
---@class (exact) nvim.gen_help_html.heading
|
||||
---@field name string
|
||||
---@field subheadings nvim.gen_help_html.heading[]
|
||||
---@field tag string
|
||||
|
||||
-- Generates HTML from node `root` recursively.
|
||||
---@param root TSNode
|
||||
---@param level integer
|
||||
---@param lang_tree TSTree
|
||||
---@param headings nvim.gen_help_html.heading[]
|
||||
---@param opt table
|
||||
---@param stats table
|
||||
local function visit_node(root, level, lang_tree, headings, opt, stats)
|
||||
level = level or 0
|
||||
|
||||
@ -433,7 +483,6 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
|
||||
-- Parent kind (string).
|
||||
local parent = root:parent() and root:parent():type() or nil
|
||||
local text = ''
|
||||
local trimmed
|
||||
-- Gets leading whitespace of `node`.
|
||||
local function ws(node)
|
||||
node = node or root
|
||||
@ -451,6 +500,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
|
||||
return string.format('%s%s', ws_, vim.treesitter.get_node_text(node, opt.buf))
|
||||
end
|
||||
|
||||
local trimmed ---@type string
|
||||
if root:named_child_count() == 0 or node_name == 'ERROR' then
|
||||
text = node_text()
|
||||
trimmed = html_esc(trim(text))
|
||||
@ -485,7 +535,9 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
|
||||
local tagname = tagnode and url_encode(node_text(tagnode:child(1), false))
|
||||
or to_heading_tag(hname)
|
||||
if node_name == 'h1' or #headings == 0 then
|
||||
table.insert(headings, { name = hname, subheadings = {}, tag = tagname })
|
||||
---@type nvim.gen_help_html.heading
|
||||
local heading = { name = hname, subheadings = {}, tag = tagname }
|
||||
headings[#headings + 1] = heading
|
||||
else
|
||||
table.insert(
|
||||
headings[#headings].subheadings,
|
||||
@ -575,7 +627,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
|
||||
if is_blank(text) then
|
||||
return ''
|
||||
end
|
||||
local code
|
||||
local code ---@type string
|
||||
if language then
|
||||
code = ('<pre><code class="language-%s">%s</code></pre>'):format(
|
||||
language,
|
||||
@ -656,8 +708,10 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_helpfiles(include)
|
||||
local dir = './build/runtime/doc'
|
||||
--- @param dir string e.g. '$VIMRUNTIME/doc'
|
||||
--- @param include string[]|nil
|
||||
--- @return string[]
|
||||
local function get_helpfiles(dir, include)
|
||||
local rv = {}
|
||||
for f, type in vim.fs.dir(dir) do
|
||||
if
|
||||
@ -698,13 +752,15 @@ end
|
||||
---
|
||||
--- @param fname string help file to parse
|
||||
--- @param parser_path string? path to non-default vimdoc.so
|
||||
--- @returns lang_tree, bufnr
|
||||
--- @return LanguageTree, integer (lang_tree, bufnr)
|
||||
local function parse_buf(fname, parser_path)
|
||||
local buf
|
||||
local buf ---@type integer
|
||||
if type(fname) == 'string' then
|
||||
vim.cmd('split ' .. vim.fn.fnameescape(fname)) -- Filename.
|
||||
buf = vim.api.nvim_get_current_buf()
|
||||
else
|
||||
-- Left for debugging
|
||||
---@diagnostic disable-next-line: no-unknown
|
||||
buf = fname
|
||||
vim.cmd('sbuffer ' .. tostring(fname)) -- Buffer number.
|
||||
end
|
||||
@ -721,7 +777,7 @@ end
|
||||
---
|
||||
--- @param fname string help file to validate
|
||||
--- @param parser_path string? path to non-default vimdoc.so
|
||||
--- @returns { invalid_links: number, parse_errors: string[] }
|
||||
--- @return { invalid_links: number, parse_errors: string[] }
|
||||
local function validate_one(fname, parser_path)
|
||||
local stats = {
|
||||
parse_errors = {},
|
||||
@ -742,7 +798,8 @@ end
|
||||
--- @param old boolean Preformat paragraphs (for old :help files which are full of arbitrary whitespace)
|
||||
--- @param parser_path string? path to non-default vimdoc.so
|
||||
---
|
||||
--- @returns html, stats
|
||||
--- @return string html
|
||||
--- @return table stats
|
||||
local function gen_one(fname, to_fname, old, commit, parser_path)
|
||||
local stats = {
|
||||
noise_lines = {},
|
||||
@ -750,6 +807,7 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
|
||||
first_tags = {}, -- Track the first few tags in doc.
|
||||
}
|
||||
local lang_tree, buf = parse_buf(fname, parser_path)
|
||||
---@type nvim.gen_help_html.heading[]
|
||||
local headings = {} -- Headings (for ToC). 2-dimensional: h1 contains h2/h3.
|
||||
local title = to_titlecase(basename_noext(fname))
|
||||
|
||||
@ -883,6 +941,7 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
|
||||
main
|
||||
)
|
||||
|
||||
---@type string
|
||||
local toc = [[
|
||||
<div class="col-narrow toc">
|
||||
<div><a href="index.html">Main</a></div>
|
||||
@ -896,6 +955,7 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
|
||||
n = n + 1 + #h1.subheadings
|
||||
end
|
||||
for _, h1 in ipairs(headings) do
|
||||
---@type string
|
||||
toc = toc .. ('<div class="help-toc-h1"><a href="#%s">%s</a>\n'):format(h1.tag, h1.name)
|
||||
if n < 30 or #headings < 10 then -- Show subheadings only if there aren't too many.
|
||||
for _, h2 in ipairs(h1.subheadings) do
|
||||
@ -1113,25 +1173,34 @@ local function gen_css(fname)
|
||||
tofile(fname, css)
|
||||
end
|
||||
|
||||
function M._test()
|
||||
tagmap = get_helptags('./build/runtime/doc')
|
||||
helpfiles = get_helpfiles()
|
||||
-- Testing
|
||||
|
||||
local function ok(cond, expected, actual)
|
||||
local function ok(cond, expected, actual, message)
|
||||
assert(
|
||||
(not expected and not actual) or (expected and actual),
|
||||
'if "expected" is given, "actual" is also required'
|
||||
)
|
||||
if expected then
|
||||
assert(
|
||||
(not expected and not actual) or (expected and actual),
|
||||
'if "expected" is given, "actual" is also required'
|
||||
cond,
|
||||
('%sexpected %s, got: %s'):format(
|
||||
message and (message .. '\n') or '',
|
||||
vim.inspect(expected),
|
||||
vim.inspect(actual)
|
||||
)
|
||||
)
|
||||
if expected then
|
||||
assert(cond, ('expected %s, got: %s'):format(vim.inspect(expected), vim.inspect(actual)))
|
||||
return cond
|
||||
else
|
||||
return assert(cond)
|
||||
end
|
||||
end
|
||||
local function eq(expected, actual)
|
||||
return ok(expected == actual, expected, actual)
|
||||
return cond
|
||||
else
|
||||
return assert(cond)
|
||||
end
|
||||
end
|
||||
local function eq(expected, actual, message)
|
||||
return ok(vim.deep_equal(expected, actual), expected, actual, message)
|
||||
end
|
||||
|
||||
function M._test()
|
||||
tagmap = get_helptags('$VIMRUNTIME/doc')
|
||||
helpfiles = get_helpfiles(vim.fn.expand('$VIMRUNTIME/doc'))
|
||||
|
||||
ok(vim.tbl_count(tagmap) > 3000, '>3000', vim.tbl_count(tagmap))
|
||||
ok(
|
||||
@ -1169,20 +1238,25 @@ function M._test()
|
||||
eq('https://example.com', fixed_url)
|
||||
eq('', removed_chars)
|
||||
|
||||
print('all tests passed')
|
||||
print('all tests passed.\n')
|
||||
end
|
||||
|
||||
--- @class nvim.gen_help_html.gen_result
|
||||
--- @field helpfiles string[] list of generated HTML files, from the source docs {include}
|
||||
--- @field err_count integer number of parse errors in :help docs
|
||||
--- @field invalid_links table<string, any>
|
||||
|
||||
--- Generates HTML from :help docs located in `help_dir` and writes the result in `to_dir`.
|
||||
---
|
||||
--- Example:
|
||||
---
|
||||
--- gen('./build/runtime/doc', '/path/to/neovim.github.io/_site/doc/', {'api.txt', 'autocmd.txt', 'channel.txt'}, nil)
|
||||
--- gen('$VIMRUNTIME/doc', '/path/to/neovim.github.io/_site/doc/', {'api.txt', 'autocmd.txt', 'channel.txt'}, nil)
|
||||
---
|
||||
--- @param help_dir string Source directory containing the :help files. Must run `make helptags` first.
|
||||
--- @param to_dir string Target directory where the .html files will be written.
|
||||
--- @param include table|nil Process only these filenames. Example: {'api.txt', 'autocmd.txt', 'channel.txt'}
|
||||
--- @param include string[]|nil Process only these filenames. Example: {'api.txt', 'autocmd.txt', 'channel.txt'}
|
||||
---
|
||||
--- @returns info dict
|
||||
--- @return nvim.gen_help_html.gen_result result
|
||||
function M.gen(help_dir, to_dir, include, commit, parser_path)
|
||||
vim.validate {
|
||||
help_dir = {
|
||||
@ -1207,7 +1281,7 @@ function M.gen(help_dir, to_dir, include, commit, parser_path)
|
||||
local err_count = 0
|
||||
ensure_runtimepath()
|
||||
tagmap = get_helptags(vim.fn.expand(help_dir))
|
||||
helpfiles = get_helpfiles(include)
|
||||
helpfiles = get_helpfiles(help_dir, include)
|
||||
to_dir = vim.fn.expand(to_dir)
|
||||
parser_path = parser_path and vim.fn.expand(parser_path) or nil
|
||||
|
||||
@ -1233,6 +1307,7 @@ function M.gen(help_dir, to_dir, include, commit, parser_path)
|
||||
print(('total errors: %d'):format(err_count))
|
||||
print(('invalid tags:\n%s'):format(vim.inspect(invalid_links)))
|
||||
|
||||
--- @type nvim.gen_help_html.gen_result
|
||||
return {
|
||||
helpfiles = helpfiles,
|
||||
err_count = err_count,
|
||||
@ -1240,13 +1315,21 @@ function M.gen(help_dir, to_dir, include, commit, parser_path)
|
||||
}
|
||||
end
|
||||
|
||||
-- Validates all :help files found in `help_dir`:
|
||||
-- - checks that |tag| links point to valid helptags.
|
||||
-- - recursively counts parse errors ("ERROR" nodes)
|
||||
--
|
||||
-- This is 10x faster than gen(), for use in CI.
|
||||
--
|
||||
-- @returns results dict
|
||||
--- @class nvim.gen_help_html.validate_result
|
||||
--- @field helpfiles integer number of generated helpfiles
|
||||
--- @field err_count integer number of parse errors
|
||||
--- @field parse_errors table<string, string[]>
|
||||
--- @field invalid_links table<string, any> invalid tags in :help docs
|
||||
--- @field invalid_urls table<string, any> invalid URLs in :help docs
|
||||
--- @field invalid_spelling table<string, table<string, string>> invalid spelling in :help docs
|
||||
|
||||
--- Validates all :help files found in `help_dir`:
|
||||
--- - checks that |tag| links point to valid helptags.
|
||||
--- - recursively counts parse errors ("ERROR" nodes)
|
||||
---
|
||||
--- This is 10x faster than gen(), for use in CI.
|
||||
---
|
||||
--- @return nvim.gen_help_html.validate_result result
|
||||
function M.validate(help_dir, include, parser_path)
|
||||
vim.validate {
|
||||
help_dir = {
|
||||
@ -1265,15 +1348,15 @@ function M.validate(help_dir, include, parser_path)
|
||||
'valid vimdoc.{so,dll} filepath',
|
||||
},
|
||||
}
|
||||
local err_count = 0
|
||||
local files_to_errors = {}
|
||||
local err_count = 0 ---@type integer
|
||||
local files_to_errors = {} ---@type table<string, string[]>
|
||||
ensure_runtimepath()
|
||||
tagmap = get_helptags(vim.fn.expand(help_dir))
|
||||
helpfiles = get_helpfiles(include)
|
||||
helpfiles = get_helpfiles(help_dir, include)
|
||||
parser_path = parser_path and vim.fn.expand(parser_path) or nil
|
||||
|
||||
for _, f in ipairs(helpfiles) do
|
||||
local helpfile = vim.fs.basename(f)
|
||||
local helpfile = assert(vim.fs.basename(f))
|
||||
local rv = validate_one(f, parser_path)
|
||||
print(('validated (%-4s errors): %s'):format(#rv.parse_errors, helpfile))
|
||||
if #rv.parse_errors > 0 then
|
||||
@ -1285,14 +1368,65 @@ function M.validate(help_dir, include, parser_path)
|
||||
err_count = err_count + #rv.parse_errors
|
||||
end
|
||||
|
||||
---@type nvim.gen_help_html.validate_result
|
||||
return {
|
||||
helpfiles = #helpfiles,
|
||||
err_count = err_count,
|
||||
parse_errors = files_to_errors,
|
||||
invalid_links = invalid_links,
|
||||
invalid_urls = invalid_urls,
|
||||
invalid_spelling = invalid_spelling,
|
||||
parse_errors = files_to_errors,
|
||||
}
|
||||
end
|
||||
|
||||
--- Validates vimdoc files on $VIMRUNTIME. and print human-readable error messages if fails.
|
||||
---
|
||||
--- If this fails, try these steps (in order):
|
||||
--- 1. Fix/cleanup the :help docs.
|
||||
--- 2. Fix the parser: https://github.com/neovim/tree-sitter-vimdoc
|
||||
--- 3. File a parser bug, and adjust the tolerance of this test in the meantime.
|
||||
---
|
||||
--- @param help_dir? string e.g. '$VIMRUNTIME/doc' or './runtime/doc'
|
||||
function M.run_validate(help_dir)
|
||||
help_dir = vim.fn.expand(help_dir or '$VIMRUNTIME/doc')
|
||||
print('doc path = ' .. vim.uv.fs_realpath(help_dir))
|
||||
|
||||
local rv = M.validate(help_dir)
|
||||
|
||||
-- Check that we actually found helpfiles.
|
||||
ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles)
|
||||
|
||||
eq({}, rv.parse_errors, 'no parse errors')
|
||||
eq(0, rv.err_count, 'no parse errors')
|
||||
eq({}, rv.invalid_links, 'invalid tags in :help docs')
|
||||
eq({}, rv.invalid_urls, 'invalid URLs in :help docs')
|
||||
eq(
|
||||
{},
|
||||
rv.invalid_spelling,
|
||||
'invalid spelling in :help docs (see spell_dict in scripts/gen_help_html.lua)'
|
||||
)
|
||||
end
|
||||
|
||||
--- Test-generates HTML from docs.
|
||||
---
|
||||
--- 1. Test that gen_help_html.lua actually works.
|
||||
--- 2. Test that parse errors did not increase wildly. Because we explicitly test only a few
|
||||
--- :help files, we can be precise about the tolerances here.
|
||||
--- @param help_dir? string e.g. '$VIMRUNTIME/doc' or './runtime/doc'
|
||||
function M.test_gen(help_dir)
|
||||
local tmpdir = assert(vim.fs.dirname(vim.fn.tempname()))
|
||||
help_dir = vim.fn.expand(help_dir or '$VIMRUNTIME/doc')
|
||||
print('doc path = ' .. vim.uv.fs_realpath(help_dir))
|
||||
|
||||
local rv = M.gen(
|
||||
help_dir,
|
||||
tmpdir,
|
||||
-- Because gen() is slow (~30s), this test is limited to a few files.
|
||||
{ 'pi_health.txt', 'help.txt', 'index.txt', 'nvim.txt' }
|
||||
)
|
||||
eq(4, #rv.helpfiles)
|
||||
eq(0, rv.err_count, 'parse errors in :help docs')
|
||||
eq({}, rv.invalid_links, 'invalid tags in :help docs')
|
||||
end
|
||||
|
||||
return M
|
||||
|
20
scripts/lintdoc.lua
Executable file
20
scripts/lintdoc.lua
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env -S nvim -l
|
||||
|
||||
-- Validate vimdoc files on $VIMRUNTIME/doc, and test generating HTML docs.
|
||||
-- Checks for duplicate/missing tags, parse errors, and invalid links/urls/spellings.
|
||||
-- See also `make lintdoc`.
|
||||
--
|
||||
-- Usage:
|
||||
-- $ nvim -l scripts/lintdoc.lua
|
||||
-- $ make lintdoc
|
||||
|
||||
print('Running lintdoc ...')
|
||||
|
||||
-- gen_help_html requires :helptags to be generated on $VIMRUNTIME/doc
|
||||
-- :helptags checks for duplicate tags.
|
||||
vim.cmd [[ helptags ALL ]]
|
||||
|
||||
require('scripts.gen_help_html').run_validate()
|
||||
require('scripts.gen_help_html').test_gen()
|
||||
|
||||
print('lintdoc PASSED.')
|
@ -953,3 +953,10 @@ add_custom_target(doc-eval DEPENDS ${GEN_EVAL_TOUCH})
|
||||
add_custom_target(doc-vim DEPENDS ${VIMDOC_FILES})
|
||||
add_custom_target(doc)
|
||||
add_dependencies(doc doc-vim doc-eval)
|
||||
|
||||
add_custom_target(lintdoc
|
||||
COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}"
|
||||
$<TARGET_FILE:nvim_bin> --clean -l scripts/lintdoc.lua
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
USES_TERMINAL)
|
||||
add_dependencies(lintdoc nvim)
|
||||
|
@ -748,20 +748,32 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
||||
col2 = c;
|
||||
}
|
||||
|
||||
DecorPriority subpriority = DECOR_PRIORITY_BASE;
|
||||
if (HAS_KEY(opts, set_extmark, _subpriority)) {
|
||||
VALIDATE_RANGE((opts->_subpriority >= 0 && opts->_subpriority <= UINT16_MAX),
|
||||
"_subpriority", {
|
||||
goto error;
|
||||
});
|
||||
subpriority = (DecorPriority)opts->_subpriority;
|
||||
}
|
||||
|
||||
if (kv_size(virt_text.data.virt_text)) {
|
||||
decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true);
|
||||
decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true,
|
||||
subpriority);
|
||||
}
|
||||
if (kv_size(virt_lines.data.virt_lines)) {
|
||||
decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true);
|
||||
decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true,
|
||||
subpriority);
|
||||
}
|
||||
if (url != NULL) {
|
||||
DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT;
|
||||
sh.url = url;
|
||||
decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0);
|
||||
decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0, subpriority);
|
||||
}
|
||||
if (has_hl) {
|
||||
DecorSignHighlight sh = decor_sh_from_inline(hl);
|
||||
decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id);
|
||||
decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id,
|
||||
subpriority);
|
||||
}
|
||||
} else {
|
||||
if (opts->ephemeral) {
|
||||
|
@ -55,6 +55,8 @@ typedef struct {
|
||||
Boolean ui_watched;
|
||||
Boolean undo_restore;
|
||||
String url;
|
||||
|
||||
Integer _subpriority;
|
||||
} Dict(set_extmark);
|
||||
|
||||
typedef struct {
|
||||
|
@ -151,7 +151,7 @@ bool try_end(Error *err)
|
||||
if (should_free) {
|
||||
xfree(msg);
|
||||
}
|
||||
} else if (did_throw) {
|
||||
} else if (did_throw || need_rethrow) {
|
||||
if (*current_exception->throw_name != NUL) {
|
||||
if (current_exception->throw_lnum != 0) {
|
||||
api_set_error(err, kErrorTypeException, "%s, line %" PRIdLINENR ": %s",
|
||||
|
@ -122,6 +122,37 @@ Window nvim_tabpage_get_win(Tabpage tabpage, Error *err)
|
||||
abort();
|
||||
}
|
||||
|
||||
/// Sets the current window in a tabpage
|
||||
///
|
||||
/// @param tabpage Tabpage handle, or 0 for current tabpage
|
||||
/// @param win Window handle, must already belong to {tabpage}
|
||||
/// @param[out] err Error details, if any
|
||||
void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err)
|
||||
FUNC_API_SINCE(12)
|
||||
{
|
||||
tabpage_T *tp = find_tab_by_handle(tabpage, err);
|
||||
if (!tp) {
|
||||
return;
|
||||
}
|
||||
|
||||
win_T *wp = find_window_by_handle(win, err);
|
||||
if (!wp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tabpage_win_valid(tp, wp)) {
|
||||
api_set_error(err, kErrorTypeException, "Window does not belong to tabpage %d", tp->handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tp == curtab) {
|
||||
win_enter(wp, true);
|
||||
} else if (tp->tp_curwin != wp) {
|
||||
tp->tp_prevwin = tp->tp_curwin;
|
||||
tp->tp_curwin = wp;
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the tabpage number
|
||||
///
|
||||
/// @param tabpage Tabpage handle, or 0 for current tabpage
|
||||
|
@ -35,6 +35,10 @@ void set_title(String title)
|
||||
FUNC_API_SINCE(3);
|
||||
void set_icon(String icon)
|
||||
FUNC_API_SINCE(3);
|
||||
void set_cursor(void)
|
||||
FUNC_API_SINCE(3);
|
||||
void reset_cursor(void)
|
||||
FUNC_API_SINCE(3);
|
||||
void screenshot(String path)
|
||||
FUNC_API_SINCE(7);
|
||||
void option_set(String name, Object value)
|
||||
|
@ -1022,7 +1022,7 @@ Integer nvim_open_term(Buffer buffer, Dict(open_term) *opts, Error *err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmdwin_type != 0 && buf == curbuf) {
|
||||
if (buf == cmdwin_buf) {
|
||||
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
||||
return 0;
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
if (cmdwin_type != 0 && (enter || buf == curbuf)) {
|
||||
if ((cmdwin_type != 0 && enter) || buf == cmdwin_buf) {
|
||||
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
||||
return 0;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
|
||||
if (!win || !buf) {
|
||||
return;
|
||||
}
|
||||
if (cmdwin_type != 0 && (win == curwin || win == cmdwin_old_curwin || buf == curbuf)) {
|
||||
if (win == cmdwin_win || win == cmdwin_old_curwin || buf == cmdwin_buf) {
|
||||
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
||||
return;
|
||||
}
|
||||
|
@ -1183,6 +1183,32 @@ static int empty_curbuf(bool close_others, int forceit, int action)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Remove every jump list entry referring to a given buffer.
|
||||
/// This function will also adjust the current jump list index.
|
||||
void buf_remove_from_jumplist(buf_T *deleted_buf)
|
||||
{
|
||||
// Remove all jump list entries that match the deleted buffer.
|
||||
for (int i = curwin->w_jumplistlen - 1; i >= 0; i--) {
|
||||
buf_T *buf = buflist_findnr(curwin->w_jumplist[i].fmark.fnum);
|
||||
|
||||
if (buf == deleted_buf) {
|
||||
// Found an entry that we want to delete.
|
||||
curwin->w_jumplistlen -= 1;
|
||||
|
||||
// If the current jump list index behind the entry we want to
|
||||
// delete, move it back by one.
|
||||
if (curwin->w_jumplistidx > i && curwin->w_jumplistidx > 0) {
|
||||
curwin->w_jumplistidx -= 1;
|
||||
}
|
||||
|
||||
// Actually remove the entry from the jump list.
|
||||
for (int d = i; d < curwin->w_jumplistlen; d++) {
|
||||
curwin->w_jumplist[d] = curwin->w_jumplist[d + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of the commands for the buffer list.
|
||||
///
|
||||
/// action == DOBUF_GOTO go to specified buffer
|
||||
@ -1205,6 +1231,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
|
||||
{
|
||||
buf_T *buf;
|
||||
buf_T *bp;
|
||||
bool update_jumplist = true;
|
||||
bool unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
|
||||
|| action == DOBUF_WIPE);
|
||||
|
||||
@ -1362,7 +1389,11 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
|
||||
|
||||
// If the buffer to be deleted is not the current one, delete it here.
|
||||
if (buf != curbuf) {
|
||||
// Remove the buffer to be deleted from the jump list.
|
||||
buf_remove_from_jumplist(buf);
|
||||
|
||||
close_windows(buf, false);
|
||||
|
||||
if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) {
|
||||
close_buffer(NULL, buf, action, false, false);
|
||||
}
|
||||
@ -1382,40 +1413,53 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
|
||||
if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)) {
|
||||
buf = au_new_curbuf.br_buf;
|
||||
} else if (curwin->w_jumplistlen > 0) {
|
||||
int jumpidx = curwin->w_jumplistidx - 1;
|
||||
if (jumpidx < 0) {
|
||||
jumpidx = curwin->w_jumplistlen - 1;
|
||||
}
|
||||
// Remove the current buffer from the jump list.
|
||||
buf_remove_from_jumplist(curbuf);
|
||||
|
||||
forward = jumpidx;
|
||||
while (jumpidx != curwin->w_jumplistidx) {
|
||||
buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
|
||||
if (buf != NULL) {
|
||||
// Skip current and unlisted bufs. Also skip a quickfix
|
||||
// buffer, it might be deleted soon.
|
||||
if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)) {
|
||||
buf = NULL;
|
||||
} else if (buf->b_ml.ml_mfp == NULL) {
|
||||
// skip unloaded buf, but may keep it for later
|
||||
if (bp == NULL) {
|
||||
bp = buf;
|
||||
// It's possible that we removed all jump list entries, in that case we need to try another
|
||||
// approach
|
||||
if (curwin->w_jumplistlen > 0) {
|
||||
// If the index is the same as the length, the current position was not yet added to the jump
|
||||
// list. So we can safely go back to the last entry and search from there.
|
||||
if (curwin->w_jumplistidx == curwin->w_jumplistlen) {
|
||||
curwin->w_jumplistidx = curwin->w_jumplistlen - 1;
|
||||
}
|
||||
|
||||
int jumpidx = curwin->w_jumplistidx;
|
||||
|
||||
forward = jumpidx;
|
||||
do {
|
||||
buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
|
||||
|
||||
if (buf != NULL) {
|
||||
// Skip unlisted bufs. Also skip a quickfix
|
||||
// buffer, it might be deleted soon.
|
||||
if (!buf->b_p_bl || bt_quickfix(buf)) {
|
||||
buf = NULL;
|
||||
} else if (buf->b_ml.ml_mfp == NULL) {
|
||||
// skip unloaded buf, but may keep it for later
|
||||
if (bp == NULL) {
|
||||
bp = buf;
|
||||
}
|
||||
buf = NULL;
|
||||
}
|
||||
buf = NULL;
|
||||
}
|
||||
}
|
||||
if (buf != NULL) { // found a valid buffer: stop searching
|
||||
break;
|
||||
}
|
||||
// advance to older entry in jump list
|
||||
if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) {
|
||||
break;
|
||||
}
|
||||
if (--jumpidx < 0) {
|
||||
jumpidx = curwin->w_jumplistlen - 1;
|
||||
}
|
||||
if (jumpidx == forward) { // List exhausted for sure
|
||||
break;
|
||||
}
|
||||
if (buf != NULL) { // found a valid buffer: stop searching
|
||||
curwin->w_jumplistidx = jumpidx;
|
||||
update_jumplist = false;
|
||||
break;
|
||||
}
|
||||
// advance to older entry in jump list
|
||||
if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) {
|
||||
break;
|
||||
}
|
||||
if (--jumpidx < 0) {
|
||||
jumpidx = curwin->w_jumplistlen - 1;
|
||||
}
|
||||
if (jumpidx == forward) { // List exhausted for sure
|
||||
break;
|
||||
}
|
||||
} while (jumpidx != curwin->w_jumplistidx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1511,7 +1555,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
|
||||
}
|
||||
|
||||
// Go to the other buffer.
|
||||
set_curbuf(buf, action);
|
||||
set_curbuf(buf, action, update_jumplist);
|
||||
|
||||
if (action == DOBUF_SPLIT) {
|
||||
RESET_BINDING(curwin); // reset 'scrollbind' and 'cursorbind'
|
||||
@ -1533,14 +1577,17 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
|
||||
/// DOBUF_UNLOAD unload it
|
||||
/// DOBUF_DEL delete it
|
||||
/// DOBUF_WIPE wipe it out
|
||||
void set_curbuf(buf_T *buf, int action)
|
||||
void set_curbuf(buf_T *buf, int action, bool update_jumplist)
|
||||
{
|
||||
buf_T *prevbuf;
|
||||
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
|
||||
|| action == DOBUF_WIPE);
|
||||
OptInt old_tw = curbuf->b_p_tw;
|
||||
|
||||
setpcmark();
|
||||
if (update_jumplist) {
|
||||
setpcmark();
|
||||
}
|
||||
|
||||
if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) {
|
||||
curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file
|
||||
}
|
||||
@ -1677,6 +1724,7 @@ void enter_buffer(buf_T *buf)
|
||||
curwin->w_topfill = 0;
|
||||
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
|
||||
apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, false, curbuf);
|
||||
ui_call_set_cursor();
|
||||
}
|
||||
|
||||
// If autocommands did not change the cursor position, restore cursor lnum
|
||||
@ -3675,7 +3723,7 @@ void ex_buffer_all(exarg_T *eap)
|
||||
|
||||
// Open the buffer in this window.
|
||||
swap_exists_action = SEA_DIALOG;
|
||||
set_curbuf(buf, DOBUF_GOTO);
|
||||
set_curbuf(buf, DOBUF_GOTO, false);
|
||||
if (!bufref_valid(&bufref)) {
|
||||
// Autocommands deleted the buffer.
|
||||
swap_exists_action = SEA_NONE;
|
||||
@ -4012,6 +4060,9 @@ char *buf_spname(buf_T *buf)
|
||||
if (buf->b_fname != NULL) {
|
||||
return buf->b_fname;
|
||||
}
|
||||
if (buf == cmdwin_buf) {
|
||||
return _("[Command Line]");
|
||||
}
|
||||
if (bt_prompt(buf)) {
|
||||
return _("[Prompt]");
|
||||
}
|
||||
@ -4129,6 +4180,7 @@ void wipe_buffer(buf_T *buf, bool aucmd)
|
||||
/// - Always considered 'nomodified'
|
||||
///
|
||||
/// @param bufnr Buffer to switch to, or 0 to create a new buffer.
|
||||
/// @param bufname Buffer name, or NULL.
|
||||
///
|
||||
/// @see curbufIsChanged()
|
||||
///
|
||||
@ -4138,9 +4190,11 @@ int buf_open_scratch(handle_T bufnr, char *bufname)
|
||||
if (do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
|
||||
setfname(curbuf, bufname, NULL, true);
|
||||
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
|
||||
if (bufname != NULL) {
|
||||
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
|
||||
setfname(curbuf, bufname, NULL, true);
|
||||
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
|
||||
}
|
||||
set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
|
||||
set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
|
||||
set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL);
|
||||
|
@ -713,7 +713,7 @@ struct file_buffer {
|
||||
|
||||
// Measurements of the deleted or replaced region since the last update
|
||||
// event. Some consumers of buffer changes need to know the byte size (like
|
||||
// tree-sitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
|
||||
// treesitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
|
||||
// deleted text.
|
||||
size_t deleted_bytes;
|
||||
size_t deleted_bytes2;
|
||||
|
@ -29,7 +29,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
SHAPE_BLOCK = 0, ///< block cursor
|
||||
SHAPE_HOR = 1, ///< horizontal bar cursor
|
||||
SHAPE_VER = 2, ///< vertical bar cursor
|
||||
SHAPE_VER = 2, ///< vertical bar cursor
|
||||
} CursorShape;
|
||||
|
||||
#define MSHAPE_NUMBERED 1000 // offset for shapes identified by number
|
||||
|
@ -449,18 +449,21 @@ static void decor_range_add_from_inline(DecorState *state, int start_row, int st
|
||||
if (decor.ext) {
|
||||
DecorVirtText *vt = decor.data.ext.vt;
|
||||
while (vt) {
|
||||
decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned);
|
||||
decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned,
|
||||
DECOR_PRIORITY_BASE);
|
||||
vt = vt->next;
|
||||
}
|
||||
uint32_t idx = decor.data.ext.sh_idx;
|
||||
while (idx != DECOR_ID_INVALID) {
|
||||
DecorSignHighlight *sh = &kv_A(decor_items, idx);
|
||||
decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id);
|
||||
decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id,
|
||||
DECOR_PRIORITY_BASE);
|
||||
idx = sh->next;
|
||||
}
|
||||
} else {
|
||||
DecorSignHighlight sh = decor_sh_from_inline(decor.data.hl);
|
||||
decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id);
|
||||
decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id,
|
||||
DECOR_PRIORITY_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,7 +473,8 @@ static void decor_range_insert(DecorState *state, DecorRange range)
|
||||
size_t index;
|
||||
for (index = kv_size(state->active) - 1; index > 0; index--) {
|
||||
DecorRange item = kv_A(state->active, index - 1);
|
||||
if (item.priority <= range.priority) {
|
||||
if ((item.priority < range.priority)
|
||||
|| ((item.priority == range.priority) && (item.subpriority <= range.subpriority))) {
|
||||
break;
|
||||
}
|
||||
kv_A(state->active, index) = kv_A(state->active, index - 1);
|
||||
@ -479,7 +483,7 @@ static void decor_range_insert(DecorState *state, DecorRange range)
|
||||
}
|
||||
|
||||
void decor_range_add_virt(DecorState *state, int start_row, int start_col, int end_row, int end_col,
|
||||
DecorVirtText *vt, bool owned)
|
||||
DecorVirtText *vt, bool owned, DecorPriority subpriority)
|
||||
{
|
||||
bool is_lines = vt->flags & kVTIsLines;
|
||||
DecorRange range = {
|
||||
@ -489,13 +493,15 @@ void decor_range_add_virt(DecorState *state, int start_row, int start_col, int e
|
||||
.attr_id = 0,
|
||||
.owned = owned,
|
||||
.priority = vt->priority,
|
||||
.subpriority = subpriority,
|
||||
.draw_col = -10,
|
||||
};
|
||||
decor_range_insert(state, range);
|
||||
}
|
||||
|
||||
void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end_row, int end_col,
|
||||
DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id)
|
||||
DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id,
|
||||
DecorPriority subpriority)
|
||||
{
|
||||
if (sh->flags & kSHIsSign) {
|
||||
return;
|
||||
@ -508,6 +514,7 @@ void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end
|
||||
.attr_id = 0,
|
||||
.owned = owned,
|
||||
.priority = sh->priority,
|
||||
.subpriority = subpriority,
|
||||
.draw_col = -10,
|
||||
};
|
||||
|
||||
@ -629,9 +636,9 @@ next_mark:
|
||||
} else if (item.data.sh.flags & kSHSpellOff) {
|
||||
spell = kFalse;
|
||||
}
|
||||
}
|
||||
if (active && item.data.sh.url != NULL) {
|
||||
attr = hl_add_url(attr, item.data.sh.url);
|
||||
if (item.data.sh.url != NULL) {
|
||||
attr = hl_add_url(attr, item.data.sh.url);
|
||||
}
|
||||
}
|
||||
if (item.start_row == state->row && item.start_col <= col
|
||||
&& decor_virt_pos(&item) && item.draw_col == -10) {
|
||||
|
@ -48,6 +48,8 @@ typedef struct {
|
||||
int attr_id; ///< cached lookup of inl.hl_id if it was a highlight
|
||||
bool owned; ///< ephemeral decoration, free memory immediately
|
||||
DecorPriority priority;
|
||||
DecorPriority subpriority; ///< Secondary priority value used for ordering (#27131).
|
||||
///< Reflects the order of patterns/captures in the query file.
|
||||
DecorRangeKind kind;
|
||||
/// Screen column to draw the virtual text.
|
||||
/// When -1, the virtual text may be drawn after deciding where.
|
||||
|
@ -1219,7 +1219,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
||||
statuscol.draw = true;
|
||||
statuscol.sattrs = wlv.sattrs;
|
||||
statuscol.foldinfo = foldinfo;
|
||||
statuscol.width = win_col_off(wp) - (cmdwin_type != 0 && wp == curwin);
|
||||
statuscol.width = win_col_off(wp) - (wp == cmdwin_win);
|
||||
statuscol.use_cul = use_cursor_line_highlight(wp, lnum);
|
||||
statuscol.sign_cul_id = statuscol.use_cul ? sign_cul_attr : 0;
|
||||
statuscol.num_attr = sign_num_attr > 0 ? syn_id2attr(sign_num_attr) : 0;
|
||||
@ -1511,7 +1511,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
||||
|
||||
assert(wlv.off == 0);
|
||||
|
||||
if (cmdwin_type != 0 && wp == curwin) {
|
||||
if (wp == cmdwin_win) {
|
||||
// Draw the cmdline character.
|
||||
draw_col_fill(&wlv, schar_from_ascii(cmdwin_type), 1, win_hl_attr(wp, HLF_AT));
|
||||
}
|
||||
|
@ -838,6 +838,7 @@ void setcursor_mayforce(bool force)
|
||||
|
||||
grid_adjust(&grid, &row, &col);
|
||||
ui_grid_cursor_goto(grid->handle, row, col);
|
||||
ui_call_reset_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3219,6 +3219,8 @@ M.funcs = {
|
||||
bufnr Buffer number.
|
||||
changed TRUE if the buffer is modified.
|
||||
changedtick Number of changes made to the buffer.
|
||||
command TRUE if the buffer belongs to the
|
||||
command-line window |cmdwin|.
|
||||
hidden TRUE if the buffer is hidden.
|
||||
lastused Timestamp in seconds, like
|
||||
|localtime()|, when the buffer was
|
||||
@ -3461,7 +3463,7 @@ M.funcs = {
|
||||
32 mouse double click
|
||||
64 mouse triple click
|
||||
96 mouse quadruple click (== 32 + 64)
|
||||
128 command (Macintosh only)
|
||||
128 command (Mac) or super
|
||||
Only the modifiers that have not been included in the
|
||||
character itself are obtained. Thus Shift-a results in "A"
|
||||
without a modifier. Returns 0 if no modifiers are used.
|
||||
|
@ -494,6 +494,7 @@ static dict_T *get_buffer_info(buf_T *buf)
|
||||
tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("hidden"), buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
|
||||
tv_dict_add_nr(dict, S_LEN("command"), buf == cmdwin_buf);
|
||||
|
||||
// Get a reference to buffer variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
|
||||
|
@ -755,7 +755,7 @@ void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
rettv->vval.v_string = xstrdup("preview");
|
||||
} else if (wp->w_floating) {
|
||||
rettv->vval.v_string = xstrdup("popup");
|
||||
} else if (wp == curwin && cmdwin_type != 0) {
|
||||
} else if (wp == cmdwin_win) {
|
||||
rettv->vval.v_string = xstrdup("command");
|
||||
} else if (bt_quickfix(wp->w_buffer)) {
|
||||
rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
|
||||
|
@ -2305,10 +2305,19 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
|
||||
// If the current buffer was empty and has no file name, curbuf
|
||||
// is returned by buflist_new(), nothing to do here.
|
||||
if (buf != curbuf) {
|
||||
// Should only be possible to get here if the cmdwin is closed, or
|
||||
// if it's opening and its buffer hasn't been set yet (the new
|
||||
// buffer is for it).
|
||||
assert(cmdwin_buf == NULL);
|
||||
|
||||
const int save_cmdwin_type = cmdwin_type;
|
||||
win_T *const save_cmdwin_win = cmdwin_win;
|
||||
win_T *const save_cmdwin_old_curwin = cmdwin_old_curwin;
|
||||
|
||||
// BufLeave applies to the old buffer.
|
||||
cmdwin_type = 0;
|
||||
cmdwin_win = NULL;
|
||||
cmdwin_old_curwin = NULL;
|
||||
|
||||
// Be careful: The autocommands may delete any buffer and change
|
||||
// the current buffer.
|
||||
@ -2324,7 +2333,11 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
|
||||
const bufref_T save_au_new_curbuf = au_new_curbuf;
|
||||
set_bufref(&au_new_curbuf, buf);
|
||||
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
|
||||
|
||||
cmdwin_type = save_cmdwin_type;
|
||||
cmdwin_win = save_cmdwin_win;
|
||||
cmdwin_old_curwin = save_cmdwin_old_curwin;
|
||||
|
||||
if (!bufref_valid(&au_new_curbuf)) {
|
||||
// New buffer has been deleted.
|
||||
delbuf_msg(new_name); // Frees new_name.
|
||||
|
@ -1612,7 +1612,7 @@ module.cmds = {
|
||||
},
|
||||
{
|
||||
command = 'lua',
|
||||
flags = bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, LOCK_OK),
|
||||
flags = bit.bor(RANGE, EXTRA, CMDWIN, LOCK_OK),
|
||||
addr_type = 'ADDR_LINES',
|
||||
func = 'ex_lua',
|
||||
},
|
||||
|
@ -405,7 +405,7 @@ buf_found:
|
||||
|
||||
// Open the changed buffer in the current window.
|
||||
if (buf != curbuf) {
|
||||
set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
|
||||
set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO, true);
|
||||
}
|
||||
|
||||
theend:
|
||||
|
@ -309,6 +309,33 @@ static void msg_verbose_cmd(linenr_T lnum, char *cmd)
|
||||
no_wait_return--;
|
||||
}
|
||||
|
||||
static int cmdline_call_depth = 0; ///< recursiveness
|
||||
|
||||
/// Start executing an Ex command line.
|
||||
///
|
||||
/// @return FAIL if too recursive, OK otherwise.
|
||||
static int do_cmdline_start(void)
|
||||
{
|
||||
assert(cmdline_call_depth >= 0);
|
||||
// It's possible to create an endless loop with ":execute", catch that
|
||||
// here. The value of 200 allows nested function calls, ":source", etc.
|
||||
// Allow 200 or 'maxfuncdepth', whatever is larger.
|
||||
if (cmdline_call_depth >= 200 && cmdline_call_depth >= p_mfd) {
|
||||
return FAIL;
|
||||
}
|
||||
cmdline_call_depth++;
|
||||
start_batch_changes();
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// End executing an Ex command line.
|
||||
static void do_cmdline_end(void)
|
||||
{
|
||||
cmdline_call_depth--;
|
||||
assert(cmdline_call_depth >= 0);
|
||||
end_batch_changes();
|
||||
}
|
||||
|
||||
/// Execute a simple command line. Used for translated commands like "*".
|
||||
int do_cmdline_cmd(const char *cmd)
|
||||
{
|
||||
@ -359,7 +386,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
|
||||
char *(*cmd_getline)(int, void *, int, bool);
|
||||
void *cmd_cookie;
|
||||
struct loop_cookie cmd_loop_cookie;
|
||||
static int call_depth = 0; // recursiveness
|
||||
|
||||
// For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory
|
||||
// location for storing error messages to be converted to an exception.
|
||||
@ -371,10 +397,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
|
||||
msg_list = &private_msg_list;
|
||||
private_msg_list = NULL;
|
||||
|
||||
// It's possible to create an endless loop with ":execute", catch that
|
||||
// here. The value of 200 allows nested function calls, ":source", etc.
|
||||
// Allow 200 or 'maxfuncdepth', whatever is larger.
|
||||
if (call_depth >= 200 && call_depth >= p_mfd) {
|
||||
if (do_cmdline_start() == FAIL) {
|
||||
emsg(_(e_command_too_recursive));
|
||||
// When converting to an exception, we do not include the command name
|
||||
// since this is not an error of the specific command.
|
||||
@ -382,8 +405,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
|
||||
msg_list = saved_msg_list;
|
||||
return FAIL;
|
||||
}
|
||||
call_depth++;
|
||||
start_batch_changes();
|
||||
|
||||
ga_init(&lines_ga, (int)sizeof(wcmd_T), 10);
|
||||
|
||||
@ -884,8 +905,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
|
||||
|
||||
did_endif = false; // in case do_cmdline used recursively
|
||||
|
||||
call_depth--;
|
||||
end_batch_changes();
|
||||
do_cmdline_end();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1669,9 +1689,13 @@ static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool pre
|
||||
/// @param preview Execute command preview callback instead of actual command
|
||||
int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
|
||||
{
|
||||
const char *errormsg = NULL;
|
||||
int retv = 0;
|
||||
if (do_cmdline_start() == FAIL) {
|
||||
emsg(_(e_command_too_recursive));
|
||||
return retv;
|
||||
}
|
||||
|
||||
const char *errormsg = NULL;
|
||||
#undef ERROR
|
||||
#define ERROR(msg) \
|
||||
do { \
|
||||
@ -1738,9 +1762,12 @@ end:
|
||||
if (errormsg != NULL && *errormsg != NUL) {
|
||||
emsg(errormsg);
|
||||
}
|
||||
|
||||
// Undo command modifiers
|
||||
undo_cmdmod(&cmdmod);
|
||||
cmdmod = save_cmdmod;
|
||||
|
||||
do_cmdline_end();
|
||||
return retv;
|
||||
#undef ERROR
|
||||
}
|
||||
|
@ -219,6 +219,9 @@ static int cedit_key = -1; ///< key value of 'cedit' option
|
||||
static handle_T cmdpreview_bufnr = 0;
|
||||
static int cmdpreview_ns = 0;
|
||||
|
||||
static const char e_active_window_or_buffer_changed_or_deleted[]
|
||||
= N_("E199: Active window or buffer changed or deleted");
|
||||
|
||||
static void save_viewstate(win_T *wp, viewstate_T *vs)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
@ -4323,23 +4326,50 @@ static int open_cmdwin(void)
|
||||
ga_clear(&winsizes);
|
||||
return K_IGNORE;
|
||||
}
|
||||
// win_split() autocommands may have messed with the old window or buffer.
|
||||
// Treat it as abandoning this command-line.
|
||||
if (!win_valid(old_curwin) || curwin == old_curwin || !bufref_valid(&old_curbuf)
|
||||
|| old_curwin->w_buffer != old_curbuf.br_buf) {
|
||||
beep_flush();
|
||||
ga_clear(&winsizes);
|
||||
return Ctrl_C;
|
||||
}
|
||||
// Don't let quitting the More prompt make this fail.
|
||||
got_int = false;
|
||||
|
||||
// Set "cmdwin_type" before any autocommands may mess things up.
|
||||
// Set "cmdwin_..." variables before any autocommands may mess things up.
|
||||
cmdwin_type = get_cmdline_type();
|
||||
cmdwin_level = ccline.level;
|
||||
cmdwin_win = curwin;
|
||||
cmdwin_old_curwin = old_curwin;
|
||||
|
||||
// Create empty command-line buffer.
|
||||
if (buf_open_scratch(0, _("[Command Line]")) == FAIL) {
|
||||
// Some autocommand messed it up?
|
||||
win_close(curwin, true, false);
|
||||
ga_clear(&winsizes);
|
||||
// Create empty command-line buffer. Be especially cautious of BufLeave
|
||||
// autocommands from do_ecmd(), as cmdwin restrictions do not apply to them!
|
||||
const int newbuf_status = buf_open_scratch(0, NULL);
|
||||
const bool cmdwin_valid = win_valid(cmdwin_win);
|
||||
if (newbuf_status == FAIL || !cmdwin_valid || curwin != cmdwin_win || !win_valid(old_curwin)
|
||||
|| !bufref_valid(&old_curbuf) || old_curwin->w_buffer != old_curbuf.br_buf) {
|
||||
if (newbuf_status == OK) {
|
||||
set_bufref(&bufref, curbuf);
|
||||
}
|
||||
if (cmdwin_valid && !last_window(cmdwin_win)) {
|
||||
win_close(cmdwin_win, true, false);
|
||||
}
|
||||
// win_close() autocommands may have already deleted the buffer.
|
||||
if (newbuf_status == OK && bufref_valid(&bufref) && bufref.br_buf != curbuf) {
|
||||
close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false, false);
|
||||
}
|
||||
|
||||
cmdwin_type = 0;
|
||||
cmdwin_level = 0;
|
||||
cmdwin_win = NULL;
|
||||
cmdwin_old_curwin = NULL;
|
||||
beep_flush();
|
||||
ga_clear(&winsizes);
|
||||
return Ctrl_C;
|
||||
}
|
||||
cmdwin_buf = curbuf;
|
||||
|
||||
// Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer.
|
||||
set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL);
|
||||
curbuf->b_p_ma = true;
|
||||
@ -4434,15 +4464,18 @@ static int open_cmdwin(void)
|
||||
|
||||
cmdwin_type = 0;
|
||||
cmdwin_level = 0;
|
||||
cmdwin_buf = NULL;
|
||||
cmdwin_win = NULL;
|
||||
cmdwin_old_curwin = NULL;
|
||||
|
||||
exmode_active = save_exmode;
|
||||
|
||||
// Safety check: The old window or buffer was deleted: It's a bug when
|
||||
// this happens!
|
||||
if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf)) {
|
||||
// Safety check: The old window or buffer was changed or deleted: It's a bug
|
||||
// when this happens!
|
||||
if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf)
|
||||
|| old_curwin->w_buffer != old_curbuf.br_buf) {
|
||||
cmdwin_result = Ctrl_C;
|
||||
emsg(_("E199: Active window or buffer deleted"));
|
||||
emsg(_(e_active_window_or_buffer_changed_or_deleted));
|
||||
} else {
|
||||
win_T *wp;
|
||||
// autocmds may abort script processing
|
||||
|
@ -366,6 +366,7 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr
|
||||
|
||||
if (put_line(fd, "enew | setl bt=help") == FAIL
|
||||
|| fprintf(fd, "help %s", curtag) < 0 || put_eol(fd) == FAIL) {
|
||||
xfree(fname_esc);
|
||||
return FAIL;
|
||||
}
|
||||
} else if (wp->w_buffer->b_ffname != NULL
|
||||
|
@ -70,9 +70,10 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
|
||||
extmark_del_id(buf, ns_id, id);
|
||||
} else {
|
||||
assert(marktree_itr_valid(itr));
|
||||
bool invalid = mt_invalid(old_mark);
|
||||
if (old_mark.pos.row == row && old_mark.pos.col == col) {
|
||||
// not paired: we can revise in place
|
||||
if (mt_decor_any(old_mark)) {
|
||||
if (!invalid && mt_decor_any(old_mark)) {
|
||||
mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_DECOR_SIGNTEXT;
|
||||
buf_decor_remove(buf, row, row, mt_decor(old_mark), true);
|
||||
}
|
||||
@ -82,7 +83,9 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
|
||||
goto revised;
|
||||
}
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true);
|
||||
if (!invalid) {
|
||||
buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*ns = MAX(*ns, id);
|
||||
|
@ -1146,10 +1146,10 @@ static void gotchars(const uint8_t *chars, size_t len)
|
||||
maptick++;
|
||||
}
|
||||
|
||||
/// Record a <Nop> key.
|
||||
void gotchars_nop(void)
|
||||
/// Record an <Ignore> key.
|
||||
void gotchars_ignore(void)
|
||||
{
|
||||
uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_NOP };
|
||||
uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_IGNORE };
|
||||
gotchars(nop_buf, 3);
|
||||
}
|
||||
|
||||
@ -2746,9 +2746,9 @@ static int vgetorpeek(bool advance)
|
||||
}
|
||||
|
||||
if (timedout && c == ESC) {
|
||||
// When recording there will be no timeout. Add a <Nop> after the ESC
|
||||
// to avoid that it forms a key code with following characters.
|
||||
gotchars_nop();
|
||||
// When recording there will be no timeout. Add an <Ignore> after the
|
||||
// ESC to avoid that it forms a key code with following characters.
|
||||
gotchars_ignore();
|
||||
}
|
||||
|
||||
vgetc_busy--;
|
||||
|
@ -752,6 +752,8 @@ EXTERN bool km_startsel INIT( = false);
|
||||
EXTERN int cmdwin_type INIT( = 0); ///< type of cmdline window or 0
|
||||
EXTERN int cmdwin_result INIT( = 0); ///< result of cmdline window or 0
|
||||
EXTERN int cmdwin_level INIT( = 0); ///< cmdline recursion level
|
||||
EXTERN buf_T *cmdwin_buf INIT( = NULL); ///< buffer of cmdline window or NULL
|
||||
EXTERN win_T *cmdwin_win INIT( = NULL); ///< window of cmdline window or NULL
|
||||
EXTERN win_T *cmdwin_old_curwin INIT( = NULL); ///< curwin before opening cmdline window or NULL
|
||||
|
||||
EXTERN char no_lines_msg[] INIT( = N_("--No lines in buffer--"));
|
||||
|
@ -701,6 +701,9 @@ void get_local_additions(void)
|
||||
const char *const f1 = fnames[i1];
|
||||
const char *const t1 = path_tail(f1);
|
||||
const char *const e1 = strrchr(t1, '.');
|
||||
if (e1 == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (path_fnamecmp(e1, ".txt") != 0
|
||||
&& path_fnamecmp(e1, fname + 4) != 0) {
|
||||
// Not .txt and not .abx, remove it.
|
||||
@ -715,7 +718,7 @@ void get_local_additions(void)
|
||||
}
|
||||
const char *const t2 = path_tail(f2);
|
||||
const char *const e2 = strrchr(t2, '.');
|
||||
if (e1 == NULL || e2 == NULL) {
|
||||
if (e2 == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (e1 - f1 != e2 - f2
|
||||
|
@ -310,7 +310,7 @@ static const char *highlight_init_light[] = {
|
||||
"Normal guifg=NvimDarkGrey2 guibg=NvimLightGrey2 ctermfg=NONE ctermbg=NONE",
|
||||
|
||||
// UI
|
||||
"Added guifg=NvimDarGreen ctermfg=2",
|
||||
"Added guifg=NvimDarkGreen ctermfg=2",
|
||||
"Changed guifg=NvimDarkCyan ctermfg=6",
|
||||
"ColorColumn guibg=NvimLightGrey4 cterm=reverse",
|
||||
"Conceal guifg=NvimLightGrey4",
|
||||
|
@ -1641,27 +1641,38 @@ bool nlua_is_deferred_safe(void)
|
||||
return in_fast_callback == 0;
|
||||
}
|
||||
|
||||
/// Run lua string
|
||||
/// Executes Lua code.
|
||||
///
|
||||
/// Used for :lua.
|
||||
/// Implements `:lua` and `:lua ={expr}`.
|
||||
///
|
||||
/// @param eap Vimscript command being run.
|
||||
/// @param eap Vimscript `:lua {code}`, `:{range}lua`, or `:lua ={expr}` command.
|
||||
void ex_lua(exarg_T *const eap)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// ":{range}lua"
|
||||
if (eap->addr_count > 0 || *eap->arg == NUL) {
|
||||
if (eap->addr_count > 0 && *eap->arg == NUL) {
|
||||
cmd_source_buffer(eap, true);
|
||||
} else {
|
||||
semsg(_(e_invarg2), "exactly one of {chunk} or {range} required");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
char *code = script_get(eap, &len);
|
||||
if (eap->skip || code == NULL) {
|
||||
xfree(code);
|
||||
return;
|
||||
}
|
||||
// When =expr is used transform it to vim.print(expr)
|
||||
|
||||
// ":lua {code}", ":={expr}" or ":lua ={expr}"
|
||||
//
|
||||
// When "=expr" is used transform it to "vim.print(expr)".
|
||||
if (eap->cmdidx == CMD_equal || code[0] == '=') {
|
||||
size_t off = (eap->cmdidx == CMD_equal) ? 0 : 1;
|
||||
len += sizeof("vim.print()") - 1 - off;
|
||||
// code_buf needs to be 1 char larger then len for null byte in the end.
|
||||
// lua nlua_typval_exec doesn't expect null terminated string so len
|
||||
// needs to end before null byte.
|
||||
// `nlua_typval_exec` doesn't expect NUL-terminated string so `len` must end before NUL byte.
|
||||
char *code_buf = xmallocz(len);
|
||||
vim_snprintf(code_buf, len + 1, "vim.print(%s)", code + off);
|
||||
xfree(code);
|
||||
@ -1673,11 +1684,11 @@ void ex_lua(exarg_T *const eap)
|
||||
xfree(code);
|
||||
}
|
||||
|
||||
/// Run lua string for each line in range
|
||||
/// Executes Lua code for-each line in a buffer range.
|
||||
///
|
||||
/// Used for :luado.
|
||||
/// Implements `:luado`.
|
||||
///
|
||||
/// @param eap Vimscript command being run.
|
||||
/// @param eap Vimscript `:luado {code}` command.
|
||||
void ex_luado(exarg_T *const eap)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
@ -1754,11 +1765,11 @@ void ex_luado(exarg_T *const eap)
|
||||
redraw_curbuf_later(UPD_NOT_VALID);
|
||||
}
|
||||
|
||||
/// Run lua file
|
||||
/// Executes Lua code from a file location.
|
||||
///
|
||||
/// Used for :luafile.
|
||||
/// Implements `:luafile`.
|
||||
///
|
||||
/// @param eap Vimscript command being run.
|
||||
/// @param eap Vimscript `:luafile {file}` command.
|
||||
void ex_luafile(exarg_T *const eap)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
// lua bindings for tree-sitter.
|
||||
// NB: this file mostly contains a generic lua interface for tree-sitter
|
||||
// lua bindings for treesitter.
|
||||
// NB: this file mostly contains a generic lua interface for treesitter
|
||||
// trees and nodes, and could be broken out as a reusable lua package
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -1326,18 +1326,18 @@ retnomove:
|
||||
&& !sep_line_offset
|
||||
&& (wp->w_p_rl
|
||||
? col < wp->w_width_inner - fdc
|
||||
: col >= fdc + (cmdwin_type == 0 && wp == curwin ? 0 : 1))
|
||||
: col >= fdc + (wp != cmdwin_win ? 0 : 1))
|
||||
&& (flags & MOUSE_MAY_STOP_VIS)))) {
|
||||
end_visual_mode();
|
||||
redraw_curbuf_later(UPD_INVERTED); // delete the inversion
|
||||
}
|
||||
if (cmdwin_type != 0 && wp != curwin) {
|
||||
if (cmdwin_type != 0 && wp != cmdwin_win) {
|
||||
// A click outside the command-line window: Use modeless
|
||||
// selection if possible. Allow dragging the status lines.
|
||||
sep_line_offset = 0;
|
||||
row = 0;
|
||||
col += wp->w_wincol;
|
||||
wp = curwin;
|
||||
wp = cmdwin_win;
|
||||
}
|
||||
// Only change window focus when not clicking on or dragging the
|
||||
// status line. Do change focus when releasing the mouse button
|
||||
|
@ -760,7 +760,7 @@ int win_col_off(win_T *wp)
|
||||
{
|
||||
return ((wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc != NUL)
|
||||
? (number_width(wp) + (*wp->w_p_stc == NUL)) : 0)
|
||||
+ ((cmdwin_type == 0 || wp != curwin) ? 0 : 1)
|
||||
+ ((wp != cmdwin_win) ? 0 : 1)
|
||||
+ win_fdccol_count(wp) + (wp->w_scwidth * SIGN_WIDTH);
|
||||
}
|
||||
|
||||
|
@ -845,10 +845,10 @@ static void normal_get_additional_char(NormalState *s)
|
||||
no_mapping++;
|
||||
// Vim may be in a different mode when the user types the next key,
|
||||
// but when replaying a recording the next key is already in the
|
||||
// typeahead buffer, so record a <Nop> before that to prevent the
|
||||
// vpeekc() above from applying wrong mappings when replaying.
|
||||
// typeahead buffer, so record an <Ignore> before that to prevent
|
||||
// the vpeekc() above from applying wrong mappings when replaying.
|
||||
no_u_sync++;
|
||||
gotchars_nop();
|
||||
gotchars_ignore();
|
||||
no_u_sync--;
|
||||
}
|
||||
}
|
||||
|
@ -1779,7 +1779,7 @@ freeall:
|
||||
static void cmd_source(char *fname, exarg_T *eap)
|
||||
{
|
||||
if (eap != NULL && *fname == NUL) {
|
||||
cmd_source_buffer(eap);
|
||||
cmd_source_buffer(eap, false);
|
||||
} else if (eap != NULL && eap->forceit) {
|
||||
// ":source!": read Normal mode commands
|
||||
// Need to execute the commands directly. This is required at least
|
||||
@ -1989,7 +1989,7 @@ static int source_using_linegetter(void *cookie, LineGetter fgetline, const char
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void cmd_source_buffer(const exarg_T *const eap)
|
||||
void cmd_source_buffer(const exarg_T *const eap, bool ex_lua)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
if (curbuf == NULL) {
|
||||
@ -2012,9 +2012,10 @@ static void cmd_source_buffer(const exarg_T *const eap)
|
||||
.buf = ga.ga_data,
|
||||
.offset = 0,
|
||||
};
|
||||
if (strequal(curbuf->b_p_ft, "lua")
|
||||
if (ex_lua || strequal(curbuf->b_p_ft, "lua")
|
||||
|| (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) {
|
||||
nlua_source_using_linegetter(get_str_line, (void *)&cookie, ":source (no file)");
|
||||
char *name = ex_lua ? ":{range}lua" : ":source (no file)";
|
||||
nlua_source_using_linegetter(get_str_line, (void *)&cookie, name);
|
||||
} else {
|
||||
source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)");
|
||||
}
|
||||
|
@ -93,6 +93,7 @@
|
||||
#include "nvim/types_defs.h"
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/vim_defs.h"
|
||||
#include "nvim/window.h"
|
||||
|
||||
typedef struct {
|
||||
VimState state;
|
||||
@ -615,6 +616,8 @@ static int terminal_check(VimState *state)
|
||||
curbuf->b_locked--;
|
||||
}
|
||||
|
||||
may_trigger_win_scrolled_resized();
|
||||
|
||||
if (need_maketitle) { // Update title in terminal-mode. #7248
|
||||
maketitle();
|
||||
}
|
||||
|
@ -763,7 +763,7 @@ int comp_textwidth(bool ff)
|
||||
// The width is the window width minus 'wrapmargin' minus all the
|
||||
// things that add to the margin.
|
||||
textwidth = curwin->w_width_inner - (int)curbuf->b_p_wm;
|
||||
if (cmdwin_type != 0) {
|
||||
if (curbuf == cmdwin_buf) {
|
||||
textwidth -= 1;
|
||||
}
|
||||
textwidth -= win_fdccol_count(curwin);
|
||||
|
@ -269,6 +269,10 @@ static void tui_query_kitty_keyboard(TUIData *tui)
|
||||
out(tui, S_LEN("\x1b[?u\x1b[c"));
|
||||
}
|
||||
|
||||
/// Enable the alternate screen and emit other control sequences to start the TUI.
|
||||
///
|
||||
/// This is also called when the TUI is resumed after being suspended. We reinitialize all state
|
||||
/// from terminfo just in case the controlling terminal has changed (#27177).
|
||||
static void terminfo_start(TUIData *tui)
|
||||
{
|
||||
tui->scroll_region_is_full_screen = true;
|
||||
@ -418,6 +422,7 @@ static void terminfo_start(TUIData *tui)
|
||||
flush_buf(tui);
|
||||
}
|
||||
|
||||
/// Disable the alternate screen and prepare for the TUI to close.
|
||||
static void terminfo_stop(TUIData *tui)
|
||||
{
|
||||
// Destroy output stuff
|
||||
@ -489,7 +494,7 @@ static void tui_terminal_after_startup(TUIData *tui)
|
||||
flush_buf(tui);
|
||||
}
|
||||
|
||||
/// stop the terminal but allow it to restart later (like after suspend)
|
||||
/// Stop the terminal but allow it to restart later (like after suspend)
|
||||
static void tui_terminal_stop(TUIData *tui)
|
||||
{
|
||||
if (uv_is_closing((uv_handle_t *)&tui->output_handle)) {
|
||||
@ -1151,6 +1156,17 @@ void tui_mode_info_set(TUIData *tui, bool guicursor_enabled, Array args)
|
||||
tui_set_mode(tui, tui->showing_mode);
|
||||
}
|
||||
|
||||
void tui_set_cursor(TUIData *tui)
|
||||
{
|
||||
tui_set_mode(tui, tui->showing_mode);
|
||||
}
|
||||
|
||||
void tui_reset_cursor(TUIData *tui)
|
||||
{
|
||||
unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color);
|
||||
unibi_out_ext(tui, tui->unibi_ext.reset_cursor_style);
|
||||
}
|
||||
|
||||
void tui_update_menu(TUIData *tui)
|
||||
{
|
||||
// Do nothing; menus are for GUI only
|
||||
|
@ -1557,7 +1557,7 @@ bool win_valid(const win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
/// Check if "win" is a pointer to an existing window in tabpage "tp".
|
||||
///
|
||||
/// @param win window to check
|
||||
static bool tabpage_win_valid(const tabpage_T *tp, const win_T *win)
|
||||
bool tabpage_win_valid(const tabpage_T *tp, const win_T *win)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
if (win == NULL) {
|
||||
@ -2485,7 +2485,7 @@ bool can_close_in_cmdwin(win_T *win, Error *err)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
if (cmdwin_type != 0) {
|
||||
if (win == curwin) {
|
||||
if (win == cmdwin_win) {
|
||||
cmdwin_result = Ctrl_C;
|
||||
return false;
|
||||
} else if (win == cmdwin_old_curwin) {
|
||||
@ -2553,6 +2553,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
|
||||
/// "abort_if_last" is passed to close_buffer(): abort closing if all other
|
||||
/// windows are closed.
|
||||
static void win_close_buffer(win_T *win, int action, bool abort_if_last)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// Free independent synblock before the buffer is freed.
|
||||
if (win->w_buffer != NULL) {
|
||||
@ -2590,6 +2591,7 @@ static void win_close_buffer(win_T *win, int action, bool abort_if_last)
|
||||
// Called by :quit, :close, :xit, :wq and findtag().
|
||||
// Returns FAIL when the window was not closed.
|
||||
int win_close(win_T *win, bool free_buf, bool force)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
tabpage_T *prev_curtab = curtab;
|
||||
frame_T *win_frame = win->w_floating ? NULL : win->w_frame->fr_parent;
|
||||
@ -2888,6 +2890,7 @@ static void do_autocmd_winclosed(win_T *win)
|
||||
// Caller must check if buffer is hidden and whether the tabline needs to be
|
||||
// updated.
|
||||
void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// Get here with win->w_buffer == NULL when win_close() detects the tab page
|
||||
// changed.
|
||||
@ -2989,6 +2992,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
|
||||
///
|
||||
/// @return a pointer to the window that got the freed up space.
|
||||
static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
win_T *wp;
|
||||
tabpage_T *win_tp = tp == NULL ? curtab : tp;
|
||||
@ -3007,6 +3011,7 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp)
|
||||
wp = firstwin;
|
||||
}
|
||||
} else {
|
||||
assert(tp != curtab);
|
||||
if (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) {
|
||||
wp = tp->tp_prevwin;
|
||||
} else {
|
||||
@ -3030,6 +3035,9 @@ void win_free_all(void)
|
||||
{
|
||||
// avoid an error for switching tabpage with the cmdline window open
|
||||
cmdwin_type = 0;
|
||||
cmdwin_buf = NULL;
|
||||
cmdwin_win = NULL;
|
||||
cmdwin_old_curwin = NULL;
|
||||
|
||||
while (first_tabpage->tp_next != NULL) {
|
||||
tabpage_close(true);
|
||||
@ -3076,7 +3084,10 @@ void win_free_all(void)
|
||||
///
|
||||
/// @return a pointer to the window that got the freed up space.
|
||||
win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
{
|
||||
assert(tp == NULL || tp != curtab);
|
||||
|
||||
// If there is only one window there is nothing to remove.
|
||||
if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
|
||||
return NULL;
|
||||
@ -3223,7 +3234,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp)
|
||||
/// @return a pointer to the frame that will receive the empty screen space that
|
||||
/// is left over after "win" is closed.
|
||||
static frame_T *win_altframe(win_T *win, tabpage_T *tp)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
assert(tp == NULL || tp != curtab);
|
||||
|
||||
if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
|
||||
return alt_tabpage()->tp_curwin->w_frame;
|
||||
}
|
||||
@ -3287,6 +3301,7 @@ static tabpage_T *alt_tabpage(void)
|
||||
|
||||
// Find the left-upper window in frame "frp".
|
||||
win_T *frame2win(frame_T *frp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
while (frp->fr_win == NULL) {
|
||||
frp = frp->fr_child;
|
||||
@ -5139,7 +5154,10 @@ void win_append(win_T *after, win_T *wp)
|
||||
///
|
||||
/// @param tp tab page "win" is in, NULL for current
|
||||
void win_remove(win_T *wp, tabpage_T *tp)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
assert(tp == NULL || tp != curtab);
|
||||
|
||||
if (wp->w_prev != NULL) {
|
||||
wp->w_prev->w_next = wp->w_next;
|
||||
} else if (tp == NULL) {
|
||||
@ -5367,7 +5385,7 @@ static int check_window_scroll_resize(int *size_count, win_T **first_scroll_win,
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
// Skip floating windows that do not have a snapshot (usually because they are newly-created),
|
||||
// as unlike split windows, creating floating windows do not cause other windows to resize.
|
||||
// as unlike split windows, creating floating windows doesn't cause other windows to resize.
|
||||
if (wp->w_floating && wp->w_last_topline == 0) {
|
||||
wp->w_last_topline = wp->w_topline;
|
||||
wp->w_last_topfill = wp->w_topfill;
|
||||
|
@ -1798,6 +1798,36 @@ describe('API/extmarks', function()
|
||||
eq(1, #extmarks)
|
||||
eq('https://example.com', extmarks[1][4].url)
|
||||
end)
|
||||
|
||||
it('respects priority', function()
|
||||
screen = Screen.new(15, 10)
|
||||
screen:attach()
|
||||
|
||||
set_extmark(ns, marks[1], 0, 0, {
|
||||
hl_group = 'Comment',
|
||||
end_col = 2,
|
||||
priority = 20,
|
||||
})
|
||||
|
||||
-- Extmark defined after first extmark but has lower priority, first extmark "wins"
|
||||
set_extmark(ns, marks[2], 0, 0, {
|
||||
hl_group = 'String',
|
||||
end_col = 2,
|
||||
priority = 10,
|
||||
})
|
||||
|
||||
screen:expect {
|
||||
grid = [[
|
||||
{1:12}34^5 |
|
||||
{2:~ }|*8
|
||||
|
|
||||
]],
|
||||
attr_ids = {
|
||||
[1] = { foreground = Screen.colors.Blue1 },
|
||||
[2] = { foreground = Screen.colors.Blue1, bold = true },
|
||||
},
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('Extmarks buffer api with many marks', function()
|
||||
|
@ -12,15 +12,19 @@ describe('api/tabpage', function()
|
||||
|
||||
describe('list_wins and get_win', function()
|
||||
it('works', function()
|
||||
helpers.command('tabnew')
|
||||
helpers.command('vsplit')
|
||||
command('tabnew')
|
||||
command('vsplit')
|
||||
local tab1, tab2 = unpack(api.nvim_list_tabpages())
|
||||
local win1, win2, win3 = unpack(api.nvim_list_wins())
|
||||
eq({ win1 }, api.nvim_tabpage_list_wins(tab1))
|
||||
eq(win1, api.nvim_tabpage_get_win(tab1))
|
||||
eq({ win2, win3 }, api.nvim_tabpage_list_wins(tab2))
|
||||
eq(win2, api.nvim_tabpage_get_win(tab2))
|
||||
api.nvim_set_current_win(win3)
|
||||
eq(win3, api.nvim_tabpage_get_win(tab2))
|
||||
command('tabprev')
|
||||
eq(win1, api.nvim_tabpage_get_win(tab1))
|
||||
eq(win3, api.nvim_tabpage_get_win(tab2))
|
||||
end)
|
||||
|
||||
it('validates args', function()
|
||||
@ -28,6 +32,62 @@ describe('api/tabpage', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('set_win', function()
|
||||
it('works', function()
|
||||
command('tabnew')
|
||||
command('vsplit')
|
||||
local tab1, tab2 = unpack(api.nvim_list_tabpages())
|
||||
local win1, win2, win3 = unpack(api.nvim_list_wins())
|
||||
eq({ win1 }, api.nvim_tabpage_list_wins(tab1))
|
||||
eq({ win2, win3 }, api.nvim_tabpage_list_wins(tab2))
|
||||
eq(win2, api.nvim_tabpage_get_win(tab2))
|
||||
api.nvim_tabpage_set_win(tab2, win3)
|
||||
eq(win3, api.nvim_tabpage_get_win(tab2))
|
||||
end)
|
||||
|
||||
it('works in non-current tabpages', function()
|
||||
command('tabnew')
|
||||
command('vsplit')
|
||||
local tab1, tab2 = unpack(api.nvim_list_tabpages())
|
||||
local win1, win2, win3 = unpack(api.nvim_list_wins())
|
||||
eq({ win1 }, api.nvim_tabpage_list_wins(tab1))
|
||||
eq({ win2, win3 }, api.nvim_tabpage_list_wins(tab2))
|
||||
eq(win2, api.nvim_tabpage_get_win(tab2))
|
||||
eq(win2, api.nvim_get_current_win())
|
||||
|
||||
command('tabprev')
|
||||
|
||||
eq(tab1, api.nvim_get_current_tabpage())
|
||||
|
||||
eq(win2, api.nvim_tabpage_get_win(tab2))
|
||||
api.nvim_tabpage_set_win(tab2, win3)
|
||||
eq(win3, api.nvim_tabpage_get_win(tab2))
|
||||
|
||||
command('tabnext')
|
||||
eq(win3, api.nvim_get_current_win())
|
||||
end)
|
||||
|
||||
it('throws an error when the window does not belong to the tabpage', function()
|
||||
command('tabnew')
|
||||
command('vsplit')
|
||||
local tab1, tab2 = unpack(api.nvim_list_tabpages())
|
||||
local win1, win2, win3 = unpack(api.nvim_list_wins())
|
||||
eq({ win1 }, api.nvim_tabpage_list_wins(tab1))
|
||||
eq({ win2, win3 }, api.nvim_tabpage_list_wins(tab2))
|
||||
eq(win2, api.nvim_get_current_win())
|
||||
|
||||
eq(
|
||||
string.format('Window does not belong to tabpage %d', tab2),
|
||||
pcall_err(api.nvim_tabpage_set_win, tab2, win1)
|
||||
)
|
||||
|
||||
eq(
|
||||
string.format('Window does not belong to tabpage %d', tab1),
|
||||
pcall_err(api.nvim_tabpage_set_win, tab1, win3)
|
||||
)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('{get,set,del}_var', function()
|
||||
it('works', function()
|
||||
api.nvim_tabpage_set_var(0, 'lua', { 1, 2, { ['3'] = 1 } })
|
||||
@ -64,12 +124,12 @@ describe('api/tabpage', function()
|
||||
local tabs = api.nvim_list_tabpages()
|
||||
eq(1, api.nvim_tabpage_get_number(tabs[1]))
|
||||
|
||||
helpers.command('tabnew')
|
||||
command('tabnew')
|
||||
local tab1, tab2 = unpack(api.nvim_list_tabpages())
|
||||
eq(1, api.nvim_tabpage_get_number(tab1))
|
||||
eq(2, api.nvim_tabpage_get_number(tab2))
|
||||
|
||||
helpers.command('-tabmove')
|
||||
command('-tabmove')
|
||||
eq(2, api.nvim_tabpage_get_number(tab1))
|
||||
eq(1, api.nvim_tabpage_get_number(tab2))
|
||||
end)
|
||||
@ -77,11 +137,11 @@ describe('api/tabpage', function()
|
||||
|
||||
describe('is_valid', function()
|
||||
it('works', function()
|
||||
helpers.command('tabnew')
|
||||
command('tabnew')
|
||||
local tab = api.nvim_list_tabpages()[2]
|
||||
api.nvim_set_current_tabpage(tab)
|
||||
ok(api.nvim_tabpage_is_valid(tab))
|
||||
helpers.command('tabclose')
|
||||
command('tabclose')
|
||||
ok(not api.nvim_tabpage_is_valid(tab))
|
||||
end)
|
||||
end)
|
||||
|
@ -399,6 +399,19 @@ describe('API', function()
|
||||
]],
|
||||
}
|
||||
end)
|
||||
|
||||
it('errors properly when command too recursive', function()
|
||||
exec_lua([[
|
||||
_G.success = false
|
||||
vim.api.nvim_create_user_command('Test', function()
|
||||
vim.api.nvim_exec2('Test', {})
|
||||
_G.success = true
|
||||
end, {})
|
||||
]])
|
||||
pcall_err(command, 'Test')
|
||||
assert_alive()
|
||||
eq(false, exec_lua('return _G.success'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_command', function()
|
||||
@ -4560,6 +4573,7 @@ describe('API', function()
|
||||
line6
|
||||
]]
|
||||
end)
|
||||
|
||||
it('works with count', function()
|
||||
insert [[
|
||||
line1
|
||||
@ -4577,6 +4591,7 @@ describe('API', function()
|
||||
line6
|
||||
]]
|
||||
end)
|
||||
|
||||
it('works with register', function()
|
||||
insert [[
|
||||
line1
|
||||
@ -4599,11 +4614,13 @@ describe('API', function()
|
||||
line6
|
||||
]]
|
||||
end)
|
||||
|
||||
it('works with bang', function()
|
||||
api.nvim_create_user_command('Foo', 'echo "<bang>"', { bang = true })
|
||||
eq('!', api.nvim_cmd({ cmd = 'Foo', bang = true }, { output = true }))
|
||||
eq('', api.nvim_cmd({ cmd = 'Foo', bang = false }, { output = true }))
|
||||
end)
|
||||
|
||||
it('works with modifiers', function()
|
||||
-- with silent = true output is still captured
|
||||
eq(
|
||||
@ -4659,6 +4676,7 @@ describe('API', function()
|
||||
feed(':call<CR><CR>')
|
||||
eq('E471: Argument required', api.nvim_cmd({ cmd = 'messages' }, { output = true }))
|
||||
end)
|
||||
|
||||
it('works with magic.file', function()
|
||||
exec_lua([[
|
||||
vim.api.nvim_create_user_command("Foo", function(opts)
|
||||
@ -4673,6 +4691,7 @@ describe('API', function()
|
||||
)
|
||||
)
|
||||
end)
|
||||
|
||||
it('splits arguments correctly', function()
|
||||
exec([[
|
||||
function! FooFunc(...)
|
||||
@ -4695,6 +4714,7 @@ describe('API', function()
|
||||
)
|
||||
)
|
||||
end)
|
||||
|
||||
it('splits arguments correctly for Lua callback', function()
|
||||
api.nvim_exec_lua(
|
||||
[[
|
||||
@ -4721,6 +4741,7 @@ describe('API', function()
|
||||
)
|
||||
)
|
||||
end)
|
||||
|
||||
it('works with buffer names', function()
|
||||
command('edit foo.txt | edit bar.txt')
|
||||
api.nvim_cmd({ cmd = 'buffer', args = { 'foo.txt' } }, {})
|
||||
@ -4728,6 +4749,7 @@ describe('API', function()
|
||||
api.nvim_cmd({ cmd = 'buffer', args = { 'bar.txt' } }, {})
|
||||
eq('bar.txt', fn.fnamemodify(api.nvim_buf_get_name(0), ':t'))
|
||||
end)
|
||||
|
||||
it('triggers CmdUndefined event if command is not found', function()
|
||||
api.nvim_exec_lua(
|
||||
[[
|
||||
@ -4742,13 +4764,16 @@ describe('API', function()
|
||||
)
|
||||
eq('foo', api.nvim_cmd({ cmd = 'Foo' }, { output = true }))
|
||||
end)
|
||||
|
||||
it('errors if command is not implemented', function()
|
||||
eq('Command not implemented: winpos', pcall_err(api.nvim_cmd, { cmd = 'winpos' }, {}))
|
||||
end)
|
||||
|
||||
it('works with empty arguments list', function()
|
||||
api.nvim_cmd({ cmd = 'update' }, {})
|
||||
api.nvim_cmd({ cmd = 'buffer', count = 0 }, {})
|
||||
end)
|
||||
|
||||
it("doesn't suppress errors when used in keymapping", function()
|
||||
api.nvim_exec_lua(
|
||||
[[
|
||||
@ -4760,6 +4785,7 @@ describe('API', function()
|
||||
feed('[l')
|
||||
neq(nil, string.find(eval('v:errmsg'), 'E5108:'))
|
||||
end)
|
||||
|
||||
it('handles 0 range #19608', function()
|
||||
api.nvim_buf_set_lines(0, 0, -1, false, { 'aa' })
|
||||
api.nvim_cmd({ cmd = 'delete', range = { 0 } }, {})
|
||||
@ -4767,12 +4793,14 @@ describe('API', function()
|
||||
eq({ 'aa' }, api.nvim_buf_get_lines(0, 0, 1, false))
|
||||
assert_alive()
|
||||
end)
|
||||
|
||||
it('supports filename expansion', function()
|
||||
api.nvim_cmd({ cmd = 'argadd', args = { '%:p:h:t', '%:p:h:t' } }, {})
|
||||
local arg = fn.expand('%:p:h:t')
|
||||
eq({ arg, arg }, fn.argv())
|
||||
end)
|
||||
it("'make' command works when argument count isn't 1 #19696", function()
|
||||
|
||||
it(":make command works when argument count isn't 1 #19696", function()
|
||||
command('set makeprg=echo')
|
||||
command('set shellquote=')
|
||||
matches('^:!echo ', api.nvim_cmd({ cmd = 'make' }, { output = true }))
|
||||
@ -4789,6 +4817,7 @@ describe('API', function()
|
||||
)
|
||||
assert_alive()
|
||||
end)
|
||||
|
||||
it("doesn't display messages when output=true", function()
|
||||
local screen = Screen.new(40, 6)
|
||||
screen:attach()
|
||||
@ -4817,31 +4846,37 @@ describe('API', function()
|
||||
]],
|
||||
}
|
||||
end)
|
||||
|
||||
it('works with non-String args', function()
|
||||
eq('2', api.nvim_cmd({ cmd = 'echo', args = { 2 } }, { output = true }))
|
||||
eq('1', api.nvim_cmd({ cmd = 'echo', args = { true } }, { output = true }))
|
||||
end)
|
||||
|
||||
describe('first argument as count', function()
|
||||
it('works', function()
|
||||
command('vsplit | enew')
|
||||
api.nvim_cmd({ cmd = 'bdelete', args = { api.nvim_get_current_buf() } }, {})
|
||||
eq(1, api.nvim_get_current_buf())
|
||||
end)
|
||||
|
||||
it('works with :sleep using milliseconds', function()
|
||||
local start = uv.now()
|
||||
api.nvim_cmd({ cmd = 'sleep', args = { '100m' } }, {})
|
||||
ok(uv.now() - start <= 300)
|
||||
end)
|
||||
end)
|
||||
|
||||
it(':call with unknown function does not crash #26289', function()
|
||||
eq(
|
||||
'Vim:E117: Unknown function: UnknownFunc',
|
||||
pcall_err(api.nvim_cmd, { cmd = 'call', args = { 'UnknownFunc()' } }, {})
|
||||
)
|
||||
end)
|
||||
|
||||
it(':throw does not crash #24556', function()
|
||||
eq('42', pcall_err(api.nvim_cmd, { cmd = 'throw', args = { '42' } }, {}))
|
||||
end)
|
||||
|
||||
it('can use :return #24556', function()
|
||||
exec([[
|
||||
func Foo()
|
||||
@ -4854,5 +4889,18 @@ describe('API', function()
|
||||
eq('before', api.nvim_get_var('pos'))
|
||||
eq({ 1, 2, 3 }, api.nvim_get_var('result'))
|
||||
end)
|
||||
|
||||
it('errors properly when command too recursive #27210', function()
|
||||
exec_lua([[
|
||||
_G.success = false
|
||||
vim.api.nvim_create_user_command('Test', function()
|
||||
vim.api.nvim_cmd({ cmd = 'Test' }, {})
|
||||
_G.success = true
|
||||
end, {})
|
||||
]])
|
||||
pcall_err(command, 'Test')
|
||||
assert_alive()
|
||||
eq(false, exec_lua('return _G.success'))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@ -1,18 +1,20 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, curbuf, curbuf_contents, curwin, eq, neq, ok, feed, insert, eval =
|
||||
local clear, curbuf, curbuf_contents, curwin, eq, neq, matches, ok, feed, insert, eval =
|
||||
helpers.clear,
|
||||
helpers.api.nvim_get_current_buf,
|
||||
helpers.curbuf_contents,
|
||||
helpers.api.nvim_get_current_win,
|
||||
helpers.eq,
|
||||
helpers.neq,
|
||||
helpers.matches,
|
||||
helpers.ok,
|
||||
helpers.feed,
|
||||
helpers.insert,
|
||||
helpers.eval
|
||||
local poke_eventloop = helpers.poke_eventloop
|
||||
local exec = helpers.exec
|
||||
local exec_lua = helpers.exec_lua
|
||||
local fn = helpers.fn
|
||||
local request = helpers.request
|
||||
local NIL = vim.NIL
|
||||
@ -51,7 +53,7 @@ describe('API/win', function()
|
||||
eq('Invalid window id: 23', pcall_err(api.nvim_win_set_buf, 23, api.nvim_get_current_buf()))
|
||||
end)
|
||||
|
||||
it('disallowed in cmdwin if win={old_}curwin or buf=curbuf', function()
|
||||
it('disallowed in cmdwin if win=cmdwin_{old_cur}win or buf=cmdwin_buf', function()
|
||||
local new_buf = api.nvim_create_buf(true, true)
|
||||
local old_win = api.nvim_get_current_win()
|
||||
local new_win = api.nvim_open_win(new_buf, false, {
|
||||
@ -74,6 +76,36 @@ describe('API/win', function()
|
||||
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
|
||||
pcall_err(api.nvim_win_set_buf, new_win, 0)
|
||||
)
|
||||
matches(
|
||||
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
|
||||
pcall_err(
|
||||
exec_lua,
|
||||
[[
|
||||
local cmdwin_buf = vim.api.nvim_get_current_buf()
|
||||
local new_win, new_buf = ...
|
||||
vim.api.nvim_buf_call(new_buf, function()
|
||||
vim.api.nvim_win_set_buf(new_win, cmdwin_buf)
|
||||
end)
|
||||
]],
|
||||
new_win,
|
||||
new_buf
|
||||
)
|
||||
)
|
||||
matches(
|
||||
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
|
||||
pcall_err(
|
||||
exec_lua,
|
||||
[[
|
||||
local cmdwin_win = vim.api.nvim_get_current_win()
|
||||
local new_win, new_buf = ...
|
||||
vim.api.nvim_win_call(new_win, function()
|
||||
vim.api.nvim_win_set_buf(cmdwin_win, new_buf)
|
||||
end)
|
||||
]],
|
||||
new_win,
|
||||
new_buf
|
||||
)
|
||||
)
|
||||
|
||||
local next_buf = api.nvim_create_buf(true, true)
|
||||
api.nvim_win_set_buf(new_win, next_buf)
|
||||
@ -546,6 +578,7 @@ describe('API/win', function()
|
||||
it('in cmdline-window #9767', function()
|
||||
command('split')
|
||||
eq(2, #api.nvim_list_wins())
|
||||
local oldbuf = api.nvim_get_current_buf()
|
||||
local oldwin = api.nvim_get_current_win()
|
||||
local otherwin = api.nvim_open_win(0, false, {
|
||||
relative = 'editor',
|
||||
@ -570,6 +603,46 @@ describe('API/win', function()
|
||||
api.nvim_win_close(0, true)
|
||||
eq(2, #api.nvim_list_wins())
|
||||
eq('', fn.getcmdwintype())
|
||||
|
||||
-- Closing curwin in context of a different window shouldn't close cmdwin.
|
||||
otherwin = api.nvim_open_win(0, false, {
|
||||
relative = 'editor',
|
||||
row = 10,
|
||||
col = 10,
|
||||
width = 10,
|
||||
height = 10,
|
||||
})
|
||||
feed('q:')
|
||||
exec_lua(
|
||||
[[
|
||||
vim.api.nvim_win_call(..., function()
|
||||
vim.api.nvim_win_close(0, true)
|
||||
end)
|
||||
]],
|
||||
otherwin
|
||||
)
|
||||
eq(false, api.nvim_win_is_valid(otherwin))
|
||||
eq(':', fn.getcmdwintype())
|
||||
-- Closing cmdwin in context of a non-previous window is still OK.
|
||||
otherwin = api.nvim_open_win(oldbuf, false, {
|
||||
relative = 'editor',
|
||||
row = 10,
|
||||
col = 10,
|
||||
width = 10,
|
||||
height = 10,
|
||||
})
|
||||
exec_lua(
|
||||
[[
|
||||
local otherwin, cmdwin = ...
|
||||
vim.api.nvim_win_call(otherwin, function()
|
||||
vim.api.nvim_win_close(cmdwin, true)
|
||||
end)
|
||||
]],
|
||||
otherwin,
|
||||
api.nvim_get_current_win()
|
||||
)
|
||||
eq('', fn.getcmdwintype())
|
||||
eq(true, api.nvim_win_is_valid(otherwin))
|
||||
end)
|
||||
|
||||
it('closing current (float) window of another tabpage #15313', function()
|
||||
@ -646,6 +719,7 @@ describe('API/win', function()
|
||||
api.nvim_win_hide(0)
|
||||
eq('', fn.getcmdwintype())
|
||||
|
||||
local old_buf = api.nvim_get_current_buf()
|
||||
local old_win = api.nvim_get_current_win()
|
||||
local other_win = api.nvim_open_win(0, false, {
|
||||
relative = 'win',
|
||||
@ -663,6 +737,45 @@ describe('API/win', function()
|
||||
-- Can close other windows.
|
||||
api.nvim_win_hide(other_win)
|
||||
eq(false, api.nvim_win_is_valid(other_win))
|
||||
|
||||
-- Closing curwin in context of a different window shouldn't close cmdwin.
|
||||
other_win = api.nvim_open_win(old_buf, false, {
|
||||
relative = 'editor',
|
||||
row = 10,
|
||||
col = 10,
|
||||
width = 10,
|
||||
height = 10,
|
||||
})
|
||||
exec_lua(
|
||||
[[
|
||||
vim.api.nvim_win_call(..., function()
|
||||
vim.api.nvim_win_hide(0)
|
||||
end)
|
||||
]],
|
||||
other_win
|
||||
)
|
||||
eq(false, api.nvim_win_is_valid(other_win))
|
||||
eq(':', fn.getcmdwintype())
|
||||
-- Closing cmdwin in context of a non-previous window is still OK.
|
||||
other_win = api.nvim_open_win(old_buf, false, {
|
||||
relative = 'editor',
|
||||
row = 10,
|
||||
col = 10,
|
||||
width = 10,
|
||||
height = 10,
|
||||
})
|
||||
exec_lua(
|
||||
[[
|
||||
local otherwin, cmdwin = ...
|
||||
vim.api.nvim_win_call(otherwin, function()
|
||||
vim.api.nvim_win_hide(cmdwin)
|
||||
end)
|
||||
]],
|
||||
other_win,
|
||||
api.nvim_get_current_win()
|
||||
)
|
||||
eq('', fn.getcmdwintype())
|
||||
eq(true, api.nvim_win_is_valid(other_win))
|
||||
end)
|
||||
end)
|
||||
|
||||
@ -1055,7 +1168,7 @@ describe('API/win', function()
|
||||
eq(1, fn.exists('g:fired'))
|
||||
end)
|
||||
|
||||
it('disallowed in cmdwin if enter=true or buf=curbuf', function()
|
||||
it('disallowed in cmdwin if enter=true or buf=cmdwin_buf', function()
|
||||
local new_buf = api.nvim_create_buf(true, true)
|
||||
feed('q:')
|
||||
eq(
|
||||
@ -1078,6 +1191,20 @@ describe('API/win', function()
|
||||
height = 5,
|
||||
})
|
||||
)
|
||||
matches(
|
||||
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
|
||||
pcall_err(
|
||||
exec_lua,
|
||||
[[
|
||||
local cmdwin_buf = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function()
|
||||
vim.api.nvim_open_win(cmdwin_buf, false, {
|
||||
relative='editor', row=5, col=5, width=5, height=5,
|
||||
})
|
||||
end)
|
||||
]]
|
||||
)
|
||||
)
|
||||
|
||||
eq(
|
||||
new_buf,
|
||||
|
@ -39,6 +39,23 @@ describe('WinResized', function()
|
||||
eq(2, eval('g:resized'))
|
||||
eq({ windows = { 1002, 1001, 1000 } }, eval('g:v_event'))
|
||||
end)
|
||||
|
||||
it('is triggered in terminal mode #21197 #27207', function()
|
||||
exec([[
|
||||
autocmd TermOpen * startinsert
|
||||
let g:resized = 0
|
||||
autocmd WinResized * let g:resized += 1
|
||||
]])
|
||||
eq(0, eval('g:resized'))
|
||||
|
||||
command('vsplit term://')
|
||||
eq({ mode = 't', blocking = false }, api.nvim_get_mode())
|
||||
eq(1, eval('g:resized'))
|
||||
|
||||
command('split')
|
||||
eq({ mode = 't', blocking = false }, api.nvim_get_mode())
|
||||
eq(2, eval('g:resized'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('WinScrolled', function()
|
||||
|
@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local dedent = helpers.dedent
|
||||
local eq = helpers.eq
|
||||
local fn = helpers.fn
|
||||
local feed = helpers.feed
|
||||
@ -192,6 +193,131 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('buffer deletion', function()
|
||||
local base_file = 'Xtest-functional-buffer-deletion'
|
||||
local file1 = base_file .. '1'
|
||||
local file2 = base_file .. '2'
|
||||
local file3 = base_file .. '3'
|
||||
local base_content = 'text'
|
||||
local content1 = base_content .. '1'
|
||||
local content2 = base_content .. '2'
|
||||
local content3 = base_content .. '3'
|
||||
|
||||
local function format_jumplist(input)
|
||||
return dedent(input)
|
||||
:gsub('%{file1%}', file1)
|
||||
:gsub('%{file2%}', file2)
|
||||
:gsub('%{file3%}', file3)
|
||||
:gsub('%{content1%}', content1)
|
||||
:gsub('%{content2%}', content2)
|
||||
:gsub('%{content3%}', content3)
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
command('clearjumps')
|
||||
|
||||
write_file(file1, content1, false, false)
|
||||
write_file(file2, content2, false, false)
|
||||
write_file(file3, content3, false, false)
|
||||
|
||||
command('edit ' .. file1)
|
||||
command('edit ' .. file2)
|
||||
command('edit ' .. file3)
|
||||
end)
|
||||
|
||||
it('deletes jump list entries when the current buffer is deleted', function()
|
||||
command('edit ' .. file1)
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
3 1 0 {content1}
|
||||
2 1 0 {file2}
|
||||
1 1 0 {file3}
|
||||
>]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
|
||||
command('bwipeout')
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
1 1 0 {file2}
|
||||
> 0 1 0 {content3}]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
end)
|
||||
|
||||
it('deletes jump list entries when another buffer is deleted', function()
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
2 1 0 {file1}
|
||||
1 1 0 {file2}
|
||||
>]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
|
||||
command('bwipeout ' .. file2)
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
1 1 0 {file1}
|
||||
>]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
end)
|
||||
|
||||
it('sets the correct jump index when the current buffer is deleted', function()
|
||||
feed('<C-O>')
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
1 1 0 {file1}
|
||||
> 0 1 0 {content2}
|
||||
1 1 0 {file3}]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
|
||||
command('bw')
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
1 1 0 {file1}
|
||||
> 0 1 0 {content3}]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
end)
|
||||
|
||||
it('sets the correct jump index when the another buffer is deleted', function()
|
||||
feed('<C-O>')
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
1 1 0 {file1}
|
||||
> 0 1 0 {content2}
|
||||
1 1 0 {file3}]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
|
||||
command('bwipeout ' .. file1)
|
||||
|
||||
eq(
|
||||
format_jumplist([[
|
||||
jump line col file/text
|
||||
> 0 1 0 {content2}
|
||||
1 1 0 {file3}]]),
|
||||
exec_capture('jumps')
|
||||
)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('jumpoptions=view', function()
|
||||
local file1 = 'Xtestfile-functional-editor-jumps'
|
||||
local file2 = 'Xtestfile-functional-editor-jumps-2'
|
||||
|
@ -22,7 +22,7 @@ local remove_trace = helpers.remove_trace
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe(':lua command', function()
|
||||
describe(':lua', function()
|
||||
it('works', function()
|
||||
eq('', exec_capture('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})'))
|
||||
eq({ '', 'TEST' }, api.nvim_buf_get_lines(0, 0, 100, false))
|
||||
@ -54,7 +54,14 @@ describe(':lua command', function()
|
||||
)
|
||||
)
|
||||
end)
|
||||
|
||||
it('throws catchable errors', function()
|
||||
for _, cmd in ipairs({ 'lua', '1lua chunk' }) do
|
||||
eq(
|
||||
'Vim(lua):E475: Invalid argument: exactly one of {chunk} or {range} required',
|
||||
pcall_err(command, cmd)
|
||||
)
|
||||
end
|
||||
eq(
|
||||
[[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']],
|
||||
pcall_err(command, 'lua ()')
|
||||
@ -69,9 +76,11 @@ describe(':lua command', function()
|
||||
)
|
||||
eq({ '' }, api.nvim_buf_get_lines(0, 0, 100, false))
|
||||
end)
|
||||
|
||||
it('works with NULL errors', function()
|
||||
eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)'))
|
||||
end)
|
||||
|
||||
it('accepts embedded NLs without heredoc', function()
|
||||
-- Such code is usually used for `:execute 'lua' {generated_string}`:
|
||||
-- heredocs do not work in this case.
|
||||
@ -83,12 +92,14 @@ describe(':lua command', function()
|
||||
]])
|
||||
eq({ '', 'ETTS', 'TTSE', 'STTE' }, api.nvim_buf_get_lines(0, 0, 100, false))
|
||||
end)
|
||||
|
||||
it('preserves global and not preserves local variables', function()
|
||||
eq('', exec_capture('lua gvar = 42'))
|
||||
eq('', exec_capture('lua local lvar = 100500'))
|
||||
eq(NIL, fn.luaeval('lvar'))
|
||||
eq(42, fn.luaeval('gvar'))
|
||||
end)
|
||||
|
||||
it('works with long strings', function()
|
||||
local s = ('x'):rep(100500)
|
||||
|
||||
@ -192,6 +203,34 @@ describe(':lua command', function()
|
||||
exec_capture('=x(false)')
|
||||
)
|
||||
end)
|
||||
|
||||
it('with range', function()
|
||||
local screen = Screen.new(40, 10)
|
||||
screen:attach()
|
||||
api.nvim_buf_set_lines(0, 0, 0, 0, { 'nonsense', 'function x() print "hello" end', 'x()' })
|
||||
|
||||
-- ":{range}lua" fails on invalid Lua code.
|
||||
eq(
|
||||
[[:{range}lua: Vim(lua):E5107: Error loading lua [string ":{range}lua"]:0: '=' expected near '<eof>']],
|
||||
pcall_err(command, '1lua')
|
||||
)
|
||||
|
||||
-- ":{range}lua" executes valid Lua code.
|
||||
feed(':2,3lua<CR>')
|
||||
screen:expect {
|
||||
grid = [[
|
||||
nonsense |
|
||||
function x() print "hello" end |
|
||||
x() |
|
||||
^ |
|
||||
{1:~ }|*5
|
||||
hello |
|
||||
]],
|
||||
attr_ids = {
|
||||
[1] = { foreground = Screen.colors.Blue, bold = true },
|
||||
},
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
||||
describe(':luado command', function()
|
||||
|
@ -1,60 +0,0 @@
|
||||
-- Tests for gen_help_html.lua. Validates :help tags/links and HTML doc generation.
|
||||
--
|
||||
-- TODO: extract parts of gen_help_html.lua into Nvim stdlib?
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear = helpers.clear
|
||||
local exec_lua = helpers.exec_lua
|
||||
local eq = helpers.eq
|
||||
local ok = helpers.ok
|
||||
|
||||
if helpers.skip(helpers.is_ci('cirrus'), 'No need to run this on Cirrus') then
|
||||
return
|
||||
end
|
||||
|
||||
describe(':help docs', function()
|
||||
before_each(clear)
|
||||
it('validate', function()
|
||||
-- If this test fails, try these steps (in order):
|
||||
-- 1. Fix/cleanup the :help docs.
|
||||
-- 2. Fix the parser: https://github.com/neovim/tree-sitter-vimdoc
|
||||
-- 3. File a parser bug, and adjust the tolerance of this test in the meantime.
|
||||
|
||||
local rv = exec_lua([[return require('scripts.gen_help_html').validate('./build/runtime/doc')]])
|
||||
-- Check that we actually found helpfiles.
|
||||
ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles)
|
||||
|
||||
eq({}, rv.parse_errors, 'no parse errors')
|
||||
eq(0, rv.err_count, 'no parse errors')
|
||||
eq({}, rv.invalid_links, 'invalid tags in :help docs')
|
||||
eq({}, rv.invalid_urls, 'invalid URLs in :help docs')
|
||||
eq(
|
||||
{},
|
||||
rv.invalid_spelling,
|
||||
'invalid spelling in :help docs (see spell_dict in scripts/gen_help_html.lua)'
|
||||
)
|
||||
end)
|
||||
|
||||
it('gen_help_html.lua generates HTML', function()
|
||||
-- 1. Test that gen_help_html.lua actually works.
|
||||
-- 2. Test that parse errors did not increase wildly. Because we explicitly test only a few
|
||||
-- :help files, we can be precise about the tolerances here.
|
||||
|
||||
local tmpdir = exec_lua('return vim.fs.dirname(vim.fn.tempname())')
|
||||
-- Because gen() is slow (~30s), this test is limited to a few files.
|
||||
local rv = exec_lua(
|
||||
[[
|
||||
local to_dir = ...
|
||||
return require('scripts.gen_help_html').gen(
|
||||
'./build/runtime/doc',
|
||||
to_dir,
|
||||
{ 'pi_health.txt', 'help.txt', 'index.txt', 'nvim.txt', }
|
||||
)
|
||||
]],
|
||||
tmpdir
|
||||
)
|
||||
eq(4, #rv.helpfiles)
|
||||
eq(0, rv.err_count, 'parse errors in :help docs')
|
||||
eq({}, rv.invalid_links, 'invalid tags in :help docs')
|
||||
end)
|
||||
end)
|
@ -5,9 +5,11 @@ local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local exec_lua = helpers.exec_lua
|
||||
local feed = helpers.feed
|
||||
local fn = helpers.fn
|
||||
local matches = helpers.matches
|
||||
local pcall_err = helpers.pcall_err
|
||||
local sleep = vim.uv.sleep
|
||||
local poke_eventloop = helpers.poke_eventloop
|
||||
local retry = helpers.retry
|
||||
|
||||
describe('vim.snippet', function()
|
||||
before_each(function()
|
||||
@ -35,6 +37,12 @@ describe('vim.snippet', function()
|
||||
eq(expected, buf_lines(0))
|
||||
end
|
||||
|
||||
local function wait_for_pum()
|
||||
retry(nil, nil, function()
|
||||
eq(1, fn.pumvisible())
|
||||
end)
|
||||
end
|
||||
|
||||
--- @param snippet string
|
||||
--- @param err string
|
||||
local function test_expand_fail(snippet, err)
|
||||
@ -185,16 +193,16 @@ describe('vim.snippet', function()
|
||||
|
||||
it('inserts choice', function()
|
||||
test_expand_success({ 'console.${1|assert,log,error|}()' }, { 'console.()' })
|
||||
sleep(100)
|
||||
wait_for_pum()
|
||||
feed('<Down><C-y>')
|
||||
eq({ 'console.log()' }, buf_lines(0))
|
||||
end)
|
||||
|
||||
it('closes the choice completion menu when jumping', function()
|
||||
test_expand_success({ 'console.${1|assert,log,error|}($2)' }, { 'console.()' })
|
||||
sleep(100)
|
||||
wait_for_pum()
|
||||
exec_lua('vim.snippet.jump(1)')
|
||||
eq(0, exec_lua('return vim.fn.pumvisible()'))
|
||||
eq(0, fn.pumvisible())
|
||||
end)
|
||||
|
||||
it('jumps to next tabstop after inserting choice', function()
|
||||
@ -202,9 +210,9 @@ describe('vim.snippet', function()
|
||||
{ '${1|public,protected,private|} function ${2:name}() {', '\t$0', '}' },
|
||||
{ ' function name() {', '\t', '}' }
|
||||
)
|
||||
sleep(100)
|
||||
wait_for_pum()
|
||||
feed('<C-y><Tab>')
|
||||
sleep(10)
|
||||
poke_eventloop()
|
||||
feed('foo')
|
||||
eq({ 'public function foo() {', '\t', '}' }, buf_lines(0))
|
||||
end)
|
||||
|
@ -8,7 +8,6 @@ local helpers = require('test.functional.helpers')(after_each)
|
||||
local thelpers = require('test.functional.terminal.helpers')
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local eq = helpers.eq
|
||||
local feed_command = helpers.feed_command
|
||||
local feed_data = thelpers.feed_data
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
@ -2778,13 +2777,23 @@ describe('TUI', function()
|
||||
local req = args.data
|
||||
local payload = req:match('^\027P%+q([%x;]+)$')
|
||||
if payload then
|
||||
vim.g.xtgettcap = true
|
||||
local t = {}
|
||||
for cap in vim.gsplit(payload, ';') do
|
||||
local resp = string.format('\027P1+r%s\027\\', payload)
|
||||
vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp)
|
||||
t[vim.text.hexdecode(cap)] = true
|
||||
end
|
||||
vim.g.xtgettcap = t
|
||||
return true
|
||||
end
|
||||
end,
|
||||
})
|
||||
]])
|
||||
|
||||
local child_server = new_pipename()
|
||||
screen = thelpers.setup_child_nvim({
|
||||
'--listen',
|
||||
child_server,
|
||||
'-u',
|
||||
'NONE',
|
||||
'-i',
|
||||
@ -2800,9 +2809,58 @@ describe('TUI', function()
|
||||
},
|
||||
})
|
||||
|
||||
screen:expect({ any = '%[No Name%]' })
|
||||
|
||||
local child_session = helpers.connect(child_server)
|
||||
retry(nil, 1000, function()
|
||||
eq(true, eval("get(g:, 'xtgettcap', v:false)"))
|
||||
eq(1, eval('&termguicolors'))
|
||||
eq({
|
||||
Tc = true,
|
||||
RGB = true,
|
||||
setrgbf = true,
|
||||
setrgbb = true,
|
||||
}, eval("get(g:, 'xtgettcap', '')"))
|
||||
eq({ true, 1 }, { child_session:request('nvim_eval', '&termguicolors') })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('queries the terminal for OSC 52 support', function()
|
||||
clear()
|
||||
exec_lua([[
|
||||
vim.api.nvim_create_autocmd('TermRequest', {
|
||||
callback = function(args)
|
||||
local req = args.data
|
||||
local payload = req:match('^\027P%+q([%x;]+)$')
|
||||
if payload and vim.text.hexdecode(payload) == 'Ms' then
|
||||
vim.g.xtgettcap = 'Ms'
|
||||
local resp = string.format('\027P1+r%s=%s\027\\', payload, vim.text.hexencode('\027]52;;\027\\'))
|
||||
vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp)
|
||||
return true
|
||||
end
|
||||
end,
|
||||
})
|
||||
]])
|
||||
|
||||
local child_server = new_pipename()
|
||||
screen = thelpers.setup_child_nvim({
|
||||
'--listen',
|
||||
child_server,
|
||||
-- Use --clean instead of -u NONE to load the osc52 plugin
|
||||
'--clean',
|
||||
}, {
|
||||
env = {
|
||||
VIMRUNTIME = os.getenv('VIMRUNTIME'),
|
||||
|
||||
-- Only queries when SSH_TTY is set
|
||||
SSH_TTY = '/dev/pts/1',
|
||||
},
|
||||
})
|
||||
|
||||
screen:expect({ any = '%[No Name%]' })
|
||||
|
||||
local child_session = helpers.connect(child_server)
|
||||
retry(nil, 1000, function()
|
||||
eq('Ms', eval("get(g:, 'xtgettcap', '')"))
|
||||
eq({ true, 'OSC 52' }, { child_session:request('nvim_eval', 'g:clipboard.name') })
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
@ -2810,17 +2868,13 @@ end)
|
||||
describe('TUI bg color', function()
|
||||
before_each(clear)
|
||||
|
||||
local attr_ids = {
|
||||
[1] = { reverse = true },
|
||||
[2] = { bold = true },
|
||||
[3] = { reverse = true, bold = true },
|
||||
[4] = { foreground = tonumber('0x00000a') },
|
||||
}
|
||||
|
||||
it('is properly set in a nested Nvim instance when background=dark', function()
|
||||
command('highlight clear Normal')
|
||||
command('set background=dark') -- set outer Nvim background
|
||||
local child_server = new_pipename()
|
||||
local screen = thelpers.setup_child_nvim({
|
||||
'--listen',
|
||||
child_server,
|
||||
'-u',
|
||||
'NONE',
|
||||
'-i',
|
||||
@ -2830,26 +2884,20 @@ describe('TUI bg color', function()
|
||||
'--cmd',
|
||||
'set noswapfile',
|
||||
})
|
||||
screen:set_default_attr_ids(attr_ids)
|
||||
retry(nil, 30000, function() -- wait for automatic background processing
|
||||
screen:sleep(20)
|
||||
feed_command('set background?') -- check nested Nvim background
|
||||
screen:expect([[
|
||||
{1: } |
|
||||
{2:~} |
|
||||
{2:~} |
|
||||
{2:~} |
|
||||
{3:[No Name] 0,0-1 All}|
|
||||
background=dark |
|
||||
{4:-- TERMINAL --} |
|
||||
]])
|
||||
screen:expect({ any = '%[No Name%]' })
|
||||
local child_session = helpers.connect(child_server)
|
||||
retry(nil, nil, function()
|
||||
eq({ true, 'dark' }, { child_session:request('nvim_eval', '&background') })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('is properly set in a nested Nvim instance when background=light', function()
|
||||
command('highlight clear Normal')
|
||||
command('set background=light') -- set outer Nvim background
|
||||
local child_server = new_pipename()
|
||||
local screen = thelpers.setup_child_nvim({
|
||||
'--listen',
|
||||
child_server,
|
||||
'-u',
|
||||
'NONE',
|
||||
'-i',
|
||||
@ -2859,18 +2907,10 @@ describe('TUI bg color', function()
|
||||
'--cmd',
|
||||
'set noswapfile',
|
||||
})
|
||||
retry(nil, 30000, function() -- wait for automatic background processing
|
||||
screen:sleep(20)
|
||||
feed_command('set background?') -- check nested Nvim background
|
||||
screen:expect([[
|
||||
{1: } |
|
||||
{3:~} |
|
||||
{3:~} |
|
||||
{3:~} |
|
||||
{5:[No Name] 0,0-1 All}|
|
||||
background=light |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
screen:expect({ any = '%[No Name%]' })
|
||||
local child_session = helpers.connect(child_server)
|
||||
retry(nil, nil, function()
|
||||
eq({ true, 'light' }, { child_session:request('nvim_eval', '&background') })
|
||||
end)
|
||||
end)
|
||||
|
||||
@ -2914,18 +2954,13 @@ describe('TUI bg color', function()
|
||||
'-c',
|
||||
'autocmd OptionSet background echo "did OptionSet, yay!"',
|
||||
})
|
||||
retry(nil, 30000, function() -- wait for automatic background processing
|
||||
screen:sleep(20)
|
||||
screen:expect([[
|
||||
screen:expect([[
|
||||
{1: } |
|
||||
{3:~} |
|
||||
{3:~} |
|
||||
{3:~} |
|
||||
{3:~} |*3
|
||||
{5:[No Name] 0,0-1 All}|
|
||||
did OptionSet, yay! |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
end)
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
|
@ -675,126 +675,3 @@ t2]])
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('treesitter foldtext', function()
|
||||
local test_text = [[
|
||||
void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *))
|
||||
{
|
||||
int width = INT_MAX, height = INT_MAX;
|
||||
bool ext_widgets[kUIExtCount];
|
||||
for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
|
||||
ext_widgets[i] = true;
|
||||
}
|
||||
|
||||
bool inclusive = ui_override();
|
||||
for (size_t i = 0; i < ui_count; i++) {
|
||||
UI *ui = uis[i];
|
||||
width = MIN(ui->width, width);
|
||||
height = MIN(ui->height, height);
|
||||
foo = BAR(ui->bazaar, bazaar);
|
||||
for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
|
||||
ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
|
||||
}
|
||||
}
|
||||
}]]
|
||||
local screen
|
||||
|
||||
before_each(function()
|
||||
screen = Screen.new(60, 5)
|
||||
screen:set_default_attr_ids({
|
||||
[0] = { foreground = Screen.colors.Blue, bold = true },
|
||||
[1] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray },
|
||||
[2] = {
|
||||
bold = true,
|
||||
background = Screen.colors.LightGray,
|
||||
foreground = Screen.colors.SeaGreen,
|
||||
},
|
||||
[3] = { foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGray },
|
||||
[4] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGray },
|
||||
[5] = { bold = true, background = Screen.colors.LightGray, foreground = Screen.colors.Brown },
|
||||
[6] = { background = Screen.colors.Red1 },
|
||||
[7] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Red },
|
||||
[8] = { foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red },
|
||||
[9] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Red },
|
||||
[10] = { bold = true },
|
||||
})
|
||||
screen:attach()
|
||||
end)
|
||||
|
||||
it('displays highlighted content', function()
|
||||
command([[set foldmethod=manual foldtext=v:lua.vim.treesitter.foldtext() updatetime=50]])
|
||||
insert(test_text)
|
||||
exec_lua([[vim.treesitter.get_parser(0, "c")]])
|
||||
|
||||
feed('ggVGzf')
|
||||
screen:expect {
|
||||
grid = [[
|
||||
{4:^void}{1: }{3:qsort}{4:(void}{1: }{5:*}{3:base}{4:,}{1: }{4:size_t}{1: }{3:nel}{4:,}{1: }{4:size_t}{1: }{3:width}{4:,}{1: }{4:int}{1: }{4:(}{5:*}{3:compa}|
|
||||
{0:~ }|*3
|
||||
|
|
||||
]],
|
||||
}
|
||||
end)
|
||||
|
||||
it('handles deep nested captures', function()
|
||||
command([[set foldmethod=manual foldtext=v:lua.vim.treesitter.foldtext() updatetime=50]])
|
||||
insert([[
|
||||
function FoldInfo.new()
|
||||
return setmetatable({
|
||||
start_counts = {},
|
||||
stop_counts = {},
|
||||
levels0 = {},
|
||||
levels = {},
|
||||
}, FoldInfo)
|
||||
end]])
|
||||
exec_lua([[vim.treesitter.get_parser(0, "lua")]])
|
||||
|
||||
feed('ggjVGkzfgg')
|
||||
screen:expect {
|
||||
grid = [[
|
||||
^function FoldInfo.new() |
|
||||
{1: }{5:return}{1: }{4:setmetatable({}{1:·····································}|
|
||||
end |
|
||||
{0:~ }|
|
||||
|
|
||||
]],
|
||||
}
|
||||
|
||||
command('hi! Visual guibg=Red')
|
||||
feed('GVgg')
|
||||
screen:expect {
|
||||
grid = [[
|
||||
^f{6:unction FoldInfo.new()} |
|
||||
{7: }{8:return}{7: }{9:setmetatable({}{7:·····································}|
|
||||
{6:end} |
|
||||
{0:~ }|
|
||||
{10:-- VISUAL LINE --} |
|
||||
]],
|
||||
}
|
||||
|
||||
feed('10l<C-V>')
|
||||
screen:expect {
|
||||
grid = [[
|
||||
{6:function F}^oldInfo.new() |
|
||||
{7: }{8:return}{7: }{9:se}{4:tmetatable({}{1:·····································}|
|
||||
{6:end} |
|
||||
{0:~ }|
|
||||
{10:-- VISUAL BLOCK --} |
|
||||
]],
|
||||
}
|
||||
end)
|
||||
|
||||
it('falls back to default', function()
|
||||
command([[set foldmethod=manual foldtext=v:lua.vim.treesitter.foldtext()]])
|
||||
insert(test_text)
|
||||
|
||||
feed('ggVGzf')
|
||||
screen:expect {
|
||||
grid = [[
|
||||
{1:^+-- 19 lines: void qsort(void *base, size_t nel, size_t widt}|
|
||||
{0:~ }|*3
|
||||
|
|
||||
]],
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
@ -687,7 +687,7 @@ describe('decorations providers', function()
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('can add new providers during redraw #26652', function()
|
||||
it('can add new providers during redraw #26652', function()
|
||||
setup_provider [[
|
||||
local ns = api.nvim_create_namespace('test_no_add')
|
||||
function on_do(...)
|
||||
@ -697,6 +697,47 @@ describe('decorations providers', function()
|
||||
|
||||
helpers.assert_alive()
|
||||
end)
|
||||
|
||||
it('supports subpriorities (order of definitions in a query file #27131)', function()
|
||||
insert(mulholland)
|
||||
setup_provider [[
|
||||
local test_ns = api.nvim_create_namespace('mulholland')
|
||||
function on_do(event, ...)
|
||||
if event == "line" then
|
||||
local win, buf, line = ...
|
||||
api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
|
||||
end_row = line + 1,
|
||||
hl_eol = true,
|
||||
hl_group = 'Comment',
|
||||
ephemeral = true,
|
||||
priority = 100,
|
||||
_subpriority = 20,
|
||||
})
|
||||
|
||||
-- This extmark is set last but has a lower subpriority, so the first extmark "wins"
|
||||
api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
|
||||
end_row = line + 1,
|
||||
hl_eol = true,
|
||||
hl_group = 'String',
|
||||
ephemeral = true,
|
||||
priority = 100,
|
||||
_subpriority = 10,
|
||||
})
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
screen:expect{grid=[[
|
||||
{4:// just to see if there was an accident }|
|
||||
{4:// on Mulholland Drive }|
|
||||
{4:try_start(); }|
|
||||
{4:bufref_T save_buf; }|
|
||||
{4:switch_buffer(&save_buf, buf); }|
|
||||
{4:posp = getmark(mark, false); }|
|
||||
{4:restore_buffer(&save_buf);^ }|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
end)
|
||||
|
||||
local example_text = [[
|
||||
|
@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
|
||||
local neq, eq, command = helpers.neq, helpers.eq, helpers.command
|
||||
local clear = helpers.clear
|
||||
local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval
|
||||
local exec_lua = helpers.exec_lua
|
||||
local insert, pcall_err = helpers.insert, helpers.pcall_err
|
||||
local matches = helpers.matches
|
||||
local api = helpers.api
|
||||
@ -106,6 +107,19 @@ describe('eval-API', function()
|
||||
pcall_err(api.nvim_open_term, 0, {})
|
||||
)
|
||||
|
||||
matches(
|
||||
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
|
||||
pcall_err(
|
||||
exec_lua,
|
||||
[[
|
||||
local cmdwin_buf = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function()
|
||||
vim.api.nvim_open_term(cmdwin_buf, {})
|
||||
end)
|
||||
]]
|
||||
)
|
||||
)
|
||||
|
||||
-- But turning a different buffer into a terminal from the cmdwin is OK.
|
||||
local term_buf = api.nvim_create_buf(false, true)
|
||||
api.nvim_open_term(term_buf, {})
|
||||
|
@ -1885,7 +1885,7 @@ func Test_cmdwin_tabpage()
|
||||
tabclose!
|
||||
endfunc
|
||||
|
||||
func Test_cmdwin_interrupted()
|
||||
func Test_cmdwin_interrupted_more_prompt()
|
||||
CheckScreendump
|
||||
|
||||
" aborting the :smile output caused the cmdline window to use the current
|
||||
|
@ -93,4 +93,116 @@ func Test_cmdwin_restore_heights()
|
||||
set cmdheight& showtabline& laststatus&
|
||||
endfunc
|
||||
|
||||
func Test_cmdwin_temp_curwin()
|
||||
func CheckWraps(expect_wrap)
|
||||
setlocal textwidth=0 wrapmargin=1
|
||||
|
||||
call deletebufline('', 1, '$')
|
||||
let as = repeat('a', winwidth(0) - 2 - &wrapmargin)
|
||||
call setline(1, as .. ' b')
|
||||
normal! gww
|
||||
|
||||
setlocal textwidth& wrapmargin&
|
||||
call assert_equal(a:expect_wrap ? [as, 'b'] : [as .. ' b'], getline(1, '$'))
|
||||
endfunc
|
||||
|
||||
func CheckCmdWin()
|
||||
call assert_equal('command', win_gettype())
|
||||
" textoff and &wrapmargin formatting considers the cmdwin_type char.
|
||||
call assert_equal(1, getwininfo(win_getid())[0].textoff)
|
||||
call CheckWraps(1)
|
||||
endfunc
|
||||
|
||||
func CheckOtherWin()
|
||||
call assert_equal('', win_gettype())
|
||||
call assert_equal(0, getwininfo(win_getid())[0].textoff)
|
||||
call CheckWraps(0)
|
||||
endfunc
|
||||
|
||||
call feedkeys("q::call CheckCmdWin()\<CR>:call win_execute(win_getid(winnr('#')), 'call CheckOtherWin()')\<CR>:q<CR>", 'ntx')
|
||||
|
||||
%bwipe!
|
||||
delfunc CheckWraps
|
||||
delfunc CheckCmdWin
|
||||
delfunc CheckOtherWin
|
||||
endfunc
|
||||
|
||||
func Test_cmdwin_interrupted()
|
||||
func CheckInterrupted()
|
||||
call feedkeys("q::call assert_equal('', getcmdwintype())\<CR>:call assert_equal('', getcmdtype())\<CR>:q<CR>", 'ntx')
|
||||
endfunc
|
||||
|
||||
augroup CmdWin
|
||||
|
||||
" While opening the cmdwin's split:
|
||||
" Close the cmdwin's window.
|
||||
au WinEnter * ++once quit
|
||||
call CheckInterrupted()
|
||||
|
||||
" Close the old window.
|
||||
au WinEnter * ++once execute winnr('#') 'quit'
|
||||
call CheckInterrupted()
|
||||
|
||||
" Switch back to the old window.
|
||||
au WinEnter * ++once wincmd p
|
||||
call CheckInterrupted()
|
||||
|
||||
" Change the old window's buffer.
|
||||
au WinEnter * ++once call win_execute(win_getid(winnr('#')), 'enew')
|
||||
call CheckInterrupted()
|
||||
|
||||
" Using BufLeave autocmds as cmdwin restrictions do not apply to them when
|
||||
" fired from opening the cmdwin...
|
||||
" After opening the cmdwin's split, while creating the cmdwin's buffer:
|
||||
" Delete the cmdwin's buffer.
|
||||
au BufLeave * ++once bwipe
|
||||
call CheckInterrupted()
|
||||
|
||||
" Close the cmdwin's window.
|
||||
au BufLeave * ++once quit
|
||||
call CheckInterrupted()
|
||||
|
||||
" Close the old window.
|
||||
au BufLeave * ++once execute winnr('#') 'quit'
|
||||
call CheckInterrupted()
|
||||
|
||||
" Switch to a different window.
|
||||
au BufLeave * ++once split
|
||||
call CheckInterrupted()
|
||||
|
||||
" Change the old window's buffer.
|
||||
au BufLeave * ++once call win_execute(win_getid(winnr('#')), 'enew')
|
||||
call CheckInterrupted()
|
||||
|
||||
" However, changing the current buffer is OK and does not interrupt.
|
||||
au BufLeave * ++once edit other
|
||||
call feedkeys("q::let t=getcmdwintype()\<CR>:let b=bufnr()\<CR>:clo<CR>", 'ntx')
|
||||
call assert_equal(':', t)
|
||||
call assert_equal(1, bufloaded('other'))
|
||||
call assert_notequal(b, bufnr('other'))
|
||||
|
||||
augroup END
|
||||
|
||||
" No autocmds should remain, but clear the augroup to be sure.
|
||||
augroup CmdWin
|
||||
au!
|
||||
augroup END
|
||||
|
||||
%bwipe!
|
||||
delfunc CheckInterrupted
|
||||
endfunc
|
||||
|
||||
func Test_cmdwin_existing_bufname()
|
||||
func CheckName()
|
||||
call assert_equal(1, getbufinfo('')[0].command)
|
||||
call assert_equal(0, getbufinfo('[Command Line]')[0].command)
|
||||
call assert_match('#a\s*"\[Command Line\]"', execute('ls'))
|
||||
call assert_match('%a\s*"\[Command Line\]"', execute('ls'))
|
||||
endfunc
|
||||
file [Command Line]
|
||||
call feedkeys("q::call CheckName()\<CR>:q\<CR>", 'ntx')
|
||||
0file
|
||||
delfunc CheckName
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -235,6 +235,24 @@ func Test_map_meta_multibyte()
|
||||
iunmap <M-á>
|
||||
endfunc
|
||||
|
||||
func Test_map_super_quotes()
|
||||
if has('gui_gtk') || has('gui_gtk3') || has("macos")
|
||||
imap <D-"> foo
|
||||
call feedkeys("Go-\<*D-\">-\<Esc>", "xt")
|
||||
call assert_equal("-foo-", getline('$'))
|
||||
set nomodified
|
||||
iunmap <D-">
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func Test_map_super_multibyte()
|
||||
if has('gui_gtk') || has('gui_gtk3') || has("macos")
|
||||
imap <D-á> foo
|
||||
call assert_match('i <D-á>\s*foo', execute('imap'))
|
||||
iunmap <D-á>
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func Test_abbr_after_line_join()
|
||||
new
|
||||
abbr foo bar
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user