Compare commits

...

25 Commits

Author SHA1 Message Date
glepnir
a9a5a77db5
Merge 8a3bc607d6 into a0d8c2b86e 2024-09-16 17:27:59 +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
glepnir
8a3bc607d6 fix(diagnostic): add cursorlinehl in vim.diagnotic.opts.Signs
Problem: extmark also support cursorline_hl_group when cursorline is on.

Solution: support it on vim.diangostic.optss.Signs
2024-09-03 18:14:54 +08:00
83 changed files with 681 additions and 536 deletions

View File

@ -26,3 +26,21 @@ jobs:
pull_title: "${pull_title}" pull_title: "${pull_title}"
label_pattern: "^ci:backport ([^ ]+)$" label_pattern: "^ci:backport ([^ ]+)$"
github_token: ${{ steps.app-token.outputs.token }} 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: workflow_call:
jobs: jobs:
request-reviewer: 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 runs-on: ubuntu-latest
permissions: permissions:
pull-requests: write 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_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333 LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/ab28a2ddb86a144194a798bcf1fef1ab4f981ab7.tar.gz UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz
UNIBILIUM_SHA256 7c0386fc48452632868e0dcb8e7ed140d67a3da79e39ceee54c1ba7a495ad625 UNIBILIUM_SHA256 370ecb07fbbc20d91d1b350c55f1c806b06bf86797e164081ccc977fc9b3af7a
LUV_URL https://github.com/luvit/luv/releases/download/1.48.0-2/luv-1.48.0-2.tar.gz LUV_URL https://github.com/luvit/luv/releases/download/1.48.0-2/luv-1.48.0-2.tar.gz
LUV_SHA256 2c3a1ddfebb4f6550293a40ee789f7122e97647eede51511f57203de48c03b7a LUV_SHA256 2c3a1ddfebb4f6550293a40ee789f7122e97647eede51511f57203de48c03b7a

View File

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

View File

@ -526,28 +526,32 @@ Lua module: vim.diagnostic *diagnostic-api*
*vim.diagnostic.Opts.Signs* *vim.diagnostic.Opts.Signs*
Fields: ~ Fields: ~
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual text • {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual
for diagnostics matching the given severity text for diagnostics matching the given severity
|diagnostic-severity| |diagnostic-severity|
• {priority}? (`integer`, default: `10`) Base priority to use for • {priority}? (`integer`, default: `10`) Base priority to use for
signs. When {severity_sort} is used, the priority of a signs. When {severity_sort} is used, the priority of a
sign is adjusted based on its severity. Otherwise, all sign is adjusted based on its severity. Otherwise, all
signs use the same priority. signs use the same priority.
• {text}? (`table<vim.diagnostic.Severity,string>`) A table mapping • {text}? (`table<vim.diagnostic.Severity,string>`) A table
|diagnostic-severity| to the sign text to display in the mapping |diagnostic-severity| to the sign text to
sign column. The default is to use `"E"`, `"W"`, `"I"`, display in the sign column. The default is to use
and `"H"` for errors, warnings, information, and hints, `"E"`, `"W"`, `"I"`, and `"H"` for errors, warnings,
respectively. Example: >lua information, and hints, respectively. Example: >lua
vim.diagnostic.config({ vim.diagnostic.config({
signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } } signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } }
}) })
< <
• {numhl}? (`table<vim.diagnostic.Severity,string>`) A table mapping • {numhl}? (`table<vim.diagnostic.Severity,string>`) A table
|diagnostic-severity| to the highlight group used for the mapping |diagnostic-severity| to the highlight group
line number where the sign is placed. used for the line number where the sign is placed.
• {linehl}? (`table<vim.diagnostic.Severity,string>`) A table mapping • {linehl}? (`table<vim.diagnostic.Severity,string>`) A table
|diagnostic-severity| to the highlight group used for the mapping |diagnostic-severity| to the highlight group
whole line the sign is placed in. used for the whole line the sign is placed in.
• {cursorlinehl} (`table<vim.diagnostic.Severity,string>`) A table
mapping |diagnostic-severity| to the highlight group
used for the highlight the sign column text when
cursor is on target line and 'cursorline' is enabled.
*vim.diagnostic.Opts.Underline* *vim.diagnostic.Opts.Underline*

View File

@ -2559,7 +2559,7 @@ vim.ui.input({opts}, {on_confirm}) *vim.ui.input()*
typed (it might be an empty string if nothing was typed (it might be an empty string if nothing was
entered), or `nil` if the user aborted the dialog. 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 Opens `path` with the system default handler (macOS `open`, Windows
`explorer.exe`, Linux `xdg-open`, …), or returns (but does not show) an `explorer.exe`, Linux `xdg-open`, …), or returns (but does not show) an
error message on failure. error message on failure.
@ -2570,6 +2570,8 @@ vim.ui.open({path}) *vim.ui.open()*
-- Asynchronous. -- Asynchronous.
vim.ui.open("https://neovim.io/") vim.ui.open("https://neovim.io/")
vim.ui.open("~/path/to/file") 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). -- Synchronous (wait until the process exits).
local cmd, err = vim.ui.open("$VIMRUNTIME") local cmd, err = vim.ui.open("$VIMRUNTIME")
if cmd then if cmd then
@ -2579,6 +2581,8 @@ vim.ui.open({path}) *vim.ui.open()*
Parameters: ~ Parameters: ~
• {path} (`string`) Path or URL to open • {path} (`string`) Path or URL to open
• {opt} (`{ cmd?: string[] }?`) Options
• cmd string[]|nil Command used to open the path or URL.
Return (multiple): ~ Return (multiple): ~
(`vim.SystemObj?`) Command object, or nil if not found. (`vim.SystemObj?`) Command object, or nil if not found.

View File

@ -194,7 +194,10 @@ TUI
UI 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* CHANGED FEATURES *news-changed*

View File

@ -1683,6 +1683,12 @@ In order to highlight nested parens with different colors, define colors for
or > or >
:hi javaParen ctermfg=blue guifg=#0000ff :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 If you notice highlighting errors while scrolling backwards, which are fixed
when redrawing with CTRL-L, try setting the "g:java_minlines" variable to when redrawing with CTRL-L, try setting the "g:java_minlines" variable to
a larger number: > a larger number: >

View File

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

View File

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

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 --- If the buffer doesn't exist or isn't a prompt buffer, an empty
--- string is returned. --- string is returned.
--- ---
--- @param buf any --- @param buf integer|string
--- @return any --- @return any
function vim.fn.prompt_getprompt(buf) end function vim.fn.prompt_getprompt(buf) end
@ -6738,8 +6738,8 @@ function vim.fn.prompt_getprompt(buf) end
--- endfunc --- endfunc
--- call prompt_setcallback(bufnr(), function('s:TextEntered')) --- call prompt_setcallback(bufnr(), function('s:TextEntered'))
--- ---
--- @param buf any --- @param buf integer|string
--- @param expr any --- @param expr string|function
--- @return any --- @return any
function vim.fn.prompt_setcallback(buf, expr) end 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, --- mode. Without setting a callback Vim will exit Insert mode,
--- as in any buffer. --- as in any buffer.
--- ---
--- @param buf any --- @param buf integer|string
--- @param expr any --- @param expr string|function
--- @return any --- @return any
function vim.fn.prompt_setinterrupt(buf, expr) end 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: ') --- call prompt_setprompt(bufnr(''), 'command: ')
--- < --- <
--- ---
--- @param buf any --- @param buf integer|string
--- @param text any --- @param text string
--- @return any --- @return any
function vim.fn.prompt_setprompt(buf, text) end function vim.fn.prompt_setprompt(buf, text) end

View File

@ -243,6 +243,10 @@ local M = {}
--- A table mapping |diagnostic-severity| to the highlight group used for the --- A table mapping |diagnostic-severity| to the highlight group used for the
--- whole line the sign is placed in. --- whole line the sign is placed in.
--- @field linehl? table<vim.diagnostic.Severity,string> --- @field linehl? table<vim.diagnostic.Severity,string>
---
--- A table mapping |diagnostic-severity| to the highlight group used for the
--- highlight the sign column text when cursor is on target line and 'cursorline' is enabled.
--- @field cursorlinehl table<vim.diagnostic.Severity,string>
--- @class vim.diagnostic.Opts.Jump --- @class vim.diagnostic.Opts.Jump
--- ---
@ -1447,6 +1451,7 @@ M.handlers.signs = {
local numhl = opts.signs.numhl or {} local numhl = opts.signs.numhl or {}
local linehl = opts.signs.linehl or {} local linehl = opts.signs.linehl or {}
local curlinehl = opts.signs.cursorlinehl or {}
local line_count = api.nvim_buf_line_count(bufnr) local line_count = api.nvim_buf_line_count(bufnr)
@ -1457,6 +1462,7 @@ M.handlers.signs = {
sign_hl_group = sign_highlight_map[diagnostic.severity], sign_hl_group = sign_highlight_map[diagnostic.severity],
number_hl_group = numhl[diagnostic.severity], number_hl_group = numhl[diagnostic.severity],
line_hl_group = linehl[diagnostic.severity], line_hl_group = linehl[diagnostic.severity],
cursorline_hl_group = vim.wo.cursorline and curlinehl[diagnostic.severity] or nil,
priority = get_priority(diagnostic.severity), priority = get_priority(diagnostic.severity),
}) })
end end

View File

@ -280,12 +280,7 @@ local extension = {
cfi = 'cf', cfi = 'cf',
hgrc = 'cfg', 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,
CFg = detect.cfg,
CFG = detect.cfg, CFG = detect.cfg,
chf = 'ch', chf = 'ch',
chai = 'chaiscript', chai = 'chaiscript',
@ -370,12 +365,7 @@ local extension = {
drt = 'dart', drt = 'dart',
ds = 'datascript', 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,
DAt = detect.dat,
DAT = detect.dat, DAT = detect.dat,
dcd = 'dcd', dcd = 'dcd',
decl = detect.decl, decl = detect.decl,
@ -658,12 +648,7 @@ local extension = {
kt = 'kotlin', kt = 'kotlin',
ktm = 'kotlin', ktm = 'kotlin',
sub = 'krl', sub = 'krl',
suB = 'krl',
sUb = 'krl',
sUB = 'krl',
Sub = 'krl', Sub = 'krl',
SuB = 'krl',
SUb = 'krl',
SUB = 'krl', SUB = 'krl',
ks = 'kscript', ks = 'kscript',
k = 'kwt', k = 'kwt',
@ -699,12 +684,7 @@ local extension = {
lite = 'lite', lite = 'lite',
livemd = 'livebook', 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,
LOg = detect.log,
LOG = detect.log, LOG = detect.log,
lgt = 'logtalk', lgt = 'logtalk',
lotos = 'lotos', lotos = 'lotos',
@ -773,12 +753,7 @@ local extension = {
mmp = 'mmp', mmp = 'mmp',
mms = detect.mms, 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,
MOd = detect.mod,
MOD = detect.mod, MOD = detect.mod,
DEF = 'modula2', DEF = 'modula2',
m3 = 'modula3', m3 = 'modula3',
@ -948,12 +923,7 @@ local extension = {
ih = 'ppwiz', ih = 'ppwiz',
action = 'privoxy', 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,
PRg = detect.prg,
PRG = detect.prg, PRG = detect.prg,
pc = 'proc', pc = 'proc',
pdb = 'prolog', pdb = 'prolog',
@ -1133,12 +1103,7 @@ local extension = {
sqr = 'sqr', sqr = 'sqr',
nut = 'squirrel', 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,
SRc = detect.src,
SRC = detect.src, SRC = detect.src,
s28 = 'srec', s28 = 'srec',
s37 = 'srec', s37 = 'srec',
@ -1168,12 +1133,7 @@ local extension = {
swig = 'swig', swig = 'swig',
swg = '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,
SYs = detect.sys,
SYS = detect.sys, SYS = detect.sys,
svh = 'systemverilog', svh = 'systemverilog',
sv = 'systemverilog', sv = 'systemverilog',

View File

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

View File

@ -154,7 +154,7 @@ end
---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16 ---@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` ---@return integer byte (utf-8) index of `encoding` index `index` in `line`
function M._str_byteindex_enc(line, index, encoding) function M._str_byteindex_enc(line, index, encoding)
local len = vim.fn.strlen(line) local len = #line
if index > len then if index > len then
-- LSP spec: if character > line length, default to the line length. -- LSP spec: if character > line length, default to the line length.
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
@ -167,7 +167,7 @@ function M._str_byteindex_enc(line, index, encoding)
if index then if index then
return index return index
else else
return #line return len
end end
elseif encoding == 'utf-16' then elseif encoding == 'utf-16' then
return vim.str_byteindex(line, index, true) return vim.str_byteindex(line, index, true)

View File

@ -74,14 +74,14 @@ end
--- Returns the parser for a specific buffer and attaches it to the buffer --- 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 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 lang (string|nil) Language of this parser (default: from buffer filetype)
---@param opts (table|nil) Options to pass to the created language tree ---@param opts (table|nil) Options to pass to the created language tree
--- ---
---@return vim.treesitter.LanguageTree object to use for parsing ---@return vim.treesitter.LanguageTree? object to use for parsing, or `nil` if not found
function M.get_parser(bufnr, lang, opts) function M._get_parser(bufnr, lang, opts)
opts = opts or {} opts = opts or {}
if bufnr == nil or bufnr == 0 then 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 valid_lang(lang) then
if not parsers[bufnr] then if not parsers[bufnr] then
error( return nil
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
)
)
end end
elseif parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then elseif parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then
assert(lang, 'lang should be valid') local parser = vim.F.npcall(M._create_parser, bufnr, lang, opts)
parsers[bufnr] = M._create_parser(bufnr, lang, opts) if not parser then
return nil
end
parsers[bufnr] = parser
end end
parsers[bufnr]:register_cbs(opts.buf_attach_cbs) parsers[bufnr]:register_cbs(opts.buf_attach_cbs)
@ -113,6 +109,29 @@ function M.get_parser(bufnr, lang, opts)
return parsers[bufnr] return parsers[bufnr]
end 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 --- Returns a string parser
--- ---
---@param str string Text to parse ---@param str string Text to parse
@ -386,7 +405,7 @@ function M.get_node(opts)
local ts_range = { row, col, row, col } 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 if not root_lang_tree then
return return
end end
@ -419,7 +438,11 @@ end
---@param lang (string|nil) Language of the parser (default: from buffer filetype) ---@param lang (string|nil) Language of the parser (default: from buffer filetype)
function M.start(bufnr, lang) function M.start(bufnr, lang)
bufnr = bufnr or api.nvim_get_current_buf() 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) M.highlighter.new(parser)
end end

View File

@ -114,7 +114,7 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
srow = srow or 0 srow = srow or 0
erow = erow or api.nvim_buf_line_count(bufnr) 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) parser:parse(parse_injections and { srow, erow } or nil)
@ -392,7 +392,7 @@ function M.foldexpr(lnum)
lnum = lnum or vim.v.lnum lnum = lnum or vim.v.lnum
local bufnr = api.nvim_get_current_buf() 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 if not parser then
return '0' return '0'
end end

View File

@ -172,7 +172,7 @@ function M.lint(buf, opts)
--- @type (table|nil) --- @type (table|nil)
local parser_info = vim.F.npcall(vim.treesitter.language.inspect, lang) 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:parse()
parser:for_each_tree(function(tree, ltree) parser:for_each_tree(function(tree, ltree)
if ltree:lang() == 'query' then if ltree:lang() == 'query' then

View File

@ -76,10 +76,9 @@ end
--- ---
---@package ---@package
function TSTreeView:new(bufnr, lang) function TSTreeView:new(bufnr, lang)
local ok, parser = pcall(vim.treesitter.get_parser, bufnr or 0, lang) local parser = vim.treesitter._get_parser(bufnr or 0, lang)
if not ok then if not parser then
local err = parser --[[ @as string ]] return nil, 'No parser available for the given buffer.'
return nil, 'No parser available for the given buffer:\n' .. err
end end
-- For each child tree (injected language), find the root of the tree and locate the node within -- 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 function update_editor_highlights(query_win, base_win, lang)
local base_buf = api.nvim_win_get_buf(base_win) local base_buf = api.nvim_win_get_buf(base_win)
local query_buf = api.nvim_win_get_buf(query_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) 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') 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 end
vim.cmd(cmd) vim.cmd(cmd)
local ok, parser = pcall(vim.treesitter.get_parser, buf, lang) local parser = vim.treesitter._get_parser(buf, lang)
if not ok then if not parser then
return nil, 'No parser available for the given buffer' return nil, 'No parser available for the given buffer'
end end
lang = parser:lang() lang = parser:lang()

View File

@ -117,6 +117,8 @@ end
--- -- Asynchronous. --- -- Asynchronous.
--- vim.ui.open("https://neovim.io/") --- vim.ui.open("https://neovim.io/")
--- vim.ui.open("~/path/to/file") --- 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). --- -- Synchronous (wait until the process exits).
--- local cmd, err = vim.ui.open("$VIMRUNTIME") --- local cmd, err = vim.ui.open("$VIMRUNTIME")
--- if cmd then --- if cmd then
@ -125,12 +127,14 @@ end
--- ``` --- ```
--- ---
---@param path string Path or URL to open ---@param path string Path or URL to open
---@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 vim.SystemObj|nil # Command object, or nil if not found.
---@return nil|string # Error message on failure, or nil on success. ---@return nil|string # Error message on failure, or nil on success.
--- ---
---@see |vim.system()| ---@see |vim.system()|
function M.open(path) function M.open(path, opt)
vim.validate({ vim.validate({
path = { path, 'string' }, path = { path, 'string' },
}) })
@ -139,12 +143,13 @@ function M.open(path)
path = vim.fs.normalize(path) path = vim.fs.normalize(path)
end end
local cmd --- @type string[] opt = opt or {}
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 opt.cmd then
cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { path })
if vim.fn.has('mac') == 1 then elseif vim.fn.has('mac') == 1 then
cmd = { 'open', path } cmd = { 'open', path }
elseif vim.fn.has('win32') == 1 then elseif vim.fn.has('win32') == 1 then
if vim.fn.executable('rundll32') == 1 then if vim.fn.executable('rundll32') == 1 then
@ -154,8 +159,8 @@ function M.open(path)
end end
elseif vim.fn.executable('xdg-open') == 1 then elseif vim.fn.executable('xdg-open') == 1 then
cmd = { 'xdg-open', path } cmd = { 'xdg-open', path }
opts.stdout = false job_opt.stdout = false
opts.stderr = false job_opt.stderr = false
elseif vim.fn.executable('wslview') == 1 then elseif vim.fn.executable('wslview') == 1 then
cmd = { 'wslview', path } cmd = { 'wslview', path }
elseif vim.fn.executable('explorer.exe') == 1 then elseif vim.fn.executable('explorer.exe') == 1 then
@ -164,7 +169,7 @@ function M.open(path)
return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)' return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
end end
return vim.system(cmd, opts), nil return vim.system(cmd, job_opt), nil
end end
--- Returns all URLs at cursor, if any. --- Returns all URLs at cursor, if any.

View File

@ -33,7 +33,7 @@ end
--- Show a table of contents for the help buffer in a loclist --- Show a table of contents for the help buffer in a loclist
function M.show_toc() function M.show_toc()
local bufnr = vim.api.nvim_get_current_buf() 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( local query = vim.treesitter.query.parse(
parser:lang(), parser:lang(),
[[ [[

View File

@ -3,7 +3,7 @@
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com> " Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com> " Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
" Repository: https://github.com/zzzyxwvut/java-vim.git " Repository: https://github.com/zzzyxwvut/java-vim.git
" Last Change: 2024 Sep 10 " Last Change: 2024 Sep 11
" Please check :help java.vim for comments on some of the options available. " Please check :help java.vim for comments on some of the options available.
@ -663,7 +663,7 @@ hi def link javaStorageClass StorageClass
hi def link javaMethodDecl javaStorageClass hi def link javaMethodDecl javaStorageClass
hi def link javaClassDecl javaStorageClass hi def link javaClassDecl javaStorageClass
hi def link javaScopeDecl javaStorageClass hi def link javaScopeDecl javaStorageClass
hi def link javaConceptKind NonText hi def link javaConceptKind javaStorageClass
hi def link javaBoolean Boolean hi def link javaBoolean Boolean
hi def link javaSpecial Special hi def link javaSpecial Special

View File

@ -685,7 +685,7 @@ if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimfunctionerror")
syn match vimBufnrWarn /\<bufnr\s*(\s*["']\.['"]\s*)/ syn match vimBufnrWarn /\<bufnr\s*(\s*["']\.['"]\s*)/
endif 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 " Match: {{{2
" ===== " =====

View File

@ -786,7 +786,7 @@ local function parse_buf(fname, parser_path)
if parser_path then if parser_path then
vim.treesitter.language.add('vimdoc', { path = parser_path }) vim.treesitter.language.add('vimdoc', { path = parser_path })
end 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 return lang_tree, buf
end end

View File

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

View File

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

View File

@ -417,10 +417,10 @@ list(SORT NVIM_HEADERS)
foreach(sfile ${NVIM_SOURCES}) foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME) 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}) list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif() 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}) list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif() endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$") 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)$") if(WIN32 AND ${f} MATCHES "^(unix_defs.h)$")
list(REMOVE_ITEM NVIM_HEADERS ${hfile}) list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif() 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}) list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif() endif()
if(NOT WIN32 AND ${f} MATCHES "^(win_defs.h)$") 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) set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h)
if(WIN32) if(WIN32)
list(APPEND EXCLUDE_CLANG_TIDY list(APPEND EXCLUDE_CLANG_TIDY
os/pty_process_unix.h os/pty_proc_unix.h
os/unix_defs.h) os/unix_defs.h)
else() else()
list(APPEND EXCLUDE_CLANG_TIDY list(APPEND EXCLUDE_CLANG_TIDY
os/win_defs.h os/win_defs.h
os/pty_process_win.h os/pty_proc_win.h
os/pty_conpty_win.h os/pty_conpty_win.h
os/os_win_console.h) os/os_win_console.h)
endif() endif()

View File

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

View File

@ -19,7 +19,7 @@
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"
#include "nvim/event/loop.h" #include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h" #include "nvim/event/multiqueue.h"
#include "nvim/event/process.h" #include "nvim/event/proc.h"
#include "nvim/event/rstream.h" #include "nvim/event/rstream.h"
#include "nvim/event/socket.h" #include "nvim/event/socket.h"
#include "nvim/event/stream.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) bool channel_close(uint64_t id, ChannelPart part, const char **error)
{ {
Channel *chan; Channel *chan;
Process *proc; Proc *proc;
const char *dummy; const char *dummy;
if (!error) { if (!error) {
@ -139,8 +139,8 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
if (part == kChannelPartStderr || part == kChannelPartAll) { if (part == kChannelPartStderr || part == kChannelPartAll) {
rstream_may_close(&proc->err); rstream_may_close(&proc->err);
} }
if (proc->type == kProcessTypePty && part == kChannelPartAll) { if (proc->type == kProcTypePty && part == kChannelPartAll) {
pty_process_close_master(&chan->stream.pty); pty_proc_close_master(&chan->stream.pty);
} }
break; break;
@ -289,7 +289,7 @@ static void channel_destroy(Channel *chan)
} }
if (chan->streamtype == kChannelStreamProc) { if (chan->streamtype == kChannelStreamProc) {
process_free(&chan->stream.proc); proc_free(&chan->stream.proc);
} }
callback_reader_free(&chan->on_data); 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; *status_out = 0;
return NULL; return NULL;
} }
chan->stream.pty = pty_process_init(&main_loop, chan); chan->stream.pty = pty_proc_init(&main_loop, chan);
if (pty_width > 0) { if (pty_width > 0) {
chan->stream.pty.width = pty_width; 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; chan->stream.pty.height = pty_height;
} }
} else { } 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->argv = argv;
proc->exepath = exepath; proc->exepath = exepath;
proc->cb = channel_process_exit_cb; proc->cb = channel_proc_exit_cb;
proc->events = chan->events; proc->events = chan->events;
proc->detach = detach; proc->detach = detach;
proc->cwd = cwd; proc->cwd = cwd;
proc->env = env; proc->env = env;
proc->overlapped = overlapped; proc->overlapped = overlapped;
char *cmd = xstrdup(process_get_exepath(proc)); char *cmd = xstrdup(proc_get_exepath(proc));
bool has_out, has_err; bool has_out, has_err;
if (proc->type == kProcessTypePty) { if (proc->type == kProcTypePty) {
has_out = true; has_out = true;
has_err = false; has_err = false;
} else { } else {
@ -410,7 +410,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
bool has_in = stdin_mode == kChannelStdinPipe; 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) { if (status) {
semsg(_(e_jobspawn), os_strerror(status), cmd); semsg(_(e_jobspawn), os_strerror(status), cmd);
xfree(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; Channel *chan = data;
if (chan->term) { 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) static void term_resize(uint16_t width, uint16_t height, void *data)
{ {
Channel *chan = 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) 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) static void term_close(void *data)
{ {
Channel *chan = data; Channel *chan = data;
process_stop(&chan->stream.proc); proc_stop(&chan->stream.proc);
multiqueue_put(chan->events, term_delayed_free, data); multiqueue_put(chan->events, term_delayed_free, data);
} }
@ -907,7 +907,7 @@ bool channel_job_running(uint64_t id)
Channel *chan = find_channel(id); Channel *chan = find_channel(id);
return (chan return (chan
&& chan->streamtype == kChannelStreamProc && chan->streamtype == kChannelStreamProc
&& !process_is_stopped(&chan->stream.proc)); && !proc_is_stopped(&chan->stream.proc));
} }
Dictionary channel_info(uint64_t id, Arena *arena) Dictionary channel_info(uint64_t id, Arena *arena)
@ -924,8 +924,8 @@ Dictionary channel_info(uint64_t id, Arena *arena)
switch (chan->streamtype) { switch (chan->streamtype) {
case kChannelStreamProc: { case kChannelStreamProc: {
stream_desc = "job"; stream_desc = "job";
if (chan->stream.proc.type == kProcessTypePty) { if (chan->stream.proc.type == kProcTypePty) {
const char *name = pty_process_tty_name(&chan->stream.pty); const char *name = pty_proc_tty_name(&chan->stream.pty);
PUT_C(info, "pty", CSTR_TO_ARENA_OBJ(arena, name)); 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/channel_defs.h" // IWYU pragma: keep
#include "nvim/eval/typval_defs.h" #include "nvim/eval/typval_defs.h"
#include "nvim/event/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/macros_defs.h"
#include "nvim/map_defs.h" #include "nvim/map_defs.h"
#include "nvim/msgpack_rpc/channel_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" #include "nvim/types_defs.h"
struct Channel { struct Channel {
@ -21,9 +21,9 @@ struct Channel {
ChannelStreamType streamtype; ChannelStreamType streamtype;
union { union {
Process proc; Proc proc;
LibuvProcess uv; LibuvProc uv;
PtyProcess pty; PtyProc pty;
RStream socket; RStream socket;
StdioPair stdio; StdioPair stdio;
StderrState err; 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 // cache previous calculations depending on w_virtcol
static int saved_w_virtcol; static int saved_w_virtcol;
static win_T *prev_wp; static win_T *prev_wp;
static int prev_width1;
static int prev_width2;
static int prev_left_col; static int prev_left_col;
static int prev_right_col; static int prev_right_col;
static int prev_col_off;
int cur_col_off = win_col_off(wp); int cur_col_off = win_col_off(wp);
int width1; int width1 = wp->w_width_inner - cur_col_off;
int width2; int width2 = width1 + win_col_off2(wp);
if (saved_w_virtcol == wp->w_virtcol && prev_wp == 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; *right_col = prev_right_col;
*left_col = prev_left_col; *left_col = prev_left_col;
return; return;
} }
width1 = wp->w_width_inner - cur_col_off;
width2 = width1 + win_col_off2(wp);
*left_col = 0; *left_col = 0;
*right_col = width1; *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; *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2;
} }
if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) { 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_left_col = *left_col;
prev_right_col = *right_col; prev_right_col = *right_col;
prev_wp = wp; prev_wp = wp;
prev_width1 = width1;
prev_width2 = width2;
saved_w_virtcol = wp->w_virtcol; 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. /// 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/eval/vars.h"
#include "nvim/event/loop.h" #include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h" #include "nvim/event/multiqueue.h"
#include "nvim/event/process.h" #include "nvim/event/proc.h"
#include "nvim/event/time.h" #include "nvim/event/time.h"
#include "nvim/ex_cmds.h" #include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h" #include "nvim/ex_docmd.h"
@ -8506,7 +8506,7 @@ Channel *find_job(uint64_t id, bool show_error)
{ {
Channel *data = find_channel(id); Channel *data = find_channel(id);
if (!data || data->streamtype != kChannelStreamProc if (!data || data->streamtype != kChannelStreamProc
|| process_is_stopped(&data->stream.proc)) { || proc_is_stopped(&data->stream.proc)) {
if (show_error) { if (show_error) {
if (data && data->streamtype != kChannelStreamProc) { if (data && data->streamtype != kChannelStreamProc) {
emsg(_(e_invchanjob)); emsg(_(e_invchanjob));

View File

@ -8044,7 +8044,7 @@ M.funcs = {
]=], ]=],
name = 'prompt_getprompt', name = 'prompt_getprompt',
params = { { 'buf', 'any' } }, params = { { 'buf', 'integer|string' } },
signature = 'prompt_getprompt({buf})', signature = 'prompt_getprompt({buf})',
}, },
prompt_setcallback = { prompt_setcallback = {
@ -8084,7 +8084,7 @@ M.funcs = {
]=], ]=],
name = 'prompt_setcallback', name = 'prompt_setcallback',
params = { { 'buf', 'any' }, { 'expr', 'any' } }, params = { { 'buf', 'integer|string' }, { 'expr', 'string|function' } },
signature = 'prompt_setcallback({buf}, {expr})', signature = 'prompt_setcallback({buf}, {expr})',
}, },
prompt_setinterrupt = { prompt_setinterrupt = {
@ -8101,7 +8101,7 @@ M.funcs = {
]=], ]=],
name = 'prompt_setinterrupt', name = 'prompt_setinterrupt',
params = { { 'buf', 'any' }, { 'expr', 'any' } }, params = { { 'buf', 'integer|string' }, { 'expr', 'string|function' } },
signature = 'prompt_setinterrupt({buf}, {expr})', signature = 'prompt_setinterrupt({buf}, {expr})',
}, },
prompt_setprompt = { prompt_setprompt = {
@ -8116,7 +8116,7 @@ M.funcs = {
< <
]=], ]=],
name = 'prompt_setprompt', name = 'prompt_setprompt',
params = { { 'buf', 'any' }, { 'text', 'any' } }, params = { { 'buf', 'integer|string' }, { 'text', 'string' } },
signature = 'prompt_setprompt({buf}, {text})', signature = 'prompt_setprompt({buf}, {text})',
}, },
pum_getpos = { pum_getpos = {

View File

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

View File

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

View File

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

View File

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

View File

@ -4,24 +4,24 @@
#include <uv.h> #include <uv.h>
#include "klib/klist.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/loop.h"
#include "nvim/event/multiqueue.h" #include "nvim/event/multiqueue.h"
#include "nvim/event/process.h" #include "nvim/event/proc.h"
#include "nvim/event/rstream.h" #include "nvim/event/rstream.h"
#include "nvim/event/stream.h" #include "nvim/event/stream.h"
#include "nvim/event/wstream.h" #include "nvim/event/wstream.h"
#include "nvim/globals.h" #include "nvim/globals.h"
#include "nvim/log.h" #include "nvim/log.h"
#include "nvim/main.h" #include "nvim/main.h"
#include "nvim/os/process.h" #include "nvim/os/proc.h"
#include "nvim/os/pty_process.h" #include "nvim/os/pty_proc.h"
#include "nvim/os/shell.h" #include "nvim/os/shell.h"
#include "nvim/os/time.h" #include "nvim/os/time.h"
#include "nvim/ui_client.h" #include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/process.c.generated.h" # include "event/proc.c.generated.h"
#endif #endif
// Time for a process to exit cleanly before we send KILL. // Time for a process to exit cleanly before we send KILL.
@ -33,13 +33,13 @@
void __gcov_flush(void); void __gcov_flush(void);
#endif #endif
static bool process_is_tearing_down = false; static bool proc_is_tearing_down = false;
// Delay exit until handles are closed, to avoid deadlocks // Delay exit until handles are closed, to avoid deadlocks
static int exit_need_delay = 0; static int exit_need_delay = 0;
/// @returns zero on success, or negative error code /// @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 FUNC_ATTR_NONNULL_ALL
{ {
// forwarding stderr contradicts with processing it internally // forwarding stderr contradicts with processing it internally
@ -70,11 +70,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
int status; int status;
switch (proc->type) { switch (proc->type) {
case kProcessTypeUv: case kProcTypeUv:
status = libuv_process_spawn((LibuvProcess *)proc); status = libuv_proc_spawn((LibuvProc *)proc);
break; break;
case kProcessTypePty: case kProcTypePty:
status = pty_process_spawn((PtyProcess *)proc); status = pty_proc_spawn((PtyProc *)proc);
break; 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); uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL);
} }
if (proc->type == kProcessTypeUv) { if (proc->type == kProcTypeUv) {
uv_close((uv_handle_t *)&(((LibuvProcess *)proc)->uv), NULL); uv_close((uv_handle_t *)&(((LibuvProc *)proc)->uv), NULL);
} else { } else {
process_close(proc); proc_close(proc);
} }
process_free(proc); proc_free(proc);
proc->status = -1; proc->status = -1;
return status; return status;
} }
@ -102,52 +102,52 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
if (in) { if (in) {
stream_init(NULL, &proc->in, -1, (uv_stream_t *)&proc->in.uv.pipe); stream_init(NULL, &proc->in, -1, (uv_stream_t *)&proc->in.uv.pipe);
proc->in.internal_data = proc; 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++; proc->refcount++;
} }
if (out) { if (out) {
stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe); 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_data = proc;
proc->out.s.internal_close_cb = on_process_stream_close; proc->out.s.internal_close_cb = on_proc_stream_close;
proc->refcount++; proc->refcount++;
} }
if (err) { if (err) {
stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe); 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_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->refcount++;
} }
proc->internal_exit_cb = on_process_exit; proc->internal_exit_cb = on_proc_exit;
proc->internal_close_cb = decref; proc->internal_close_cb = decref;
proc->refcount++; proc->refcount++;
kl_push(WatcherPtr, proc->loop->children, proc); 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; 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) { kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data; Proc *proc = (*current)->data;
if (proc->detach || proc->type == kProcessTypePty) { if (proc->detach || proc->type == kProcTypePty) {
// Close handles to process without killing it. // Close handles to process without killing it.
CREATE_EVENT(loop->events, process_close_handles, proc); CREATE_EVENT(loop->events, proc_close_handles, proc);
} else { } else {
process_stop(proc); proc_stop(proc);
} }
} }
// Wait until all children exit and all close events are processed. // Wait until all children exit and all close events are processed.
LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1,
kl_empty(loop->children) && multiqueue_empty(loop->events)); 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); wstream_may_close(&proc->in);
rstream_may_close(&proc->out); 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. /// @return Exit code of the process. proc->status will have the same value.
/// -1 if the timeout expired while the process is still running. /// -1 if the timeout expired while the process is still running.
/// -2 if the user interrupted the wait. /// -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) FUNC_ATTR_NONNULL_ARG(1)
{ {
if (!proc->refcount) { 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. // Assume that a user hitting CTRL-C does not like the current job. Kill it.
if (got_int) { if (got_int) {
got_int = false; got_int = false;
process_stop(proc); proc_stop(proc);
if (ms == -1) { if (ms == -1) {
// We can only return if all streams/handles are closed and the job // We can only return if all streams/handles are closed and the job
// exited. // 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 /// 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); bool exited = (proc->status >= 0);
if (exited || proc->stopped_time) { if (exited || proc->stopped_time) {
@ -224,13 +224,13 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
proc->exit_signal = SIGTERM; proc->exit_signal = SIGTERM;
switch (proc->type) { switch (proc->type) {
case kProcessTypeUv: case kProcTypeUv:
os_proc_tree_kill(proc->pid, SIGTERM); os_proc_tree_kill(proc->pid, SIGTERM);
break; break;
case kProcessTypePty: case kProcTypePty:
// close all streams for pty processes to send SIGHUP to the process // close all streams for pty processes to send SIGHUP to the process
process_close_streams(proc); proc_close_streams(proc);
pty_process_close_master((PtyProcess *)proc); pty_proc_close_master((PtyProc *)proc);
break; break;
} }
@ -240,7 +240,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
} }
/// Frees process-owned resources. /// 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) { if (proc->argv != NULL) {
shell_free_argv(proc->argv); 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 /// 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) static void children_kill_cb(uv_timer_t *handle)
{ {
Loop *loop = handle->loop->data; Loop *loop = handle->loop->data;
kl_iter(WatcherPtr, loop->children, current) { kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data; Proc *proc = (*current)->data;
bool exited = (proc->status >= 0); bool exited = (proc->status >= 0);
if (exited || !proc->stopped_time) { if (exited || !proc->stopped_time) {
continue; continue;
} }
uint64_t term_sent = UINT64_MAX == proc->stopped_time; 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; proc->exit_signal = SIGKILL;
os_proc_tree_kill(proc->pid, SIGKILL); os_proc_tree_kill(proc->pid, SIGKILL);
} else { } 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) { if (proc->cb) {
// User (hint: channel_job_start) is responsible for calling // User (hint: channel_job_start) is responsible for calling
// process_free(). // proc_free().
proc->cb(proc, proc->status, proc->data); proc->cb(proc, proc->status, proc->data);
} else { } else {
process_free(proc); proc_free(proc);
} }
} }
static void decref(Process *proc) static void decref(Proc *proc)
{ {
if (--proc->refcount != 0) { if (--proc->refcount != 0) {
return; return;
@ -303,13 +303,13 @@ static void decref(Process *proc)
} }
assert(node); assert(node);
kl_shift_at(WatcherPtr, loop->children, 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) 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) { && proc->closed) {
// If a detached/pty process dies while tearing down it might get closed // If a detached/pty process dies while tearing down it might get closed
// twice. // twice.
@ -319,17 +319,17 @@ static void process_close(Process *proc)
proc->closed = true; proc->closed = true;
if (proc->detach) { if (proc->detach) {
if (proc->type == kProcessTypeUv) { if (proc->type == kProcTypeUv) {
uv_unref((uv_handle_t *)&(((LibuvProcess *)proc)->uv)); uv_unref((uv_handle_t *)&(((LibuvProc *)proc)->uv));
} }
} }
switch (proc->type) { switch (proc->type) {
case kProcessTypeUv: case kProcTypeUv:
libuv_process_close((LibuvProcess *)proc); libuv_proc_close((LibuvProc *)proc);
break; break;
case kProcessTypePty: case kProcTypePty:
pty_process_close((PtyProcess *)proc); pty_proc_close((PtyProc *)proc);
break; break;
} }
} }
@ -338,7 +338,7 @@ static void process_close(Process *proc)
/// ///
/// @param proc Process, for which an output stream should be flushed. /// @param proc Process, for which an output stream should be flushed.
/// @param stream Stream to flush. /// @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) FUNC_ATTR_NONNULL_ARG(1)
{ {
if (!stream || stream->s.closed) { 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++; exit_need_delay++;
flush_stream(proc, &proc->out); flush_stream(proc, &proc->out);
flush_stream(proc, &proc->err); flush_stream(proc, &proc->err);
process_close_streams(proc); proc_close_streams(proc);
process_close(proc); proc_close(proc);
exit_need_delay--; 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); 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; Loop *loop = proc->loop;
ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status, 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 // 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 // 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 // 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; 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); decref(proc);
} }

View File

@ -6,9 +6,9 @@
#include "nvim/event/defs.h" // IWYU pragma: keep #include "nvim/event/defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" #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, .type = type,
.data = data, .data = data,
.loop = loop, .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. /// 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]; 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); bool exited = (proc->status >= 0);
return exited || (proc->stopped_time != 0); return exited || (proc->stopped_time != 0);
} }
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/process.h.generated.h" # include "event/proc.h.generated.h"
#endif #endif

View File

@ -43,7 +43,7 @@
#include "nvim/eval/userfunc.h" #include "nvim/eval/userfunc.h"
#include "nvim/event/loop.h" #include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h" #include "nvim/event/multiqueue.h"
#include "nvim/event/process.h" #include "nvim/event/proc.h"
#include "nvim/event/stream.h" #include "nvim/event/stream.h"
#include "nvim/ex_cmds.h" #include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.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. loop_poll_events(&main_loop, 0); // Drain thread_events, fast_events.
input_stop(); input_stop();
channel_teardown(); channel_teardown();
process_teardown(&main_loop); proc_teardown(&main_loop);
timer_teardown(); timer_teardown();
server_teardown(); server_teardown();
signal_teardown(); signal_teardown();
@ -2207,7 +2207,7 @@ static void usage(void)
printf(_(" --headless Don't start a user interface\n")); printf(_(" --headless Don't start a user interface\n"));
printf(_(" --listen <address> Serve RPC API from this address\n")); printf(_(" --listen <address> Serve RPC API from this address\n"));
printf(_(" --remote[-subcommand] Execute commands remotely on a server\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(_(" --startuptime <file> Write startup timing messages to <file>\n"));
printf(_("\nSee \":help startup-options\" for all options.\n")); printf(_("\nSee \":help startup-options\" for all options.\n"));
} }

View File

@ -84,7 +84,7 @@
#include "nvim/os/input.h" #include "nvim/os/input.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/os/os_defs.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.h"
#include "nvim/os/time_defs.h" #include "nvim/os/time_defs.h"
#include "nvim/path.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. /// @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. /// @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; FileInfo st;
double uptime; double uptime;
@ -1214,7 +1214,7 @@ void ml_recover(bool checkext)
msg(_("Recovery completed. Buffer contents equals file contents."), 0); msg(_("Recovery completed. Buffer contents equals file contents."), 0);
} }
msg_puts(_("\nYou may want to delete the .swp file now.")); 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 // Warn there could be an active Vim on the same file, the user may
// want to kill it. // want to kill it.
msg_puts(_("\nNote: process STILL RUNNING: ")); 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. // PID of swapfile owner, or zero if not running.
static int process_running; static int proc_running;
/// For Vimscript "swapinfo()". /// 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, tv_dict_add_str_len(d, S_LEN("fname"), b0.b0_fname,
B0_FNAME_SIZE_ORG); 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("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("dirty"), b0.b0_dirty ? 1 : 0);
tv_dict_add_nr(d, S_LEN("inode"), char_to_long(b0.b0_ino)); 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) { if (char_to_long(b0.b0_pid) != 0) {
msg_puts(_("\n process ID: ")); msg_puts(_("\n process ID: "));
msg_outnum((int)char_to_long(b0.b0_pid)); 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)")); msg_puts(_(" (STILL RUNNING)"));
} }
} }
@ -1640,7 +1640,7 @@ static bool swapfile_unchanged(char *fname)
} }
// process must be known and not running. // 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; 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); fd = os_open(fname, O_RDONLY, 0);
if (fd >= 0) { if (fd >= 0) {
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { 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 // If the swapfile has the same directory as the
// buffer don't compare the directory names, they can // 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; 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) { if (choice == SEA_CHOICE_NONE) {
// Show info about the existing swapfile. // Show info about the existing swapfile.
attention_message(buf, fname); 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, = do_dialog(VIM_WARNING,
_("VIM - ATTENTION"), _("VIM - ATTENTION"),
name, 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&Quit\n&Abort")
: _("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), : _("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"),
1, NULL, false); 1, NULL, false);
if (process_running && dialog_result >= 4) { if (proc_running && dialog_result >= 4) {
// compensate for missing "Delete it" button // compensate for missing "Delete it" button
dialog_result++; dialog_result++;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,20 +10,20 @@
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/os/pty_conpty_win.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 #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_win.c.generated.h" # include "os/pty_proc_win.c.generated.h"
#endif #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 FUNC_ATTR_NONNULL_ALL
{ {
PtyProcess *ptyproc = (PtyProcess *)context; PtyProc *ptyproc = (PtyProc *)context;
Process *proc = (Process *)ptyproc; Proc *proc = (Proc *)ptyproc;
os_conpty_free(ptyproc->conpty); 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. // 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)); 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) static void start_wait_eof_timer(void **argv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
PtyProcess *ptyproc = (PtyProcess *)argv[0]; PtyProc *ptyproc = (PtyProc *)argv[0];
if (ptyproc->finish_wait != NULL) { if (ptyproc->finish_wait != NULL) {
uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200); 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. /// @returns zero on success, or negative error code.
int pty_process_spawn(PtyProcess *ptyproc) int pty_proc_spawn(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
Process *proc = (Process *)ptyproc; Proc *proc = (Proc *)ptyproc;
int status = 0; int status = 0;
conpty_t *conpty_object = NULL; conpty_t *conpty_object = NULL;
char *in_name = NULL; char *in_name = NULL;
char *out_name = NULL; char *out_name = NULL;
HANDLE process_handle = NULL; HANDLE proc_handle = NULL;
uv_connect_t *in_req = NULL; uv_connect_t *in_req = NULL;
uv_connect_t *out_req = NULL; uv_connect_t *out_req = NULL;
wchar_t *cmd_line = NULL; wchar_t *cmd_line = NULL;
@ -69,7 +69,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_pipe_connect(in_req, uv_pipe_connect(in_req,
&proc->in.uv.pipe, &proc->in.uv.pipe,
in_name, in_name,
pty_process_connect_cb); pty_proc_connect_cb);
} }
if (!proc->out.s.closed) { if (!proc->out.s.closed) {
@ -77,7 +77,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_pipe_connect(out_req, uv_pipe_connect(out_req,
&proc->out.s.uv.pipe, &proc->out.s.uv.pipe,
out_name, out_name,
pty_process_connect_cb); pty_proc_connect_cb);
} }
if (proc->cwd != NULL) { if (proc->cwd != NULL) {
@ -105,7 +105,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
} }
if (!os_conpty_spawn(conpty_object, if (!os_conpty_spawn(conpty_object,
&process_handle, &proc_handle,
NULL, NULL,
cmd_line, cmd_line,
cwd, cwd,
@ -114,42 +114,42 @@ int pty_process_spawn(PtyProcess *ptyproc)
status = (int)GetLastError(); status = (int)GetLastError();
goto cleanup; goto cleanup;
} }
proc->pid = (int)GetProcessId(process_handle); proc->pid = (int)GetProcessId(proc_handle);
uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer); uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer);
ptyproc->wait_eof_timer.data = (void *)ptyproc; ptyproc->wait_eof_timer.data = (void *)ptyproc;
if (!RegisterWaitForSingleObject(&ptyproc->finish_wait, if (!RegisterWaitForSingleObject(&ptyproc->finish_wait,
process_handle, proc_handle,
pty_process_finish1, pty_proc_finish1,
ptyproc, ptyproc,
INFINITE, INFINITE,
WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) { WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) {
abort(); 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) while ((in_req != NULL && in_req->handle != NULL)
|| (out_req != NULL && out_req->handle != NULL)) { || (out_req != NULL && out_req->handle != NULL)) {
uv_run(&proc->loop->uv, UV_RUN_ONCE); uv_run(&proc->loop->uv, UV_RUN_ONCE);
} }
ptyproc->conpty = conpty_object; ptyproc->conpty = conpty_object;
ptyproc->process_handle = process_handle; ptyproc->proc_handle = proc_handle;
conpty_object = NULL; conpty_object = NULL;
process_handle = NULL; proc_handle = NULL;
cleanup: cleanup:
if (status) { if (status) {
// In the case of an error of MultiByteToWideChar or CreateProcessW. // 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); proc->argv[0], emsg, status);
status = os_translate_sys_error(status); status = os_translate_sys_error(status);
} }
os_conpty_free(conpty_object); os_conpty_free(conpty_object);
xfree(in_name); xfree(in_name);
xfree(out_name); xfree(out_name);
if (process_handle != NULL) { if (proc_handle != NULL) {
CloseHandle(process_handle); CloseHandle(proc_handle);
} }
xfree(in_req); xfree(in_req);
xfree(out_req); xfree(out_req);
@ -159,32 +159,32 @@ cleanup:
return status; return status;
} }
const char *pty_process_tty_name(PtyProcess *ptyproc) const char *pty_proc_tty_name(PtyProc *ptyproc)
{ {
return "?"; 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 FUNC_ATTR_NONNULL_ALL
{ {
os_conpty_set_size(ptyproc->conpty, width, height); os_conpty_set_size(ptyproc->conpty, width, height);
} }
void pty_process_close(PtyProcess *ptyproc) void pty_proc_close(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL 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) { if (ptyproc->finish_wait != NULL) {
UnregisterWaitEx(ptyproc->finish_wait, NULL); UnregisterWaitEx(ptyproc->finish_wait, NULL);
ptyproc->finish_wait = NULL; ptyproc->finish_wait = NULL;
uv_close((uv_handle_t *)&ptyproc->wait_eof_timer, NULL); uv_close((uv_handle_t *)&ptyproc->wait_eof_timer, NULL);
} }
if (ptyproc->process_handle != NULL) { if (ptyproc->proc_handle != NULL) {
CloseHandle(ptyproc->process_handle); CloseHandle(ptyproc->proc_handle);
ptyproc->process_handle = NULL; ptyproc->proc_handle = NULL;
} }
if (proc->internal_close_cb) { 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 FUNC_ATTR_NONNULL_ALL
{ {
} }
void pty_process_teardown(Loop *loop) void pty_proc_teardown(Loop *loop)
FUNC_ATTR_NONNULL_ALL 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 FUNC_ATTR_NONNULL_ALL
{ {
assert(status == 0); 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) static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
PtyProcess *ptyproc = wait_eof_timer->data; PtyProc *ptyproc = wait_eof_timer->data;
Process *proc = (Process *)ptyproc; Proc *proc = (Proc *)ptyproc;
assert(ptyproc->finish_wait != NULL); assert(ptyproc->finish_wait != NULL);
if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) { if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) {
uv_timer_stop(&ptyproc->wait_eof_timer); 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 FUNC_ATTR_NONNULL_ALL
{ {
Process *proc = (Process *)ptyproc; Proc *proc = (Proc *)ptyproc;
DWORD exit_code = 0; 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->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code;
proc->internal_exit_cb(proc); proc->internal_exit_cb(proc);
@ -427,14 +427,14 @@ cleanup:
return rc; return rc;
} }
PtyProcess pty_process_init(Loop *loop, void *data) PtyProc pty_proc_init(Loop *loop, void *data)
{ {
PtyProcess rv; PtyProc rv;
rv.process = process_init(loop, kProcessTypePty, data); rv.proc = proc_init(loop, kProcTypePty, data);
rv.width = 80; rv.width = 80;
rv.height = 24; rv.height = 24;
rv.conpty = NULL; rv.conpty = NULL;
rv.finish_wait = NULL; rv.finish_wait = NULL;
rv.process_handle = NULL; rv.proc_handle = NULL;
return rv; return rv;
} }

View File

@ -1,20 +1,20 @@
#pragma once #pragma once
// IWYU pragma: private, include "nvim/os/pty_process.h" // IWYU pragma: private, include "nvim/os/pty_proc.h"
#include <uv.h> #include <uv.h>
#include "nvim/event/process.h" #include "nvim/event/proc.h"
#include "nvim/lib/queue_defs.h" #include "nvim/lib/queue_defs.h"
#include "nvim/os/pty_conpty_win.h" #include "nvim/os/pty_conpty_win.h"
typedef struct pty_process { typedef struct pty_process {
Process process; Proc proc;
uint16_t width, height; uint16_t width, height;
conpty_t *conpty; conpty_t *conpty;
HANDLE finish_wait; HANDLE finish_wait;
HANDLE process_handle; HANDLE proc_handle;
uv_timer_t wait_eof_timer; uv_timer_t wait_eof_timer;
} PtyProcess; } PtyProc;
// Structure used by build_cmd_line() // Structure used by build_cmd_line()
typedef struct arg_node { typedef struct arg_node {
@ -23,5 +23,5 @@ typedef struct arg_node {
} ArgNode; } ArgNode;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_win.h.generated.h" # include "os/pty_proc_win.h.generated.h"
#endif #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.h"
#include "nvim/eval/typval_defs.h" #include "nvim/eval/typval_defs.h"
#include "nvim/event/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/loop.h"
#include "nvim/event/multiqueue.h" #include "nvim/event/multiqueue.h"
#include "nvim/event/process.h" #include "nvim/event/proc.h"
#include "nvim/event/rstream.h" #include "nvim/event/rstream.h"
#include "nvim/event/stream.h" #include "nvim/event/stream.h"
#include "nvim/event/wstream.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]; char prog[MAXPATHL];
xstrlcpy(prog, argv[0], MAXPATHL); xstrlcpy(prog, argv[0], MAXPATHL);
LibuvProcess uvproc = libuv_process_init(&main_loop, &buf); LibuvProc uvproc = libuv_proc_init(&main_loop, &buf);
Process *proc = &uvproc.process; Proc *proc = &uvproc.proc;
MultiQueue *events = multiqueue_new_child(main_loop.events); MultiQueue *events = multiqueue_new_child(main_loop.events);
proc->events = events; proc->events = events;
proc->argv = argv; proc->argv = argv;
int status = process_spawn(proc, has_input, true, true); int status = proc_spawn(proc, has_input, true, true);
if (status) { if (status) {
loop_poll_events(&main_loop, 0); loop_poll_events(&main_loop, 0);
// Failed, probably 'shell' is not executable. // 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)) { if (!wstream_write(&proc->in, input_buffer)) {
// couldn't write, stop the process and tell the user about it // couldn't write, stop the process and tell the user about it
process_stop(proc); proc_stop(proc);
return -1; return -1;
} }
// close the input stream after everything is written // 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; msg_no_more = true;
lines_left = -1; 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)) { if (!got_int && out_data_decide_throttle(0)) {
// Last chunk of output was skipped; display it now. // Last chunk of output was skipped; display it now.
out_data_ring(NULL, SIZE_MAX); out_data_ring(NULL, SIZE_MAX);

View File

@ -950,8 +950,8 @@ void time_msg(const char *mesg, const proftime_T *start)
/// Initializes the `time_fd` stream for the --startuptime report. /// Initializes the `time_fd` stream for the --startuptime report.
/// ///
/// @param fname startuptime report file path /// @param fname startuptime report file path
/// @param process_name name of the current Nvim process to write in the report. /// @param proc_name name of the current Nvim process to write in the report.
void time_init(const char *fname, const char *process_name) void time_init(const char *fname, const char *proc_name)
{ {
const size_t bufsize = 8192; // Big enough for the entire --startuptime report. const size_t bufsize = 8192; // Big enough for the entire --startuptime report.
time_fd = fopen(fname, "a"); 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)); semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r));
return; 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 /// 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 // In a location list window and none of the other windows is
// referring to this location list. Mark the location list // referring to this location list. Mark the location list
// context as still in use. // 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; return true;
} }
} }

View File

@ -103,7 +103,7 @@ Debugging tests
DBG 2022-06-15T18:37:45.227 T57.58016.0/c UI: stop 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 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) 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): - 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 return true, result
end end
--- Runs the event loop.
function Session:run(request_cb, notification_cb, setup_cb, timeout) function Session:run(request_cb, notification_cb, setup_cb, timeout)
local function on_request(method, args, response) local function on_request(method, args, response)
coroutine_exec(request_cb, method, args, function(status, result, flag) coroutine_exec(request_cb, method, args, function(status, result, flag)

View File

@ -1,6 +1,6 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local clear = n.clear local clear = n.clear
local feed_command = n.feed_command local feed_command = n.feed_command

View File

@ -1,6 +1,6 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local uv = vim.uv local uv = vim.uv
local clear, command, testprg = n.clear, n.command, n.testprg local clear, command, testprg = n.clear, n.command, n.testprg
@ -199,7 +199,7 @@ end)
describe('autocmd TextChangedT', function() describe('autocmd TextChangedT', function()
clear() clear()
local screen = tt.screen_setup() local screen = tt.setup_screen()
it('works', function() it('works', function()
command('autocmd TextChangedT * ++once let g:called = 1') command('autocmd TextChangedT * ++once let g:called = 1')

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local clear = n.clear local clear = n.clear
local eq = t.eq local eq = t.eq

View File

@ -1,6 +1,6 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local assert_log = t.assert_log local assert_log = t.assert_log
local clear = n.clear local clear = n.clear

View File

@ -2347,6 +2347,7 @@ describe('vim.diagnostic', function()
-- Legacy signs for diagnostics were deprecated in 0.10 and will be removed in 0.12 -- Legacy signs for diagnostics were deprecated in 0.10 and will be removed in 0.12
eq(0, n.fn.has('nvim-0.12')) eq(0, n.fn.has('nvim-0.12'))
n.command('set cursorline')
n.command('sign define DiagnosticSignError text= texthl= linehl=ErrorMsg numhl=ErrorMsg') n.command('sign define DiagnosticSignError text= texthl= linehl=ErrorMsg numhl=ErrorMsg')
n.command('sign define DiagnosticSignWarn text= texthl= linehl=WarningMsg numhl=WarningMsg') n.command('sign define DiagnosticSignWarn text= texthl= linehl=WarningMsg numhl=WarningMsg')
n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined') n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined')
@ -2354,7 +2355,7 @@ describe('vim.diagnostic', function()
local result = exec_lua(function() local result = exec_lua(function()
vim.diagnostic.config({ vim.diagnostic.config({
signs = true, signs = { cursorlinehl = { 'DiagnosticError', 'DiagnosticWarn' } },
}) })
local diagnostics = { local diagnostics = {
@ -2382,6 +2383,7 @@ describe('vim.diagnostic', function()
text = s[4].sign_text or '', text = s[4].sign_text or '',
numhl = s[4].number_hl_group, numhl = s[4].number_hl_group,
linehl = s[4].line_hl_group, linehl = s[4].line_hl_group,
culhl = s[4].cursorline_hl_group,
} }
end end
return result return result
@ -2393,6 +2395,7 @@ describe('vim.diagnostic', function()
text = '', text = '',
numhl = 'ErrorMsg', numhl = 'ErrorMsg',
linehl = 'ErrorMsg', linehl = 'ErrorMsg',
culhl = 'DiagnosticError',
}, result[1]) }, result[1])
eq({ eq({
@ -2401,6 +2404,7 @@ describe('vim.diagnostic', function()
text = '', text = '',
numhl = 'WarningMsg', numhl = 'WarningMsg',
linehl = 'WarningMsg', linehl = 'WarningMsg',
culhl = 'DiagnosticWarn',
}, result[2]) }, result[2])
end) end)
end) end)

View File

@ -157,5 +157,28 @@ describe('vim.ui', function()
exec_lua [[local _, err = vim.ui.open('foo') ; return err]] exec_lua [[local _, err = vim.ui.open('foo') ; return err]]
) )
end) end)
it('opt.cmd #29490', function()
t.matches(
'ENOENT: no such file or directory',
t.pcall_err(exec_lua, function()
vim.ui.open('foo', { cmd = { 'non-existent-tool' } })
end)
)
eq(
{
code = 0,
signal = 0,
stderr = '',
stdout = 'arg1=arg1;arg2=https://example.com;',
},
exec_lua(function(cmd_)
local cmd, err = vim.ui.open('https://example.com', { cmd = cmd_ })
assert(cmd and not err)
return cmd:wait()
end, { n.testprg('printargs-test'), 'arg1' })
)
end)
end) end)
end) end)

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local clear, eq, api = n.clear, t.eq, n.api local clear, eq, api = n.clear, t.eq, n.api
local feed = n.feed local feed = n.feed
local feed_data = tt.feed_data local feed_data = tt.feed_data
@ -17,7 +17,7 @@ describe(':terminal altscreen', function()
before_each(function() before_each(function()
clear() clear()
screen = tt.screen_setup() screen = tt.setup_screen()
feed_data({ feed_data({
'line1', 'line1',
'line2', 'line2',

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local ok = t.ok local ok = t.ok
if t.skip(t.is_os('win')) then if t.skip(t.is_os('win')) then

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local assert_alive = n.assert_alive local assert_alive = n.assert_alive
local feed, clear = n.feed, n.clear local feed, clear = n.feed, n.clear
@ -29,7 +29,7 @@ describe(':terminal buffer', function()
before_each(function() before_each(function()
clear() clear()
command('set modifiable swapfile undolevels=20') command('set modifiable swapfile undolevels=20')
screen = tt.screen_setup() screen = tt.setup_screen()
end) end)
it('terminal-mode forces various options', function() it('terminal-mode forces various options', function()
@ -574,7 +574,7 @@ if is_os('win') then
feed_command('set modifiable swapfile undolevels=20') feed_command('set modifiable swapfile undolevels=20')
poke_eventloop() poke_eventloop()
local cmd = { 'cmd.exe', '/K', 'PROMPT=$g$s' } local cmd = { 'cmd.exe', '/K', 'PROMPT=$g$s' }
screen = tt.screen_setup(nil, cmd) screen = tt.setup_screen(nil, cmd)
end) end)
it('"put" operator sends data normally', function() it('"put" operator sends data normally', function()

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear local feed, clear = n.feed, n.clear
local testprg, command = n.testprg, n.command local testprg, command = n.testprg, n.command
@ -18,7 +18,7 @@ describe(':terminal cursor', function()
before_each(function() before_each(function()
clear() clear()
screen = tt.screen_setup() screen = tt.setup_screen()
end) end)
it('moves the screen cursor when focused', function() it('moves the screen cursor when focused', function()

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear local feed, clear = n.feed, n.clear
local api = n.api local api = n.api

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local clear, eq, eval = n.clear, t.eq, n.eval local clear, eq, eval = n.clear, t.eq, n.eval
local feed, api, command = n.feed, n.api, n.command local feed, api, command = n.feed, n.api, n.command
local feed_data = tt.feed_data local feed_data = tt.feed_data
@ -14,7 +14,7 @@ describe(':terminal mouse', function()
before_each(function() before_each(function()
clear() clear()
api.nvim_set_option_value('statusline', '==========', {}) api.nvim_set_option_value('statusline', '==========', {})
screen = tt.screen_setup() screen = tt.setup_screen()
command('highlight StatusLine NONE') command('highlight StatusLine NONE')
command('highlight StatusLineNC NONE') command('highlight StatusLineNC NONE')
command('highlight StatusLineTerm NONE') command('highlight StatusLineTerm NONE')

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local clear, eq = n.clear, t.eq local clear, eq = n.clear, t.eq
local feed, testprg = n.feed, n.testprg local feed, testprg = n.feed, n.testprg
@ -22,7 +22,7 @@ describe(':terminal scrollback', function()
before_each(function() before_each(function()
clear() clear()
screen = tt.screen_setup(nil, nil, 30) screen = tt.setup_screen(nil, nil, 30)
end) end)
describe('when the limit is exceeded', function() describe('when the limit is exceeded', function()
@ -399,9 +399,9 @@ describe("'scrollback' option", function()
it('set to 0 behaves as 1', function() it('set to 0 behaves as 1', function()
local screen local screen
if is_os('win') then if is_os('win') then
screen = tt.screen_setup(nil, { 'cmd.exe' }, 30) screen = tt.setup_screen(nil, { 'cmd.exe' }, 30)
else else
screen = tt.screen_setup(nil, { 'sh' }, 30) screen = tt.setup_screen(nil, { 'sh' }, 30)
end end
api.nvim_set_option_value('scrollback', 0, {}) api.nvim_set_option_value('scrollback', 0, {})
@ -416,10 +416,10 @@ describe("'scrollback' option", function()
local screen local screen
if is_os('win') then if is_os('win') then
command([[let $PROMPT='$$']]) command([[let $PROMPT='$$']])
screen = tt.screen_setup(nil, { 'cmd.exe' }, 30) screen = tt.setup_screen(nil, { 'cmd.exe' }, 30)
else else
command('let $PS1 = "$"') command('let $PS1 = "$"')
screen = tt.screen_setup(nil, { 'sh' }, 30) screen = tt.setup_screen(nil, { 'sh' }, 30)
end end
api.nvim_set_option_value('scrollback', 200, {}) api.nvim_set_option_value('scrollback', 200, {})
@ -480,8 +480,8 @@ describe("'scrollback' option", function()
end) end)
it('deletes extra lines immediately', function() it('deletes extra lines immediately', function()
-- Scrollback is 10 on screen_setup -- Scrollback is 10 on setup_screen
local screen = tt.screen_setup(nil, nil, 30) local screen = tt.setup_screen(nil, nil, 30)
local lines = {} local lines = {}
for i = 1, 30 do for i = 1, 30 do
table.insert(lines, 'line' .. tostring(i)) table.insert(lines, 'line' .. tostring(i))

View File

@ -7,7 +7,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local eq = t.eq local eq = t.eq
local feed_data = tt.feed_data local feed_data = tt.feed_data
@ -2111,7 +2111,7 @@ describe('TUI', function()
finally(function() finally(function()
os.remove('testF') os.remove('testF')
end) end)
local screen = tt.screen_setup( local screen = tt.setup_screen(
0, 0,
('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format( ('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format(
nvim_prog nvim_prog

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local feed_data = tt.feed_data local feed_data = tt.feed_data
local feed, clear = n.feed, n.clear local feed, clear = n.feed, n.clear
local poke_eventloop = n.poke_eventloop local poke_eventloop = n.poke_eventloop
@ -37,7 +37,7 @@ describe(':terminal window', function()
before_each(function() before_each(function()
clear() clear()
screen = tt.screen_setup() screen = tt.setup_screen()
end) end)
it('sets topline correctly #8556', function() it('sets topline correctly #8556', function()
@ -198,7 +198,7 @@ describe(':terminal with multigrid', function()
before_each(function() before_each(function()
clear() clear()
screen = tt.screen_setup(0, nil, 50, nil, { ext_multigrid = true }) screen = tt.setup_screen(0, nil, 50, nil, { ext_multigrid = true })
end) end)
it('resizes to requested size', function() it('resizes to requested size', function()

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local assert_alive = n.assert_alive local assert_alive = n.assert_alive
local clear = n.clear local clear = n.clear
local feed = n.feed local feed = n.feed
@ -22,7 +22,7 @@ describe(':terminal', function()
-- set the statusline to a constant value because of variables like pid -- set the statusline to a constant value because of variables like pid
-- and current directory and to improve visibility of splits -- and current directory and to improve visibility of splits
api.nvim_set_option_value('statusline', '==========', {}) api.nvim_set_option_value('statusline', '==========', {})
screen = tt.screen_setup(3) screen = tt.setup_screen(3)
command('highlight StatusLine NONE') command('highlight StatusLine NONE')
command('highlight StatusLineNC NONE') command('highlight StatusLineNC NONE')
command('highlight StatusLineTerm NONE') command('highlight StatusLineTerm NONE')

View File

@ -250,6 +250,8 @@ function M.set_method_error(err)
method_error = err method_error = err
end end
--- Runs the event loop of the given session.
---
--- @param lsession test.Session --- @param lsession test.Session
--- @param request_cb function? --- @param request_cb function?
--- @param notification_cb function? --- @param notification_cb function?
@ -296,6 +298,7 @@ function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
return lsession.eof_err return lsession.eof_err
end end
--- Runs the event loop of the current global session.
function M.run(request_cb, notification_cb, setup_cb, timeout) function M.run(request_cb, notification_cb, setup_cb, timeout)
assert(session) assert(session)
return M.run_session(session, request_cb, notification_cb, setup_cb, timeout) return M.run_session(session, request_cb, notification_cb, setup_cb, timeout)

View File

@ -1,6 +1,13 @@
-- To test tui/input.c, this module spawns `nvim` inside :terminal and sends -- Functions to test :terminal and the Nvim TUI.
-- bytes via jobsend(). Note: the functional/testutil.lua test-session methods -- Starts a child process in a `:terminal` and sends bytes to the child via nvim_chan_send().
-- operate on the _host_ session, _not_ the child session. -- Note: the global functional/testutil.lua test-session is _host_ session, _not_
-- the child session.
--
-- - Use `setup_screen()` to test `:terminal` behavior with an arbitrary command.
-- - Use `setup_child_nvim()` to test the Nvim TUI.
-- - NOTE: Only use this if your test actually needs the full lifecycle/capabilities of the
-- builtin Nvim TUI. Most tests should just use `Screen.new()` directly, or plain old API calls.
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
@ -9,18 +16,20 @@ local exec_lua = n.exec_lua
local api = n.api local api = n.api
local nvim_prog = n.nvim_prog local nvim_prog = n.nvim_prog
local function feed_data(data) local M = {}
function M.feed_data(data)
if type(data) == 'table' then if type(data) == 'table' then
data = table.concat(data, '\n') data = table.concat(data, '\n')
end end
exec_lua('vim.api.nvim_chan_send(vim.b.terminal_job_id, ...)', data) exec_lua('vim.api.nvim_chan_send(vim.b.terminal_job_id, ...)', data)
end end
local function feed_termcode(data) function M.feed_termcode(data)
feed_data('\027' .. data) M.feed_data('\027' .. data)
end end
local function make_lua_executor(session) function M.make_lua_executor(session)
return function(code, ...) return function(code, ...)
local status, rv = session:request('nvim_exec_lua', code, { ... }) local status, rv = session:request('nvim_exec_lua', code, { ... })
if not status then if not status then
@ -34,60 +43,68 @@ end
-- some t for controlling the terminal. the codes were taken from -- some t for controlling the terminal. the codes were taken from
-- infocmp xterm-256color which is less what libvterm understands -- infocmp xterm-256color which is less what libvterm understands
-- civis/cnorm -- civis/cnorm
local function hide_cursor() function M.hide_cursor()
feed_termcode('[?25l') M.feed_termcode('[?25l')
end end
local function show_cursor() function M.show_cursor()
feed_termcode('[?25h') M.feed_termcode('[?25h')
end end
-- smcup/rmcup -- smcup/rmcup
local function enter_altscreen() function M.enter_altscreen()
feed_termcode('[?1049h') M.feed_termcode('[?1049h')
end end
local function exit_altscreen() function M.exit_altscreen()
feed_termcode('[?1049l') M.feed_termcode('[?1049l')
end end
-- character attributes -- character attributes
local function set_fg(num) function M.set_fg(num)
feed_termcode('[38;5;' .. num .. 'm') M.feed_termcode('[38;5;' .. num .. 'm')
end end
local function set_bg(num) function M.set_bg(num)
feed_termcode('[48;5;' .. num .. 'm') M.feed_termcode('[48;5;' .. num .. 'm')
end end
local function set_bold() function M.set_bold()
feed_termcode('[1m') M.feed_termcode('[1m')
end end
local function set_italic() function M.set_italic()
feed_termcode('[3m') M.feed_termcode('[3m')
end end
local function set_underline() function M.set_underline()
feed_termcode('[4m') M.feed_termcode('[4m')
end end
local function set_underdouble() function M.set_underdouble()
feed_termcode('[4:2m') M.feed_termcode('[4:2m')
end end
local function set_undercurl() function M.set_undercurl()
feed_termcode('[4:3m') M.feed_termcode('[4:3m')
end end
local function set_strikethrough() function M.set_strikethrough()
feed_termcode('[9m') M.feed_termcode('[9m')
end end
local function clear_attrs() function M.clear_attrs()
feed_termcode('[0;10m') M.feed_termcode('[0;10m')
end end
-- mouse -- mouse
local function enable_mouse() function M.enable_mouse()
feed_termcode('[?1002h') M.feed_termcode('[?1002h')
end end
local function disable_mouse() function M.disable_mouse()
feed_termcode('[?1002l') M.feed_termcode('[?1002l')
end end
local default_command = { testprg('tty-test') } local default_command = { testprg('tty-test') }
local function screen_setup(extra_rows, command, cols, env, screen_opts) --- Runs `cmd` in a :terminal, and returns a `Screen` object.
---
---@param extra_rows? integer Extra rows to add to the default screen.
---@param cmd? string|string[] Command to run in the terminal (default: `{ 'tty-test' }`)
---@param cols? integer Create screen with this many columns (default: 50)
---@param env? table Environment set on the `cmd` job.
---@param screen_opts? table Options for `Screen.new()`.
---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session.
function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
extra_rows = extra_rows and extra_rows or 0 extra_rows = extra_rows and extra_rows or 0
command = command and command or default_command cmd = cmd and cmd or default_command
cols = cols and cols or 50 cols = cols and cols or 50
api.nvim_command('highlight TermCursor cterm=reverse') api.nvim_command('highlight TermCursor cterm=reverse')
@ -120,7 +137,7 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
screen:attach(screen_opts or { rgb = false }) screen:attach(screen_opts or { rgb = false })
api.nvim_command('enew') api.nvim_command('enew')
api.nvim_call_function('termopen', { command, env and { env = env } or nil }) api.nvim_call_function('termopen', { cmd, env and { env = env } or nil })
api.nvim_input('<CR>') api.nvim_input('<CR>')
local vim_errmsg = api.nvim_eval('v:errmsg') local vim_errmsg = api.nvim_eval('v:errmsg')
if vim_errmsg and '' ~= vim_errmsg then if vim_errmsg and '' ~= vim_errmsg then
@ -133,7 +150,7 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
-- tty-test puts the terminal into raw mode and echoes input. Tests work by -- tty-test puts the terminal into raw mode and echoes input. Tests work by
-- feeding termcodes to control the display and asserting by screen:expect. -- feeding termcodes to control the display and asserting by screen:expect.
if command == default_command and screen_opts == nil then if cmd == default_command and screen_opts == nil then
-- Wait for "tty ready" to be printed before each test or the terminal may -- Wait for "tty ready" to be printed before each test or the terminal may
-- still be in canonical mode (will echo characters for example). -- still be in canonical mode (will echo characters for example).
local empty_line = (' '):rep(cols) local empty_line = (' '):rep(cols)
@ -160,37 +177,24 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
return screen return screen
end end
local function setup_child_nvim(args, opts) --- Spawns Nvim with `args` in a :terminal, and returns a `Screen` object.
---
--- @note Only use this if you actually need the full lifecycle/capabilities of the builtin Nvim
--- TUI. Most tests should just use `Screen.new()` directly, or plain old API calls.
---
---@param args? string[] Args passed to child Nvim.
---@param opts? table Options
---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session.
function M.setup_child_nvim(args, opts)
opts = opts or {} opts = opts or {}
local argv = { nvim_prog, unpack(args) } local argv = { nvim_prog, unpack(args or {}) }
local env = opts.env or {} local env = opts.env or {}
if not env.VIMRUNTIME then if not env.VIMRUNTIME then
env.VIMRUNTIME = os.getenv('VIMRUNTIME') env.VIMRUNTIME = os.getenv('VIMRUNTIME')
end end
return screen_setup(opts.extra_rows, argv, opts.cols, env) return M.setup_screen(opts.extra_rows, argv, opts.cols, env)
end end
return { return M
feed_data = feed_data,
feed_termcode = feed_termcode,
make_lua_executor = make_lua_executor,
hide_cursor = hide_cursor,
show_cursor = show_cursor,
enter_altscreen = enter_altscreen,
exit_altscreen = exit_altscreen,
set_fg = set_fg,
set_bg = set_bg,
set_bold = set_bold,
set_italic = set_italic,
set_underline = set_underline,
set_underdouble = set_underdouble,
set_undercurl = set_undercurl,
set_strikethrough = set_strikethrough,
clear_attrs = clear_attrs,
enable_mouse = enable_mouse,
disable_mouse = disable_mouse,
screen_setup = screen_setup,
setup_child_nvim = setup_child_nvim,
}

View File

@ -8,6 +8,7 @@ local exec_lua = n.exec_lua
local pcall_err = t.pcall_err local pcall_err = t.pcall_err
local matches = t.matches local matches = t.matches
local insert = n.insert local insert = n.insert
local NIL = vim.NIL
before_each(clear) before_each(clear)
@ -15,10 +16,12 @@ describe('treesitter language API', function()
-- error tests not requiring a parser library -- error tests not requiring a parser library
it('handles missing language', function() it('handles missing language', function()
eq( eq(
".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", '.../treesitter.lua:0: Parser not found.',
pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')") pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')")
) )
eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')"))
-- actual message depends on platform -- actual message depends on platform
matches( matches(
"Failed to load parser for language 'borklang': uv_dlopen: .+", "Failed to load parser for language 'borklang': uv_dlopen: .+",
@ -105,9 +108,10 @@ describe('treesitter language API', function()
command('set filetype=borklang') command('set filetype=borklang')
-- Should throw an error when filetype changes to borklang -- Should throw an error when filetype changes to borklang
eq( eq(
".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", '.../treesitter.lua:0: Parser not found.',
pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')") pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')")
) )
eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')"))
end end
) )

View File

@ -135,9 +135,7 @@ void ui_refresh(void)
insert(test_text) insert(test_text)
eq( eq(
'.../treesitter.lua:0: There is no parser available for buffer 1 and one' '.../treesitter.lua:0: Parser not found.',
.. ' could not be created because lang could not be determined. Either'
.. ' pass lang or set the buffer filetype',
pcall_err(exec_lua, 'vim.treesitter.get_parser(0)') pcall_err(exec_lua, 'vim.treesitter.get_parser(0)')
) )

View File

@ -1078,6 +1078,44 @@ describe('CursorLine and CursorLineNr highlights', function()
]]) ]])
end) end)
-- oldtest: Test_cursorline_screenline_resize()
it("'cursorlineopt' screenline is updated on window resize", function()
local screen = Screen.new(75, 8)
screen:attach()
exec([[
50vnew
call setline(1, repeat('xyz ', 30))
setlocal number cursorline cursorlineopt=screenline
normal! $
]])
screen:expect([[
{8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy |
{8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz {1:~ }|
{8: }{21:xyz xyz xyz xyz xyz xyz xyz^ }{1:~ }|
{1:~ }{1:~ }|*3
{3:[No Name] [+] }{2:[No Name] }|
|
]])
command('vertical resize -4')
screen:expect([[
{8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy |
{8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz {1:~ }|
{8: }{21:xyz xyz xyz xyz xyz xyz xyz xyz xyz^ }{1:~ }|
{1:~ }{1:~ }|*3
{3:[No Name] [+] }{2:[No Name] }|
|
]])
command('set cpoptions+=n')
screen:expect([[
{8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy |
z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz {1:~ }|
{21:xyz xyz xyz xyz xyz xyz xyz xyz^ }{1:~ }|
{1:~ }{1:~ }|*3
{3:[No Name] [+] }{2:[No Name] }|
|
]])
end)
-- oldtest: Test_cursorline_after_yank() -- oldtest: Test_cursorline_after_yank()
it('always updated. vim-patch:8.1.0849', function() it('always updated. vim-patch:8.1.0849', function()
local screen = Screen.new(50, 5) local screen = Screen.new(50, 5)

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local clear, insert = n.clear, n.insert local clear, insert = n.clear, n.insert
local command = n.command local command = n.command

View File

@ -1,7 +1,7 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.terminal.testutil') local tt = require('test.functional.testterm')
local assert_alive = n.assert_alive local assert_alive = n.assert_alive
local mkdir, write_file, rmdir = t.mkdir, t.write_file, n.rmdir local mkdir, write_file, rmdir = t.mkdir, t.write_file, n.rmdir

View File

@ -262,14 +262,34 @@ func Test_cursorline_callback()
call timer_start(300, 'Func') call timer_start(300, 'Func')
END END
call writefile(lines, 'Xcul_timer') call writefile(lines, 'Xcul_timer', 'D')
let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8}) let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8})
call TermWait(buf, 310) call TermWait(buf, 310)
call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {}) call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {})
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
call delete('Xcul_timer') endfunc
func Test_cursorline_screenline_resize()
CheckScreendump
let lines =<< trim END
50vnew
call setline(1, repeat('xyz ', 30))
setlocal number cursorline cursorlineopt=screenline
normal! $
END
call writefile(lines, 'Xcul_screenline_resize', 'D')
let buf = RunVimInTerminal('-S Xcul_screenline_resize', #{rows: 8})
call VerifyScreenDump(buf, 'Test_cursorline_screenline_resize_1', {})
call term_sendkeys(buf, ":vertical resize -4\<CR>")
call VerifyScreenDump(buf, 'Test_cursorline_screenline_resize_2', {})
call term_sendkeys(buf, ":set cpoptions+=n\<CR>")
call VerifyScreenDump(buf, 'Test_cursorline_screenline_resize_3', {})
call StopVimInTerminal(buf)
endfunc endfunc
func Test_cursorline_screenline_update() func Test_cursorline_screenline_update()
@ -280,7 +300,7 @@ func Test_cursorline_screenline_update()
set cursorline cursorlineopt=screenline set cursorline cursorlineopt=screenline
inoremap <F2> <Cmd>call cursor(1, 1)<CR> inoremap <F2> <Cmd>call cursor(1, 1)<CR>
END END
call writefile(lines, 'Xcul_screenline') call writefile(lines, 'Xcul_screenline', 'D')
let buf = RunVimInTerminal('-S Xcul_screenline', #{rows: 8}) let buf = RunVimInTerminal('-S Xcul_screenline', #{rows: 8})
call term_sendkeys(buf, "A") call term_sendkeys(buf, "A")
@ -290,7 +310,17 @@ func Test_cursorline_screenline_update()
call term_sendkeys(buf, "\<Esc>") call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
call delete('Xcul_screenline') endfunc
func Test_cursorline_screenline_zero_width()
CheckOption foldcolumn
set cursorline culopt=screenline winminwidth=1 foldcolumn=1
" This used to crash Vim
1vnew | redraw
bwipe!
set cursorline& culopt& winminwidth& foldcolumn&
endfunc endfunc
func Test_cursorline_cursorbind_horizontal_scroll() func Test_cursorline_cursorbind_horizontal_scroll()

View File

@ -1150,15 +1150,14 @@ func Test_cfg_file()
unlet g:filetype_cfg unlet g:filetype_cfg
" RAPID cfg " RAPID cfg
let ext = 'cfg'
for i in ['EIO', 'MMC', 'MOC', 'PROC', 'SIO', 'SYS'] for i in ['EIO', 'MMC', 'MOC', 'PROC', 'SIO', 'SYS']
call writefile([i .. ':CFG'], 'cfgfile.' .. ext) for ext in ['cfg', 'Cfg', 'CFG']
execute "split cfgfile." .. ext call writefile([i .. ':CFG'], 'cfgfile.' .. ext)
call assert_equal('rapid', &filetype) execute "split cfgfile." .. ext
bwipe! call assert_equal('rapid', &filetype)
call delete('cfgfile.' .. ext) bwipe!
" check different case of file extension call delete('cfgfile.' .. ext)
let ext = substitute(ext, '\(\l\)', '\u\1', '') endfor
endfor endfor
" clean up " clean up

View File

@ -4071,11 +4071,23 @@ func Test_ll_window_ctx()
enew | only enew | only
endfunc endfunc
" Similar to the problem above, but for user data.
func Test_ll_window_user_data()
call setloclist(0, [#{bufnr: bufnr(), user_data: {}}])
lopen
wincmd t
close
call test_garbagecollect_now()
call feedkeys("\<CR>", 'tx')
call test_garbagecollect_now()
%bwipe!
endfunc
" The following test used to crash vim " The following test used to crash vim
func Test_lfile_crash() func Test_lfile_crash()
sp Xtest sp Xtest
au QuickFixCmdPre * bw au QuickFixCmdPre * bw
call assert_fails('lfile', 'E40') call assert_fails('lfile', 'E40:')
au! QuickFixCmdPre au! QuickFixCmdPre
endfunc endfunc