Compare commits

..

68 Commits

Author SHA1 Message Date
Justin M. Keyes
ef5662544a
Merge d9b4d321d0 into a0d8c2b86e 2024-09-16 10:34:07 +00:00
Justin M. Keyes
d9b4d321d0 feat(vim.ui): vim.ui.open() DWIM mode
Problem:
The `gx` mapping has too much logic in it, so the logic is not in user
configs or plugins, and it lacks test coverage.

Solution:
Move the logic into `vim.ui.open()`.
2024-09-16 12:33:54 +02:00
glepnir
a0d8c2b86e
docs(eval): update param types of prompt-buffer functions (#30392) 2024-09-16 18:33:35 +08:00
Justin M. Keyes
549c00c791
Merge #29490 feat(vim.ui.open): configurable opener 2024-09-16 03:21:40 -07:00
Justin M. Keyes
23dcd7cd73 test(vim.ui.open): opt.cmd 2024-09-16 11:58:04 +02:00
Matěj Cepl
3f15e57b26 feat(vim.ui): configurable "gx" / vim.ui.open() tool
Problem:
User cannot configure the tool used by `vim.ui.open` (or `gx`). With
netrw this was supported by `g:netrw_browsex_viewer`.

Solution:
Introduce `opts.cmd`. Users that want to set this globally can
monkey-patch `vim.ui.open` in the same way described at `:help vim.paste()`.

Fixes https://github.com/neovim/neovim/issues/29488

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2024-09-16 11:58:02 +02:00
Christian Clason
a9031cc4a6 vim-patch:5e95c8f: runtime(java): Highlight javaConceptKind modifiers with StorageClass
Stop assigning by default the NonText highlighting group for
javaConceptKind modifiers since its colour is hardly
distinguishable from a background colour for a range of
colour schemes.

fixes vim/vim#15237
related vim/vim#15238
closes: vim/vim#15664

5e95c8f637

Co-authored-by: Aliaksei Budavei <0x000c70@gmail.com>
Co-authored-by: Dexter Gaon-Shatford <dexter@gaonshatford.ca>
2024-09-16 08:16:32 +02:00
Christian Clason
5e7933693b vim-patch:0f5effb: runtime(netrw): delete confirmation not strict enough
fixes: vim/vim#15680

0f5effbd1f

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-09-16 08:16:20 +02:00
Christian Clason
f408603f4f vim-patch:9.1.0731: inconsistent case sensitive extension matching
Problem:  inconsistent case sensitive extension matching
Solution: unify case sensitive extension matching (Evgeni Chasnovski).

There are different approaches of how extensions are matched with
respect to case sensitivity. In particular, '\c' flag is used in pattern
whereas in most places case sensitive matching is guarded behind
`has("fname_case")` condition.

Replace all instances of '\c' with an explicit case sensitive pattern
variants guarded by `has("fname_case")`. Strictly speaking, this is a
breaking change because only two (most common and prevailingly tested)
variants are now matched: upper first letter and upper all letters.

closes: vim/vim#15672

59b089c9df

Co-authored-by: Evgeni Chasnovski <evgeni.chasnovski@gmail.com>
2024-09-16 08:16:07 +02:00
zeertzjq
78b8510933
vim-patch:4d427d4: runtime(vim): Update base-syntax, match Vim9 bool/null literal args to :if/:while/:return (#30391)
Match Vim9 boolean and null literals in expression arguments of :if,
:elseif, :while and :return.

closes: vim/vim#15684

4d427d4cab

Co-authored-by: Doug Kearns <dougkearns@gmail.com>
2024-09-15 22:57:16 +00:00
Justin M. Keyes
057d27a9d6
refactor: rename "process" => "proc" #30387
Problem:
- "process" is often used as a verb (`multiqueue_process_events`), which
  is ambiguous for cases where it's used as a topic.
- The documented naming convention for processes is "proc".
  - `:help dev-name-common`
- Shorter is better, when it doesn't harm readability or
  discoverability.

Solution:
Rename "process" => "proc" in all C symbols and module names.
2024-09-15 12:20:58 -07:00
Justin M. Keyes
5792546777
refactor(tests): rename terminal/testutil.lua => testterm.lua #30372
This module is generally used by any tests that need the full Nvim TUI
instead of `screen.lua`. Thus it should live in `functional/` instead of
in `functional/terminal/`.
2024-09-15 03:28:14 -07:00
zeertzjq
3b54adc6c6
Merge pull request #30378 from zeertzjq/vim-9.1.0729
vim-patch:9.1.{0729,0730}
2024-09-14 19:51:11 +08:00
zeertzjq
325d349f9d
vim-patch:9.1.0728: [security]: heap-use-after-free in garbage collection with location list user data (#30377)
Problem:  heap-use-after-free in garbage collection with location list
          user data.
Solution: Mark user data as in use when no other window is referencing
          the location list (zeertzjq)

fixes: neovim/neovim#30371
closes: vim/vim#15683

be4bd189d2
2024-09-14 19:38:33 +08:00
zeertzjq
5191a11d66 vim-patch:9.1.0730: Crash with cursor-screenline and narrow window
Problem:  Crash with cursor-screenline and narrow window
          (elig0n)
Solution: Don't set right_col when width2 is 0 (zeertzjq).

fixes: vim/vim#15677
closes: vim/vim#15678

59149f0269
2024-09-14 19:29:40 +08:00
zeertzjq
90585e47fe vim-patch:9.1.0729: Wrong cursor-screenline when resizing window
Problem:  Wrong cursor-screenline when resizing window
Solution: Invalidate saved left_col and right_col when width1 or width2
          change.

closes: vim/vim#15679

86dc4f8b43
2024-09-14 19:29:37 +08:00
Jaehwang Jung
f2173b1aa2
fix(defaults): cannot remove "How-to disable mouse" menu item #30375 2024-09-14 02:18:38 -07:00
dundargoc
67d6b6f27e ci: skip automerge step if backport failed 2024-09-14 01:55:36 +02:00
Mathias Fussenegger
8512f669f0 fix(lsp): handle nil bytes in strings
Problem:

The LSP omnifunc can insert nil bytes, which when read in other places
(like semantic token) could cause an error:

    semantic_tokens.lua:304: Vim:E976: Using a Blob as a String

Solution:

Use `#line` instead of `vim.fn.strlen(line)`. Both return UTF-8 bytes
but the latter can't handle nil bytes.

Completion candidates can currently insert nil bytes, if other parts of
Alternative fix to https://github.com/neovim/neovim/pull/30359

Note that https://github.com/neovim/neovim/pull/30315 will avoid the
insertion of nil bytes from the LSP omnifunc, but the change of this PR
can more easily be backported.
2024-09-13 22:34:49 +02:00
dundargoc
755512ed60 ci: don't add reviewers for PRs created by a bot
This will ensure automatic backports created by the backport action does
not request reviewers (since the commit in question has already been
vetted and merged), but manual backports created by users does request
reviewers as these commits has not been vetted previously.
2024-09-13 16:58:15 +02:00
dundargoc
4c23b83456 ci: add needs:backport label on backport PRs with conflict
This makes it easy to keep track of which backport PRs have failed and
need manual intervention to fix.
2024-09-13 16:49:35 +02:00
dundargoc
5284a2a793 build: bump unibilium to v2.1.2
There is no real practical difference from previous commit except that
this is a tagged release.
2024-09-13 15:56:37 +02:00
Riley Bruins
b9b408a56c
feat(treesitter): start moving get_parser to return nil #30313
**Problem:** `vim.treesitter.get_parser` will throw an error if no parser
can be found.

- This means the caller is responsible for wrapping it in a `pcall`,
  which is easy to forget
- It also makes it slightly harder to potentially memoize `get_parser`
  in the future
- It's a bit unintuitive since many other `get_*` style functions
  conventionally return `nil` if no object is found (e.g. `get_node`,
  `get_lang`, `query.get`, etc.)

**Solution:** Return `nil` if no parser can be found or created

- This requires a function signature change, and some new assertions in
  places where the parser will always (or should always) be found.
- This commit starts by making this change internally, since it is
  breaking. Eventually it will be rolled out to the public API.
2024-09-13 05:09:11 -07:00
James Trew
8654a97006
fix(lsp): handle empty call hierarchy items #30349
Ensure that the function `pick_call_hierarchy_item` correctly handles
the case where `call_hierarchy_items` is nil or an empty table. This
prevents potential errors when the function is called with no items.
2024-09-13 04:59:49 -07:00
dundargoc
057314345a ci: enable automerge by default when backporting
This will automatically merge backported PRs without human intervention
if the tests pass.
2024-09-13 12:31:33 +02:00
Justin M. Keyes
deac7df80a
refactor(stream.c): unused params in stream_close #30356 2024-09-12 09:16:57 -07:00
Christian Clason
ae917dbd06 fix(treesitter): sync queries from upstream 2024-09-12 13:41:15 +02:00
Christian Clason
c65153893a build(deps): bump tree-sitter-c to v0.23.0 2024-09-12 13:41:15 +02:00
Christian Clason
f6cc0394ae build(deps): bump tree-sitter-markdown to v0.3.2 2024-09-12 13:41:15 +02:00
Christian Clason
f347c292d1 build(deps): bump tree-sitter-lua to v0.2.0 2024-09-12 13:41:15 +02:00
zeertzjq
48c14d3544
vim-patch:9.1.0725: filetype: swiftinterface files are not recognized (#30350)
Problem:  filetype: swiftinterface files are not recognized
Solution: Detect '*.swiftinterface' files as swift filetype
          (LosFarmosCTL)

closes: vim/vim#15658

03cac4b70d

Co-authored-by: LosFarmosCTL <80157503+LosFarmosCTL@users.noreply.github.com>
2024-09-12 15:16:58 +08:00
Justin M. Keyes
5931f780e0
feat(log): use "ui" as default name for TUI client #30345
The default "session name" for the builtin TUI is "ui".

before:

    INF 2024-09-10T14:57:35.385 hello.sock os_exit:692: Nvim exit: 1
    INF 2024-09-10T14:57:35.388 ?.4543     os_exit:692: Nvim exit: 1

after:

    INF 2024-09-10T14:59:19.919 hello.sock os_exit:692: Nvim exit: 1
    INF 2024-09-10T14:59:19.922 ui.5684    os_exit:692: Nvim exit: 1
2024-09-11 17:25:00 -07:00
Gregory Anders
98ba65b8be
fix: replace NVIM with Nvim in default titlestring (#30348) 2024-09-11 20:32:08 +00:00
glepnir
f9bf64d746
fix(lsp): check buffer is loaded and valid #30330
Problem: buffer mabye not valid when callback handler invoke.

Soliton: check buffer is valid and loaded in handler.
2024-09-11 08:11:09 -07:00
Justin M. Keyes
a30afeeb85
Merge #30342 :checkhealth completion 2024-09-11 03:01:48 -07:00
Justin M. Keyes
7b680e0ca9 test(health): "test_plug/health/init.lua" completes as "test_plug" 2024-09-11 11:40:56 +02:00
Christian Clason
8501fe621a build(deps): bump unibilium to HEAD - ab28a2ddb 2024-09-11 11:10:40 +02:00
Christian Clason
a5bd6665b0 fix(scripts): update bundled dependencies in bump_deps 2024-09-11 11:10:40 +02:00
Christian Clason
4ac733f6ef vim-patch:fc72a2f: runtime(idlang): update syntax script
closes: vim/vim#15419

fc72a2fa48

Co-authored-by: Joe Sapp <992873+sappjw@users.noreply.github.com>
2024-09-11 09:47:30 +02:00
Christian Clason
c1a4b8680b vim-patch:e401576: runtime(spec): Recognize epoch when making spec changelog in ftplugin
closes: vim/vim#15537

e40157641c

Co-authored-by: fundawang <fundawang@yeah.net>
2024-09-11 09:47:30 +02:00
Christian Clason
f6579a4db1 vim-patch:2241f08: runtime(spec): add file triggers to syntax script
closes: vim/vim#15569

2241f0845f

Co-authored-by: fundawang <fundawang@yeah.net>
2024-09-11 09:47:30 +02:00
Christian Clason
608ef83fc6 vim-patch:077d1d2: runtime(make): add compiler/make.vim to reset compiler plugin settings
closes: vim/vim#15645

077d1d2cff

Co-authored-by: Konfekt <Konfekt@users.noreply.github.com>
Co-authored-by: K.Takata <kentkt@csc.jp>
2024-09-11 09:47:30 +02:00
Christian Clason
57db94235c vim-patch:a9ae38d: runtime(java): Recognise all available standard doclet tags
* Complement the tag set with @spec, {@systemProperty},
  {@summary}, @provides, @uses, @hidden, and {@index}.
* Do not hoard all tags under a single highlighting group.
* Skip over nested balanced braces in inline tags.
* Observe that tag names are case sensitive: both {@docRoot}
  and {@inheritDoc} are valid, whereas {@inheritdoc} and
  {@docroot} are not.
* In the @see tag arguments, allow for:
  - module name prefixes (e.g. java.base/java.lang.String);
  - references to arbitrary URI fragments (e.g. ##foo);
  - matching any tag variation arguments on the next line.
* Test directives and tags for Java module declarations.
* Enforce the word end for "module-info" candidates.

References:
https://bugs.openjdk.org/browse/JDK-8226279 (@spec)
https://bugs.openjdk.org/browse/JDK-8214559 ({@systemProperty})
https://bugs.openjdk.org/browse/JDK-8173425 ({@summary})
https://bugs.openjdk.org/browse/JDK-8160196 (@provides & @uses)
https://bugs.openjdk.org/browse/JDK-8073100 (@hidden)
https://bugs.openjdk.org/browse/JDK-8044243 ({@index})
https://docs.oracle.com/en/java/javase/21/docs/specs/javadoc/doc-comment-spec.html
https://github.com/openjdk/jdk/blob/jdk-21-ga/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java

closes: vim/vim#15652

a9ae38dc3f

Co-authored-by: Aliaksei Budavei <0x000c70@gmail.com>
2024-09-11 09:47:30 +02:00
Christian Clason
cdab8c8ebb vim-patch:c0982f9: runtime(dosini): Update syntax script, spellcheck comments only
By default spell checking is enabled for all text, but adding
`contains=@Spell` to syntax rules restricts spell checking to those
syntax rules.  See `:help spell-syntax` for full details.

Variable names and headers are far more likely than comments to contain
spelling errors, so only enable spell checking in comments.

Introduced in https://github.com/xuhdev/syntax-dosini.vim/pull/8

cc @tobinjt

closes: vim/vim#15655

c0982f9f79

Co-authored-by: John Tobin <johntobin@johntobin.ie>
2024-09-11 09:47:30 +02:00
Christian Clason
830cf054bc vim-patch:d30ffdc: runtime(pandoc): Update compiler plugin to use actual 'spelllang'
Previously these would be cached in buffer-local variables and
would not change on :compiler pandoc

closes: vim/vim#15642

d30ffdca49

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-09-11 09:47:30 +02:00
Christian Clason
def6111118 vim-patch:7cc0e91: runtime(groff): Add compiler plugin for groff
Groff MOM (Macros for Manuscripts) is a macro package for the GNU
troff (groff) typesetting system, a light-weight alternative
to LaTeX for professional-quality documents.

closes: vim/vim#15646

7cc0e9145d

Co-authored-by: Konfekt <Konfekt@users.noreply.github.com>
2024-09-11 09:47:30 +02:00
monkoose
237d2aef4d
fix(health): return correct name from 'path2name()'
`path2name()` function doesn't process `'pluginname/health/init.lua'` correctly. Instead of retruning `'pluginname'` it returns `'pluginname.health'`
2024-09-11 07:55:37 +03:00
zeertzjq
15bfdf73ea
vim-patch:9.1.0727: too many strlen() calls in option.c (#30338)
Problem:  too many strlen() calls in option.c
Solution: refactor the code to reduce the number of strlen() calls
          (John Marriott)

closes: vim/vim#15604

95dacbb5fd

Co-authored-by: John Marriott <basilisk@internode.on.net>
2024-09-10 23:31:07 +00:00
dundargoc
f289161c3c test: add termkey unit tests
Skipped importing the following unit tests from libtermkey as they'd
require introducing a lot of unused code or require more effort to port
than is probably worth:

- 05read
- 12strpkey
- 20canon
- 40ti-override
2024-09-11 00:36:14 +02:00
zeertzjq
4b98d38870
vim-patch:d657d3d: runtime(doc): clarify the effect of the timeout for search()-functions (#30337)
related: vim/vim#15657
related: vim/vim#15404

d657d3d8fd

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-09-11 06:09:58 +08:00
bfredl
4c5bce9cb4
Merge pull request #30295 from glepnir/nfloat
fix(highlight): floating windows inherit NormalFloat from global-ns
2024-09-10 11:11:07 +02:00
Justin M. Keyes
5d7853f229
refactor(os/input.c): rename os_inchar => input_get #30327
Problem:
The name `os_inchar` (from Vim's old `mch_inchar`) is ambiguous:
"inchar" sounds like it could be reading or enqueuing (setting) input.
Its docstring is also ambiguous.

Solution:
- Rename `os_inchar` to `input_get`.
- Write some mf'ing docstrings.
- Add assert() in TRY_READ().
2024-09-10 01:14:18 -07:00
tris203
f279d1ae33 fix(lsp): handle encoding bounds in str_utfindex_enc
Problem:
str_utfindex_enc could return an error if the index was longer than the
line length. This was handled in each of the calls to it individually

Solution:
* Fix the call at the source level so that if the index is higher than
  the line length, utf length is returned
2024-09-10 09:25:04 +02:00
LosFarmosCTL
9ddfcb64bf
fix(runtime): add remaining missing commentstrings (#30252) 2024-09-10 15:01:25 +08:00
glepnir
8e81212e15 fix(highlight): floating windows inherit NormalFloat from global-ns
Problem:
floating windows did not correctly inherit the NormalFloat highlight
group from the global namespace when it was not defined in the window-specific
namespace. This led to floating windows losing their background highlight when
switching between namespaces.

Solution:
Updated the window highlight logic in update_window_hl() to handle the fallback.

This fix resolves issues with floating window backgrounds not displaying as expected
in certain namespace configurations.
2024-09-10 13:31:42 +08:00
Justin M. Keyes
648d6426c8
fix(server): CID 509282: DEADCODE #30316
listen_addr cannot be NULL at this point.
2024-09-09 05:14:47 -07:00
Justin M. Keyes
f0334c2c71
Merge #30312 from justinmk/testslashes 2024-09-09 04:00:35 -07:00
Justin M. Keyes
c8e3618e0e fix(test): "tempdir not a directory" in CI logs
$NVIM_LOG_FILE: /Users/runner/work/neovim/neovim/build/.nvimlog
    WRN 2024-09-08T21:48:13.279 ?.21134    vim_mktempdir:3281: $TMPDIR tempdir not a directory (or does not exist): TMPDIR-should-be-ignored
    WRN 2024-09-08T21:48:13.312 ?.21137    vim_mktempdir:3281: $TMPDIR tempdir not a directory (or does not exist): TMPDIR-should-be-ignored
2024-09-09 12:23:54 +02:00
Justin M. Keyes
ed832b9ddf refactor(test): rename alter_slashes, invert its behavior
- `alter_slashes` belongs in `testutil.lua`, not `testnvim.lua`.
- `alter_slashes` is an unusual name. Rename it to `fix_slashes`.
- invert its behavior, to emphasize that `/` slashes are the preferred,
  pervasive convention, not `\` slashes.
2024-09-09 12:23:54 +02:00
Justin M. Keyes
8a2aec9974
fix(startup): server fails if $NVIM_APPNAME is relative dir #30310
Problem:
If $NVIM_APPNAME is a relative dir path, Nvim fails to start its
primary/default server, and `v:servername` is empty.
Root cause is d34c64e342, but this wasn't
noticed until 96128a5076 started reporting the error more loudly.

Solution:
- `server_address_new`: replace slashes "/" in the appname before using
  it as a servername.
- `vim_mktempdir`: always prefer the system-wide top-level "nvim.user/"
  directory. That isn't intended to be specific to NVIM_APPNAME; rather,
  each *subdirectory* ("nvim.user/xxx") is owned by each Nvim instance.
  Nvim "apps" can be identified by the server socket(s) stored in those
  per-Nvim subdirs.

fix #30256
2024-09-08 12:48:32 -07:00
Christian Clason
3a88113246 fix(lua): revert vim.tbl_extend behavior change and document it
Problem: vim.tbl_deep_extend had an undocumented feature where arrays
(integer-indexed tables) were not merged but compared literally (used
for merging default and user config, where one list should overwrite the
other completely). Turns out this behavior was relied on in quite a
number of plugins (even though it wasn't a robust solution even for that
use case, since lists of tables (e.g., plugin specs) can be array-like
as well).

Solution: Revert the removal of this special feature. Check for
list-like (contiguous integer indices) instead, as this is closer to the
intent. Document this behavior.
2024-09-08 21:06:13 +02:00
Justin M. Keyes
08153ddd1c
fix(startup): ignore broken $XDG_RUNTIME_DIR #30285
Problem:
$XDG_RUNTIME_DIR may be broken on WSL, which prevents starting (and even
building) Nvim. #30282

Solution:
- When startup fails, mention the servername in the error message.
- If an autogenerated server address fails, log an error and continue
  with an empty `v:servername`. It's only fatal if a user provides a bad
  `--listen` or `$NVIM_LISTEN_ADDRESS` address.

Before:

    $ nvim --headless --listen ./hello.sock
    nvim: Failed to --listen: "address already in use"
    $ NVIM_LISTEN_ADDRESS='./hello.sock' ./build/bin/nvim --headless
    nvim: Failed to --listen: "address already in use"

After:

    $ nvim --headless --listen ./hello.sock
    nvim: Failed to --listen: address already in use: "./hello.sock"
    $ NVIM_LISTEN_ADDRESS='./hello.sock' ./build/bin/nvim --headless
    nvim: Failed $NVIM_LISTEN_ADDRESS: address already in use: "./hello.sock"
2024-09-08 07:07:19 -07:00
Tristan Knight
003b8a251d
fix(lsp): handle out-of-bounds character positions #30288
Problem:
str_byteindex_enc could return an error if the index was longer than the
lline length. This was handled in each of the calls to it individually

Solution:
* Fix the call at the source level so that if the index is higher than
  the line length, line length is returned as per LSP specification
* Remove pcalls on str_byteindex_enc calls. No longer needed now that
  str_byteindex_enc has a bounds check.
2024-09-08 03:44:46 -07:00
Justin M. Keyes
0cfbc6eaff
Merge #30105 fix(tohtml): quote font-family names 2024-09-08 03:32:33 -07:00
Justin M. Keyes
95b65a7554 test(tohtml): simplify font test 2024-09-08 12:17:42 +02:00
yayoyuyu
e37404f7fe fix(tohtml): enclose font-family names in quotation marks
Font-family names must be enclosed in quotation marks to ensure that
fonts are applied correctly when there are spaces in the name.

Fix an issue where multiple fonts specified in `vim.o.guifont` are
inserted as a single element, treating them as a single font.

Support for escaping commas with backslash and ignoring spaces
after a comma.

ref `:help 'guifont'`
2024-09-08 12:15:50 +02:00
zeertzjq
b40ec083ae
vim-patch:b584117: runtime(doc): buffers can be re-used (#30300)
while at it, also move the note about :wincmd
directly to :h :wincmd, it doesn't seem to belong to the buffer section.

closes: vim/vim#15636

b584117b05

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-09-08 05:41:44 +08:00
Yi Ming
d338ec9cb2
fix(vim.ui.open): prefer xdg-open on WSL #30302
xdg-open is usually not installed in WSL. But if the user deliberately
installs it, presumably they want to prioritize it.
2024-09-07 14:14:37 -07:00
143 changed files with 2875 additions and 1270 deletions

View File

@ -26,3 +26,21 @@ jobs:
pull_title: "${pull_title}"
label_pattern: "^ci:backport ([^ ]+)$"
github_token: ${{ steps.app-token.outputs.token }}
- name: Create failed backport label
if: ${{ steps.backport.outputs.was_successful == 'false' }}
uses: actions/github-script@v7
with:
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['needs:backport']
})
- name: Enable automerge
if: ${{ steps.backport.outputs.was_successful == 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --rebase --auto ${{ steps.backport.outputs.created_pull_numbers }}

View File

@ -5,7 +5,7 @@ on:
workflow_call:
jobs:
request-reviewer:
if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false
if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false && !endsWith(github.actor, '[bot]')
runs-on: ubuntu-latest
permissions:
pull-requests: write

View File

@ -7,8 +7,8 @@ LUAJIT_SHA256 2b5514bd6a6573cb6111b43d013e952cbaf46762d14ebe26c872ddb80b5a84e0
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/d72c3598e7ac5d1ebf86ee268b8b4ed95c0fa628.tar.gz
UNIBILIUM_SHA256 9c4747c862ab5e3076dcf8fa8f0ea7a6b50f20ec5905618b9536655596797487
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz
UNIBILIUM_SHA256 370ecb07fbbc20d91d1b350c55f1c806b06bf86797e164081ccc977fc9b3af7a
LUV_URL https://github.com/luvit/luv/releases/download/1.48.0-2/luv-1.48.0-2.tar.gz
LUV_SHA256 2c3a1ddfebb4f6550293a40ee789f7122e97647eede51511f57203de48c03b7a
@ -38,18 +38,18 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/3de4596fbe28956855df2ecb3c11c0bbc3535838.tar.gz
UTF8PROC_SHA256 fb4a16bb659b58afb7f921fcc8928d0b3c1fcab135366c8a4f9ca7de1b1cfada
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.21.3.tar.gz
TREESITTER_C_SHA256 75a3780df6114cd37496761c4a7c9fd900c78bee3a2707f590d78c0ca3a24368
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.1.0.tar.gz
TREESITTER_LUA_SHA256 230cfcbfa74ed1f7b8149e9a1f34c2efc4c589a71fe0f5dc8560622f8020d722
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.0.tar.gz
TREESITTER_C_SHA256 ee58c925e2e507c23d735aad46bf7fb0af31ca06d6f4f41bc008216d9232b0cb
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.2.0.tar.gz
TREESITTER_LUA_SHA256 6c41227cd0a59047b19d31f0031d4d901f08bfd78d6fc7f55c89e5b8374c794e
TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz
TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.0.tar.gz
TREESITTER_VIMDOC_SHA256 a639bf92bf57bfa1cdc90ca16af27bfaf26a9779064776dd4be34c1ef1453f6c
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz
TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e
TREESITTER_MARKDOWN_URL https://github.com/MDeiml/tree-sitter-markdown/archive/v0.2.3.tar.gz
TREESITTER_MARKDOWN_SHA256 4909d6023643f1afc3ab219585d4035b7403f3a17849782ab803c5f73c8a31d5
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.3.2.tar.gz
TREESITTER_MARKDOWN_SHA256 5dac48a6d971eb545aab665d59a18180d21963afc781bbf40f9077c06cb82ae5
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.23.0.tar.gz
TREESITTER_SHA256 6403b361b0014999e96f61b9c84d6950d42f0c7d6e806be79382e0232e48a11b

View File

@ -23,6 +23,7 @@
" 2024 Aug 15 by Vim Project: style changes, prevent E121 (#15501)
" 2024 Aug 22 by Vim Project: fix mf-selection highlight (#15551)
" 2024 Aug 22 by Vim Project: adjust echo output of mx command (#15550)
" 2024 Sep 15 by Vim Project: more strict confirmation dialog (#15680)
" }}}
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
@ -11275,7 +11276,7 @@ fun! s:NetrwLocalRm(path) range
let ok= s:NetrwLocalRmFile(a:path,fname,all)
if ok =~# 'q\%[uit]' || ok == "no"
break
elseif ok =~# 'a\%[ll]'
elseif ok =~# '^a\%[ll]$'
let all= 1
endif
endfor
@ -11304,7 +11305,7 @@ fun! s:NetrwLocalRm(path) range
let ok= s:NetrwLocalRmFile(a:path,curword,all)
if ok =~# 'q\%[uit]' || ok == "no"
break
elseif ok =~# 'a\%[ll]'
elseif ok =~# '^a\%[ll]$'
let all= 1
endif
let ctr= ctr + 1
@ -11351,12 +11352,12 @@ fun! s:NetrwLocalRmFile(path,fname,all)
" call Decho("response: ok<".ok.">",'~'.expand("<slnum>"))
let ok= substitute(ok,'\[{y(es)},n(o),a(ll),q(uit)]\s*','','e')
" call Decho("response: ok<".ok."> (after sub)",'~'.expand("<slnum>"))
if ok =~# 'a\%[ll]'
if ok =~# '^a\%[ll]$'
let all= 1
endif
endif
if all || ok =~# 'y\%[es]' || ok == ""
if all || ok =~# '^y\%[es]$' || ok == ""
let ret= s:NetrwDelete(rmfile)
" call Decho("errcode=".v:shell_error." ret=".ret,'~'.expand("<slnum>"))
endif
@ -11372,13 +11373,13 @@ fun! s:NetrwLocalRmFile(path,fname,all)
if ok == ""
let ok="no"
endif
if ok =~# 'a\%[ll]'
if ok =~# '^a\%[ll]$'
let all= 1
endif
endif
let rmfile= substitute(rmfile,'[\/]$','','e')
if all || ok =~# 'y\%[es]' || ok == ""
if all || ok =~# '^y\%[es]$' || ok == ""
if delete(rmfile,"rf")
call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".rmfile.">!",103)
endif

View File

@ -4,6 +4,8 @@ They are used with the ":compiler" command.
These scripts usually set options, for example 'errorformat'.
See ":help write-compiler-plugin".
To undo the effect of a compiler plugin, use the make compiler plugin.
If you want to write your own compiler plugin, have a look at the other files
for how to do it, the format is simple.

View File

@ -0,0 +1,45 @@
" Vim compiler file
" Compiler: Groff
" Maintainer: Konfekt
" Last Change: 2024 Sep 8
"
" Expects output file extension, say `:make html` or `:make pdf`.
" Supported devices as of Sept 2024 are: (x)html, pdf, ps, dvi, lj4, lbp ...
" Adjust command-line flags, language, encoding by buffer-local/global variables
" groff_compiler_args, groff_compiler_lang, and groff_compiler_encoding,
" which default to '', &spelllang and 'utf8'.
if exists("current_compiler")
finish
endif
let s:keepcpo = &cpo
set cpo&vim
let current_compiler = 'groff'
silent! function s:groff_compiler_lang()
let lang = get(b:, 'groff_compiler_lang',
\ &spell ? matchstr(&spelllang, '^\a\a') : '')
if lang ==# 'en' | let lang = '' | endif
return empty(lang) ? '' : '-m'..lang
endfunction
" Requires output format (= device) to be set by user after :make.
execute 'CompilerSet makeprg=groff'..escape(
\ ' '..s:groff_compiler_lang()..
\ ' -K'..get(b:, 'groff_compiler_encoding', get(g:, 'groff_compiler_encoding', 'utf8'))..
\ ' '..get(b:, 'groff_compiler_args', get(g:, 'groff_compiler_args', ''))..
\ ' -mom -T$* -- %:S > %:r:S.$*', ' ')
" From Gavin Freeborn's https://github.com/Gavinok/vim-troff under Vim License
" https://github.com/Gavinok/vim-troff/blob/91017b1423caa80aba541c997909a4f810edd275/compiler/troff.vim#L39
CompilerSet errorformat=%o:<standard\ input>\ (%f):%l:%m,
\%o:\ <standard\ input>\ (%f):%l:%m,
\%o:%f:%l:%m,
\%o:\ %f:%l:%m,
\%f:%l:\ macro\ %trror:%m,
\%f:%l:%m,
\%W%tarning:\ file\ '%f'\\,\ around\ line\ %l:,%Z%m
let &cpo = s:keepcpo
unlet s:keepcpo

13
runtime/compiler/make.vim Normal file
View File

@ -0,0 +1,13 @@
" Vim compiler plugin
"
" Maintainer: The Vim Project <https://github.com/vim/vim>
" Last Change: 2024 Sep 10
" Original Author: Konfekt
"
" This compiler plugin is used to reset previously set compiler options.
if exists("g:current_compiler") | unlet g:current_compiler | endif
if exists("b:current_compiler") | unlet b:current_compiler | endif
CompilerSet makeprg&
CompilerSet errorformat&

View File

@ -1,10 +1,12 @@
" Vim compiler file
" Compiler: Pandoc
" Maintainer: Konfekt
" Last Change: 2024 Aug 20
" Last Change: 2024 Sep 8
"
" Expects output file extension, say `:make html` or `:make pdf`.
" Passes additional arguments to pandoc, say `:make html --self-contained`.
" Adjust command-line flags by buffer-local/global variable
" b/g:pandoc_compiler_args which defaults to empty.
if exists("current_compiler")
finish
@ -40,18 +42,21 @@ silent! function s:PandocFiletype(filetype) abort
endif
endfunction
let b:pandoc_compiler_from = get(b:, 'pandoc_compiler_from', s:PandocFiletype(&filetype))
let b:pandoc_compiler_lang = get(b:, 'pandoc_compiler_lang', &spell ? matchstr(&spelllang, '^\a\a') : '')
silent! function s:PandocLang()
let lang = get(b:, 'pandoc_compiler_lang',
\ &spell ? matchstr(&spelllang, '^\a\a') : '')
if lang ==# 'en' | let lang = '' | endif
return empty(lang) ? '' : '--metadata lang='..lang
endfunction
execute 'CompilerSet makeprg=pandoc'..escape(
\ ' --standalone' .
\ (b:pandoc_compiler_from ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
\ '' : ' --metadata title=%:t:r:S') .
\ (empty(b:pandoc_compiler_lang) ?
\ '' : ' --metadata lang='..b:pandoc_compiler_lang) .
\ ' --from='..b:pandoc_compiler_from .
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', '')) .
\ ' --output %:r:S.$* -- %:S', ' ')
\ ' --standalone'..
\ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
\ '' : ' --metadata title=%:t:r:S')..
\ ' '..s:PandocLang()..
\ ' --from='..s:PandocFiletype(&filetype)..
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', ''))..
\ ' --output %:r:S.$* -- %:S', ' ')
CompilerSet errorformat=\"%f\",\ line\ %l:\ %m
let &cpo = s:keepcpo

View File

@ -6201,6 +6201,9 @@ search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) *search()*
The value must not be negative. A zero value is like not
giving the argument.
Note: the timeout is only considered when searching, not
while evaluating the {skip} expression.
If the {skip} expression is given it is evaluated with the
cursor positioned on the start of a match. If it evaluates to
non-zero this match is skipped. This can be used, for

View File

@ -2230,6 +2230,12 @@ vim.tbl_count({t}) *vim.tbl_count()*
vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()*
Merges recursively two or more tables.
Only values that are empty tables or tables that are not |lua-list|s
(indexed by consecutive integers starting from 1) are merged recursively.
This is useful for merging nested tables like default and user
configurations where lists should be treated as literals (i.e., are
overwritten instead of merged).
Parameters: ~
• {behavior} (`'error'|'keep'|'force'`) Decides what to do if a key is
found in more than one map:
@ -2553,7 +2559,7 @@ vim.ui.input({opts}, {on_confirm}) *vim.ui.input()*
typed (it might be an empty string if nothing was
entered), or `nil` if the user aborted the dialog.
vim.ui.open({path}) *vim.ui.open()*
vim.ui.open({path}, {opt}) *vim.ui.open()*
Opens `path` with the system default handler (macOS `open`, Windows
`explorer.exe`, Linux `xdg-open`, …), or returns (but does not show) an
error message on failure.
@ -2564,6 +2570,8 @@ vim.ui.open({path}) *vim.ui.open()*
-- Asynchronous.
vim.ui.open("https://neovim.io/")
vim.ui.open("~/path/to/file")
-- Use the "osurl" command to handle the path or URL.
vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } })
-- Synchronous (wait until the process exits).
local cmd, err = vim.ui.open("$VIMRUNTIME")
if cmd then
@ -2573,6 +2581,8 @@ vim.ui.open({path}) *vim.ui.open()*
Parameters: ~
• {path} (`string`) Path or URL to open
• {opt} (`{ cmd?: string[] }?`) Options
• cmd string[]|nil Command used to open the path or URL.
Return (multiple): ~
(`vim.SystemObj?`) Command object, or nil if not found.

View File

@ -189,11 +189,15 @@ TREESITTER
TUI
• TODO
• |log| messages written by the builtin UI client (TUI, |--remote-ui|) are
now prefixed with "ui" instead of "?".
UI
• TODO
• |vim.ui.open()| (by default bound to |gx|) accepts an `opt.cmd` parameter
which controls the tool used to open the given path or URL. If you want to
globally set this, you can override vim.ui.open using the same approach
described at |vim.paste()|.
==============================================================================
CHANGED FEATURES *news-changed*
@ -214,9 +218,6 @@ These existing features changed their behavior.
more emoji characters than before, including those encoded with multiple
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
• |vim.tbl_deep_extend()| no longer ignores any values for which |vim.isarray()|
returns `true`.
==============================================================================
REMOVED FEATURES *news-removed*

View File

@ -6713,7 +6713,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
When on, the title of the window will be set to the value of
'titlestring' (if it is not empty), or to:
filename [+=-] (path) - NVIM
filename [+=-] (path) - Nvim
Where:
filename the name of the file being edited
- indicates the file cannot be modified, 'ma' off
@ -6721,7 +6721,7 @@ A jump table for the options with a short description can be found at |Q_op|.
= indicates the file is read-only
=+ indicates the file is read-only and modified
(path) is the path of the file being edited
- NVIM the server name |v:servername| or "NVIM"
- Nvim the server name |v:servername| or "Nvim"
*'titlelen'*
'titlelen' number (default 85)

View File

@ -1262,6 +1262,7 @@ not "b:current_compiler". What the command actually does is the following:
For writing a compiler plugin, see |write-compiler-plugin|.
Use the |compiler-make| plugin to undo the effect of a compiler plugin.
DOTNET *compiler-dotnet*
@ -1277,7 +1278,6 @@ Example: limit output to only display errors, and suppress the project name: >
let dotnet_show_project_file = v:false
compiler dotnet
<
GCC *quickfix-gcc* *compiler-gcc*
There's one variable you can set for the GCC compiler:
@ -1294,6 +1294,24 @@ Commonly used compiler options can be added to 'makeprg' by setting the
g:javac_makeprg_params variable. For example: >
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
<
GNU MAKE *compiler-make*
Since the default make program is "make", the compiler plugin for make,
:compiler make, will reset the 'makeprg' and 'errorformat' option to
the default values and unlet any variables that may have been set by a
previous compiler plugin.
GROFF *quickfix-groff* *compiler-groff*
The GROFF compiler plugin uses the mom macro set (documented in the groff_mom
manpage) as input and expects that the output file type extension is passed to
make, say :make html or :make pdf.
Additional arguments can be passed to groff by setting them in
`b:groff_compiler_args` or `g:groff_compiler_args`. The `language` argument
passed to groff is set using 'spelllang'; it can be overridden by setting
`b:groff_compiler_lang`. The default enconding is `UTF-8` and can be changed
by setting `b:groff_compiler_encoding` or `g:groff_compiler_encoding`.
PANDOC *quickfix-pandoc* *compiler-pandoc*
@ -1307,8 +1325,7 @@ Additional arguments can be passed to pandoc:
The `--from` argument is an educated guess using the buffer file type;
it can be overridden by setting `b:pandoc_compiler_from`.
Likewise the `--metadata lang` argument is set using `&spelllang`;
it can be overridden by setting `b:pandoc_compiler_lang`.
The `--metadata lang` argument is set using 'spelllang';
If `--from=markdown` is assumed and no title set in a title header or
YAML block, then the filename (without extension) is used as the title.

View File

@ -1683,6 +1683,12 @@ In order to highlight nested parens with different colors, define colors for
or >
:hi javaParen ctermfg=blue guifg=#0000ff
Certain modifiers are incompatible with each other, e.g. `abstract` and
`final`: >
:syn list javaConceptKind
and can be differently highlighted as a group than other modifiers with >
:hi link javaConceptKind NonText
If you notice highlighting errors while scrolling backwards, which are fixed
when redrawing with CTRL-L, try setting the "g:java_minlines" variable to
a larger number: >

View File

@ -53,11 +53,17 @@ active yes yes 'a'
hidden no yes 'h'
inactive no no ' '
Note: All CTRL-W commands can also be executed with |:wincmd|, for those
places where a Normal mode command can't be used or is inconvenient.
*buffer-reuse*
Each buffer has a unique number and the number will not change within a Vim
session. The |bufnr()| and |bufname()| functions can be used to convert
between a buffer name and the buffer number. There is one exception: if a new
empty buffer is created and it is not modified, the buffer will be re-used
when loading another file into that buffer. This also means the buffer number
will not change.
The main Vim window can hold several split windows. There are also tab pages
|tab-page|, each of which can hold multiple windows.
*window-ID* *winid* *windowid*
Each window has a unique identifier called the window ID. This identifier
will not change within a Vim session. The |win_getid()| and |win_id2tabwin()|
@ -69,9 +75,6 @@ across tabs. For most functions that take a window ID or a window number, the
window number only applies to the current tab, while the window ID can refer
to a window in any tab.
Each buffer has a unique number and the number will not change within a Vim
session. The |bufnr()| and |bufname()| functions can be used to convert
between a buffer name and the buffer number.
==============================================================================
2. Starting Vim *windows-starting*
@ -468,6 +471,10 @@ These commands can also be executed with ":wincmd":
:exe nr .. "wincmd w"
< This goes to window "nr".
Note: All CTRL-W commands can also be executed with |:wincmd|, for those
places where a Normal mode command can't be used or is inconvenient (e.g.
in a browser-based terminal).
==============================================================================
5. Moving windows around *window-moving*

3
runtime/ftplugin/dot.lua Normal file
View File

@ -0,0 +1,3 @@
vim.bo.commentstring = '// %s'
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'

View File

@ -0,0 +1,3 @@
vim.bo.commentstring = '// %s'
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'

View File

@ -2,8 +2,9 @@
" Filename: spec.vim
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
" Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014)
" Last Change: Mon Jun 01 21:15 MSK 2015 Igor Gnatenko
" Update by Zdenek Dohnal, 2022 May 17
" Last Change: 2015 Jun 01
" Update by Zdenek Dohnal, 2022 May 17
" 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537
if exists("b:did_ftplugin")
finish
@ -66,9 +67,11 @@ if !exists("*s:SpecChangelog")
endif
let line = 0
let name = ""
let epoch = ""
let ver = ""
let rel = ""
let nameline = -1
let epochline = -1
let verline = -1
let relline = -1
let chgline = -1
@ -77,6 +80,9 @@ if !exists("*s:SpecChangelog")
if name == "" && linestr =~? '^Name:'
let nameline = line
let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
elseif epoch == "" && linestr =~? '^Epoch:'
let epochline = line
let epoch = substitute(strpart(linestr,6), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
elseif ver == "" && linestr =~? '^Version:'
let verline = line
let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
@ -93,6 +99,7 @@ if !exists("*s:SpecChangelog")
if nameline != -1 && verline != -1 && relline != -1
let include_release_info = exists("g:spec_chglog_release_info")
let name = s:ParseRpmVars(name, nameline)
let epoch = s:ParseRpmVars(epoch, epochline)
let ver = s:ParseRpmVars(ver, verline)
let rel = s:ParseRpmVars(rel, relline)
else
@ -117,6 +124,9 @@ if !exists("*s:SpecChangelog")
if chgline != -1
let tmptime = v:lc_time
language time C
if strlen(epoch)
let ver = epoch.":".ver
endif
let parsed_format = "* ".strftime(format)." - ".ver."-".rel
execute "language time" tmptime
let release_info = "+ ".name."-".ver."-".rel

View File

@ -0,0 +1,3 @@
vim.bo.commentstring = '// %s'
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'

View File

@ -0,0 +1,3 @@
vim.bo.commentstring = '// %s'
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'

View File

@ -0,0 +1,3 @@
vim.bo.commentstring = '// %s'
vim.b.undo_ftplugin = vim.b.undo_ftplugin .. ' | setl commentstring<'

View File

@ -1293,9 +1293,25 @@ local function opt_to_global_state(opt, title)
local fonts = {}
if opt.font then
fonts = type(opt.font) == 'string' and { opt.font } or opt.font --[[@as (string[])]]
for i, v in pairs(fonts) do
fonts[i] = ('"%s"'):format(v)
end
elseif vim.o.guifont:match('^[^:]+') then
table.insert(fonts, vim.o.guifont:match('^[^:]+'))
-- Example:
-- Input: "Font,Escape\,comma, Ignore space after comma"
-- Output: { "Font","Escape,comma","Ignore space after comma" }
local prev = ''
for name in vim.gsplit(vim.o.guifont:match('^[^:]+'), ',', { trimempty = true }) do
if vim.endswith(name, '\\') then
prev = prev .. vim.trim(name:sub(1, -2) .. ',')
elseif vim.trim(name) ~= '' then
table.insert(fonts, ('"%s%s"'):format(prev, vim.trim(name)))
prev = ''
end
end
end
-- Generic family names (monospace here) must not be quoted
-- because the browser recognizes them as font families.
table.insert(fonts, 'monospace')
--- @type vim.tohtml.state.global
local state = {

View File

@ -9,8 +9,8 @@
local function get_commentstring(ref_position)
local buf_cs = vim.bo.commentstring
local has_ts_parser, ts_parser = pcall(vim.treesitter.get_parser)
if not has_ts_parser then
local ts_parser = vim.treesitter._get_parser()
if not ts_parser then
return buf_cs
end

View File

@ -189,23 +189,25 @@ end
--- Default menus
do
--- Right click popup menu
local function def_menu(ctx)
vim.cmd([[
anoremenu PopUp.Go\ to\ definition <Cmd>lua vim.lsp.buf.definition()<CR>
amenu PopUp.Open\ in\ web\ browser gx
anoremenu PopUp.Inspect <Cmd>Inspect<CR>
anoremenu PopUp.-1- <Nop>
vnoremenu PopUp.Cut "+x
vnoremenu PopUp.Copy "+y
anoremenu PopUp.Paste "+gP
vnoremenu PopUp.Paste "+P
vnoremenu PopUp.Delete "_x
nnoremenu PopUp.Select\ All ggVG
vnoremenu PopUp.Select\ All gg0oG$
inoremenu PopUp.Select\ All <C-Home><C-O>VG
anoremenu PopUp.-2- <Nop>
anoremenu PopUp.How-to\ disable\ mouse <Cmd>help disable-mouse<CR>
vim.cmd([[
anoremenu PopUp.Go\ to\ definition <Cmd>lua vim.lsp.buf.definition()<CR>
amenu PopUp.Open\ in\ web\ browser gx
anoremenu PopUp.Inspect <Cmd>Inspect<CR>
anoremenu PopUp.-1- <Nop>
vnoremenu PopUp.Cut "+x
vnoremenu PopUp.Copy "+y
anoremenu PopUp.Paste "+gP
vnoremenu PopUp.Paste "+P
vnoremenu PopUp.Delete "_x
nnoremenu PopUp.Select\ All ggVG
vnoremenu PopUp.Select\ All gg0oG$
inoremenu PopUp.Select\ All <C-Home><C-O>VG
anoremenu PopUp.-2- <Nop>
anoremenu PopUp.How-to\ disable\ mouse <Cmd>help disable-mouse<CR>
]])
local function enable_ctx_menu(ctx)
vim.cmd([[
amenu disable PopUp.Go\ to\ definition
amenu disable PopUp.Open\ in\ web\ browser
]])
@ -216,7 +218,6 @@ do
vim.cmd([[anoremenu enable PopUp.Go\ to\ definition]])
end
end
def_menu()
local nvim_popupmenu_augroup = vim.api.nvim_create_augroup('nvim_popupmenu', {})
vim.api.nvim_create_autocmd('MenuPopup', {
@ -228,7 +229,7 @@ do
local urls = require('vim.ui')._get_urls()
local url = vim.startswith(urls[1], 'http')
local ctx = url and 'url' or (vim.lsp.get_clients({ bufnr = 0 })[1] and 'lsp' or nil)
def_menu(ctx)
enable_ctx_menu(ctx)
end,
})
end

View File

@ -7255,7 +7255,7 @@ vim.go.tm = vim.go.timeoutlen
--- When on, the title of the window will be set to the value of
--- 'titlestring' (if it is not empty), or to:
--- filename [+=-] (path) - NVIM
--- filename [+=-] (path) - Nvim
--- Where:
--- filename the name of the file being edited
--- - indicates the file cannot be modified, 'ma' off
@ -7263,7 +7263,7 @@ vim.go.tm = vim.go.timeoutlen
--- = indicates the file is read-only
--- =+ indicates the file is read-only and modified
--- (path) is the path of the file being edited
--- - NVIM the server name `v:servername` or "NVIM"
--- - Nvim the server name `v:servername` or "Nvim"
---
--- @type boolean
vim.o.title = false

View File

@ -6703,7 +6703,7 @@ function vim.fn.printf(fmt, expr1) end
--- If the buffer doesn't exist or isn't a prompt buffer, an empty
--- string is returned.
---
--- @param buf any
--- @param buf integer|string
--- @return any
function vim.fn.prompt_getprompt(buf) end
@ -6738,8 +6738,8 @@ function vim.fn.prompt_getprompt(buf) end
--- endfunc
--- call prompt_setcallback(bufnr(), function('s:TextEntered'))
---
--- @param buf any
--- @param expr any
--- @param buf integer|string
--- @param expr string|function
--- @return any
function vim.fn.prompt_setcallback(buf, expr) end
@ -6751,8 +6751,8 @@ function vim.fn.prompt_setcallback(buf, expr) end
--- mode. Without setting a callback Vim will exit Insert mode,
--- as in any buffer.
---
--- @param buf any
--- @param expr any
--- @param buf integer|string
--- @param expr string|function
--- @return any
function vim.fn.prompt_setinterrupt(buf, expr) end
@ -6763,8 +6763,8 @@ function vim.fn.prompt_setinterrupt(buf, expr) end
--- call prompt_setprompt(bufnr(''), 'command: ')
--- <
---
--- @param buf any
--- @param text any
--- @param buf integer|string
--- @param text string
--- @return any
function vim.fn.prompt_setprompt(buf, text) end
@ -7421,6 +7421,9 @@ function vim.fn.screenstring(row, col) end
--- The value must not be negative. A zero value is like not
--- giving the argument.
---
--- Note: the timeout is only considered when searching, not
--- while evaluating the {skip} expression.
---
--- If the {skip} expression is given it is evaluated with the
--- cursor positioned on the start of a match. If it evaluates to
--- non-zero this match is skipped. This can be used, for

View File

@ -280,12 +280,7 @@ local extension = {
cfi = 'cf',
hgrc = 'cfg',
cfg = detect.cfg,
cfG = detect.cfg,
cFg = detect.cfg,
cFG = detect.cfg,
Cfg = detect.cfg,
CfG = detect.cfg,
CFg = detect.cfg,
CFG = detect.cfg,
chf = 'ch',
chai = 'chaiscript',
@ -370,12 +365,7 @@ local extension = {
drt = 'dart',
ds = 'datascript',
dat = detect.dat,
daT = detect.dat,
dAt = detect.dat,
dAT = detect.dat,
Dat = detect.dat,
DaT = detect.dat,
DAt = detect.dat,
DAT = detect.dat,
dcd = 'dcd',
decl = detect.decl,
@ -658,12 +648,7 @@ local extension = {
kt = 'kotlin',
ktm = 'kotlin',
sub = 'krl',
suB = 'krl',
sUb = 'krl',
sUB = 'krl',
Sub = 'krl',
SuB = 'krl',
SUb = 'krl',
SUB = 'krl',
ks = 'kscript',
k = 'kwt',
@ -699,12 +684,7 @@ local extension = {
lite = 'lite',
livemd = 'livebook',
log = detect.log,
loG = detect.log,
lOg = detect.log,
lOG = detect.log,
Log = detect.log,
LoG = detect.log,
LOg = detect.log,
LOG = detect.log,
lgt = 'logtalk',
lotos = 'lotos',
@ -773,12 +753,7 @@ local extension = {
mmp = 'mmp',
mms = detect.mms,
mod = detect.mod,
moD = detect.mod,
mOd = detect.mod,
mOD = detect.mod,
Mod = detect.mod,
MoD = detect.mod,
MOd = detect.mod,
MOD = detect.mod,
DEF = 'modula2',
m3 = 'modula3',
@ -948,12 +923,7 @@ local extension = {
ih = 'ppwiz',
action = 'privoxy',
prg = detect.prg,
prG = detect.prg,
pRg = detect.prg,
pRG = detect.prg,
Prg = detect.prg,
PrG = detect.prg,
PRg = detect.prg,
PRG = detect.prg,
pc = 'proc',
pdb = 'prolog',
@ -1133,12 +1103,7 @@ local extension = {
sqr = 'sqr',
nut = 'squirrel',
src = detect.src,
srC = detect.src,
sRc = detect.src,
sRC = detect.src,
Src = detect.src,
SrC = detect.src,
SRc = detect.src,
SRC = detect.src,
s28 = 'srec',
s37 = 'srec',
@ -1164,15 +1129,11 @@ local extension = {
svelte = 'svelte',
svg = 'svg',
swift = 'swift',
swiftinterface = 'swift',
swig = 'swig',
swg = 'swig',
sys = detect.sys,
syS = detect.sys,
sYs = detect.sys,
sYS = detect.sys,
Sys = detect.sys,
SyS = detect.sys,
SYs = detect.sys,
SYS = detect.sys,
svh = 'systemverilog',
sv = 'systemverilog',

View File

@ -285,8 +285,8 @@ local path2name = function(path)
-- Remove everything up to the last /lua/ folder
path = path:gsub('^.*/lua/', '')
-- Remove the filename (health.lua)
path = vim.fs.dirname(path)
-- Remove the filename (health.lua) or (health/init.lua)
path = vim.fs.dirname(path:gsub('/init%.lua$', ''))
-- Change slashes to dots
path = path:gsub('/', '.')

View File

@ -447,11 +447,9 @@ function M.document_symbol(opts)
request_with_opts(ms.textDocument_documentSymbol, params, opts)
end
--- @param call_hierarchy_items lsp.CallHierarchyItem[]?
--- @param call_hierarchy_items lsp.CallHierarchyItem[]
--- @return lsp.CallHierarchyItem?
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then
return
end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
@ -476,7 +474,7 @@ local function call_hierarchy(method)
vim.notify(err.message, vim.log.levels.WARN)
return
end
if not result then
if not result or vim.tbl_isempty(result) then
vim.notify('No item resolved', vim.log.levels.WARN)
return
end

View File

@ -43,17 +43,16 @@ function M.on_inlayhint(err, result, ctx, _)
return
end
local bufnr = assert(ctx.bufnr)
if util.buf_versions[bufnr] ~= ctx.version then
if
util.buf_versions[bufnr] ~= ctx.version
or not result
or not api.nvim_buf_is_loaded(bufnr)
or not bufstates[bufnr].enabled
then
return
end
local client_id = ctx.client_id
if not result then
return
end
local bufstate = bufstates[bufnr]
if not bufstate.enabled then
return
end
if not (bufstate.client_hints and bufstate.version) then
bufstate.client_hints = vim.defaulttable()
bufstate.version = ctx.version
@ -77,12 +76,7 @@ function M.on_inlayhint(err, result, ctx, _)
local col = position.character
if col > 0 then
local line = lines[position.line + 1] or ''
local ok, convert_result
ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding)
if ok then
return convert_result
end
return math.min(#line, col)
return util._str_byteindex_enc(line, col, client.offset_encoding)
end
return col
end

View File

@ -140,12 +140,7 @@ local function tokens_to_ranges(data, bufnr, client, request)
local function _get_byte_pos(col)
if col > 0 then
local buf_line = lines[line + 1] or ''
local ok, result
ok, result = pcall(util._str_byteindex_enc, buf_line, col, client.offset_encoding)
if ok then
return result
end
return math.min(#buf_line, col)
return util._str_byteindex_enc(buf_line, col, client.offset_encoding)
end
return col
end

View File

@ -119,6 +119,7 @@ end
---@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
---@return integer `encoding` index of `index` in `line`
function M._str_utfindex_enc(line, index, encoding)
local len32, len16 = vim.str_utfindex(line)
if not encoding then
encoding = 'utf-16'
end
@ -129,9 +130,15 @@ function M._str_utfindex_enc(line, index, encoding)
return #line
end
elseif encoding == 'utf-16' then
if not index or index > len16 then
return len16
end
local _, col16 = vim.str_utfindex(line, index)
return col16
elseif encoding == 'utf-32' then
if not index or index > len32 then
return len32
end
local col32, _ = vim.str_utfindex(line, index)
return col32
else
@ -147,6 +154,12 @@ end
---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
---@return integer byte (utf-8) index of `encoding` index `index` in `line`
function M._str_byteindex_enc(line, index, encoding)
local len = #line
if index > len then
-- LSP spec: if character > line length, default to the line length.
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
return len
end
if not encoding then
encoding = 'utf-16'
end
@ -154,7 +167,7 @@ function M._str_byteindex_enc(line, index, encoding)
if index then
return index
else
return #line
return len
end
elseif encoding == 'utf-16' then
return vim.str_byteindex(line, index, true)
@ -165,9 +178,6 @@ function M._str_byteindex_enc(line, index, encoding)
end
end
local _str_utfindex_enc = M._str_utfindex_enc
local _str_byteindex_enc = M._str_byteindex_enc
--- Replaces text in a range with new text.
---
--- CAUTION: Changes in-place!
@ -334,12 +344,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- character
if col > 0 then
local line = get_line(bufnr, position.line) or ''
local ok, result
ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding)
if ok then
return result
end
return math.min(#line, col)
return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16')
end
return col
end
@ -436,14 +441,15 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
e.end_col = last_line_len
has_eol_text_edit = true
else
-- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
-- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length and the
-- replacement text ends with a newline We can likely assume that the replacement is assumed
-- to be meant to replace the newline with another newline and we need to make sure this
-- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
-- in the file some servers (clangd on windows) will include that character in the line
-- while nvim_buf_set_text doesn't count it as part of the line.
if
e.end_col > last_line_len
e.end_col >= last_line_len
and text_edit.range['end'].character > e.end_col
and #text_edit.newText > 0
and string.sub(text_edit.newText, -1) == '\n'
then
@ -1795,17 +1801,9 @@ function M.locations_to_items(locations, offset_encoding)
local row = pos.line
local end_row = end_pos.line
local line = lines[row] or ''
local line_len = vim.fn.strcharlen(line)
local end_line = lines[end_row] or ''
local end_line_len = vim.fn.strcharlen(end_line)
-- LSP spec: if character > line length, default to the line length.
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
local col = pos.character <= line_len
and M._str_byteindex_enc(line, pos.character, offset_encoding)
or line_len
local end_col = end_pos.character <= end_line_len
and M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
or end_line_len
local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
table.insert(items, {
filename = filename,
@ -1935,7 +1933,7 @@ local function make_position_param(window, offset_encoding)
return { line = 0, character = 0 }
end
col = _str_utfindex_enc(line, col, offset_encoding)
col = M._str_utfindex_enc(line, col, offset_encoding)
return { line = row, character = col }
end
@ -2117,11 +2115,7 @@ function M.character_offset(buf, row, col, offset_encoding)
)
offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding
end
-- If the col is past the EOL, use the line length.
if col > #line then
return _str_utfindex_enc(line, nil, offset_encoding)
end
return _str_utfindex_enc(line, col, offset_encoding)
return M._str_utfindex_enc(line, col, offset_encoding)
end
--- Helper function to return nested values in language server settings

View File

@ -354,6 +354,12 @@ function vim.tbl_isempty(t)
return next(t) == nil
end
--- We only merge empty tables or tables that are not list-like (indexed by consecutive integers
--- starting from 1)
local function can_merge(v)
return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.islist(v))
end
--- Recursive worker for tbl_extend
--- @param behavior 'error'|'keep'|'force'
--- @param deep_extend boolean
@ -368,7 +374,7 @@ local function tbl_extend_rec(behavior, deep_extend, ...)
local tbl = select(i, ...) --[[@as table<any,any>]]
if tbl then
for k, v in pairs(tbl) do
if deep_extend and type(v) == 'table' and type(ret[k]) == 'table' then
if deep_extend and can_merge(v) and can_merge(ret[k]) then
ret[k] = tbl_extend_rec(behavior, true, ret[k], v)
elseif behavior ~= 'force' and ret[k] ~= nil then
if behavior == 'error' then
@ -421,6 +427,11 @@ end
--- Merges recursively two or more tables.
---
--- Only values that are empty tables or tables that are not |lua-list|s (indexed by consecutive
--- integers starting from 1) are merged recursively. This is useful for merging nested tables
--- like default and user configurations where lists should be treated as literals (i.e., are
--- overwritten instead of merged).
---
---@see |vim.tbl_extend()|
---
---@generic T1: table

View File

@ -74,14 +74,14 @@ end
--- Returns the parser for a specific buffer and attaches it to the buffer
---
--- If needed, this will create the parser.
--- If needed, this will create the parser. If no parser can be found or created, returns `nil`.
---
---@param bufnr (integer|nil) Buffer the parser should be tied to (default: current buffer)
---@param lang (string|nil) Language of this parser (default: from buffer filetype)
---@param opts (table|nil) Options to pass to the created language tree
---
---@return vim.treesitter.LanguageTree object to use for parsing
function M.get_parser(bufnr, lang, opts)
---@return vim.treesitter.LanguageTree? object to use for parsing, or `nil` if not found
function M._get_parser(bufnr, lang, opts)
opts = opts or {}
if bufnr == nil or bufnr == 0 then
@ -94,18 +94,14 @@ function M.get_parser(bufnr, lang, opts)
if not valid_lang(lang) then
if not parsers[bufnr] then
error(
string.format(
'There is no parser available for buffer %d and one could not be'
.. ' created because lang could not be determined. Either pass lang'
.. ' or set the buffer filetype',
bufnr
)
)
return nil
end
elseif parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then
assert(lang, 'lang should be valid')
parsers[bufnr] = M._create_parser(bufnr, lang, opts)
local parser = vim.F.npcall(M._create_parser, bufnr, lang, opts)
if not parser then
return nil
end
parsers[bufnr] = parser
end
parsers[bufnr]:register_cbs(opts.buf_attach_cbs)
@ -113,6 +109,29 @@ function M.get_parser(bufnr, lang, opts)
return parsers[bufnr]
end
--- Returns the parser for a specific buffer and attaches it to the buffer
---
--- If needed, this will create the parser.
---
---@param bufnr (integer|nil) Buffer the parser should be tied to (default: current buffer)
---@param lang (string|nil) Language of this parser (default: from buffer filetype)
---@param opts (table|nil) Options to pass to the created language tree
---
---@return vim.treesitter.LanguageTree object to use for parsing
function M.get_parser(bufnr, lang, opts)
-- TODO(ribru17): Remove _get_parser and move that logic back here once the breaking function
-- signature change is acceptable.
local parser = M._get_parser(bufnr, lang, opts)
if not parser then
vim.notify_once(
'WARNING: vim.treesitter.get_parser will return nil instead of raising an error in Neovim 0.12',
vim.log.levels.WARN
)
error('Parser not found.')
end
return parser
end
--- Returns a string parser
---
---@param str string Text to parse
@ -386,7 +405,7 @@ function M.get_node(opts)
local ts_range = { row, col, row, col }
local root_lang_tree = M.get_parser(bufnr, opts.lang)
local root_lang_tree = M._get_parser(bufnr, opts.lang)
if not root_lang_tree then
return
end
@ -419,7 +438,11 @@ end
---@param lang (string|nil) Language of the parser (default: from buffer filetype)
function M.start(bufnr, lang)
bufnr = bufnr or api.nvim_get_current_buf()
local parser = M.get_parser(bufnr, lang)
local parser = M._get_parser(bufnr, lang)
if not parser then
vim.notify('No parser for the given buffer.', vim.log.levels.WARN)
return
end
M.highlighter.new(parser)
end

View File

@ -114,7 +114,7 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
srow = srow or 0
erow = erow or api.nvim_buf_line_count(bufnr)
local parser = ts.get_parser(bufnr)
local parser = assert(ts._get_parser(bufnr))
parser:parse(parse_injections and { srow, erow } or nil)
@ -392,7 +392,7 @@ function M.foldexpr(lnum)
lnum = lnum or vim.v.lnum
local bufnr = api.nvim_get_current_buf()
local parser = vim.F.npcall(ts.get_parser, bufnr)
local parser = ts._get_parser(bufnr)
if not parser then
return '0'
end

View File

@ -172,7 +172,7 @@ function M.lint(buf, opts)
--- @type (table|nil)
local parser_info = vim.F.npcall(vim.treesitter.language.inspect, lang)
local parser = vim.treesitter.get_parser(buf)
local parser = assert(vim.treesitter._get_parser(buf), 'query parser not found.')
parser:parse()
parser:for_each_tree(function(tree, ltree)
if ltree:lang() == 'query' then

View File

@ -76,10 +76,9 @@ end
---
---@package
function TSTreeView:new(bufnr, lang)
local ok, parser = pcall(vim.treesitter.get_parser, bufnr or 0, lang)
if not ok then
local err = parser --[[ @as string ]]
return nil, 'No parser available for the given buffer:\n' .. err
local parser = vim.treesitter._get_parser(bufnr or 0, lang)
if not parser then
return nil, 'No parser available for the given buffer.'
end
-- For each child tree (injected language), find the root of the tree and locate the node within
@ -539,7 +538,7 @@ local edit_ns = api.nvim_create_namespace('treesitter/dev-edit')
local function update_editor_highlights(query_win, base_win, lang)
local base_buf = api.nvim_win_get_buf(base_win)
local query_buf = api.nvim_win_get_buf(query_win)
local parser = vim.treesitter.get_parser(base_buf, lang)
local parser = assert(vim.treesitter._get_parser(base_buf, lang))
api.nvim_buf_clear_namespace(base_buf, edit_ns, 0, -1)
local query_content = table.concat(api.nvim_buf_get_lines(query_buf, 0, -1, false), '\n')
@ -596,8 +595,8 @@ function M.edit_query(lang)
end
vim.cmd(cmd)
local ok, parser = pcall(vim.treesitter.get_parser, buf, lang)
if not ok then
local parser = vim.treesitter._get_parser(buf, lang)
if not parser then
return nil, 'No parser available for the given buffer'
end
lang = parser:lang()

View File

@ -117,6 +117,8 @@ end
--- -- Asynchronous.
--- vim.ui.open("https://neovim.io/")
--- vim.ui.open("~/path/to/file")
--- -- Use the "osurl" command to handle the path or URL.
--- vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } })
--- -- Synchronous (wait until the process exits).
--- local cmd, err = vim.ui.open("$VIMRUNTIME")
--- if cmd then
@ -125,23 +127,26 @@ end
--- ```
---
---@param path? string Path or URL to open, or `nil` to get path or URL at cursor.
---@param opt? { cmd?: string[] } Options
--- - cmd string[]|nil Command used to open the path or URL.
---
---@return vim.SystemObj|nil # Command object, or nil if not found.
---@return nil|string # Error message on failure, or nil on success.
---
---@see |vim.system()|
function M.open(path)
function M.open(path, opt)
vim.validate({
path = { path, 'string', true },
})
opt = opt or {}
local function do_open(uri)
local cmd --- @type string[]
local opts --- @type vim.SystemOpts
local cmd ---@type string[]
local job_opt = { text = true, detach = true } --- @type vim.SystemOpts
opts = { text = true, detach = true }
if vim.fn.has('mac') == 1 then
if opt.cmd then
cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { uri })
elseif vim.fn.has('mac') == 1 then
cmd = { 'open', uri }
elseif vim.fn.has('win32') == 1 then
if vim.fn.executable('rundll32') == 1 then
@ -149,19 +154,19 @@ function M.open(path)
else
return nil, 'vim.ui.open: rundll32 not found'
end
elseif vim.fn.executable('xdg-open') == 1 then
cmd = { 'xdg-open', uri }
job_opt.stdout = false
job_opt.stderr = false
elseif vim.fn.executable('wslview') == 1 then
cmd = { 'wslview', uri }
elseif vim.fn.executable('explorer.exe') == 1 then
cmd = { 'explorer.exe', uri }
elseif vim.fn.executable('xdg-open') == 1 then
cmd = { 'xdg-open', uri }
opts.stdout = false
opts.stderr = false
else
return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
end
return vim.system(cmd, opts), nil
return vim.system(cmd, job_opt), nil
end
local function do_open2(uri)

View File

@ -33,7 +33,7 @@ end
--- Show a table of contents for the help buffer in a loclist
function M.show_toc()
local bufnr = vim.api.nvim_get_current_buf()
local parser = vim.treesitter.get_parser(bufnr, 'vimdoc')
local parser = assert(vim.treesitter._get_parser(bufnr, 'vimdoc'), 'vimdoc parser not found.')
local query = vim.treesitter.query.parse(
parser:lang(),
[[

View File

@ -45,6 +45,11 @@
(link_destination) @_url
(#set! @_label url @_url))
(image
(image_description) @_label
(link_destination) @_url
(#set! @_label url @_url))
; Conceal image links
(image
[

View File

@ -33,7 +33,10 @@
")"
] @punctuation.bracket
":" @punctuation.delimiter
[
":"
"/"
] @punctuation.delimiter
[
"@"

View File

@ -1,12 +1,12 @@
" Vim syntax file
" Language: Configuration File (ini file) for MSDOS/MS Windows
" Version: 2.3
" Version: 2.4
" Original Author: Sean M. McKee <mckee@misslink.net>
" Previous Maintainer: Nima Talebi <nima@it.net.au>
" Current Maintainer: Hong Xu <hong@topbug.net>
" Homepage: http://www.vim.org/scripts/script.php?script_id=3747
" Repository: https://github.com/xuhdev/syntax-dosini.vim
" Last Change: 2023 Aug 20
" Last Change: 2024 Sept 08
" quit when a syntax file was already loaded
@ -27,7 +27,7 @@ syn match dosiniNumber "=\zs\s*\d\+\s*$"
syn match dosiniNumber "=\zs\s*\d*\.\d\+\s*$"
syn match dosiniNumber "=\zs\s*\d\+e[+-]\=\d\+\s*$"
syn region dosiniHeader start="^\s*\[" end="\]"
syn match dosiniComment "^[#;].*$"
syn match dosiniComment "^[#;].*$" contains=@Spell
syn region dosiniSection start="\s*\[.*\]" end="\ze\s*\[.*\]" fold
\ contains=dosiniLabel,dosiniValue,dosiniNumber,dosiniHeader,dosiniComment

View File

@ -1,7 +1,8 @@
" Interactive Data Language syntax file (IDL, too [:-)]
" Maintainer: Aleksandar Jelenak <ajelenak AT yahoo.com>
" Last change: 2011 Apr 11
" Created by: Hermann Rochholz <Hermann.Rochholz AT gmx.de>
" Created By: Hermann Rochholz <Hermann.Rochholz AT gmx.de>
" Last Change: 2011 Apr 11
" 2024 Sep 10 by Vim Project: update syntax script, #15419
" Remove any old syntax stuff hanging around
" quit when a syntax file was already loaded
@ -16,7 +17,7 @@ syn match idlangStatement "^\s*function\s"
syn keyword idlangStatement return continue mod do break
syn keyword idlangStatement compile_opt forward_function goto
syn keyword idlangStatement begin common end of
syn keyword idlangStatement inherits on_ioerror begin
syn keyword idlangStatement inherits on_error on_ioerror begin
syn keyword idlangConditional if else then for while case switch
syn keyword idlangConditional endcase endelse endfor endswitch
@ -82,7 +83,7 @@ syn keyword idlangRoutine CALL_EXTERNAL CALL_FUNCTION CALL_METHOD
syn keyword idlangRoutine CALL_PROCEDURE CATCH CD CEIL CHEBYSHEV CHECK_MATH
syn keyword idlangRoutine CHISQR_CVF CHISQR_PDF CHOLDC CHOLSOL CINDGEN
syn keyword idlangRoutine CIR_3PNT CLOSE CLUST_WTS CLUSTER COLOR_CONVERT
syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT COMMON
syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT
syn keyword idlangRoutine COMPLEX COMPLEXARR COMPLEXROUND
syn keyword idlangRoutine COMPUTE_MESH_NORMALS COND CONGRID CONJ
syn keyword idlangRoutine CONSTRAINED_MIN CONTOUR CONVERT_COORD CONVOL
@ -98,7 +99,7 @@ syn keyword idlangRoutine CW_PALETTE_EDITOR_GET CW_PALETTE_EDITOR_SET
syn keyword idlangRoutine CW_PDMENU CW_RGBSLIDER CW_TMPL CW_ZOOM DBLARR
syn keyword idlangRoutine DCINDGEN DCOMPLEX DCOMPLEXARR DEFINE_KEY DEFROI
syn keyword idlangRoutine DEFSYSV DELETE_SYMBOL DELLOG DELVAR DERIV DERIVSIG
syn keyword idlangRoutine DETERM DEVICE DFPMIN DIALOG_MESSAGE
syn keyword idlangRoutine DETERM DEVICE DFPMIN DIAG_MATRIX DIALOG_MESSAGE
syn keyword idlangRoutine DIALOG_PICKFILE DIALOG_PRINTERSETUP
syn keyword idlangRoutine DIALOG_PRINTJOB DIALOG_READ_IMAGE
syn keyword idlangRoutine DIALOG_WRITE_IMAGE DIGITAL_FILTER DILATE DINDGEN
@ -155,7 +156,7 @@ syn keyword idlangRoutine MPEG_PUT MPEG_SAVE MSG_CAT_CLOSE MSG_CAT_COMPILE
syn keyword idlangRoutine MSG_CAT_OPEN MULTI N_ELEMENTS N_PARAMS N_TAGS
syn keyword idlangRoutine NEWTON NORM OBJ_CLASS OBJ_DESTROY OBJ_ISA OBJ_NEW
syn keyword idlangRoutine OBJ_VALID OBJARR ON_ERROR ON_IOERROR ONLINE_HELP
syn keyword idlangRoutine OPEN OPENR OPENW OPLOT OPLOTERR P_CORRELATE
syn keyword idlangRoutine OPEN OPENR OPENW OPENU OPLOT OPLOTERR P_CORRELATE
syn keyword idlangRoutine PARTICLE_TRACE PCOMP PLOT PLOT_3DBOX PLOT_FIELD
syn keyword idlangRoutine PLOTERR PLOTS PNT_LINE POINT_LUN POLAR_CONTOUR
syn keyword idlangRoutine POLAR_SURFACE POLY POLY_2D POLY_AREA POLY_FIT

View File

@ -3,7 +3,7 @@
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
" Repository: https://github.com/zzzyxwvut/java-vim.git
" Last Change: 2024 Aug 26
" Last Change: 2024 Sep 11
" Please check :help java.vim for comments on some of the options available.
@ -157,13 +157,20 @@ endif
" testing in a project without attendant confusion for IDEs, with the
" ".java\=" extension used for a production version and an arbitrary
" extension used for a testing version.
if fnamemodify(bufname("%"), ":t") =~ '^module-info\%(\.class\>\)\@!'
if fnamemodify(bufname("%"), ":t") =~ '^module-info\>\%(\.class\>\)\@!'
syn keyword javaModuleStorageClass module transitive
syn keyword javaModuleStmt open requires exports opens uses provides
syn keyword javaModuleExternal to with
hi def link javaModuleStorageClass StorageClass
hi def link javaModuleStmt Statement
hi def link javaModuleExternal Include
if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
syn match javaDocProvidesTag contained "@provides\_s\+\S\+" contains=javaDocParam
syn match javaDocUsesTag contained "@uses\_s\+\S\+" contains=javaDocParam
hi def link javaDocProvidesTag Special
hi def link javaDocUsesTag Special
endif
endif
" Fancy parameterised types (JLS-17, §4.5).
@ -335,29 +342,99 @@ if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
call s:ReportOnce(v:exception)
endtry
syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag,javaTodo,javaCommentError,javaSpaceError,@Spell fold
exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag'
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag
syn region javaDocTags contained start="{@\%(li\%(teral\|nk\%(plain\)\=\)\|inherit[Dd]oc\|doc[rR]oot\|value\)\>" end="}"
syn match javaDocTags contained "@\%(param\|exception\|throws\|since\)\s\+\S\+" contains=javaDocParam
syn match javaDocParam contained "\s\S\+"
syn match javaDocTags contained "@\%(version\|author\|return\|deprecated\|serial\%(Field\|Data\)\=\)\>"
syn region javaDocSeeTag contained matchgroup=javaDocTags start="@see\s\+" matchgroup=NONE end="\_."re=e-1 contains=javaDocSeeTagParam
syn match javaDocSeeTagParam contained @"\_[^"]\+"\|<a\s\+\_.\{-}</a>\|\%(\k\|\.\)*\%(#\k\+\%((\_[^)]*)\)\=\)\=@ contains=@javaHtml extend
syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,@javaDocTags,javaTodo,javaCommentError,javaSpaceError,@Spell fold
exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags'
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@summary\>\)\@=" matchgroup=javaCommentTitle end="}" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
" The members of javaDocTags are sub-grouped according to the Java
" version of their introduction, and sub-group members in turn are
" arranged in alphabetical order, so that future newer members can
" be pre-sorted and appended without disturbing the current member
" placement.
" Since they only have significance in javaCommentTitle, neither
" javaDocSummaryTag nor javaDocReturnTitleTag are defined.
syn cluster javaDocTags contains=javaDocAuthorTag,javaDocDeprecatedTag,javaDocExceptionTag,javaDocParamTag,javaDocReturnTag,javaDocSeeTag,javaDocVersionTag,javaDocSinceTag,javaDocLinkTag,javaDocSerialTag,javaDocSerialDataTag,javaDocSerialFieldTag,javaDocThrowsTag,javaDocDocRootTag,javaDocInheritDocTag,javaDocLinkplainTag,javaDocValueTag,javaDocCodeTag,javaDocLiteralTag,javaDocHiddenTag,javaDocIndexTag,javaDocProvidesTag,javaDocUsesTag,javaDocSystemPropertyTag,javaDocSnippetTag,javaDocSpecTag
" Anticipate non-standard inline tags in {@return} and {@summary}.
syn region javaTitleSkipBlock contained transparent start="{\%(@\%(return\|summary\)\>\)\@!" end="}"
syn match javaDocDocRootTag contained "{@docRoot}"
syn match javaDocInheritDocTag contained "{@inheritDoc}"
syn region javaIndexSkipBlock contained transparent start="{\%(@index\>\)\@!" end="}" contains=javaIndexSkipBlock,javaDocIndexTag
syn region javaDocIndexTag contained start="{@index\>" end="}" contains=javaDocIndexTag,javaIndexSkipBlock
syn region javaLinkSkipBlock contained transparent start="{\%(@link\>\)\@!" end="}" contains=javaLinkSkipBlock,javaDocLinkTag
syn region javaDocLinkTag contained start="{@link\>" end="}" contains=javaDocLinkTag,javaLinkSkipBlock
syn region javaLinkplainSkipBlock contained transparent start="{\%(@linkplain\>\)\@!" end="}" contains=javaLinkplainSkipBlock,javaDocLinkplainTag
syn region javaDocLinkplainTag contained start="{@linkplain\>" end="}" contains=javaDocLinkplainTag,javaLinkplainSkipBlock
syn region javaLiteralSkipBlock contained transparent start="{\%(@literal\>\)\@!" end="}" contains=javaLiteralSkipBlock,javaDocLiteralTag
syn region javaDocLiteralTag contained start="{@literal\>" end="}" contains=javaDocLiteralTag,javaLiteralSkipBlock
syn region javaSystemPropertySkipBlock contained transparent start="{\%(@systemProperty\>\)\@!" end="}" contains=javaSystemPropertySkipBlock,javaDocSystemPropertyTag
syn region javaDocSystemPropertyTag contained start="{@systemProperty\>" end="}" contains=javaDocSystemPropertyTag,javaSystemPropertySkipBlock
syn region javaValueSkipBlock contained transparent start="{\%(@value\>\)\@!" end="}" contains=javaValueSkipBlock,javaDocValueTag
syn region javaDocValueTag contained start="{@value\>" end="}" contains=javaDocValueTag,javaValueSkipBlock
syn match javaDocParam contained "\s\zs\S\+"
syn match javaDocExceptionTag contained "@exception\s\+\S\+" contains=javaDocParam
syn match javaDocParamTag contained "@param\s\+\S\+" contains=javaDocParam
syn match javaDocSinceTag contained "@since\s\+\S\+" contains=javaDocParam
syn match javaDocThrowsTag contained "@throws\s\+\S\+" contains=javaDocParam
syn match javaDocSpecTag contained "@spec\_s\+\S\+\ze\_s\+\S\+" contains=javaDocParam
syn match javaDocAuthorTag contained "@author\>"
syn match javaDocDeprecatedTag contained "@deprecated\>"
syn match javaDocHiddenTag contained "@hidden\>"
syn match javaDocReturnTag contained "@return\>"
syn match javaDocSerialTag contained "@serial\>"
syn match javaDocSerialDataTag contained "@serialData\>"
syn match javaDocSerialFieldTag contained "@serialField\>"
syn match javaDocVersionTag contained "@version\>"
syn match javaDocSeeTag contained "@see\>" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTagStar skipwhite skipempty
syn match javaDocSeeTagStar contained "^\s*\*\+\%(\s*{\=@\|/\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3 skipwhite skipempty
syn match javaDocSeeTag1 contained @"\_[^"]\+"@
syn match javaDocSeeTag2 contained @<a\s\+\_.\{-}</a>@ contains=@javaHtml extend
syn match javaDocSeeTag3 contained @["< \t]\@!\%(\k\|[/.]\)*\%(##\=\k\+\%((\_[^)]*)\)\=\)\=@ nextgroup=javaDocSeeTag3Label skipwhite skipempty
syn match javaDocSeeTag3Label contained @\k\%(\k\+\s*\)*$@
syn region javaCodeSkipBlock contained transparent start="{\%(@code\>\)\@!" end="}" contains=javaCodeSkipBlock,javaDocCodeTag
syn region javaDocCodeTag contained start="{@code\>" end="}" contains=javaDocCodeTag,javaCodeSkipBlock
exec 'syn region javaDocSnippetTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(class\|file\|id\|lang\|region\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/:$/ end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.\\/-]\|\k\)\+\)/ nextgroup=javaDocSnippetTagAttr skipwhite skipnl'
syn region javaSnippetSkipBlock contained transparent start="{\%(@snippet\>\)\@!" end="}" contains=javaSnippetSkipBlock,javaDocSnippetTag,javaCommentMarkupTag
syn region javaDocSnippetTag contained start="{@snippet\>" end="}" contains=javaDocSnippetTag,javaSnippetSkipBlock,javaDocSnippetTagAttr,javaCommentMarkupTag
syntax case match
hi def link javaDocComment Comment
hi def link javaDocSeeTagStar javaDocComment
hi def link javaCommentTitle SpecialComment
hi def link javaDocTags Special
hi def link javaDocCodeTag Special
hi def link javaDocSnippetTag Special
hi def link javaDocSeeTagParam Function
hi def link javaDocParam Function
hi def link javaDocAuthorTag Special
hi def link javaDocCodeTag Special
hi def link javaDocDeprecatedTag Special
hi def link javaDocDocRootTag Special
hi def link javaDocExceptionTag Special
hi def link javaDocHiddenTag Special
hi def link javaDocIndexTag Special
hi def link javaDocInheritDocTag Special
hi def link javaDocLinkTag Special
hi def link javaDocLinkplainTag Special
hi def link javaDocLiteralTag Special
hi def link javaDocParamTag Special
hi def link javaDocReturnTag Special
hi def link javaDocSeeTag Special
hi def link javaDocSeeTag1 String
hi def link javaDocSeeTag2 Special
hi def link javaDocSeeTag3 Function
hi def link javaDocSerialTag Special
hi def link javaDocSerialDataTag Special
hi def link javaDocSerialFieldTag Special
hi def link javaDocSinceTag Special
hi def link javaDocSnippetTag Special
hi def link javaDocSpecTag Special
hi def link javaDocSystemPropertyTag Special
hi def link javaDocThrowsTag Special
hi def link javaDocValueTag Special
hi def link javaDocVersionTag Special
endif
" match the special comment /**/
@ -586,7 +663,7 @@ hi def link javaStorageClass StorageClass
hi def link javaMethodDecl javaStorageClass
hi def link javaClassDecl javaStorageClass
hi def link javaScopeDecl javaStorageClass
hi def link javaConceptKind NonText
hi def link javaConceptKind javaStorageClass
hi def link javaBoolean Boolean
hi def link javaSpecial Special

View File

@ -4,6 +4,7 @@
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
" Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014)
" Last Change: 2020 May 25
" 2024 Sep 10 by Vim Project: add file triggers support, #15569
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@ -111,7 +112,7 @@ syn region specDescriptionArea matchgroup=specSection start='^%description' end=
syn region specPackageArea matchgroup=specSection start='^%package' end='^%'me=e-1 contains=specPackageOpts,specPreAmble,specComment
"%% Scripts Section %%
syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2
syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\|filetriggerin\|filetriggerun\|filetriggerpostun\|transfiletriggerin\|transfiletriggerun\|transfiletriggerpostun\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2
"%% Changelog Section %%
syn region specChangelogArea matchgroup=specSection start='^%changelog' end='^%'me=e-1 contains=specEmail,specURL,specWeekday,specMonth,specNumber,specComment,specLicense

View File

@ -685,7 +685,7 @@ if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimfunctionerror")
syn match vimBufnrWarn /\<bufnr\s*(\s*["']\.['"]\s*)/
endif
syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<retu\%[rn]\>\|\<while\>" skipwhite nextgroup=vimOper,vimOperParen,vimVar,vimFunc,vimNotation
syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<retu\%[rn]\>\|\<while\>" skipwhite nextgroup=@vimExprList,vimNotation
" Match: {{{2
" =====

View File

@ -81,6 +81,14 @@ local function get_dependency(dependency_name)
repo = 'luvit/luv',
symbol = 'LUV',
},
['unibilium'] = {
repo = 'neovim/unibilium',
symbol = 'UNIBILIUM',
},
['utf8proc'] = {
repo = 'JuliaStrings/utf8proc',
symbol = 'UTF8PROC',
},
['tree-sitter'] = {
repo = 'tree-sitter/tree-sitter',
symbol = 'TREESITTER',
@ -90,11 +98,11 @@ local function get_dependency(dependency_name)
symbol = 'TREESITTER_C',
},
['tree-sitter-lua'] = {
repo = 'MunifTanjim/tree-sitter-lua',
repo = 'tree-sitter-grammars/tree-sitter-lua',
symbol = 'TREESITTER_LUA',
},
['tree-sitter-vim'] = {
repo = 'neovim/tree-sitter-vim',
repo = 'tree-sitter-grammars/tree-sitter-vim',
symbol = 'TREESITTER_VIM',
},
['tree-sitter-vimdoc'] = {
@ -102,9 +110,21 @@ local function get_dependency(dependency_name)
symbol = 'TREESITTER_VIMDOC',
},
['tree-sitter-query'] = {
repo = 'nvim-treesitter/tree-sitter-query',
repo = 'tree-sitter-grammars/tree-sitter-query',
symbol = 'TREESITTER_QUERY',
},
['tree-sitter-markdown'] = {
repo = 'tree-sitter-grammars/tree-sitter-markdown',
symbol = 'TREESITTER_MARKDOWN',
},
['wasmtime'] = {
repo = 'bytecodealliance/wasmtime',
symbol = 'WASMTIME',
},
['uncrustify'] = {
repo = 'uncrustify/uncrustify',
symbol = 'UNCRUSTIFY',
},
}
local dependency = dependency_table[dependency_name]
if dependency == nil then

View File

@ -786,7 +786,7 @@ local function parse_buf(fname, parser_path)
if parser_path then
vim.treesitter.language.add('vimdoc', { path = parser_path })
end
local lang_tree = vim.treesitter.get_parser(buf)
local lang_tree = assert(vim.treesitter._get_parser(buf), 'vimdoc parser not found.')
return lang_tree, buf
end

View File

@ -10,7 +10,7 @@
Memcheck:Leak
fun:malloc
fun:uv_spawn
fun:libuv_process_spawn
fun:process_spawn
fun:libuv_proc_spawn
fun:proc_spawn
fun:job_start
}

View File

@ -848,7 +848,7 @@ def CheckIncludes(filename, lines, error):
or filename.endswith('.in.h')
or FileInfo(filename).RelativePath() in {
'func_attr.h',
'os/pty_process.h',
'os/pty_proc.h',
}):
return
@ -869,7 +869,7 @@ def CheckIncludes(filename, lines, error):
"src/nvim/msgpack_rpc/unpacker.h",
"src/nvim/option.h",
"src/nvim/os/pty_conpty_win.h",
"src/nvim/os/pty_process_win.h",
"src/nvim/os/pty_proc_win.h",
]
skip_headers = [

View File

@ -417,10 +417,10 @@ list(SORT NVIM_HEADERS)
foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME)
if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$")
if(WIN32 AND ${f} MATCHES "^(pty_proc_unix.c)$")
list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$")
if(NOT WIN32 AND ${f} MATCHES "^(pty_proc_win.c)$")
list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$")
@ -436,7 +436,7 @@ foreach(hfile ${NVIM_HEADERS})
if(WIN32 AND ${f} MATCHES "^(unix_defs.h)$")
list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif()
if(WIN32 AND ${f} MATCHES "^(pty_process_unix.h)$")
if(WIN32 AND ${f} MATCHES "^(pty_proc_unix.h)$")
list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(win_defs.h)$")
@ -832,12 +832,12 @@ find_program(CLANG_TIDY_PRG clang-tidy)
set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h)
if(WIN32)
list(APPEND EXCLUDE_CLANG_TIDY
os/pty_process_unix.h
os/pty_proc_unix.h
os/unix_defs.h)
else()
list(APPEND EXCLUDE_CLANG_TIDY
os/win_defs.h
os/pty_process_win.h
os/pty_proc_win.h
os/pty_conpty_win.h
os/os_win_console.h)
endif()

View File

@ -70,7 +70,7 @@
#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os_defs.h"
#include "nvim/os/process.h"
#include "nvim/os/proc.h"
#include "nvim/popupmenu.h"
#include "nvim/pos_defs.h"
#include "nvim/runtime.h"

View File

@ -3338,7 +3338,7 @@ void maketitle(void)
#define SPACE_FOR_FNAME (sizeof(buf) - 100)
#define SPACE_FOR_DIR (sizeof(buf) - 20)
#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM".
#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - Nvim".
char *buf_p = buf;
if (curbuf->b_fname == NULL) {
const size_t size = xstrlcpy(buf_p, _("[No Name]"),
@ -3412,7 +3412,7 @@ void maketitle(void)
append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)));
xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf)));
xstrlcat(buf_p, " - Nvim", (sizeof(buf) - (size_t)(buf_p - buf)));
if (maxlen > 0) {
// Make it shorter by removing a bit in the middle.

View File

@ -19,7 +19,7 @@
#include "nvim/eval/typval.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/rstream.h"
#include "nvim/event/socket.h"
#include "nvim/event/stream.h"
@ -88,7 +88,7 @@ void channel_free_all_mem(void)
bool channel_close(uint64_t id, ChannelPart part, const char **error)
{
Channel *chan;
Process *proc;
Proc *proc;
const char *dummy;
if (!error) {
@ -139,8 +139,8 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
if (part == kChannelPartStderr || part == kChannelPartAll) {
rstream_may_close(&proc->err);
}
if (proc->type == kProcessTypePty && part == kChannelPartAll) {
pty_process_close_master(&chan->stream.pty);
if (proc->type == kProcTypePty && part == kChannelPartAll) {
pty_proc_close_master(&chan->stream.pty);
}
break;
@ -289,7 +289,7 @@ static void channel_destroy(Channel *chan)
}
if (chan->streamtype == kChannelStreamProc) {
process_free(&chan->stream.proc);
proc_free(&chan->stream.proc);
}
callback_reader_free(&chan->on_data);
@ -376,7 +376,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
*status_out = 0;
return NULL;
}
chan->stream.pty = pty_process_init(&main_loop, chan);
chan->stream.pty = pty_proc_init(&main_loop, chan);
if (pty_width > 0) {
chan->stream.pty.width = pty_width;
}
@ -384,22 +384,22 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
chan->stream.pty.height = pty_height;
}
} else {
chan->stream.uv = libuv_process_init(&main_loop, chan);
chan->stream.uv = libuv_proc_init(&main_loop, chan);
}
Process *proc = &chan->stream.proc;
Proc *proc = &chan->stream.proc;
proc->argv = argv;
proc->exepath = exepath;
proc->cb = channel_process_exit_cb;
proc->cb = channel_proc_exit_cb;
proc->events = chan->events;
proc->detach = detach;
proc->cwd = cwd;
proc->env = env;
proc->overlapped = overlapped;
char *cmd = xstrdup(process_get_exepath(proc));
char *cmd = xstrdup(proc_get_exepath(proc));
bool has_out, has_err;
if (proc->type == kProcessTypePty) {
if (proc->type == kProcTypePty) {
has_out = true;
has_err = false;
} else {
@ -410,7 +410,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
bool has_in = stdin_mode == kChannelStdinPipe;
int status = process_spawn(proc, has_in, has_out, has_err);
int status = proc_spawn(proc, has_in, has_out, has_err);
if (status) {
semsg(_(e_jobspawn), os_strerror(status), cmd);
xfree(cmd);
@ -760,7 +760,7 @@ void channel_reader_callbacks(Channel *chan, CallbackReader *reader)
}
}
static void channel_process_exit_cb(Process *proc, int status, void *data)
static void channel_proc_exit_cb(Proc *proc, int status, void *data)
{
Channel *chan = data;
if (chan->term) {
@ -847,7 +847,7 @@ static void term_write(const char *buf, size_t size, void *data)
static void term_resize(uint16_t width, uint16_t height, void *data)
{
Channel *chan = data;
pty_process_resize(&chan->stream.pty, width, height);
pty_proc_resize(&chan->stream.pty, width, height);
}
static inline void term_delayed_free(void **argv)
@ -867,7 +867,7 @@ static inline void term_delayed_free(void **argv)
static void term_close(void *data)
{
Channel *chan = data;
process_stop(&chan->stream.proc);
proc_stop(&chan->stream.proc);
multiqueue_put(chan->events, term_delayed_free, data);
}
@ -907,7 +907,7 @@ bool channel_job_running(uint64_t id)
Channel *chan = find_channel(id);
return (chan
&& chan->streamtype == kChannelStreamProc
&& !process_is_stopped(&chan->stream.proc));
&& !proc_is_stopped(&chan->stream.proc));
}
Dictionary channel_info(uint64_t id, Arena *arena)
@ -924,8 +924,8 @@ Dictionary channel_info(uint64_t id, Arena *arena)
switch (chan->streamtype) {
case kChannelStreamProc: {
stream_desc = "job";
if (chan->stream.proc.type == kProcessTypePty) {
const char *name = pty_process_tty_name(&chan->stream.pty);
if (chan->stream.proc.type == kProcTypePty) {
const char *name = pty_proc_tty_name(&chan->stream.pty);
PUT_C(info, "pty", CSTR_TO_ARENA_OBJ(arena, name));
}

View File

@ -7,11 +7,11 @@
#include "nvim/channel_defs.h" // IWYU pragma: keep
#include "nvim/eval/typval_defs.h"
#include "nvim/event/defs.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/libuv_proc.h"
#include "nvim/macros_defs.h"
#include "nvim/map_defs.h"
#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/pty_proc.h"
#include "nvim/types_defs.h"
struct Channel {
@ -21,9 +21,9 @@ struct Channel {
ChannelStreamType streamtype;
union {
Process proc;
LibuvProcess uv;
PtyProcess pty;
Proc proc;
LibuvProc uv;
PtyProc pty;
RStream socket;
StdioPair stdio;
StderrState err;

View File

@ -170,28 +170,26 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
// cache previous calculations depending on w_virtcol
static int saved_w_virtcol;
static win_T *prev_wp;
static int prev_width1;
static int prev_width2;
static int prev_left_col;
static int prev_right_col;
static int prev_col_off;
int cur_col_off = win_col_off(wp);
int width1;
int width2;
int width1 = wp->w_width_inner - cur_col_off;
int width2 = width1 + win_col_off2(wp);
if (saved_w_virtcol == wp->w_virtcol && prev_wp == wp
&& prev_col_off == cur_col_off) {
&& prev_width1 == width1 && prev_width2 == width2) {
*right_col = prev_right_col;
*left_col = prev_left_col;
return;
}
width1 = wp->w_width_inner - cur_col_off;
width2 = width1 + win_col_off2(wp);
*left_col = 0;
*right_col = width1;
if (wp->w_virtcol >= (colnr_T)width1) {
if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) {
*right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2;
}
if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) {
@ -202,8 +200,9 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
prev_left_col = *left_col;
prev_right_col = *right_col;
prev_wp = wp;
prev_width1 = width1;
prev_width2 = width2;
saved_w_virtcol = wp->w_virtcol;
prev_col_off = cur_col_off;
}
/// Put a single char from an UTF-8 buffer into a line buffer.

View File

@ -32,7 +32,7 @@
#include "nvim/eval/vars.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/time.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
@ -8506,7 +8506,7 @@ Channel *find_job(uint64_t id, bool show_error)
{
Channel *data = find_channel(id);
if (!data || data->streamtype != kChannelStreamProc
|| process_is_stopped(&data->stream.proc)) {
|| proc_is_stopped(&data->stream.proc)) {
if (show_error) {
if (data && data->streamtype != kChannelStreamProc) {
emsg(_(e_invchanjob));

View File

@ -8044,7 +8044,7 @@ M.funcs = {
]=],
name = 'prompt_getprompt',
params = { { 'buf', 'any' } },
params = { { 'buf', 'integer|string' } },
signature = 'prompt_getprompt({buf})',
},
prompt_setcallback = {
@ -8084,7 +8084,7 @@ M.funcs = {
]=],
name = 'prompt_setcallback',
params = { { 'buf', 'any' }, { 'expr', 'any' } },
params = { { 'buf', 'integer|string' }, { 'expr', 'string|function' } },
signature = 'prompt_setcallback({buf}, {expr})',
},
prompt_setinterrupt = {
@ -8101,7 +8101,7 @@ M.funcs = {
]=],
name = 'prompt_setinterrupt',
params = { { 'buf', 'any' }, { 'expr', 'any' } },
params = { { 'buf', 'integer|string' }, { 'expr', 'string|function' } },
signature = 'prompt_setinterrupt({buf}, {expr})',
},
prompt_setprompt = {
@ -8116,7 +8116,7 @@ M.funcs = {
<
]=],
name = 'prompt_setprompt',
params = { { 'buf', 'any' }, { 'text', 'any' } },
params = { { 'buf', 'integer|string' }, { 'text', 'string' } },
signature = 'prompt_setprompt({buf}, {text})',
},
pum_getpos = {
@ -8927,6 +8927,9 @@ M.funcs = {
The value must not be negative. A zero value is like not
giving the argument.
Note: the timeout is only considered when searching, not
while evaluating the {skip} expression.
If the {skip} expression is given it is evaluated with the
cursor positioned on the start of a match. If it evaluates to
non-zero this match is skipped. This can be used, for

View File

@ -49,7 +49,7 @@
#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/time.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
@ -101,7 +101,7 @@
#include "nvim/os/fs.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/pty_proc.h"
#include "nvim/os/shell.h"
#include "nvim/os/stdpaths_defs.h"
#include "nvim/os/time.h"
@ -3770,7 +3770,7 @@ static void f_jobpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
Process *proc = &data->stream.proc;
Proc *proc = &data->stream.proc;
rettv->vval.v_number = proc->pid;
}
@ -3796,13 +3796,13 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
if (data->stream.proc.type != kProcessTypePty) {
if (data->stream.proc.type != kProcTypePty) {
emsg(_(e_channotpty));
return;
}
pty_process_resize(&data->stream.pty, (uint16_t)argvars[1].vval.v_number,
(uint16_t)argvars[2].vval.v_number);
pty_proc_resize(&data->stream.pty, (uint16_t)argvars[1].vval.v_number,
(uint16_t)argvars[2].vval.v_number);
rettv->vval.v_number = 1;
}
@ -4077,7 +4077,7 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// Ignore return code, but show error later.
channel_close(data->id, kChannelPartRpc, &error);
}
process_stop(&data->stream.proc);
proc_stop(&data->stream.proc);
rettv->vval.v_number = 1;
if (error) {
emsg(error);
@ -4113,10 +4113,10 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|| !(chan = find_channel((uint64_t)TV_LIST_ITEM_TV(arg)->vval.v_number))
|| chan->streamtype != kChannelStreamProc) {
jobs[i] = NULL; // Invalid job.
} else if (process_is_stopped(&chan->stream.proc)) {
} else if (proc_is_stopped(&chan->stream.proc)) {
// Job is stopped but not fully destroyed.
// Ensure all callbacks on its event queue are executed. #15402
process_wait(&chan->stream.proc, -1, NULL);
proc_wait(&chan->stream.proc, -1, NULL);
jobs[i] = NULL; // Invalid job.
} else {
jobs[i] = chan;
@ -4144,8 +4144,8 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (jobs[i] == NULL) {
continue; // Invalid job, will assign status=-3 below.
}
int status = process_wait(&jobs[i]->stream.proc, remaining,
waiting_jobs);
int status = proc_wait(&jobs[i]->stream.proc, remaining,
waiting_jobs);
if (status < 0) {
break; // Interrupted (CTRL-C) or timeout, skip remaining jobs.
}
@ -7641,7 +7641,7 @@ static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
return;
}
const void *iter = NULL;
const char *appname = get_appname();
const char *appname = get_appname(false);
do {
size_t dir_len;
const char *dir;
@ -8207,7 +8207,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
int pid = chan->stream.pty.process.pid;
int pid = chan->stream.pty.proc.pid;
// "./…" => "/home/foo/…"
vim_FullName(cwd, NameBuff, sizeof(NameBuff), false);

View File

@ -142,30 +142,31 @@ struct socket_watcher {
};
typedef enum {
kProcessTypeUv,
kProcessTypePty,
} ProcessType;
kProcTypeUv,
kProcTypePty,
} ProcType;
typedef struct process Process;
typedef void (*process_exit_cb)(Process *proc, int status, void *data);
typedef void (*internal_process_cb)(Process *proc);
/// OS process
typedef struct proc Proc;
typedef void (*proc_exit_cb)(Proc *proc, int status, void *data);
typedef void (*internal_proc_cb)(Proc *proc);
struct process {
ProcessType type;
struct proc {
ProcType type;
Loop *loop;
void *data;
int pid, status, refcount;
uint8_t exit_signal; // Signal used when killing (on Windows).
uint64_t stopped_time; // process_stop() timestamp
uint64_t stopped_time; // proc_stop() timestamp
const char *cwd;
char **argv;
const char *exepath;
dict_T *env;
Stream in;
RStream out, err;
/// Exit handler. If set, user must call process_free().
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
/// Exit handler. If set, user must call proc_free().
proc_exit_cb cb;
internal_proc_cb internal_exit_cb, internal_close_cb;
bool closed, detach, overlapped, fwd_err;
MultiQueue *events;
};

View File

@ -5,9 +5,9 @@
#include "nvim/eval/typval.h"
#include "nvim/event/defs.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/libuv_proc.h"
#include "nvim/event/loop.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/log.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
@ -15,15 +15,15 @@
#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/libuv_process.c.generated.h"
# include "event/libuv_proc.c.generated.h"
#endif
/// @returns zero on success, or negative error code
int libuv_process_spawn(LibuvProcess *uvproc)
int libuv_proc_spawn(LibuvProc *uvproc)
FUNC_ATTR_NONNULL_ALL
{
Process *proc = (Process *)uvproc;
uvproc->uvopts.file = process_get_exepath(proc);
Proc *proc = (Proc *)uvproc;
uvproc->uvopts.file = proc_get_exepath(proc);
uvproc->uvopts.args = proc->argv;
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
#ifdef MSWIN
@ -101,7 +101,7 @@ int libuv_process_spawn(LibuvProcess *uvproc)
return status;
}
void libuv_process_close(LibuvProcess *uvproc)
void libuv_proc_close(LibuvProc *uvproc)
FUNC_ATTR_NONNULL_ARG(1)
{
uv_close((uv_handle_t *)&uvproc->uv, close_cb);
@ -109,11 +109,11 @@ void libuv_process_close(LibuvProcess *uvproc)
static void close_cb(uv_handle_t *handle)
{
Process *proc = handle->data;
Proc *proc = handle->data;
if (proc->internal_close_cb) {
proc->internal_close_cb(proc);
}
LibuvProcess *uvproc = (LibuvProcess *)proc;
LibuvProc *uvproc = (LibuvProc *)proc;
if (uvproc->uvopts.env) {
os_free_fullenv(uvproc->uvopts.env);
}
@ -121,7 +121,7 @@ static void close_cb(uv_handle_t *handle)
static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
{
Process *proc = handle->data;
Proc *proc = handle->data;
#if defined(MSWIN)
// Use stored/expected signal.
term_signal = proc->exit_signal;
@ -130,10 +130,10 @@ static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
proc->internal_exit_cb(proc);
}
LibuvProcess libuv_process_init(Loop *loop, void *data)
LibuvProc libuv_proc_init(Loop *loop, void *data)
{
LibuvProcess rv = {
.process = process_init(loop, kProcessTypeUv, data)
LibuvProc rv = {
.proc = proc_init(loop, kProcTypeUv, data)
};
return rv;
}

View File

@ -5,12 +5,12 @@
#include "nvim/event/defs.h"
typedef struct {
Process process;
Proc proc;
uv_process_t uv;
uv_process_options_t uvopts;
uv_stdio_container_t uvstdio[4];
} LibuvProcess;
} LibuvProc;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/libuv_process.h.generated.h"
# include "event/libuv_proc.h.generated.h"
#endif

View File

@ -16,15 +16,14 @@ struct loop {
uv_loop_t uv;
MultiQueue *events;
MultiQueue *thread_events;
// Immediate events:
// "Processed after exiting uv_run() (to avoid recursion), but before
// returning from loop_poll_events()." 502aee690c98
// Practical consequence (for main_loop): these events are processed by
// state_enter()..os_inchar()
// whereas "regular" events (main_loop.events) are processed by
// state_enter()..VimState.execute()
// But state_enter()..os_inchar() can be "too early" if you want the event
// to trigger UI updates and other user-activity-related side-effects.
// Immediate events.
// - "Processed after exiting `uv_run()` (to avoid recursion), but before returning from
// `loop_poll_events()`." 502aee690c98
// - Practical consequence (for `main_loop`):
// - these are processed by `state_enter()..input_get()` whereas "regular" events
// (`main_loop.events`) are processed by `state_enter()..VimState.execute()`
// - `state_enter()..input_get()` can be "too early" if you want the event to trigger UI
// updates and other user-activity-related side-effects.
MultiQueue *fast_events;
// used by process/job-control subsystem

View File

@ -4,24 +4,24 @@
#include <uv.h>
#include "klib/klist.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/libuv_proc.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/rstream.h"
#include "nvim/event/stream.h"
#include "nvim/event/wstream.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/main.h"
#include "nvim/os/process.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/proc.h"
#include "nvim/os/pty_proc.h"
#include "nvim/os/shell.h"
#include "nvim/os/time.h"
#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/process.c.generated.h"
# include "event/proc.c.generated.h"
#endif
// Time for a process to exit cleanly before we send KILL.
@ -33,13 +33,13 @@
void __gcov_flush(void);
#endif
static bool process_is_tearing_down = false;
static bool proc_is_tearing_down = false;
// Delay exit until handles are closed, to avoid deadlocks
static int exit_need_delay = 0;
/// @returns zero on success, or negative error code
int process_spawn(Process *proc, bool in, bool out, bool err)
int proc_spawn(Proc *proc, bool in, bool out, bool err)
FUNC_ATTR_NONNULL_ALL
{
// forwarding stderr contradicts with processing it internally
@ -70,11 +70,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
int status;
switch (proc->type) {
case kProcessTypeUv:
status = libuv_process_spawn((LibuvProcess *)proc);
case kProcTypeUv:
status = libuv_proc_spawn((LibuvProc *)proc);
break;
case kProcessTypePty:
status = pty_process_spawn((PtyProcess *)proc);
case kProcTypePty:
status = pty_proc_spawn((PtyProc *)proc);
break;
}
@ -89,12 +89,12 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL);
}
if (proc->type == kProcessTypeUv) {
uv_close((uv_handle_t *)&(((LibuvProcess *)proc)->uv), NULL);
if (proc->type == kProcTypeUv) {
uv_close((uv_handle_t *)&(((LibuvProc *)proc)->uv), NULL);
} else {
process_close(proc);
proc_close(proc);
}
process_free(proc);
proc_free(proc);
proc->status = -1;
return status;
}
@ -102,52 +102,52 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
if (in) {
stream_init(NULL, &proc->in, -1, (uv_stream_t *)&proc->in.uv.pipe);
proc->in.internal_data = proc;
proc->in.internal_close_cb = on_process_stream_close;
proc->in.internal_close_cb = on_proc_stream_close;
proc->refcount++;
}
if (out) {
stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe);
proc->out.s.internal_data = proc;
proc->out.s.internal_close_cb = on_process_stream_close;
proc->out.s.internal_close_cb = on_proc_stream_close;
proc->refcount++;
}
if (err) {
stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe);
proc->err.s.internal_data = proc;
proc->err.s.internal_close_cb = on_process_stream_close;
proc->err.s.internal_close_cb = on_proc_stream_close;
proc->refcount++;
}
proc->internal_exit_cb = on_process_exit;
proc->internal_exit_cb = on_proc_exit;
proc->internal_close_cb = decref;
proc->refcount++;
kl_push(WatcherPtr, proc->loop->children, proc);
DLOG("new: pid=%d exepath=[%s]", proc->pid, process_get_exepath(proc));
DLOG("new: pid=%d exepath=[%s]", proc->pid, proc_get_exepath(proc));
return 0;
}
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
void proc_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
{
process_is_tearing_down = true;
proc_is_tearing_down = true;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
if (proc->detach || proc->type == kProcessTypePty) {
Proc *proc = (*current)->data;
if (proc->detach || proc->type == kProcTypePty) {
// Close handles to process without killing it.
CREATE_EVENT(loop->events, process_close_handles, proc);
CREATE_EVENT(loop->events, proc_close_handles, proc);
} else {
process_stop(proc);
proc_stop(proc);
}
}
// Wait until all children exit and all close events are processed.
LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1,
kl_empty(loop->children) && multiqueue_empty(loop->events));
pty_process_teardown(loop);
pty_proc_teardown(loop);
}
void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
void proc_close_streams(Proc *proc) FUNC_ATTR_NONNULL_ALL
{
wstream_may_close(&proc->in);
rstream_may_close(&proc->out);
@ -162,7 +162,7 @@ void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
/// @return Exit code of the process. proc->status will have the same value.
/// -1 if the timeout expired while the process is still running.
/// -2 if the user interrupted the wait.
int process_wait(Process *proc, int ms, MultiQueue *events)
int proc_wait(Proc *proc, int ms, MultiQueue *events)
FUNC_ATTR_NONNULL_ARG(1)
{
if (!proc->refcount) {
@ -186,7 +186,7 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
// Assume that a user hitting CTRL-C does not like the current job. Kill it.
if (got_int) {
got_int = false;
process_stop(proc);
proc_stop(proc);
if (ms == -1) {
// We can only return if all streams/handles are closed and the job
// exited.
@ -214,7 +214,7 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
}
/// Ask a process to terminate and eventually kill if it doesn't respond
void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
void proc_stop(Proc *proc) FUNC_ATTR_NONNULL_ALL
{
bool exited = (proc->status >= 0);
if (exited || proc->stopped_time) {
@ -224,13 +224,13 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
proc->exit_signal = SIGTERM;
switch (proc->type) {
case kProcessTypeUv:
case kProcTypeUv:
os_proc_tree_kill(proc->pid, SIGTERM);
break;
case kProcessTypePty:
case kProcTypePty:
// close all streams for pty processes to send SIGHUP to the process
process_close_streams(proc);
pty_process_close_master((PtyProcess *)proc);
proc_close_streams(proc);
pty_proc_close_master((PtyProc *)proc);
break;
}
@ -240,7 +240,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
}
/// Frees process-owned resources.
void process_free(Process *proc) FUNC_ATTR_NONNULL_ALL
void proc_free(Proc *proc) FUNC_ATTR_NONNULL_ALL
{
if (proc->argv != NULL) {
shell_free_argv(proc->argv);
@ -249,19 +249,19 @@ void process_free(Process *proc) FUNC_ATTR_NONNULL_ALL
}
/// Sends SIGKILL (or SIGTERM..SIGKILL for PTY jobs) to processes that did
/// not terminate after process_stop().
/// not terminate after proc_stop().
static void children_kill_cb(uv_timer_t *handle)
{
Loop *loop = handle->loop->data;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
Proc *proc = (*current)->data;
bool exited = (proc->status >= 0);
if (exited || !proc->stopped_time) {
continue;
}
uint64_t term_sent = UINT64_MAX == proc->stopped_time;
if (kProcessTypePty != proc->type || term_sent) {
if (kProcTypePty != proc->type || term_sent) {
proc->exit_signal = SIGKILL;
os_proc_tree_kill(proc->pid, SIGKILL);
} else {
@ -275,19 +275,19 @@ static void children_kill_cb(uv_timer_t *handle)
}
}
static void process_close_event(void **argv)
static void proc_close_event(void **argv)
{
Process *proc = argv[0];
Proc *proc = argv[0];
if (proc->cb) {
// User (hint: channel_job_start) is responsible for calling
// process_free().
// proc_free().
proc->cb(proc, proc->status, proc->data);
} else {
process_free(proc);
proc_free(proc);
}
}
static void decref(Process *proc)
static void decref(Proc *proc)
{
if (--proc->refcount != 0) {
return;
@ -303,13 +303,13 @@ static void decref(Process *proc)
}
assert(node);
kl_shift_at(WatcherPtr, loop->children, node);
CREATE_EVENT(proc->events, process_close_event, proc);
CREATE_EVENT(proc->events, proc_close_event, proc);
}
static void process_close(Process *proc)
static void proc_close(Proc *proc)
FUNC_ATTR_NONNULL_ARG(1)
{
if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty)
if (proc_is_tearing_down && (proc->detach || proc->type == kProcTypePty)
&& proc->closed) {
// If a detached/pty process dies while tearing down it might get closed
// twice.
@ -319,17 +319,17 @@ static void process_close(Process *proc)
proc->closed = true;
if (proc->detach) {
if (proc->type == kProcessTypeUv) {
uv_unref((uv_handle_t *)&(((LibuvProcess *)proc)->uv));
if (proc->type == kProcTypeUv) {
uv_unref((uv_handle_t *)&(((LibuvProc *)proc)->uv));
}
}
switch (proc->type) {
case kProcessTypeUv:
libuv_process_close((LibuvProcess *)proc);
case kProcTypeUv:
libuv_proc_close((LibuvProc *)proc);
break;
case kProcessTypePty:
pty_process_close((PtyProcess *)proc);
case kProcTypePty:
pty_proc_close((PtyProc *)proc);
break;
}
}
@ -338,7 +338,7 @@ static void process_close(Process *proc)
///
/// @param proc Process, for which an output stream should be flushed.
/// @param stream Stream to flush.
static void flush_stream(Process *proc, RStream *stream)
static void flush_stream(Proc *proc, RStream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
if (!stream || stream->s.closed) {
@ -382,16 +382,16 @@ static void flush_stream(Process *proc, RStream *stream)
}
}
static void process_close_handles(void **argv)
static void proc_close_handles(void **argv)
{
Process *proc = argv[0];
Proc *proc = argv[0];
exit_need_delay++;
flush_stream(proc, &proc->out);
flush_stream(proc, &proc->err);
process_close_streams(proc);
process_close(proc);
proc_close_streams(proc);
proc_close(proc);
exit_need_delay--;
}
@ -426,7 +426,7 @@ void exit_from_channel(int status)
multiqueue_put(main_loop.fast_events, exit_event, (void *)(intptr_t)status);
}
static void on_process_exit(Process *proc)
static void on_proc_exit(Proc *proc)
{
Loop *loop = proc->loop;
ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status,
@ -439,13 +439,13 @@ static void on_process_exit(Process *proc)
// Process has terminated, but there could still be data to be read from the
// OS. We are still in the libuv loop, so we cannot call code that polls for
// more data directly. Instead delay the reading after the libuv loop by
// queueing process_close_handles() as an event.
// queueing proc_close_handles() as an event.
MultiQueue *queue = proc->events ? proc->events : loop->events;
CREATE_EVENT(queue, process_close_handles, proc);
CREATE_EVENT(queue, proc_close_handles, proc);
}
static void on_process_stream_close(Stream *stream, void *data)
static void on_proc_stream_close(Stream *stream, void *data)
{
Process *proc = data;
Proc *proc = data;
decref(proc);
}

View File

@ -6,9 +6,9 @@
#include "nvim/event/defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h"
static inline Process process_init(Loop *loop, ProcessType type, void *data)
static inline Proc proc_init(Loop *loop, ProcType type, void *data)
{
return (Process) {
return (Proc) {
.type = type,
.data = data,
.loop = loop,
@ -33,17 +33,17 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
}
/// Get the path to the executable of the process.
static inline const char *process_get_exepath(Process *proc)
static inline const char *proc_get_exepath(Proc *proc)
{
return proc->exepath != NULL ? proc->exepath : proc->argv[0];
}
static inline bool process_is_stopped(Process *proc)
static inline bool proc_is_stopped(Proc *proc)
{
bool exited = (proc->status >= 0);
return exited || (proc->stopped_time != 0);
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/process.h.generated.h"
# include "event/proc.h.generated.h"
#endif

View File

@ -94,14 +94,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
stream->events = NULL;
}
void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream)
void stream_may_close(Stream *stream, bool rstream)
FUNC_ATTR_NONNULL_ARG(1)
{
if (stream->closed) {
return;
}
assert(!stream->closed);
DLOG("closing Stream: %p", (void *)stream);
stream->closed = true;
stream->close_cb = on_stream_close;
stream->close_cb_data = data;
stream->close_cb = NULL;
stream->close_cb_data = NULL;
#ifdef MSWIN
if (UV_TTY == uv_guess_handle(stream->fd)) {
@ -115,13 +118,6 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, b
}
}
void stream_may_close(Stream *stream, bool rstream)
{
if (!stream->closed) {
stream_close(stream, NULL, NULL, rstream);
}
}
void stream_close_handle(Stream *stream, bool rstream)
FUNC_ATTR_NONNULL_ALL
{

View File

@ -3264,18 +3264,12 @@ static void vim_mktempdir(void)
char tmp[TEMP_FILE_PATH_MAXLEN];
char path[TEMP_FILE_PATH_MAXLEN];
char user[40] = { 0 };
char appname[40] = { 0 };
os_get_username(user, sizeof(user));
// Usernames may contain slashes! #19240
memchrsub(user, '/', '_', sizeof(user));
memchrsub(user, '\\', '_', sizeof(user));
// Appname may be a relative path, replace slashes to make it name-like.
xstrlcpy(appname, get_appname(), sizeof(appname));
memchrsub(appname, '/', '%', sizeof(appname));
memchrsub(appname, '\\', '%', sizeof(appname));
// Make sure the umask doesn't remove the executable bit.
// "repl" has been reported to use "0177".
mode_t umask_save = umask(0077);
@ -3283,14 +3277,15 @@ static void vim_mktempdir(void)
// Expand environment variables, leave room for "/tmp/nvim.<user>/XXXXXX/999999999".
expand_env((char *)temp_dirs[i], tmp, TEMP_FILE_PATH_MAXLEN - 64);
if (!os_isdir(tmp)) {
if (strequal("$TMPDIR", temp_dirs[i])) {
WLOG("$TMPDIR tempdir not a directory (or does not exist): %s", tmp);
}
continue;
}
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
add_pathsep(tmp);
xstrlcat(tmp, appname, sizeof(tmp));
xstrlcat(tmp, ".", sizeof(tmp));
xstrlcat(tmp, "nvim.", sizeof(tmp));
xstrlcat(tmp, user, sizeof(tmp));
os_mkdir(tmp, 0700); // Always create, to avoid a race.
bool owned = os_file_owned(tmp);

View File

@ -1858,7 +1858,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
if (!char_avail()) {
// Flush screen updates before blocking.
ui_flush();
os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
if (!multiqueue_empty(main_loop.events)) {
state_handle_k_event();
continue;
@ -2981,7 +2981,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time)
uint8_t dum[DUM_LEN + 1];
while (true) {
len = os_inchar(dum, DUM_LEN, 0, 0, NULL);
len = input_get(dum, DUM_LEN, 0, 0, NULL);
if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) {
break;
}
@ -2997,7 +2997,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time)
// Fill up to a third of the buffer, because each character may be
// tripled below.
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
len = input_get(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
}
// If the typebuf was changed further down, it is like nothing was added by

View File

@ -370,12 +370,15 @@ void update_window_hl(win_T *wp, bool invalid)
// determine window specific background set in 'winhighlight'
bool float_win = wp->w_floating && !wp->w_config.external;
if (float_win && hl_def[HLF_NFLOAT] != 0) {
if (float_win && hl_def[HLF_NFLOAT] != 0 && ns_id > 0) {
wp->w_hl_attr_normal = hl_def[HLF_NFLOAT];
} else if (hl_def[HLF_COUNT] > 0) {
wp->w_hl_attr_normal = hl_def[HLF_COUNT];
} else if (float_win) {
wp->w_hl_attr_normal = HL_ATTR(HLF_NFLOAT) > 0
? HL_ATTR(HLF_NFLOAT) : highlight_attr[HLF_NFLOAT];
} else {
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
wp->w_hl_attr_normal = 0;
}
if (wp->w_floating) {

View File

@ -37,7 +37,7 @@
/// @param[in] str Prompt: question to ask user. Is always followed by
/// " (y/n)?".
/// @param[in] direct Determines what function to use to get user input. If
/// true then os_inchar() will be used, otherwise vgetc().
/// true then input_get() will be used, otherwise vgetc().
/// I.e. when direct is true then characters are obtained
/// directly from the user without buffers involved.
///
@ -111,7 +111,7 @@ int get_keystroke(MultiQueue *events)
// First time: blocking wait. Second time: wait up to 100ms for a
// terminal code to complete.
n = os_inchar(buf + len, maxlen, len == 0 ? -1 : 100, 0, events);
n = input_get(buf + len, maxlen, len == 0 ? -1 : 100, 0, events);
if (n > 0) {
// Replace zero and K_SPECIAL by a special key code.
n = fix_input_buffer(buf + len, n);

View File

@ -29,6 +29,7 @@
#include "nvim/os/stdpaths_defs.h"
#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/ui_client.h"
/// Cached location of the expanded log file path decided by log_path_init().
static char log_file_path[MAXPATHL + 1] = { 0 };
@ -322,20 +323,28 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
millis = (int)curtime.tv_usec / 1000;
}
bool ui = !!ui_client_channel_id; // Running as a UI client (--remote-ui).
// Regenerate the name when:
// - UI client (to ensure "ui" is in the name)
// - not set yet
// - no v:servername yet
bool regen = ui || name[0] == NUL || name[0] == '?';
// Get a name for this Nvim instance.
// TODO(justinmk): expose this as v:name ?
if (name[0] == NUL) {
// Parent servername.
if (regen) {
// Parent servername ($NVIM).
const char *parent = path_tail(os_getenv(ENV_NVIM));
// Servername. Empty until starting=false.
const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER));
if (parent[0] != NUL) {
snprintf(name, sizeof(name), "%s/c", parent); // "/c" indicates child.
snprintf(name, sizeof(name), ui ? "ui/c/%s" : "c/%s", parent); // "c/" = child of $NVIM.
} else if (serv[0] != NUL) {
snprintf(name, sizeof(name), "%s", serv);
snprintf(name, sizeof(name), ui ? "ui/%s" : "%s", serv);
} else {
int64_t pid = os_get_pid();
snprintf(name, sizeof(name), "?.%-5" PRId64, pid);
snprintf(name, sizeof(name), "%s.%-5" PRId64, ui ? "ui" : "?", pid);
}
}
@ -348,10 +357,6 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
log_levels[log_level], date_time, millis, name,
(context == NULL ? "" : context),
func_name, line_num);
if (name[0] == '?') {
// No v:servername yet. Clear `name` so that the next log can try again.
name[0] = NUL;
}
if (rv < 0) {
return false;

View File

@ -43,7 +43,7 @@
#include "nvim/eval/userfunc.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/stream.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
@ -174,7 +174,7 @@ bool event_teardown(void)
loop_poll_events(&main_loop, 0); // Drain thread_events, fast_events.
input_stop();
channel_teardown();
process_teardown(&main_loop);
proc_teardown(&main_loop);
timer_teardown();
server_teardown();
signal_teardown();
@ -266,7 +266,7 @@ int main(int argc, char **argv)
if (argc > 1 && STRICMP(argv[1], "-ll") == 0) {
if (argc == 2) {
print_mainerr(err_arg_missing, argv[1]);
print_mainerr(err_arg_missing, argv[1], NULL);
exit(1);
}
nlua_run_script(argv, argc, 3);
@ -357,10 +357,8 @@ int main(int argc, char **argv)
assert(!ui_client_channel_id && !use_builtin_ui);
// Nvim server...
int listen_rv = server_init(params.listen_addr);
if (listen_rv != 0) {
mainerr("Failed to --listen", listen_rv < 0
? os_strerror(listen_rv) : (listen_rv == 1 ? "empty address" : NULL));
if (!server_init(params.listen_addr)) {
mainerr(IObuff, NULL, NULL);
}
TIME_MSG("expanding arguments");
@ -1053,7 +1051,7 @@ static void command_line_scan(mparm_T *parmp)
// "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
if (argv[0][0] == '+' && !had_minmin) {
if (parmp->n_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
mainerr(err_extra_cmd, NULL, NULL);
}
argv_idx = -1; // skip to next argument
if (argv[0][1] == NUL) {
@ -1074,7 +1072,7 @@ static void command_line_scan(mparm_T *parmp)
parmp->no_swap_file = true;
} else {
if (parmp->edit_type > EDIT_STDIN) {
mainerr(err_too_many_args, argv[0]);
mainerr(err_too_many_args, argv[0], NULL);
}
parmp->had_stdin_file = true;
parmp->edit_type = EDIT_STDIN;
@ -1137,7 +1135,7 @@ static void command_line_scan(mparm_T *parmp)
nlua_disable_preload = true;
} else {
if (argv[0][argv_idx]) {
mainerr(err_opt_unknown, argv[0]);
mainerr(err_opt_unknown, argv[0], NULL);
}
had_minmin = true;
}
@ -1211,7 +1209,7 @@ static void command_line_scan(mparm_T *parmp)
break;
case 'q': // "-q" QuickFix mode
if (parmp->edit_type != EDIT_NONE) {
mainerr(err_too_many_args, argv[0]);
mainerr(err_too_many_args, argv[0], NULL);
}
parmp->edit_type = EDIT_QF;
if (argv[0][argv_idx]) { // "-q{errorfile}"
@ -1240,7 +1238,7 @@ static void command_line_scan(mparm_T *parmp)
break;
case 't': // "-t {tag}" or "-t{tag}" jump to tag
if (parmp->edit_type != EDIT_NONE) {
mainerr(err_too_many_args, argv[0]);
mainerr(err_too_many_args, argv[0], NULL);
}
parmp->edit_type = EDIT_TAG;
if (argv[0][argv_idx]) { // "-t{tag}"
@ -1274,7 +1272,7 @@ static void command_line_scan(mparm_T *parmp)
case 'c': // "-c{command}" or "-c {command}" exec command
if (argv[0][argv_idx] != NUL) {
if (parmp->n_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
mainerr(err_extra_cmd, NULL, NULL);
}
parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
argv_idx = -1;
@ -1291,19 +1289,19 @@ static void command_line_scan(mparm_T *parmp)
break;
default:
mainerr(err_opt_unknown, argv[0]);
mainerr(err_opt_unknown, argv[0], NULL);
}
// Handle option arguments with argument.
if (want_argument) {
// Check for garbage immediately after the option letter.
if (argv[0][argv_idx] != NUL) {
mainerr(err_opt_garbage, argv[0]);
mainerr(err_opt_garbage, argv[0], NULL);
}
argc--;
if (argc < 1 && c != 'S') { // -S has an optional argument
mainerr(err_arg_missing, argv[0]);
mainerr(err_arg_missing, argv[0], NULL);
}
argv++;
argv_idx = -1;
@ -1312,7 +1310,7 @@ static void command_line_scan(mparm_T *parmp)
case 'c': // "-c {command}" execute command
case 'S': // "-S {file}" execute Vim script
if (parmp->n_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
mainerr(err_extra_cmd, NULL, NULL);
}
if (c == 'S') {
char *a;
@ -1343,7 +1341,7 @@ static void command_line_scan(mparm_T *parmp)
if (strequal(argv[-1], "--cmd")) {
// "--cmd {command}" execute command
if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
mainerr(err_extra_cmd, NULL, NULL);
}
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
} else if (strequal(argv[-1], "--listen")) {
@ -1425,7 +1423,7 @@ scripterror:
// Check for only one type of editing.
if (parmp->edit_type > EDIT_STDIN) {
mainerr(err_too_many_args, argv[0]);
mainerr(err_too_many_args, argv[0], NULL);
}
parmp->edit_type = EDIT_FILE;
@ -1472,7 +1470,7 @@ scripterror:
}
if (embedded_mode && (silent_mode || parmp->luaf)) {
mainerr(_("--embed conflicts with -es/-Es/-l"), NULL);
mainerr(_("--embed conflicts with -es/-Es/-l"), NULL, NULL);
}
// If there is a "+123" or "-c" command, set v:swapcommand to the first one.
@ -2135,28 +2133,30 @@ static int execute_env(char *env)
return OK;
}
/// Prints the following then exits:
/// - An error message `errstr`
/// - A string `str` if not null
/// Prints a message of the form "{msg1}: {msg2}: {msg3}", then exits with code 1.
///
/// @param errstr string containing an error message
/// @param str string to append to the primary error message, or NULL
static void mainerr(const char *errstr, const char *str)
/// @param msg1 error message
/// @param msg2 extra message, or NULL
/// @param msg3 extra message, or NULL
static void mainerr(const char *msg1, const char *msg2, const char *msg3)
FUNC_ATTR_NORETURN
{
print_mainerr(errstr, str);
print_mainerr(msg1, msg2, msg3);
os_exit(1);
}
static void print_mainerr(const char *errstr, const char *str)
static void print_mainerr(const char *msg1, const char *msg2, const char *msg3)
{
char *prgname = path_tail(argv0);
signal_stop(); // kill us with CTRL-C here, if you like
fprintf(stderr, "%s: %s", prgname, _(errstr));
if (str != NULL) {
fprintf(stderr, ": \"%s\"", str);
fprintf(stderr, "%s: %s", prgname, _(msg1));
if (msg2 != NULL) {
fprintf(stderr, ": \"%s\"", msg2);
}
if (msg3 != NULL) {
fprintf(stderr, ": \"%s\"", msg3);
}
fprintf(stderr, _("\nMore info with \""));
fprintf(stderr, "%s -h\"\n", prgname);
@ -2207,7 +2207,7 @@ static void usage(void)
printf(_(" --headless Don't start a user interface\n"));
printf(_(" --listen <address> Serve RPC API from this address\n"));
printf(_(" --remote[-subcommand] Execute commands remotely on a server\n"));
printf(_(" --server <address> Specify RPC server to send commands to\n"));
printf(_(" --server <address> Connect to this Nvim server\n"));
printf(_(" --startuptime <file> Write startup timing messages to <file>\n"));
printf(_("\nSee \":help startup-options\" for all options.\n"));
}

View File

@ -84,7 +84,7 @@
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/os/process.h"
#include "nvim/os/proc.h"
#include "nvim/os/time.h"
#include "nvim/os/time_defs.h"
#include "nvim/path.h"
@ -743,7 +743,7 @@ static void add_b0_fenc(ZeroBlock *b0p, buf_T *buf)
/// @param swap_fname Name of the swapfile. If it's from before a reboot, the result is 0.
///
/// @return PID, or 0 if process is not running or the swapfile is from before a reboot.
static int swapfile_process_running(const ZeroBlock *b0p, const char *swap_fname)
static int swapfile_proc_running(const ZeroBlock *b0p, const char *swap_fname)
{
FileInfo st;
double uptime;
@ -1214,7 +1214,7 @@ void ml_recover(bool checkext)
msg(_("Recovery completed. Buffer contents equals file contents."), 0);
}
msg_puts(_("\nYou may want to delete the .swp file now."));
if (swapfile_process_running(b0p, fname_used)) {
if (swapfile_proc_running(b0p, fname_used)) {
// Warn there could be an active Vim on the same file, the user may
// want to kill it.
msg_puts(_("\nNote: process STILL RUNNING: "));
@ -1462,7 +1462,7 @@ char *make_percent_swname(char *dir, char *dir_end, const char *name)
}
// PID of swapfile owner, or zero if not running.
static int process_running;
static int proc_running;
/// For Vimscript "swapinfo()".
///
@ -1488,7 +1488,7 @@ void swapfile_dict(const char *fname, dict_T *d)
tv_dict_add_str_len(d, S_LEN("fname"), b0.b0_fname,
B0_FNAME_SIZE_ORG);
tv_dict_add_nr(d, S_LEN("pid"), swapfile_process_running(&b0, fname));
tv_dict_add_nr(d, S_LEN("pid"), swapfile_proc_running(&b0, fname));
tv_dict_add_nr(d, S_LEN("mtime"), char_to_long(b0.b0_mtime));
tv_dict_add_nr(d, S_LEN("dirty"), b0.b0_dirty ? 1 : 0);
tv_dict_add_nr(d, S_LEN("inode"), char_to_long(b0.b0_ino));
@ -1572,7 +1572,7 @@ static time_t swapfile_info(char *fname)
if (char_to_long(b0.b0_pid) != 0) {
msg_puts(_("\n process ID: "));
msg_outnum((int)char_to_long(b0.b0_pid));
if ((process_running = swapfile_process_running(&b0, fname))) {
if ((proc_running = swapfile_proc_running(&b0, fname))) {
msg_puts(_(" (STILL RUNNING)"));
}
}
@ -1640,7 +1640,7 @@ static bool swapfile_unchanged(char *fname)
}
// process must be known and not running.
if (char_to_long(b0.b0_pid) == 0 || swapfile_process_running(&b0, fname)) {
if (char_to_long(b0.b0_pid) == 0 || swapfile_proc_running(&b0, fname)) {
ret = false;
}
@ -3399,7 +3399,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_
fd = os_open(fname, O_RDONLY, 0);
if (fd >= 0) {
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
process_running = swapfile_process_running(&b0, fname);
proc_running = swapfile_proc_running(&b0, fname);
// If the swapfile has the same directory as the
// buffer don't compare the directory names, they can
@ -3459,7 +3459,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_
choice = SEA_CHOICE_READONLY;
}
process_running = 0; // Set by attention_message..swapfile_info.
proc_running = 0; // Set by attention_message..swapfile_info.
if (choice == SEA_CHOICE_NONE) {
// Show info about the existing swapfile.
attention_message(buf, fname);
@ -3491,12 +3491,12 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_
= do_dialog(VIM_WARNING,
_("VIM - ATTENTION"),
name,
process_running
proc_running
? _("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort")
: _("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"),
1, NULL, false);
if (process_running && dialog_result >= 4) {
if (proc_running && dialog_result >= 4) {
// compensate for missing "Delete it" button
dialog_result++;
}

View File

@ -14,7 +14,7 @@
#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/globals.h"

View File

@ -12,7 +12,7 @@
/// HACK: os/input.c drains this queue immediately before blocking for input.
/// Events on this queue are async-safe, but they need the resolved state
/// of os_inchar(), so they are processed "just-in-time".
/// of input_get(), so they are processed "just-in-time".
EXTERN MultiQueue *ch_before_blocking_events INIT( = NULL);
#ifdef INCLUDE_GENERATED_DECLARATIONS

View File

@ -11,12 +11,14 @@
#include "nvim/event/socket.h"
#include "nvim/garray.h"
#include "nvim/garray_defs.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/server.h"
#include "nvim/os/os.h"
#include "nvim/os/stdpaths_defs.h"
#include "nvim/types_defs.h"
#define MAX_CONNECTIONS 32
#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
@ -27,37 +29,31 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE;
# include "msgpack_rpc/server.c.generated.h"
#endif
/// Initializes the module
/// Initializes resources, handles `--listen`, starts the primary server at v:servername.
///
/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
int server_init(const char *listen_addr)
/// @returns true on success, false on fatal error (message stored in IObuff)
bool server_init(const char *listen_addr)
{
bool ok = true;
bool must_free = false;
TriState user_arg = kTrue; // User-provided --listen arg.
ga_init(&watchers, sizeof(SocketWatcher *), 1);
// $NVIM_LISTEN_ADDRESS (deprecated)
if ((!listen_addr || listen_addr[0] == '\0') && os_env_exists(ENV_LISTEN)) {
user_arg = kFalse; // User-provided env var.
listen_addr = os_getenv(ENV_LISTEN);
}
if (!listen_addr || listen_addr[0] == '\0') {
user_arg = kNone; // Autogenerated server address.
listen_addr = server_address_new(NULL);
must_free = true;
}
if (!listen_addr) {
abort(); // Cannot happen.
}
int rv = server_start(listen_addr);
if (os_env_exists(ENV_LISTEN)) {
// Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be
// leaked to child jobs or :terminal.
os_unsetenv(ENV_LISTEN);
}
// TODO(justinmk): this is for logging_spec. Can remove this after nvim_log #7062 is merged.
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
if (os_env_exists("__NVIM_TEST_LOG")) {
ELOG("test log message");
}
@ -66,7 +62,28 @@ int server_init(const char *listen_addr)
xfree((char *)listen_addr);
}
return rv;
if (rv == 0 || user_arg == kNone) {
// The autogenerated servername can fail if the user has a broken $XDG_RUNTIME_DIR. #30282
// But that is not fatal (startup will continue, logged in $NVIM_LOGFILE, empty v:servername).
goto end;
}
(void)snprintf(IObuff, IOSIZE,
user_arg ==
kTrue ? "Failed to --listen: %s: \"%s\""
: "Failed $NVIM_LISTEN_ADDRESS: %s: \"%s\"",
rv < 0 ? os_strerror(rv) : (rv == 1 ? "empty address" : "?"),
listen_addr);
ok = false;
end:
if (os_env_exists(ENV_LISTEN)) {
// Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be
// leaked to child jobs or :terminal.
os_unsetenv(ENV_LISTEN);
}
return ok;
}
/// Teardown a single server
@ -97,17 +114,19 @@ void server_teardown(void)
/// - Windows: "\\.\pipe\<name>.<pid>.<counter>"
/// - Other: "/tmp/nvim.user/xxx/<name>.<pid>.<counter>"
char *server_address_new(const char *name)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
{
static uint32_t count = 0;
char fmt[ADDRESS_MAX_SIZE];
const char *appname = get_appname();
#ifdef MSWIN
(void)get_appname(true);
int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
name ? name : appname, os_get_pid(), count++);
name ? name : NameBuff, os_get_pid(), count++);
#else
char *dir = stdpaths_get_xdg_var(kXDGRuntimeDir);
(void)get_appname(true);
int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
dir, name ? name : appname, os_get_pid(), count++);
dir, name ? name : NameBuff, os_get_pid(), count++);
xfree(dir);
#endif
if ((size_t)r >= sizeof(fmt)) {

View File

@ -6597,11 +6597,11 @@ static void nv_open(cmdarg_T *cap)
static void nv_event(cmdarg_T *cap)
{
// Garbage collection should have been executed before blocking for events in
// the `os_inchar` in `state_enter`, but we also disable it here in case the
// `os_inchar` branch was not executed (!multiqueue_empty(loop.events), which
// the `input_get` in `state_enter`, but we also disable it here in case the
// `input_get` branch was not executed (!multiqueue_empty(loop.events), which
// could have `may_garbage_collect` set to true in `normal_check`).
//
// That is because here we may run code that calls `os_inchar`
// That is because here we may run code that calls `input_get`
// later(`f_confirm` or `get_keystroke` for example), but in these cases it is
// not safe to perform garbage collection because there could be unreferenced
// lists or dicts being used.

View File

@ -210,39 +210,53 @@ static void set_init_default_backupskip(void)
OptIndex opt_idx = kOptBackupskip;
ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
bool mustfree = true;
char *p;
size_t plen;
#ifdef UNIX
if (*names[n] == NUL) {
if (*names[i] == NUL) {
# ifdef __APPLE__
p = "/private/tmp";
plen = STRLEN_LITERAL("/private/tmp");
# else
p = "/tmp";
plen = STRLEN_LITERAL("/tmp");
# endif
mustfree = false;
} else
#endif
{
p = vim_getenv(names[n]);
p = vim_getenv(names[i]);
plen = 0; // will be calcuated below
}
if (p != NULL && *p != NUL) {
// First time count the NUL, otherwise count the ','.
const size_t len = strlen(p) + 3;
char *item = xmalloc(len);
xstrlcpy(item, p, len);
add_pathsep(item);
xstrlcat(item, "*", len);
if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
== NULL) {
ga_grow(&ga, (int)len);
if (!GA_EMPTY(&ga)) {
strcat(ga.ga_data, ",");
bool has_trailing_path_sep = false;
if (plen == 0) {
// the value was retrieved from the environment
plen = strlen(p);
// does the value include a trailing path separator?
if (after_pathsep(p, p + plen)) {
has_trailing_path_sep = true;
}
strcat(ga.ga_data, p);
add_pathsep(ga.ga_data);
strcat(ga.ga_data, "*");
ga.ga_len += (int)len;
}
// item size needs to be large enough to include "/*" and a trailing NUL
// note: the value (and therefore plen) may already include a path separator
size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2;
char *item = xmalloc(itemsize);
// add a preceeding comma as a separator after the first item
size_t itemseplen = (ga.ga_len == 0) ? 0 : 1;
size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p,
has_trailing_path_sep ? "" : PATHSEPSTR);
if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) {
ga_grow(&ga, (int)(itemseplen + itemlen + 1));
ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len,
itemseplen + itemlen + 1,
"%s%s", (itemseplen > 0) ? "," : "", item);
}
xfree(item);
}
@ -526,7 +540,8 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
/// For an option value that contains comma separated items, find "newval" in
/// "origval". Return NULL if not found.
static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
static char *find_dup_item(char *origval, const char *newval, const size_t newvallen,
uint32_t flags)
FUNC_ATTR_NONNULL_ARG(2)
{
if (origval == NULL) {
@ -535,11 +550,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
int bs = 0;
const size_t newlen = strlen(newval);
for (char *s = origval; *s != NUL; s++) {
if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
&& strncmp(s, newval, newlen) == 0
&& (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) {
&& strncmp(s, newval, newvallen) == 0
&& (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) {
return s;
}
// Count backslashes. Only a comma with an even number of backslashes
@ -697,10 +711,10 @@ void set_helplang_default(const char *lang)
}
p_hlg = xmemdupz(lang, lang_len);
// zh_CN becomes "cn", zh_TW becomes "tw".
if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) {
if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) {
p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]);
p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]);
} else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') {
} else if (lang_len && *p_hlg == 'C') {
// any C like setting, such as C.UTF-8, becomes "en"
p_hlg[0] = 'e';
p_hlg[1] = 'n';
@ -950,7 +964,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void
int len = 0;
if (op == OP_REMOVING || (flags & P_NODUP)) {
len = (int)strlen(newval);
s = find_dup_item(origval, newval, flags);
s = find_dup_item(origval, newval, (size_t)len, flags);
// do not add if already there
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
@ -1464,11 +1478,10 @@ int do_set(char *arg, int opt_flags)
}
if (errmsg != NULL) {
xstrlcpy(IObuff, _(errmsg), IOSIZE);
int i = (int)strlen(IObuff) + 2;
int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2;
if (i + (arg - startarg) < IOSIZE) {
// append the argument with the error
xstrlcat(IObuff, ": ", IOSIZE);
xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2));
assert(arg >= startarg);
memmove(IObuff + i, startarg, (size_t)(arg - startarg));
IObuff[i + (arg - startarg)] = NUL;
@ -5431,7 +5444,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
xp->xp_pattern = arg;
return;
}
char *p = arg + strlen(arg) - 1;
char *const argend = arg + strlen(arg);
char *p = argend - 1;
if (*p == ' ' && *(p - 1) != '\\') {
xp->xp_pattern = p + 1;
return;
@ -5618,7 +5632,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// Triple-backslashed escaped file names (e.g. 'path') can also be
// delimited by space.
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) {
for (p = argend - 1; p > xp->xp_pattern; p--) {
// count number of backslashes before ' ' or ','
if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
char *s = p;
@ -5642,7 +5656,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// An option that is a list of single-character flags should always start
// at the end as we don't complete words.
if (flags & P_FLAGLIST) {
xp->xp_pattern = arg + strlen(arg);
xp->xp_pattern = argend;
}
// Some options can either be using file/dir expansions, or custom value
@ -5952,7 +5966,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
int count = 0;
(*matches)[count++] = xstrdup(option_val);
(*matches)[count++] = xmemdupz(option_val, num_flags);
if (num_flags > 1) {
// If more than one flags, split the flags up and expose each

View File

@ -9047,7 +9047,7 @@ return {
desc = [=[
When on, the title of the window will be set to the value of
'titlestring' (if it is not empty), or to:
filename [+=-] (path) - NVIM
filename [+=-] (path) - Nvim
Where:
filename the name of the file being edited
- indicates the file cannot be modified, 'ma' off
@ -9055,11 +9055,11 @@ return {
= indicates the file is read-only
=+ indicates the file is read-only and modified
(path) is the path of the file being edited
- NVIM the server name |v:servername| or "NVIM"
- Nvim the server name |v:servername| or "Nvim"
]=],
full_name = 'title',
scope = { 'global' },
short_desc = N_('Vim set the title of the window'),
short_desc = N_('set the title of the window'),
type = 'boolean',
varname = 'p_title',
},

View File

@ -344,7 +344,7 @@ char *os_getenvname_at_index(size_t index)
#endif
}
/// Get the process ID of the Neovim process.
/// Get the process ID of the Nvim process.
///
/// @return the process ID.
int64_t os_get_pid(void)

View File

@ -33,12 +33,6 @@
#define READ_BUFFER_SIZE 0xfff
#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
typedef enum {
kInputNone,
kInputAvail,
kInputEof,
} InbufPollResult;
static RStream read_stream = { .s.closed = true }; // Input before UI starts.
static char input_buffer[INPUT_BUFFER_SIZE];
static char *input_read_pos = input_buffer;
@ -84,57 +78,76 @@ static void cursorhold_event(void **argv)
static void create_cursorhold_event(bool events_enabled)
{
// If events are enabled and the queue has any items, this function should not
// have been called (inbuf_poll would return kInputAvail).
// have been called (`inbuf_poll` would return `kTrue`).
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
// `state_check` callback for the states where it can be triggered.
assert(!events_enabled || multiqueue_empty(main_loop.events));
multiqueue_put(main_loop.events, cursorhold_event, NULL);
}
static void restart_cursorhold_wait(int tb_change_cnt)
static void reset_cursorhold_wait(int tb_change_cnt)
{
cursorhold_time = 0;
cursorhold_tb_change_cnt = tb_change_cnt;
}
/// Low level input function
/// Reads OS input into `buf`, and consumes pending events while waiting (if `ms != 0`).
///
/// Wait until either the input buffer is non-empty or, if `events` is not NULL
/// until `events` is non-empty.
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
/// - Consumes available input received from the OS.
/// - Consumes pending events.
/// - Manages CursorHold events.
/// - Handles EOF conditions.
///
/// Originally based on the Vim `mch_inchar` function.
///
/// @param buf Buffer to store consumed input.
/// @param maxlen Maximum bytes to read into `buf`, or 0 to skip reading.
/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
/// @param tb_change_cnt Used to detect when typeahead changes.
/// @param events (optional) Events to process.
/// @return Bytes read into buf, or 0 if no input was read
int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
{
// This check is needed so that feeding typeahead from RPC can prevent CursorHold.
if (tb_change_cnt != cursorhold_tb_change_cnt) {
restart_cursorhold_wait(tb_change_cnt);
reset_cursorhold_wait(tb_change_cnt);
}
if (maxlen && input_available()) {
restart_cursorhold_wait(tb_change_cnt);
size_t to_read = MIN((size_t)maxlen, input_available());
memcpy(buf, input_read_pos, to_read);
input_read_pos += to_read;
return (int)to_read;
}
#define TRY_READ() \
do { \
if (maxlen && input_available()) { \
reset_cursorhold_wait(tb_change_cnt); \
assert(maxlen >= 0); \
size_t to_read = MIN((size_t)maxlen, input_available()); \
memcpy(buf, input_read_pos, to_read); \
input_read_pos += to_read; \
/* This is safe because INPUT_BUFFER_SIZE fits in an int. */ \
assert(to_read <= INT_MAX); \
return (int)to_read; \
} \
} while (0)
TRY_READ();
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
ctrl_c_interrupts = false;
}
InbufPollResult result;
TriState result; ///< inbuf_poll result.
if (ms >= 0) {
if ((result = inbuf_poll(ms, events)) == kInputNone) {
if ((result = inbuf_poll(ms, events)) == kFalse) {
return 0;
}
} else {
uint64_t wait_start = os_hrtime();
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) {
if (read_stream.s.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit();
}
restart_cursorhold_wait(tb_change_cnt);
reset_cursorhold_wait(tb_change_cnt);
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
create_cursorhold_event(events == main_loop.events);
} else {
@ -153,32 +166,26 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
return 0;
}
if (maxlen && input_available()) {
restart_cursorhold_wait(tb_change_cnt);
// Safe to convert `to_read` to int, it will never overflow since
// INPUT_BUFFER_SIZE fits in an int
size_t to_read = MIN((size_t)maxlen, input_available());
memcpy(buf, input_read_pos, to_read);
input_read_pos += to_read;
return (int)to_read;
}
TRY_READ();
// If there are events, return the keys directly
if (maxlen && pending_events(events)) {
return push_event_key(buf, maxlen);
}
if (result == kInputEof) {
if (result == kNone) {
read_error_exit();
}
return 0;
#undef TRY_READ
}
// Check if a character is available for reading
bool os_char_avail(void)
{
return inbuf_poll(0, NULL) == kInputAvail;
return inbuf_poll(0, NULL) == kTrue;
}
/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
@ -463,15 +470,22 @@ bool input_blocking(void)
return blocking;
}
// This is a replacement for the old `WaitForChar` function in os_unix.c
static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
/// Checks for (but does not read) available input, and consumes `main_loop.events` while waiting.
///
/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
/// @param events (optional) Queue to check for pending events.
/// @return TriState:
/// - kTrue: Input/events available
/// - kFalse: No input/events
/// - kNone: EOF reached on the input stream
static TriState inbuf_poll(int ms, MultiQueue *events)
{
if (os_input_ready(events)) {
return kInputAvail;
return kTrue;
}
if (do_profiling == PROF_YES && ms) {
prof_inchar_enter();
prof_input_start();
}
if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) {
@ -479,20 +493,18 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
blocking = true;
multiqueue_process_events(ch_before_blocking_events);
}
DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL,
events && !multiqueue_empty(events));
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms,
os_input_ready(events) || input_eof);
DLOG("blocking... events=%s", !!events ? "true" : "false");
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, os_input_ready(events) || input_eof);
blocking = false;
if (do_profiling == PROF_YES && ms) {
prof_inchar_exit();
prof_input_end();
}
if (os_input_ready(events)) {
return kInputAvail;
return kTrue;
}
return input_eof ? kInputEof : kInputNone;
return input_eof ? kNone : kFalse;
}
static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
@ -533,8 +545,8 @@ static void process_ctrl_c(void)
}
}
// Helper function used to push bytes from the 'event' key sequence partially
// between calls to os_inchar when maxlen < 3
/// Pushes bytes from the "event" key sequence (KE_EVENT) partially between calls to input_get when
/// `maxlen < 3`.
static int push_event_key(uint8_t *buf, int maxlen)
{
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };

View File

@ -37,24 +37,24 @@
#include "nvim/log.h"
#include "nvim/memory.h"
#include "nvim/os/process.h"
#include "nvim/os/proc.h"
#ifdef MSWIN
# include "nvim/api/private/helpers.h"
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/process.c.generated.h"
# include "os/proc.c.generated.h"
#endif
#ifdef MSWIN
static bool os_proc_tree_kill_rec(HANDLE process, int sig)
static bool os_proc_tree_kill_rec(HANDLE proc, int sig)
{
if (process == NULL) {
if (proc == NULL) {
return false;
}
PROCESSENTRY32 pe;
DWORD pid = GetProcessId(process);
DWORD pid = GetProcessId(proc);
if (pid != 0) {
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@ -77,7 +77,7 @@ static bool os_proc_tree_kill_rec(HANDLE process, int sig)
}
theend:
return (bool)TerminateProcess(process, (unsigned)sig);
return (bool)TerminateProcess(proc, (unsigned)sig);
}
/// Kills process `pid` and its descendants recursively.
bool os_proc_tree_kill(int pid, int sig)

View File

@ -7,5 +7,5 @@
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/process.h.generated.h"
# include "os/proc.h.generated.h"
#endif

View File

@ -143,7 +143,7 @@ finished:
return conpty_object;
}
bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *name,
bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *proc_handle, wchar_t *name,
wchar_t *cmd_line, wchar_t *cwd, wchar_t *env)
{
PROCESS_INFORMATION pi = { 0 };
@ -159,7 +159,7 @@ bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *n
&pi)) {
return false;
}
*process_handle = pi.hProcess;
*proc_handle = pi.hProcess;
return true;
}

7
src/nvim/os/pty_proc.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#ifdef MSWIN
# include "nvim/os/pty_proc_win.h"
#else
# include "nvim/os/pty_proc_unix.h"
#endif

View File

@ -34,16 +34,16 @@
#include "nvim/eval/typval.h"
#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/log.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/pty_process_unix.h"
#include "nvim/os/pty_proc.h"
#include "nvim/os/pty_proc_unix.h"
#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_unix.c.generated.h"
# include "os/pty_proc_unix.c.generated.h"
#endif
#if defined(__sun) && !defined(HAVE_FORKPTY)
@ -158,7 +158,7 @@ static pid_t forkpty(int *amaster, char *name, struct termios *termp, struct win
#endif
/// @returns zero on success, or negative error code
int pty_process_spawn(PtyProcess *ptyproc)
int pty_proc_spawn(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
// termios initialized at first use
@ -168,7 +168,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
int status = 0; // zero or negative error code (libuv convention)
Process *proc = (Process *)ptyproc;
Proc *proc = (Proc *)ptyproc;
assert(proc->err.s.closed);
uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 };
@ -224,29 +224,29 @@ error:
return status;
}
const char *pty_process_tty_name(PtyProcess *ptyproc)
const char *pty_proc_tty_name(PtyProc *ptyproc)
{
return ptsname(ptyproc->tty_fd);
}
void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
ptyproc->winsize = (struct winsize){ height, width, 0, 0 };
ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize);
}
void pty_process_close(PtyProcess *ptyproc)
void pty_proc_close(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
pty_process_close_master(ptyproc);
Process *proc = (Process *)ptyproc;
pty_proc_close_master(ptyproc);
Proc *proc = (Proc *)ptyproc;
if (proc->internal_close_cb) {
proc->internal_close_cb(proc);
}
}
void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
void pty_proc_close_master(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL
{
if (ptyproc->tty_fd >= 0) {
close(ptyproc->tty_fd);
@ -254,12 +254,12 @@ void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
}
}
void pty_process_teardown(Loop *loop)
void pty_proc_teardown(Loop *loop)
{
uv_signal_stop(&loop->children_watcher);
}
static void init_child(PtyProcess *ptyproc)
static void init_child(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
#if defined(HAVE__NSGETENVIRON)
@ -277,13 +277,13 @@ static void init_child(PtyProcess *ptyproc)
signal(SIGTERM, SIG_DFL);
signal(SIGALRM, SIG_DFL);
Process *proc = (Process *)ptyproc;
Proc *proc = (Proc *)ptyproc;
if (proc->cwd && os_chdir(proc->cwd) != 0) {
ELOG("chdir(%s) failed: %s", proc->cwd, strerror(errno));
return;
}
const char *prog = process_get_exepath(proc);
const char *prog = proc_get_exepath(proc);
assert(proc->env);
environ = tv_dict_to_env(proc->env);
@ -388,7 +388,7 @@ static void chld_handler(uv_signal_t *handle, int signum)
Loop *loop = handle->loop->data;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
Proc *proc = (*current)->data;
do {
pid = waitpid(proc->pid, &stat, WNOHANG);
} while (pid < 0 && errno == EINTR);
@ -406,10 +406,10 @@ static void chld_handler(uv_signal_t *handle, int signum)
}
}
PtyProcess pty_process_init(Loop *loop, void *data)
PtyProc pty_proc_init(Loop *loop, void *data)
{
PtyProcess rv;
rv.process = process_init(loop, kProcessTypePty, data);
PtyProc rv;
rv.proc = proc_init(loop, kProcTypePty, data);
rv.width = 80;
rv.height = 24;
rv.tty_fd = -1;

View File

@ -1,5 +1,5 @@
#pragma once
// IWYU pragma: private, include "nvim/os/pty_process.h"
// IWYU pragma: private, include "nvim/os/pty_proc.h"
#include <stdint.h>
#include <sys/ioctl.h>
@ -7,12 +7,12 @@
#include "nvim/event/defs.h"
typedef struct {
Process process;
Proc proc;
uint16_t width, height;
struct winsize winsize;
int tty_fd;
} PtyProcess;
} PtyProc;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_unix.h.generated.h"
# include "os/pty_proc_unix.h.generated.h"
#endif

View File

@ -10,20 +10,20 @@
#include "nvim/memory.h"
#include "nvim/os/os.h"
#include "nvim/os/pty_conpty_win.h"
#include "nvim/os/pty_process_win.h"
#include "nvim/os/pty_proc_win.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_win.c.generated.h"
# include "os/pty_proc_win.c.generated.h"
#endif
static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused)
static void CALLBACK pty_proc_finish1(void *context, BOOLEAN unused)
FUNC_ATTR_NONNULL_ALL
{
PtyProcess *ptyproc = (PtyProcess *)context;
Process *proc = (Process *)ptyproc;
PtyProc *ptyproc = (PtyProc *)context;
Proc *proc = (Proc *)ptyproc;
os_conpty_free(ptyproc->conpty);
// NB: pty_process_finish1() is called on a separate thread,
// NB: pty_proc_finish1() is called on a separate thread,
// but the timer only works properly if it's started by the main thread.
loop_schedule_fast(proc->loop, event_create(start_wait_eof_timer, ptyproc));
}
@ -31,7 +31,7 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused)
static void start_wait_eof_timer(void **argv)
FUNC_ATTR_NONNULL_ALL
{
PtyProcess *ptyproc = (PtyProcess *)argv[0];
PtyProc *ptyproc = (PtyProc *)argv[0];
if (ptyproc->finish_wait != NULL) {
uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200);
@ -39,15 +39,15 @@ static void start_wait_eof_timer(void **argv)
}
/// @returns zero on success, or negative error code.
int pty_process_spawn(PtyProcess *ptyproc)
int pty_proc_spawn(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
Process *proc = (Process *)ptyproc;
Proc *proc = (Proc *)ptyproc;
int status = 0;
conpty_t *conpty_object = NULL;
char *in_name = NULL;
char *out_name = NULL;
HANDLE process_handle = NULL;
HANDLE proc_handle = NULL;
uv_connect_t *in_req = NULL;
uv_connect_t *out_req = NULL;
wchar_t *cmd_line = NULL;
@ -69,7 +69,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_pipe_connect(in_req,
&proc->in.uv.pipe,
in_name,
pty_process_connect_cb);
pty_proc_connect_cb);
}
if (!proc->out.s.closed) {
@ -77,7 +77,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_pipe_connect(out_req,
&proc->out.s.uv.pipe,
out_name,
pty_process_connect_cb);
pty_proc_connect_cb);
}
if (proc->cwd != NULL) {
@ -105,7 +105,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
if (!os_conpty_spawn(conpty_object,
&process_handle,
&proc_handle,
NULL,
cmd_line,
cwd,
@ -114,42 +114,42 @@ int pty_process_spawn(PtyProcess *ptyproc)
status = (int)GetLastError();
goto cleanup;
}
proc->pid = (int)GetProcessId(process_handle);
proc->pid = (int)GetProcessId(proc_handle);
uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer);
ptyproc->wait_eof_timer.data = (void *)ptyproc;
if (!RegisterWaitForSingleObject(&ptyproc->finish_wait,
process_handle,
pty_process_finish1,
proc_handle,
pty_proc_finish1,
ptyproc,
INFINITE,
WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) {
abort();
}
// Wait until pty_process_connect_cb is called.
// Wait until pty_proc_connect_cb is called.
while ((in_req != NULL && in_req->handle != NULL)
|| (out_req != NULL && out_req->handle != NULL)) {
uv_run(&proc->loop->uv, UV_RUN_ONCE);
}
ptyproc->conpty = conpty_object;
ptyproc->process_handle = process_handle;
ptyproc->proc_handle = proc_handle;
conpty_object = NULL;
process_handle = NULL;
proc_handle = NULL;
cleanup:
if (status) {
// In the case of an error of MultiByteToWideChar or CreateProcessW.
ELOG("pty_process_spawn(%s): %s: error code: %d",
ELOG("pty_proc_spawn(%s): %s: error code: %d",
proc->argv[0], emsg, status);
status = os_translate_sys_error(status);
}
os_conpty_free(conpty_object);
xfree(in_name);
xfree(out_name);
if (process_handle != NULL) {
CloseHandle(process_handle);
if (proc_handle != NULL) {
CloseHandle(proc_handle);
}
xfree(in_req);
xfree(out_req);
@ -159,32 +159,32 @@ cleanup:
return status;
}
const char *pty_process_tty_name(PtyProcess *ptyproc)
const char *pty_proc_tty_name(PtyProc *ptyproc)
{
return "?";
}
void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
os_conpty_set_size(ptyproc->conpty, width, height);
}
void pty_process_close(PtyProcess *ptyproc)
void pty_proc_close(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
Process *proc = (Process *)ptyproc;
Proc *proc = (Proc *)ptyproc;
pty_process_close_master(ptyproc);
pty_proc_close_master(ptyproc);
if (ptyproc->finish_wait != NULL) {
UnregisterWaitEx(ptyproc->finish_wait, NULL);
ptyproc->finish_wait = NULL;
uv_close((uv_handle_t *)&ptyproc->wait_eof_timer, NULL);
}
if (ptyproc->process_handle != NULL) {
CloseHandle(ptyproc->process_handle);
ptyproc->process_handle = NULL;
if (ptyproc->proc_handle != NULL) {
CloseHandle(ptyproc->proc_handle);
ptyproc->proc_handle = NULL;
}
if (proc->internal_close_cb) {
@ -192,17 +192,17 @@ void pty_process_close(PtyProcess *ptyproc)
}
}
void pty_process_close_master(PtyProcess *ptyproc)
void pty_proc_close_master(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
}
void pty_process_teardown(Loop *loop)
void pty_proc_teardown(Loop *loop)
FUNC_ATTR_NONNULL_ALL
{
}
static void pty_process_connect_cb(uv_connect_t *req, int status)
static void pty_proc_connect_cb(uv_connect_t *req, int status)
FUNC_ATTR_NONNULL_ALL
{
assert(status == 0);
@ -212,23 +212,23 @@ static void pty_process_connect_cb(uv_connect_t *req, int status)
static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer)
FUNC_ATTR_NONNULL_ALL
{
PtyProcess *ptyproc = wait_eof_timer->data;
Process *proc = (Process *)ptyproc;
PtyProc *ptyproc = wait_eof_timer->data;
Proc *proc = (Proc *)ptyproc;
assert(ptyproc->finish_wait != NULL);
if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) {
uv_timer_stop(&ptyproc->wait_eof_timer);
pty_process_finish2(ptyproc);
pty_proc_finish2(ptyproc);
}
}
static void pty_process_finish2(PtyProcess *ptyproc)
static void pty_proc_finish2(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
Process *proc = (Process *)ptyproc;
Proc *proc = (Proc *)ptyproc;
DWORD exit_code = 0;
GetExitCodeProcess(ptyproc->process_handle, &exit_code);
GetExitCodeProcess(ptyproc->proc_handle, &exit_code);
proc->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code;
proc->internal_exit_cb(proc);
@ -427,14 +427,14 @@ cleanup:
return rc;
}
PtyProcess pty_process_init(Loop *loop, void *data)
PtyProc pty_proc_init(Loop *loop, void *data)
{
PtyProcess rv;
rv.process = process_init(loop, kProcessTypePty, data);
PtyProc rv;
rv.proc = proc_init(loop, kProcTypePty, data);
rv.width = 80;
rv.height = 24;
rv.conpty = NULL;
rv.finish_wait = NULL;
rv.process_handle = NULL;
rv.proc_handle = NULL;
return rv;
}

View File

@ -1,20 +1,20 @@
#pragma once
// IWYU pragma: private, include "nvim/os/pty_process.h"
// IWYU pragma: private, include "nvim/os/pty_proc.h"
#include <uv.h>
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/lib/queue_defs.h"
#include "nvim/os/pty_conpty_win.h"
typedef struct pty_process {
Process process;
Proc proc;
uint16_t width, height;
conpty_t *conpty;
HANDLE finish_wait;
HANDLE process_handle;
HANDLE proc_handle;
uv_timer_t wait_eof_timer;
} PtyProcess;
} PtyProc;
// Structure used by build_cmd_line()
typedef struct arg_node {
@ -23,5 +23,5 @@ typedef struct arg_node {
} ArgNode;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_win.h.generated.h"
# include "os/pty_proc_win.h.generated.h"
#endif

View File

@ -1,7 +0,0 @@
#pragma once
#ifdef MSWIN
# include "nvim/os/pty_process_win.h"
#else
# include "nvim/os/pty_process_unix.h"
#endif

View File

@ -14,10 +14,10 @@
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/event/defs.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/libuv_proc.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/proc.h"
#include "nvim/event/rstream.h"
#include "nvim/event/stream.h"
#include "nvim/event/wstream.h"
@ -872,12 +872,12 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
char prog[MAXPATHL];
xstrlcpy(prog, argv[0], MAXPATHL);
LibuvProcess uvproc = libuv_process_init(&main_loop, &buf);
Process *proc = &uvproc.process;
LibuvProc uvproc = libuv_proc_init(&main_loop, &buf);
Proc *proc = &uvproc.proc;
MultiQueue *events = multiqueue_new_child(main_loop.events);
proc->events = events;
proc->argv = argv;
int status = process_spawn(proc, has_input, true, true);
int status = proc_spawn(proc, has_input, true, true);
if (status) {
loop_poll_events(&main_loop, 0);
// Failed, probably 'shell' is not executable.
@ -910,7 +910,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
if (!wstream_write(&proc->in, input_buffer)) {
// couldn't write, stop the process and tell the user about it
process_stop(proc);
proc_stop(proc);
return -1;
}
// close the input stream after everything is written
@ -927,7 +927,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
msg_no_more = true;
lines_left = -1;
}
int exitcode = process_wait(proc, -1, NULL);
int exitcode = proc_wait(proc, -1, NULL);
if (!got_int && out_data_decide_throttle(0)) {
// Last chunk of output was skipped; display it now.
out_data_ring(NULL, SIZE_MAX);
@ -1292,7 +1292,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
uv_err_name(status));
}
stream_close(stream, NULL, NULL, false);
stream_may_close(stream, false);
}
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.

View File

@ -63,22 +63,32 @@ static const char *const xdg_defaults[] = {
#endif
};
/// Get the value of $NVIM_APPNAME or "nvim" if not set.
/// Gets the value of $NVIM_APPNAME, or "nvim" if not set.
///
/// @param namelike Write "name-like" value (no path separators) in `NameBuff`.
///
/// @return $NVIM_APPNAME value
const char *get_appname(void)
const char *get_appname(bool namelike)
{
const char *env_val = os_getenv("NVIM_APPNAME");
if (env_val == NULL || *env_val == NUL) {
env_val = "nvim";
}
if (namelike) {
// Appname may be a relative path, replace slashes to make it name-like.
xstrlcpy(NameBuff, env_val, sizeof(NameBuff));
memchrsub(NameBuff, '/', '-', sizeof(NameBuff));
memchrsub(NameBuff, '\\', '-', sizeof(NameBuff));
}
return env_val;
}
/// Ensure that APPNAME is valid. Must be a name or relative path.
bool appname_is_valid(void)
{
const char *appname = get_appname();
const char *appname = get_appname(false);
if (path_is_absolute(appname)
// TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
|| strequal(appname, "/")
@ -193,7 +203,7 @@ char *get_xdg_home(const XDGVarType idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
char *dir = stdpaths_get_xdg_var(idx);
const char *appname = get_appname();
const char *appname = get_appname(false);
size_t appname_len = strlen(appname);
assert(appname_len < (IOSIZE - sizeof("-data")));

View File

@ -383,19 +383,19 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg)
xp->xp_context = EXPAND_NOTHING;
}
static proftime_T inchar_time;
static proftime_T wait_time;
/// Called when starting to wait for the user to type a character.
void prof_inchar_enter(void)
void prof_input_start(void)
{
inchar_time = profile_start();
wait_time = profile_start();
}
/// Called when finished waiting for the user to type a character.
void prof_inchar_exit(void)
void prof_input_end(void)
{
inchar_time = profile_end(inchar_time);
profile_set_wait(profile_add(profile_get_wait(), inchar_time));
wait_time = profile_end(wait_time);
profile_set_wait(profile_add(profile_get_wait(), wait_time));
}
/// @return true when a function defined in the current script should be
@ -950,8 +950,8 @@ void time_msg(const char *mesg, const proftime_T *start)
/// Initializes the `time_fd` stream for the --startuptime report.
///
/// @param fname startuptime report file path
/// @param process_name name of the current Nvim process to write in the report.
void time_init(const char *fname, const char *process_name)
/// @param proc_name name of the current Nvim process to write in the report.
void time_init(const char *fname, const char *proc_name)
{
const size_t bufsize = 8192; // Big enough for the entire --startuptime report.
time_fd = fopen(fname, "a");
@ -972,7 +972,7 @@ void time_init(const char *fname, const char *process_name)
semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r));
return;
}
fprintf(time_fd, "--- Startup times for process: %s ---\n", process_name);
fprintf(time_fd, "--- Startup times for process: %s ---\n", proc_name);
}
/// Flushes the startuptimes to disk for the current process

View File

@ -6875,7 +6875,8 @@ bool set_ref_in_quickfix(int copyID)
// In a location list window and none of the other windows is
// referring to this location list. Mark the location list
// context as still in use.
if (mark_quickfix_ctx(win->w_llist_ref, copyID)) {
if (mark_quickfix_ctx(win->w_llist_ref, copyID)
|| mark_quickfix_user_data(win->w_llist_ref, copyID)) {
return true;
}
}

View File

@ -1559,7 +1559,7 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val, const ch
return dest;
}
const void *iter = NULL;
const char *appname = get_appname();
const char *appname = get_appname(false);
const size_t appname_len = strlen(appname);
do {
size_t dir_len;
@ -1626,7 +1626,7 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_
if (!after_pathsep(dest - 1, dest)) {
*dest++ = PATHSEP;
}
const char *appname = get_appname();
const char *appname = get_appname(false);
size_t appname_len = strlen(appname);
assert(appname_len < (IOSIZE - sizeof("-data")));
xmemcpyz(IObuff, appname, appname_len);
@ -1697,7 +1697,7 @@ char *runtimepath_default(bool clean_arg)
size_t config_len = 0;
size_t vimruntime_len = 0;
size_t libdir_len = 0;
const char *appname = get_appname();
const char *appname = get_appname(false);
size_t appname_len = strlen(appname);
if (data_home != NULL) {
data_len = strlen(data_home);

View File

@ -74,10 +74,9 @@ getkey:
}
// Flush screen updates before blocking.
ui_flush();
// Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the
// mapping engine.
os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
// Call `input_get` directly to block for events or user input without consuming anything from
// `os/input.c:input_buffer` or calling the mapping engine.
input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
// If an event was put into the queue, we send K_EVENT directly.
if (!input_available() && !multiqueue_empty(main_loop.events)) {
key = K_EVENT;

View File

@ -22,6 +22,7 @@
#include "nvim/memory_defs.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/tui/tui.h"
#include "nvim/tui/tui_defs.h"
@ -126,6 +127,11 @@ void ui_client_run(bool remote_ui)
ui_client_attach(width, height, term, rgb);
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
if (os_env_exists("__NVIM_TEST_LOG")) {
ELOG("test log message");
}
// os_exit() will be invoked when the client channel detaches
while (true) {
LOOP_PROCESS_EVENTS(&main_loop, resize_events, -1);

View File

@ -14,7 +14,7 @@ EXTERN size_t grid_line_buf_size INIT( = 0);
EXTERN schar_T *grid_line_buf_char INIT( = NULL);
EXTERN sattr_T *grid_line_buf_attr INIT( = NULL);
// ID of the ui client channel. If zero, the client is not running.
// Client-side UI channel. Zero during early startup or if not a (--remote-ui) UI client.
EXTERN uint64_t ui_client_channel_id INIT( = 0);
// exit status from embedded nvim process

View File

@ -103,7 +103,7 @@ Debugging tests
DBG 2022-06-15T18:37:45.227 T57.58016.0/c UI: stop
INF 2022-06-15T18:37:45.227 T57.58016.0/c os_exit:595: Nvim exit: 0
DBG 2022-06-15T18:37:45.229 T57.58016.0 read_cb:118: closing Stream (0x7fd5d700ea18): EOF (end of file)
INF 2022-06-15T18:37:45.229 T57.58016.0 on_process_exit:400: exited: pid=58017 status=0 stoptime=0
INF 2022-06-15T18:37:45.229 T57.58016.0 on_proc_exit:400: exited: pid=58017 status=0 stoptime=0
```
- You can set `$GDB` to [run functional tests under gdbserver](https://github.com/neovim/neovim/pull/1527):

View File

@ -114,6 +114,7 @@ function Session:request(method, ...)
return true, result
end
--- Runs the event loop.
function Session:run(request_cb, notification_cb, setup_cb, timeout)
local function on_request(method, args, response)
coroutine_exec(request_cb, method, args, function(status, result, flag)

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