Compare commits

...

53 Commits

Author SHA1 Message Date
Justin M. Keyes
0313615e9d
Merge 1dd6a56409 into 9f15a18fa5 2024-01-30 17:08:36 -08:00
zeertzjq
9f15a18fa5
fix(statusline): missing offset when showing 'keymap' (#27270) 2024-01-31 08:48:52 +08:00
zeertzjq
4ffc20c951
fix(lua): avoid internal error when :luado deletes lines (#27262) 2024-01-30 08:09:25 +08:00
zeertzjq
a2070ba877
vim-patch:9.1.0065: Segfault with CompleteChanged autocommand (#27261)
Problem:  Segfault with CompleteChanged autocommand
          (markonm )
Solution: Test match->cp_prev for being NULL before accessing it

closes: vim/vim#13929

fef6630166

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-01-30 07:34:37 +08:00
Jongwook Choi
be5cf33836
fix(gen_help_html): type warnings, spell_ignore_files #27254
- Add type annotations, fix most of the type warnings.
- Fix a minor bug on `spell_ignore_files`: nil error when an invalid
  spelling is found but the file is not ignored.
2024-01-29 11:02:10 -08:00
Justin M. Keyes
a060c13f55
Merge #27246 from justinmk/health 2024-01-29 09:43:49 -08:00
dundargoc
758504ec73 docs: document special labels used in CI 2024-01-29 13:46:04 +01:00
Evgeni Chasnovski
4f788f78f8
vim-patch:9.1.0061: UX of visual highlighting can be improved (#27256)
Problem:  UX of visual highlighting can be improved
Solution: Improve readibility of visual highlighting,
          by setting better foreground and background
          colors

The default visual highlighting currently is nice in that it overlays
the actual syntax highlighting by using a separate distinct background
color.

However, this can cause hard to read text, because the contrast
between the actual syntax element and the background color is way too
low. That is an issue, that has been bothering colorschemes authors for
quite some time so much, that they are defining the Visual highlighting
group to use a separate foreground and background color, so that the
syntax highlighting vanishes, but the text remains readable (ref:
vim/colorschemesvim/vim#250)

So this is an attempt to perform the same fix for the default Visual
highlighting and just use a default foreground and background color
instead of using reverse.

I also removed the hard-coded changes to the Visual highlighting in
init_highlight. It's not quite clear to me, why those were there and not
added directly to the highlighting_init_<dark|light> struct.

closes: vim/vim#13663
related: vim/colorschemes#250

e6d8b4662d

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-01-29 18:39:57 +08:00
Will Hopkins
ca9f6f5694
feat(api): add nvim_tabpage_set_win (#27222)
Allows setting the current window of a non-current tabpage
without switching tabpages.
2024-01-29 15:18:33 +08:00
Justin M. Keyes
1dd6a56409 docs: misc
fix #23251
ref https://github.com/neovim/neovim/issues/2252#issuecomment-1902662577

Co-authored-by: Kevin Pham <keevan.pham@gmail.com>
2024-01-29 07:04:52 +01:00
Justin M. Keyes
77dd1837ae feat(docs): parse [optional] 2024-01-29 05:11:00 +01:00
zeertzjq
5e5b004da4 vim-patch:cf8695d48cdd
runtime(vim): Highlight string interpolation

closes: vim/vim#13923

cf8695d48c

Co-authored-by: thinca <thinca@gmail.com>
2024-01-29 11:25:35 +08:00
zeertzjq
7db83d47b2 vim-patch:21ce159e0561
runtime(vim): Update syntax and ftplugin files (vim/vim#13924)

Improve matching of line-continuations and interspersed comments.

These are now also matched in multiline syntax command patterns,
dictionary literals, and parenthesised expressions and argument lists.

21ce159e05

Co-authored-by: dkearns <dougkearns@gmail.com>
2024-01-29 11:25:35 +08:00
zeertzjq
d62b3fa623 vim-patch:c79646dfb101
runtime(vim): Update syntax file (vim/vim#13671)

Support multiline :syntax commands.

Match :syn-cchar option in :syn-{keyword,region}.

c79646dfb1

Co-authored-by: dkearns <dougkearns@gmail.com>
2024-01-29 11:25:35 +08:00
zeertzjq
f1e51528d2 vim-patch:71b6d3397649
Update runtime files

71b6d33976

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2024-01-29 11:25:35 +08:00
Gregory Anders
15e77a56b7
feat(extmarks): subpriorities (relative to declaration order) (#27131)
The "priority" field of extmarks can be used to set priorities of
extmarks which dictates which highlight group a range will actually have
when there are multiple extmarks applied. However, when multiple
extmarks have the same priority, the only way to enforce an actual
priority is through the order in which the extmarks are set.

It is not always possible or desirable to set extmarks in a specific
order, however, so we add a new "subpriority" field that explicitly
enforces the ordering of extmarks that have the same priority.

For now this will be used only to enforce priority of treesitter
highlights. A single node in a treesitter tree may match multiple
captures, in which case that node will have multiple extmarks set. The
order in which captures are returned from the treesitter API is not
_necessarily_ in the same order they are defined in a query file, so we
use the new subpriority field to force that ordering.

For now subpriorites are not documented and are not meant to be used by
external code, and it only applies to ephemeral extmarks. We indicate
the "private" nature of subpriorities by prefixing the field name with
an "_".
2024-01-28 21:13:58 -06:00
vE5li
af6537bc66
fix(jumplist): Ctrl+o, Ctrl+i weird behavior when deleting buffers #25461
Problem:
- Navigation is not always symmetric: pressing Ctrl+o n times followed
  by Ctrl+i n times does not always gets me back to where I started.
- Invalid buffers are not skipped by Ctrl+i/o, I have to press Ctrl+i/o
  multiple times to get to the next/previous buffer.

Solution:
- Remove all entries of a buffer from the jump list when deleting it.
- Don't add a new entry to the jump list if the next buffer to be
  displayed is already in the jump list.

Closes #25365
2024-01-28 19:08:51 -08:00
Maria José Solano
eee52d3427
refactor(lsp): client_hints typo #27250 2024-01-28 18:38:36 -08:00
zeertzjq
d6f7fa14c5
refactor(window.c): add a few more assertions (#27249) 2024-01-29 10:05:33 +08:00
Jongwook Choi
5b1b765610
docs: enforce "treesitter" spelling #27110
It's the "tree-sitter" project, but "treesitter" in our code and docs.
2024-01-28 17:53:14 -08:00
zeertzjq
b0e85010fe
test: more tests for nvim_tabpage_get_win (#27248) 2024-01-29 08:32:24 +08:00
zeertzjq
ba7a52dedc
vim-patch:9.1.0060: Recorded register cannot be translated using keytrans() (#27247)
Problem:  Recorded register cannot be translated using keytrans() when
          it involves character search (iddqd505)
Solution: Record a K_IGNORE instead of a K_NOP (zeertzjq)

related: vim/vim#13916
closes: vim/vim#13925

bf321806bf
2024-01-29 07:27:15 +08:00
Justin M. Keyes
56ae85a33c
docs: .git-blame-ignore-revs #26397 2024-01-28 15:03:10 -08:00
Justin M. Keyes
e39b6d0c52 fix(health): "attempt to concatenate nil"
Problem:
If `neovim` module is not installed, python and ruby healthchecks fail:

    - ERROR Failed to run healthcheck for "provider.python" plugin. Exception:
      .../runtime/lua/provider/python/health.lua:348: attempt to concatenate local 'pyname' (a nil value)
    - ERROR Failed to run healthcheck for "provider.ruby" plugin. Exception:
      .../runtime/lua/provider/ruby/health.lua:25: attempt to index local 'host' (a nil value)

Solution:
Check for non-nil.
2024-01-28 23:56:06 +01:00
Justin M. Keyes
50cd5ed360 fix(health): check more "old" files 2024-01-28 23:56:03 +01:00
Justin M. Keyes
4ddd999f65
docs: update FAQ URLs #27236 2024-01-28 14:53:05 -08:00
Jongwook Choi
095f731af0
docs: include backtrace for bug-crash #27065
Github Issue template:

- Add pointers to |dev-tools-backtrace|.
- Add pointers to CONTRIBUTING.md (Reporting Problems), which includes
  additional helpful instructions for issue reporting.
- Search existing issues: include label `bug-crash` as well as `bug`.

CONTRIBUTING.md:

- Fix broken link on "stacktrace" after moving to help from wiki.
2024-01-28 14:26:13 -08:00
Jongwook Choi
01e82eba20
build(docs): separate lint job to validate vimdoc #27227
Summary: Separate the lint job (`make lintdoc`) to validate runtime/doc,
it is no longer as a part of functionaltest (help_spec).

Build (cmake) and CI:

- `make lintdoc`: validate vimdoc files and test-generate HTML docs.
  CI will run this as a part of the "docs" workflow.

- `scripts/lintdoc.lua` is added as an entry point (executable script)
  for validating vimdoc files.

scripts/gen_help_html.lua:

- Move the tests for validating docs and generating HTMLs from
  `help_spec.lua` to `gen_help_html`. Added:
  - `gen_help_html.run_validate()`.
  - `gen_help_html.test_gen()`.

- Do not hard-code `help_dir` to `build/runtime/doc`, but resolve from
  `$VIMRUNTIME`. Therefore, the `make lintdoc` job will check doc files
  on `./runtime/doc`, not on `./build/runtime/doc`.

- Add type annotations for gen_help_html.
2024-01-28 14:22:39 -08:00
Gregory Anders
47cd532bf1
docs: explain why TUI is reinitialized on resume (#27177) 2024-01-28 08:38:59 -06:00
zeertzjq
1bc7e18aa8
test(lua/snippet_spec): wait for completion menu (#27243)
This fixes the flakiness caused by typing a completion menu key when the
completion menu hasn't showed up.
2024-01-28 22:01:25 +08:00
Gregory Anders
6d86a6fe44
test(tui): add & improve tests for terminal queries (#27219)
Problems:

1. The test case for querying truecolor support did not check which
   capabilities were queried
2. The test case for querying truecolor support checked `&termguicolors`
   in the Nvim test runner, not the child Nvim in the the embedded
   terminal
3. The test case for querying truecolor support did not actually respond
   to the XTGETTCAP requests. `'termguicolors'` is still enabled even
   without responding to this query because libvterm understands and
   responds to the DECRQSS request, but it is still good to respond to
   the query explicitly instead of depending on hidden libvterm behavior
4. No test case exists at all for OSC 52

Solution:

Fix all of the problems listed above.
2024-01-28 07:37:57 -06:00
Sean Dewar
a757195a60
Merge pull request #24704 from seandewar/cmdwin-madness
vim-patch:9.1.{0047,0048,0049}: fun cmdwin fixes
2024-01-28 13:03:56 +00:00
Sean Dewar
d85f180f26
vim-patch:9.1.0049: Make "[Command Line]" a special buffer name
Problem:  E95 is possible if a buffer called "[Command Line]" already
          exists when opening the cmdwin. This can also happen if the
          cmdwin's buffer could not be deleted when closing.

Solution: Un-name the cmdwin buffer, and give it a special name instead,
          similar to what's done for quickfix buffers and for unnamed
          prompt and scratch buffers. As a result, BufFilePre/Post are
          no longer fired when opening the cmdwin. Add a "command" key
          to the dictionary returned by getbufinfo() to differentiate
          the cmdwin buffer instead. (Sean Dewar)

Cherry-pick test_normal changes from v9.0.0954.

1fb4103206
2024-01-28 12:29:42 +00:00
Sean Dewar
7bb0dd08db
vim-patch:9.1.0048: Abort opening cmdwin if autocmds screw things up
Problem:  Autocmds triggered from opening the cmdwin (in win_split and
          do_ecmd) can cause issues such as E199, as the current checks
          are insufficient.

Solution: Commands executed from the cmdwin apply to the old curwin/buf,
          so they should be kept in a "suspended" state; abort if
          they've changed. Also abort if cmdwin/buf was tampered with,
          and check that curwin is correct. Try to clean up the cmdwin
          buffer (only if hidden and non-current to simplify things; the
          same approach is used when closing cmdwin normally), and add a
          beep. (Sean Dewar)

Rename the old Test_cmdwin_interrupted() like in the patch (can be moved to
test_cmdwin.vim when v9.0.0027 is ported).
Move the error message to `e_active_window_or_buffer_changed_or_deleted`.

43b395ec2e
2024-01-28 12:29:42 +00:00
Sean Dewar
cf140fb25b
vim-patch:9.1.0047: issues with temp curwin/buf while cmdwin is open
Problem:  Things that temporarily change/restore curwin/buf (e.g:
          win_execute, some autocmds) may break assumptions that
          curwin/buf is the cmdwin when "cmdwin_type != 0", causing
          issues.

Solution: Expose the cmdwin's real win/buf and check that instead. Also
          try to ensure these variables are NULL if "cmdwin_type == 0",
          allowing them to be used directly in most cases without
          checking cmdwin_type. (Sean Dewar)

Reset and save `cmdwin_old_curwin` in a similar fashion.
Apply suitable changes for API functions and add Lua tests.

988f74311c
2024-01-28 12:29:26 +00:00
zeertzjq
74e695d227
Merge pull request #27221 from BugLight/fix-coverity-found-bugs
Fix bugs found by coverity
2024-01-28 13:33:38 +08:00
Daniil Zhukov
9d48266bed fix(coverity/471380): null dereference in get_local_additions()
strrchr returns null pointer if '.' is not present in file name. Notice
that filenames are filtered to match "doc/*.??[tx]" pattern earlier so
we shouldn't expect null pointer here. However later in code strrchr
return value is checked so it seems better and more consistent to do the
same here too.
2024-01-27 23:00:24 +04:00
Justin M. Keyes
2cd76a758b
docs(lua): update ":{range}lua" docs + error message #27231
- `:lua (no file)` is misleading because `:lua` never takes a file arg,
  unlike `:source`.
- Update various related docs.
2024-01-27 10:40:30 -08:00
Christian Clason
17b298b7c8 vim-patch:0cc6108fea21
runtime(ant): Update syntax file (vim/vim#13926)

Remove invalid display option from syn-keyword commands.

Take over maintenance of this file.

0cc6108fea

Co-authored-by: dkearns <dougkearns@gmail.com>
2024-01-27 19:38:05 +01:00
Gregory Anders
5ca330859c
fix(decor): check decor kind before accessing union field (#27205)
The data.sh.url field is valid only when item.kind is
kDecorKindHighlight. The `if` block just before this line already does
that check (as well as checking `active`) so move the access of
`data.sh.url` into that block.
2024-01-27 08:26:01 -06:00
Christian Clason
e35ae6fbc2 vim-patch:772f8f542513
runtime(hurl): add hurl filetype plugin(vim/vim#13921)

772f8f5425

Co-authored-by: Melker Ulander <melker.ulander@pm.me>
2024-01-27 12:02:59 +01:00
zeertzjq
bf9e92c81c
fix(events): check for WinResized/WinScrolled in terminal mode (#27226) 2024-01-27 15:18:41 +08:00
zeertzjq
7367838359
fix(api): limit depth of nvim_cmd (#27225) 2024-01-27 14:03:44 +08:00
zeertzjq
38bb0e1da8
test(tui_spec): get &background from child session directly (#27224) 2024-01-27 12:42:32 +08:00
luukvbaal
c2433589dc
feat(ex_cmds): ranged :lua #27167
:{range}lua executes the specified lines in the current buffer as
Lua code, regardless of its extension or 'filetype'.

Close #27103
2024-01-26 17:00:50 -08:00
Till Bungert
0892c080d1
revert: "feat(treesitter): add foldtext with treesitter highlighting"
This reverts commit 9ce1623 in favor of #20750.
2024-01-27 08:38:56 +08:00
Daniil Zhukov
6f49ed58c3 fix(coverity/348240): memory leak in put_view() 2024-01-26 23:36:48 +04:00
Evgeni Chasnovski
a9df0c5ce6
fix(osc52): do not use 'vim.iter' (#27218)
Problem: Using 'vim.iter' loads it during startup.

Solution: Do not use 'vim.iter'.
2024-01-26 12:06:13 -06:00
Lewis Russell
28d1640dd6 feat: improve return type annotations for vim.api.* 2024-01-26 15:07:25 +00:00
Luuk van Baal
65b1fd00a7 fix(extmarks): do not remove decor from invalid old marks 2024-01-26 15:06:25 +00:00
Jaehwang Jung
eca72def1f fix(colorscheme): typo 2024-01-26 15:26:50 +01:00
Junghyeon Park
7421a4d8b5 ci: update notes.md
Change the link to point to INSTALL.md.

The contents were moved in https://github.com/neovim/neovim/pull/26533
2024-01-26 14:54:57 +01:00
Christian Clason
b7e3003106 vim-patch:046a0f75d025
runtime(mail): fix vim/vim#13913 (vim/vim#13917)

switch to the DFA engine for the emoji collaction range

046a0f75d0

Co-authored-by: gi1242 <gi1242+github@gmail.com>
Co-authored-by: GI <gi1242+vim@gmail.com>
2024-01-26 08:51:13 +01:00
114 changed files with 2017 additions and 790 deletions

View File

@ -58,6 +58,11 @@ aa4f9c5341f5280f16cce0630ea54b84eef717b3
6ff245732a5a8ab821598a38fb0c5805e6bd3779
abf758a2977c4e6cab4dfa217f56da853d85851c
cb84f5ee530f0f32b92bed5b4ad41344e8b551aa
f98b8d2d44d289263b1a3b33b6a7f20644ef671c
544ef994df72c3cbe0dca6b856ce2dcbc5169767
45fe4d11add933df76a2ea4bf52ce8904f4a778b
517f0cc634b985057da5b95cf4ad659ee456a77e
04f2f864e270e772c6326cefdf24947f0130e492
# typos
d238b8f6003d34cae7f65ff7585b48a2cd9449fb

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -161,6 +161,7 @@ endif()
option(ENABLE_ASAN_UBSAN "Enable Clang address & undefined behavior sanitizer for nvim binary." OFF)
option(ENABLE_MSAN "Enable Clang memory sanitizer for nvim binary." OFF)
# TSAN exists to test Luv threads.
option(ENABLE_TSAN "Enable Clang thread sanitizer for nvim binary." OFF)
if((ENABLE_ASAN_UBSAN AND ENABLE_MSAN)
@ -263,7 +264,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(

View File

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

View File

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

View File

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

View File

@ -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' })

View File

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

View File

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

View File

@ -649,7 +649,7 @@ list of the current window.
list.
If [count] is omitted, the {name}s are added just
after the current entry in the argument list.
Otherwise they are added after the [count]'th file.
Otherwise they are added after the [count]th file.
If the argument list is "a b c", and "b" is the
current argument, then these commands result in:
command new argument list ~

View File

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

View File

@ -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
@ -3901,18 +3907,22 @@ Iter:flatten({depth}) *Iter:flatten()*
(`Iter`)
Iter:fold({init}, {f}) *Iter:fold()*
Folds ("reduces") an iterator into a single value.
Folds ("reduces") an iterator into a single value. *Iter:reduce()*
Examples: >lua
-- Create a new table with only even values
local t = { a = 1, b = 2, c = 3, d = 4 }
local it = vim.iter(t)
it:filter(function(k, v) return v % 2 == 0 end)
it:fold({}, function(t, k, v)
t[k] = v
return t
end)
-- { b = 2, d = 4 }
vim.iter({ a = 1, b = 2, c = 3, d = 4 })
:filter(function(k, v) return v % 2 == 0 end)
:fold({}, function(acc, k, v)
acc[k] = v
return acc
end) --> { b = 2, d = 4 }
-- Get the "maximum" item of an iterable.
vim.iter({ -99, -4, 3, 42, 0, 0, 7 })
:fold({}, function(acc, v)
acc.max = math.max(v, acc.max or v) return acc
end) --> { max = 42 }
<
Parameters: ~

View File

@ -256,7 +256,7 @@ g<End> Like |g$| but to the last non-blank character
|exclusive| motion. Ceci n'est pas une pipe.
*f*
f{char} To [count]'th occurrence of {char} to the right. The
f{char} To [count]th occurrence of {char} to the right. The
cursor is placed on {char} |inclusive|.
{char} can be entered as a digraph |digraph-arg|.
When 'encoding' is set to Unicode, composing
@ -266,18 +266,18 @@ f{char} To [count]'th occurrence of {char} to the right. The
|i_CTRL-^|.
*F*
F{char} To the [count]'th occurrence of {char} to the left.
F{char} To the [count]th occurrence of {char} to the left.
The cursor is placed on {char} |exclusive|.
{char} can be entered like with the |f| command.
*t*
t{char} Till before [count]'th occurrence of {char} to the
t{char} Till before [count]th occurrence of {char} to the
right. The cursor is placed on the character left of
{char} |inclusive|.
{char} can be entered like with the |f| command.
*T*
T{char} Till after [count]'th occurrence of {char} to the
T{char} Till after [count]th occurrence of {char} to the
left. The cursor is placed on the character right of
{char} |exclusive|.
{char} can be entered like with the |f| command.
@ -604,14 +604,14 @@ ib "inner block", select [count] blocks, from "[count] [("
a> *v_a>* *v_a<* *a>* *a<*
a< "a <> block", select [count] <> blocks, from the
[count]'th unmatched '<' backwards to the matching
[count]th unmatched '<' backwards to the matching
'>', including the '<' and '>'. The |cpo-M| option flag
is used to handle escaped '<' and '>'.
When used in Visual mode it is made charwise.
i> *v_i>* *v_i<* *i>* *i<*
i< "inner <> block", select [count] <> blocks, from
the [count]'th unmatched '<' backwards to the matching
the [count]th unmatched '<' backwards to the matching
'>', excluding the '<' and '>'. It's an error to
select an empty inner block like "<>". The |cpo-M|
option flag is used to handle escaped '<' and '>'.
@ -619,14 +619,14 @@ i< "inner <> block", select [count] <> blocks, from
*v_at* *at*
at "a tag block", select [count] tag blocks, from the
[count]'th unmatched "<aaa>" backwards to the matching
[count]th unmatched "<aaa>" backwards to the matching
"</aaa>", including the "<aaa>" and "</aaa>".
See |tag-blocks| about the details.
When used in Visual mode it is made charwise.
*v_it* *it*
it "inner tag block", select [count] tag blocks, from the
[count]'th unmatched "<aaa>" backwards to the matching
[count]th unmatched "<aaa>" backwards to the matching
"</aaa>", excluding the "<aaa>" and "</aaa>".
See |tag-blocks| about the details.
When used in Visual mode it is made charwise.

View File

@ -4,7 +4,7 @@
NVIM REFERENCE MANUAL
Notable changes in Nvim 0.9 from 0.8 *news-0.9*
Notable changes in Nvim 0.9 since 0.8 *news-0.9*
Type |gO| to see the table of contents.

View File

@ -4,9 +4,9 @@
NVIM REFERENCE MANUAL
Notable changes in Nvim 0.10 from 0.9 *news*
Notable changes since Nvim 0.9 *news*
For changes in Nvim 0.9, see |news-0.9|.
For changes in the previous release, see |news-0.9|.
Type |gO| to see the table of contents.
@ -120,10 +120,13 @@ The following changes may require adaptations in user config or plugins.
==============================================================================
BREAKING CHANGES IN HEAD *news-breaking-dev*
The following breaking changes were made during the development cycle to
unreleased features on Nvim HEAD.
====== Remove this section before release. ======
• ...
The following breaking changes were made during the development cycle to
UNRELEASED features on Nvim HEAD (the unreleased "master" branch).
• Removed `vim.treesitter.foldtext` as transparent foldtext is now supported
https://github.com/neovim/neovim/pull/20750
• ...
==============================================================================
@ -181,6 +184,8 @@ The following new APIs and features were added.
swapfile is owned by a running Nvim process, instead of prompting. If you
always want the swapfile dialog, delete the default SwapExists handler:
`autocmd! nvim_swapfile`. |default-autocmds|
• Navigating the |jumplist| with CTRL+O, CTRL+I behaves more intuitively
when deleting buffers, and avoids "invalid buffer" cases. #25461
• LSP
• LSP method names are available in |vim.lsp.protocol.Methods|.
@ -223,8 +228,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 +308,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 +346,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.

View File

@ -126,6 +126,41 @@ color index is just forwarded.
Editor highlighting (|syntax-highlighting|, |highlight-groups|, etc.) has
higher precedence: it is applied after terminal colors are resolved.
------------------------------------------------------------------------------
EVENTS *terminal-events*
Applications running in a :terminal buffer can send requests, which Nvim
exposes via the |TermRequest| event.
OSC 7: change working directory *terminal-osc7*
To handle OSC 7 emitted from :terminal processes, this code will :cd to the
directory indicated in the request. >lua
vim.api.nvim_create_autocmd({ 'TermRequest' }, {
desc = 'Handles OSC 7 dir change requests',
callback = function(ev)
if string.sub(vim.v.termrequest, 1, 4) == '\x1b]7;' then
local dir = string.gsub(vim.v.termrequest, '\x1b]7;file://[^/]*', '')
if vim.fn.isdirectory(dir) == 0 then
vim.notify('invalid dir: '..dir)
return
end
vim.api.nvim_buf_set_var(ev.buf, 'osc7_dir', dir)
if vim.o.autochdir and vim.api.nvim_get_current_buf() == ev.buf then
vim.cmd.cd(dir)
end
end
end
})
vim.api.nvim_create_autocmd({ 'BufEnter', 'WinEnter', 'DirChanged' }, {
callback = function(ev)
if vim.b.osc7_dir and vim.fn.isdirectory(vim.b.osc7_dir) == 1 then
vim.cmd.cd(vim.b.osc7_dir)
end
end
})
==============================================================================
Status Variables *terminal-status*

View File

@ -6816,6 +6816,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Level Messages ~
----------------------------------------------------------------------
1 Enables Lua tracing (see above). Does not produce messages.
2 When a file is ":source"'ed, or |shada| file is read or written.
3 UI info, terminal capabilities.
4 Shell commands.

View File

@ -15,36 +15,36 @@ explanations are in chapter 27 |usr_27.txt|.
1. Search commands *search-commands*
*/*
/{pattern}[/]<CR> Search forward for the [count]'th occurrence of
/{pattern}[/]<CR> Search forward for the [count]th occurrence of
{pattern} |exclusive|.
/{pattern}/{offset}<CR> Search forward for the [count]'th occurrence of
/{pattern}/{offset}<CR> Search forward for the [count]th occurrence of
{pattern} and go |{offset}| lines up or down.
|linewise|.
*/<CR>*
/<CR> Search forward for the [count]'th occurrence of the
/<CR> Search forward for the [count]th occurrence of the
latest used pattern |last-pattern| with latest used
|{offset}|.
//{offset}<CR> Search forward for the [count]'th occurrence of the
//{offset}<CR> Search forward for the [count]th occurrence of the
latest used pattern |last-pattern| with new
|{offset}|. If {offset} is empty no offset is used.
*?*
?{pattern}[?]<CR> Search backward for the [count]'th previous
?{pattern}[?]<CR> Search backward for the [count]th previous
occurrence of {pattern} |exclusive|.
?{pattern}?{offset}<CR> Search backward for the [count]'th previous
?{pattern}?{offset}<CR> Search backward for the [count]th previous
occurrence of {pattern} and go |{offset}| lines up or
down |linewise|.
*?<CR>*
?<CR> Search backward for the [count]'th occurrence of the
?<CR> Search backward for the [count]th occurrence of the
latest used pattern |last-pattern| with latest used
|{offset}|.
??{offset}<CR> Search backward for the [count]'th occurrence of the
??{offset}<CR> Search backward for the [count]th occurrence of the
latest used pattern |last-pattern| with new
|{offset}|. If {offset} is empty no offset is used.
@ -59,7 +59,7 @@ N Repeat the latest "/" or "?" [count] times in
opposite direction. |last-pattern|
*star* *E348* *E349*
* Search forward for the [count]'th occurrence of the
* Search forward for the [count]th occurrence of the
word nearest to the cursor. The word used for the
search is the first of:
1. the keyword under the cursor |'iskeyword'|

View File

@ -213,7 +213,7 @@ N is used to indicate an optional count that can be given before the command.
*Q_ta* Using tags
|:ta| :ta[g][!] {tag} jump to tag {tag}
|:ta| :[count]ta[g][!] jump to [count]'th newer tag in tag list
|:ta| :[count]ta[g][!] jump to [count]th newer tag in tag list
|CTRL-]| CTRL-] jump to the tag under cursor, unless changes
have been made
|:ts| :ts[elect][!] [tag] list matching tags and select one to jump to
@ -224,10 +224,10 @@ N is used to indicate an optional count that can be given before the command.
|:tags| :tags print tag list
|CTRL-T| N CTRL-T jump back from Nth older tag in tag list
|:po| :[count]po[p][!] jump back from [count]'th older tag in tag list
|:tnext| :[count]tn[ext][!] jump to [count]'th next matching tag
|:tp| :[count]tp[revious][!] jump to [count]'th previous matching tag
|:tr| :[count]tr[ewind][!] jump to [count]'th matching tag
|:po| :[count]po[p][!] jump back from [count]th older tag in tag list
|:tnext| :[count]tn[ext][!] jump to [count]th next matching tag
|:tp| :[count]tp[revious][!] jump to [count]th previous matching tag
|:tr| :[count]tr[ewind][!] jump to [count]th matching tag
|:tl| :tl[ast][!] jump to last matching tag
|:ptag| :pt[ag] {tag} open a preview window to show tag {tag}

View File

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

View File

@ -17,16 +17,26 @@ 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
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
or even manually.
Parsers are the heart of treesitter. They are libraries that treesitter will
search for in the `parser` runtime directory.
Nvim includes these parsers:
- C
- Lua
- Markdown
- Vimscript
- Vimdoc
- Treesitter query files |ft-query-plugin|
You can install more parsers manually, or with a plugin like
https://github.com/nvim-treesitter/nvim-treesitter .
Parsers are searched for as `parser/{lang}.*` in any 'runtimepath' directory.
If multiple parsers for the same language are found, the first one is used.
(NOTE: This typically implies the priority "user config > plugins > bundled".)
A parser can also be loaded manually using a full path: >lua
To load a parser from its filepath: >lua
vim.treesitter.language.add('python', { path = "/path/to/python.so" })
<
@ -43,7 +53,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 +69,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 +573,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 +634,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 +662,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
@ -907,10 +907,7 @@ get_lang({filetype}) *vim.treesitter.language.get_lang()*
(`string?`)
inspect({lang}) *vim.treesitter.language.inspect()*
Inspects the provided language.
Inspecting provides some useful information on the language like node
names, ...
Gets some useful information on the language like node names, ...
Parameters: ~
• {lang} (`string`) Language

11
runtime/ftplugin/hurl.vim Normal file
View 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<"

View File

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

View File

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

View File

@ -1,5 +1,5 @@
-- Neovim indent file
-- Language: Tree-sitter query
-- Language: Treesitter query
-- Last Change: 2022 Mar 29
-- it's a lisp!

View File

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

View File

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

View File

@ -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.',

View File

@ -157,7 +157,7 @@ do
vim.api.nvim_create_autocmd('TermRequest', {
group = nvim_terminal_augroup,
desc = 'Respond to OSC foreground/background color requests',
desc = 'Handles OSC foreground/background color requests',
callback = function(args)
local fg_request = args.data == '\027]10;?'
local bg_request = args.data == '\027]11;?'

View File

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

View File

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

View 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

View File

@ -7441,6 +7441,7 @@ vim.bo.vts = vim.bo.vartabstop
---
--- Level Messages ~
--- ----------------------------------------------------------------------
--- 1 Enables Lua tracing (see above). Does not produce messages.
--- 2 When a file is ":source"'ed, or `shada` file is read or written.
--- 3 UI info, terminal capabilities.
--- 4 Shell commands.

View File

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

View File

@ -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'),

View File

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

View File

@ -445,20 +445,24 @@ function Iter.join(self, delim)
return table.concat(self:totable(), delim)
end
--- Folds ("reduces") an iterator into a single value.
--- Folds ("reduces") an iterator into a single value. \*Iter:reduce()\*
---
--- Examples:
---
--- ```lua
--- -- Create a new table with only even values
--- local t = { a = 1, b = 2, c = 3, d = 4 }
--- local it = vim.iter(t)
--- it:filter(function(k, v) return v % 2 == 0 end)
--- it:fold({}, function(t, k, v)
--- t[k] = v
--- return t
--- end)
--- -- { b = 2, d = 4 }
--- vim.iter({ a = 1, b = 2, c = 3, d = 4 })
--- :filter(function(k, v) return v % 2 == 0 end)
--- :fold({}, function(acc, k, v)
--- acc[k] = v
--- return acc
--- end) --> { b = 2, d = 4 }
---
--- -- Get the "maximum" item of an iterable.
--- vim.iter({ -99, -4, 3, 42, 0, 0, 7 })
--- :fold({}, function(acc, v)
--- acc.max = math.max(v, acc.max or v) return acc
--- end) --> { max = 42 }
--- ```
---
---@generic A

View File

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

View File

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

View File

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

View File

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

View File

@ -138,9 +138,7 @@ function M.register(lang, filetype)
end
end
--- Inspects the provided language.
---
--- Inspecting provides some useful information on the language like node names, ...
--- Gets some useful information on the language like node names, ...
---
---@param lang string Language
---@return table

View File

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

View File

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

View File

@ -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^(\> ?)"

View File

@ -1,5 +1,5 @@
-- Neovim syntax file
-- Language: Tree-sitter query
-- Language: Treesitter query
-- Last Change: 2022 Apr 13
-- it's a lisp!

View File

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

View File

@ -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, ', ')

View File

@ -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('&', '&amp;'):gsub('<', '&lt;'):gsub('>', '&gt;')
return (s:gsub('&', '&amp;'):gsub('<', '&lt;'):gsub('>', '&gt;'))
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,
@ -555,11 +607,17 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end
return s
elseif vim.list_contains({ 'codespan', 'keycode' }, node_name) then
elseif vim.list_contains({ 'codespan', 'keycode', 'optional' }, node_name) then
if root:has_error() then
return text
end
local s = ('%s<code>%s</code>'):format(ws(), trimmed)
local class = node_name == 'optional' and ' class="optional"' or ''
local s = (
node_name == 'keycode'
-- TODO: use <kbd>. Currently has a layout issue, example: ":help _".
and ('%s<code>%s</code>'):format(ws(), trimmed)
or ('%s<code%s>%s</code>'):format(ws(), class, trimmed)
)
if opt.old and node_name == 'codespan' then
s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end
@ -575,7 +633,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 +714,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 +758,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 +783,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 +804,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 +813,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 +947,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 +961,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
@ -953,11 +1019,13 @@ local function gen_css(fname)
local css = [[
:root {
--code-color: #004b4b;
--kbd-color: red;
--tag-color: #095943;
}
@media (prefers-color-scheme: dark) {
:root {
--code-color: #00c243;
--kbd-color: red;
--tag-color: #00b7b7;
}
}
@ -1027,7 +1095,7 @@ local function gen_css(fname)
/* Tabs are used for alignment in old docs, so we must match Vim's 8-char expectation. */
tab-size: 8;
white-space: pre;
font-size: 16px;
font-size: 15px;
font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
}
.old-help-para pre {
@ -1086,7 +1154,14 @@ local function gen_css(fname)
}
code {
color: var(--code-color);
font-size: 16px;
font-size: 15px;
}
code.optional {
color: yellow;
}
kbd {
/* color: var(--kbd-color); */
font-size: 15px;
}
pre {
/* Tabs are used in codeblocks only for indentation, not alignment, so we can aggressively shrink them. */
@ -1095,7 +1170,7 @@ local function gen_css(fname)
line-height: 1.3; /* Important for ascii art. */
overflow: visible;
/* font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; */
font-size: 16px;
font-size: 15px;
margin-top: 10px;
}
pre:last-child {
@ -1113,25 +1188,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 +1253,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 +1296,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 +1322,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 +1330,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 +1363,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 +1383,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
View 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.')

View File

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

View File

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

View File

@ -55,6 +55,8 @@ typedef struct {
Boolean ui_watched;
Boolean undo_restore;
String url;
Integer _subpriority;
} Dict(set_extmark);
typedef struct {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
}
@ -3675,7 +3722,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 +4059,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 +4179,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 +4189,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);

View File

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

View File

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

View File

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

View File

@ -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));
}

View File

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

View File

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

View File

@ -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"));

View File

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

View File

@ -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',
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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--"));

View File

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

View File

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

View File

@ -2760,9 +2760,11 @@ static int info_add_completion_info(list_T *li)
// Skip the element with the CP_ORIGINAL_TEXT flag at the beginning, in case of
// forward completion, or at the end, in case of backward completion.
match = forward ? match->cp_next
: (compl_no_select && match_at_original_text(match)
? match->cp_prev : match->cp_prev->cp_prev);
match = (forward || match->cp_prev == NULL
? match->cp_next
: (compl_no_select && match_at_original_text(match)
? match->cp_prev
: match->cp_prev->cp_prev));
while (match != NULL && !match_at_original_text(match)) {
dict_T *di = tv_dict_alloc();

View File

@ -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
{
@ -1721,10 +1732,15 @@ void ex_luado(exarg_T *const eap)
nlua_error(lstate, _("E5110: Error executing lua: %.*s"));
return;
}
buf_T *const was_curbuf = curbuf;
for (linenr_T l = eap->line1; l <= eap->line2; l++) {
// Check the line number, the command may have deleted lines.
if (l > curbuf->b_ml.ml_line_count) {
break;
}
lua_pushvalue(lstate, -1);
const char *const old_line = ml_get_buf(curbuf, l);
// Get length of old_line here as calling Lua code may free it.
@ -1735,6 +1751,13 @@ void ex_luado(exarg_T *const eap)
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
break;
}
// Catch the command switching to another buffer.
// Check the line number, the command may have deleted lines.
if (curbuf != was_curbuf || l > curbuf->b_ml.ml_line_count) {
break;
}
if (lua_isstring(lstate, -1)) {
size_t new_line_len;
const char *const new_line = lua_tolstring(lstate, -1, &new_line_len);
@ -1749,16 +1772,17 @@ void ex_luado(exarg_T *const eap)
}
lua_pop(lstate, 1);
}
lua_pop(lstate, 1);
check_cursor();
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
{

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

@ -9300,6 +9300,7 @@ return {
Level Messages ~
----------------------------------------------------------------------
1 Enables Lua tracing (see above). Does not produce messages.
2 When a file is ":source"'ed, or |shada| file is read or written.
3 UI info, terminal capabilities.
4 Shell commands.

View File

@ -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)");
}

View File

@ -151,14 +151,14 @@ void win_redr_status(win_T *wp)
}
grid_line_start(&default_grid, is_stl_global ? (Rows - (int)p_ch - 1) : W_ENDROW(wp));
int col = is_stl_global ? 0 : wp->w_wincol;
const int off = is_stl_global ? 0 : wp->w_wincol;
int width = grid_line_puts(col, p, -1, attr);
grid_line_fill(width + col, this_ru_col + col, fillchar, attr);
int width = grid_line_puts(off, p, -1, attr);
grid_line_fill(off + width, off + this_ru_col, fillchar, attr);
if (get_keymap_str(wp, "<%s>", NameBuff, MAXPATHL)
&& this_ru_col - len > (int)(strlen(NameBuff) + 1)) {
grid_line_puts((int)((size_t)this_ru_col - strlen(NameBuff) - 1), NameBuff, -1, attr);
&& this_ru_col - len > (int)strlen(NameBuff) + 1) {
grid_line_puts(off + this_ru_col - (int)strlen(NameBuff) - 1, NameBuff, -1, attr);
}
win_redr_ruler(wp);
@ -168,7 +168,7 @@ void win_redr_status(win_T *wp)
const int sc_width = MIN(10, this_ru_col - len - 2);
if (sc_width > 0) {
grid_line_puts(wp->w_wincol + this_ru_col - sc_width - 1, showcmd_buf, sc_width, attr);
grid_line_puts(off + this_ru_col - sc_width - 1, showcmd_buf, sc_width, attr);
}
}
@ -615,8 +615,8 @@ void win_redr_ruler(win_T *wp)
}
}
int w = grid_line_puts(this_ru_col + off, buffer, -1, attr);
grid_line_fill(this_ru_col + off + w, off + width, fillchar, attr);
int w = grid_line_puts(off + this_ru_col, buffer, -1, attr);
grid_line_fill(off + this_ru_col + w, off + width, fillchar, attr);
}
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1078,7 +1078,24 @@ describe('completion', function()
]])
end)
it('does not crash if text is changed by first call to complete function #17489', function()
-- oldtest: Test_complete_changed_complete_info()
it('no crash calling complete_info() in CompleteChanged', function()
source([[
set completeopt=menuone
autocmd CompleteChanged * call complete_info(['items'])
call feedkeys("iii\<cr>\<c-p>")
]])
screen:expect([[
ii |
ii^ |
{2:ii }{0: }|
{0:~ }|*4
{3:-- Keyword completion (^N^P) The only match} |
]])
assert_alive()
end)
it('no crash if text changed by first call to complete function #17489', function()
source([[
func Complete(findstart, base) abort
if a:findstart
@ -1097,7 +1114,7 @@ describe('completion', function()
assert_alive()
end)
it('does not crash when using i_CTRL-X_CTRL-V to complete non-existent colorscheme', function()
it('no crash using i_CTRL-X_CTRL-V to complete non-existent colorscheme', function()
feed('icolorscheme NOSUCHCOLORSCHEME<C-X><C-V>')
expect('colorscheme NOSUCHCOLORSCHEME')
assert_alive()

Some files were not shown because too many files have changed in this diff Show More