mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
Compare commits
70 Commits
4f12cc58c8
...
d9b4d321d0
Author | SHA1 | Date | |
---|---|---|---|
|
d9b4d321d0 | ||
|
a0d8c2b86e | ||
|
549c00c791 | ||
|
23dcd7cd73 | ||
|
3f15e57b26 | ||
|
a9031cc4a6 | ||
|
5e7933693b | ||
|
f408603f4f | ||
|
78b8510933 | ||
|
057d27a9d6 | ||
|
5792546777 | ||
|
3b54adc6c6 | ||
|
325d349f9d | ||
|
5191a11d66 | ||
|
90585e47fe | ||
|
f2173b1aa2 | ||
|
67d6b6f27e | ||
|
8512f669f0 | ||
|
755512ed60 | ||
|
4c23b83456 | ||
|
5284a2a793 | ||
|
b9b408a56c | ||
|
8654a97006 | ||
|
057314345a | ||
|
deac7df80a | ||
|
ae917dbd06 | ||
|
c65153893a | ||
|
f6cc0394ae | ||
|
f347c292d1 | ||
|
48c14d3544 | ||
|
5931f780e0 | ||
|
98ba65b8be | ||
|
f9bf64d746 | ||
|
a30afeeb85 | ||
|
7b680e0ca9 | ||
|
8501fe621a | ||
|
a5bd6665b0 | ||
|
4ac733f6ef | ||
|
c1a4b8680b | ||
|
f6579a4db1 | ||
|
608ef83fc6 | ||
|
57db94235c | ||
|
cdab8c8ebb | ||
|
830cf054bc | ||
|
def6111118 | ||
|
237d2aef4d | ||
|
15bfdf73ea | ||
|
f289161c3c | ||
|
4b98d38870 | ||
|
4c5bce9cb4 | ||
|
5d7853f229 | ||
|
f279d1ae33 | ||
|
9ddfcb64bf | ||
|
8e81212e15 | ||
|
648d6426c8 | ||
|
f0334c2c71 | ||
|
c8e3618e0e | ||
|
ed832b9ddf | ||
|
8a2aec9974 | ||
|
3a88113246 | ||
|
08153ddd1c | ||
|
003b8a251d | ||
|
0cfbc6eaff | ||
|
95b65a7554 | ||
|
e37404f7fe | ||
|
b40ec083ae | ||
|
d338ec9cb2 | ||
|
5ddf2ab768 | ||
|
3d1110674e | ||
|
738a84de09 |
18
.github/workflows/backport.yml
vendored
18
.github/workflows/backport.yml
vendored
@ -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 }}
|
||||||
|
2
.github/workflows/reviewers_add.yml
vendored
2
.github/workflows/reviewers_add.yml
vendored
@ -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
|
||||||
|
@ -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/d72c3598e7ac5d1ebf86ee268b8b4ed95c0fa628.tar.gz
|
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz
|
||||||
UNIBILIUM_SHA256 9c4747c862ab5e3076dcf8fa8f0ea7a6b50f20ec5905618b9536655596797487
|
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
|
||||||
@ -38,18 +38,18 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
|
|||||||
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/3de4596fbe28956855df2ecb3c11c0bbc3535838.tar.gz
|
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/3de4596fbe28956855df2ecb3c11c0bbc3535838.tar.gz
|
||||||
UTF8PROC_SHA256 fb4a16bb659b58afb7f921fcc8928d0b3c1fcab135366c8a4f9ca7de1b1cfada
|
UTF8PROC_SHA256 fb4a16bb659b58afb7f921fcc8928d0b3c1fcab135366c8a4f9ca7de1b1cfada
|
||||||
|
|
||||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.21.3.tar.gz
|
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.0.tar.gz
|
||||||
TREESITTER_C_SHA256 75a3780df6114cd37496761c4a7c9fd900c78bee3a2707f590d78c0ca3a24368
|
TREESITTER_C_SHA256 ee58c925e2e507c23d735aad46bf7fb0af31ca06d6f4f41bc008216d9232b0cb
|
||||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.1.0.tar.gz
|
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.2.0.tar.gz
|
||||||
TREESITTER_LUA_SHA256 230cfcbfa74ed1f7b8149e9a1f34c2efc4c589a71fe0f5dc8560622f8020d722
|
TREESITTER_LUA_SHA256 6c41227cd0a59047b19d31f0031d4d901f08bfd78d6fc7f55c89e5b8374c794e
|
||||||
TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz
|
TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz
|
||||||
TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5
|
TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5
|
||||||
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.0.tar.gz
|
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.0.tar.gz
|
||||||
TREESITTER_VIMDOC_SHA256 a639bf92bf57bfa1cdc90ca16af27bfaf26a9779064776dd4be34c1ef1453f6c
|
TREESITTER_VIMDOC_SHA256 a639bf92bf57bfa1cdc90ca16af27bfaf26a9779064776dd4be34c1ef1453f6c
|
||||||
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz
|
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz
|
||||||
TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e
|
TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e
|
||||||
TREESITTER_MARKDOWN_URL https://github.com/MDeiml/tree-sitter-markdown/archive/v0.2.3.tar.gz
|
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.3.2.tar.gz
|
||||||
TREESITTER_MARKDOWN_SHA256 4909d6023643f1afc3ab219585d4035b7403f3a17849782ab803c5f73c8a31d5
|
TREESITTER_MARKDOWN_SHA256 5dac48a6d971eb545aab665d59a18180d21963afc781bbf40f9077c06cb82ae5
|
||||||
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.23.0.tar.gz
|
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.23.0.tar.gz
|
||||||
TREESITTER_SHA256 6403b361b0014999e96f61b9c84d6950d42f0c7d6e806be79382e0232e48a11b
|
TREESITTER_SHA256 6403b361b0014999e96f61b9c84d6950d42f0c7d6e806be79382e0232e48a11b
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -4,6 +4,8 @@ They are used with the ":compiler" command.
|
|||||||
These scripts usually set options, for example 'errorformat'.
|
These scripts usually set options, for example 'errorformat'.
|
||||||
See ":help write-compiler-plugin".
|
See ":help write-compiler-plugin".
|
||||||
|
|
||||||
|
To undo the effect of a compiler plugin, use the make compiler plugin.
|
||||||
|
|
||||||
If you want to write your own compiler plugin, have a look at the other files
|
If you want to write your own compiler plugin, have a look at the other files
|
||||||
for how to do it, the format is simple.
|
for how to do it, the format is simple.
|
||||||
|
|
||||||
|
45
runtime/compiler/groff.vim
Normal file
45
runtime/compiler/groff.vim
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
" Vim compiler file
|
||||||
|
" Compiler: Groff
|
||||||
|
" Maintainer: Konfekt
|
||||||
|
" Last Change: 2024 Sep 8
|
||||||
|
"
|
||||||
|
" Expects output file extension, say `:make html` or `:make pdf`.
|
||||||
|
" Supported devices as of Sept 2024 are: (x)html, pdf, ps, dvi, lj4, lbp ...
|
||||||
|
" Adjust command-line flags, language, encoding by buffer-local/global variables
|
||||||
|
" groff_compiler_args, groff_compiler_lang, and groff_compiler_encoding,
|
||||||
|
" which default to '', &spelllang and 'utf8'.
|
||||||
|
|
||||||
|
if exists("current_compiler")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:keepcpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
let current_compiler = 'groff'
|
||||||
|
|
||||||
|
silent! function s:groff_compiler_lang()
|
||||||
|
let lang = get(b:, 'groff_compiler_lang',
|
||||||
|
\ &spell ? matchstr(&spelllang, '^\a\a') : '')
|
||||||
|
if lang ==# 'en' | let lang = '' | endif
|
||||||
|
return empty(lang) ? '' : '-m'..lang
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Requires output format (= device) to be set by user after :make.
|
||||||
|
execute 'CompilerSet makeprg=groff'..escape(
|
||||||
|
\ ' '..s:groff_compiler_lang()..
|
||||||
|
\ ' -K'..get(b:, 'groff_compiler_encoding', get(g:, 'groff_compiler_encoding', 'utf8'))..
|
||||||
|
\ ' '..get(b:, 'groff_compiler_args', get(g:, 'groff_compiler_args', ''))..
|
||||||
|
\ ' -mom -T$* -- %:S > %:r:S.$*', ' ')
|
||||||
|
" From Gavin Freeborn's https://github.com/Gavinok/vim-troff under Vim License
|
||||||
|
" https://github.com/Gavinok/vim-troff/blob/91017b1423caa80aba541c997909a4f810edd275/compiler/troff.vim#L39
|
||||||
|
CompilerSet errorformat=%o:<standard\ input>\ (%f):%l:%m,
|
||||||
|
\%o:\ <standard\ input>\ (%f):%l:%m,
|
||||||
|
\%o:%f:%l:%m,
|
||||||
|
\%o:\ %f:%l:%m,
|
||||||
|
\%f:%l:\ macro\ %trror:%m,
|
||||||
|
\%f:%l:%m,
|
||||||
|
\%W%tarning:\ file\ '%f'\\,\ around\ line\ %l:,%Z%m
|
||||||
|
|
||||||
|
let &cpo = s:keepcpo
|
||||||
|
unlet s:keepcpo
|
13
runtime/compiler/make.vim
Normal file
13
runtime/compiler/make.vim
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
" Vim compiler plugin
|
||||||
|
"
|
||||||
|
" Maintainer: The Vim Project <https://github.com/vim/vim>
|
||||||
|
" Last Change: 2024 Sep 10
|
||||||
|
" Original Author: Konfekt
|
||||||
|
"
|
||||||
|
" This compiler plugin is used to reset previously set compiler options.
|
||||||
|
|
||||||
|
if exists("g:current_compiler") | unlet g:current_compiler | endif
|
||||||
|
if exists("b:current_compiler") | unlet b:current_compiler | endif
|
||||||
|
|
||||||
|
CompilerSet makeprg&
|
||||||
|
CompilerSet errorformat&
|
@ -1,10 +1,12 @@
|
|||||||
" Vim compiler file
|
" Vim compiler file
|
||||||
" Compiler: Pandoc
|
" Compiler: Pandoc
|
||||||
" Maintainer: Konfekt
|
" Maintainer: Konfekt
|
||||||
" Last Change: 2024 Aug 20
|
" Last Change: 2024 Sep 8
|
||||||
"
|
"
|
||||||
" Expects output file extension, say `:make html` or `:make pdf`.
|
" Expects output file extension, say `:make html` or `:make pdf`.
|
||||||
" Passes additional arguments to pandoc, say `:make html --self-contained`.
|
" Passes additional arguments to pandoc, say `:make html --self-contained`.
|
||||||
|
" Adjust command-line flags by buffer-local/global variable
|
||||||
|
" b/g:pandoc_compiler_args which defaults to empty.
|
||||||
|
|
||||||
if exists("current_compiler")
|
if exists("current_compiler")
|
||||||
finish
|
finish
|
||||||
@ -40,17 +42,20 @@ silent! function s:PandocFiletype(filetype) abort
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let b:pandoc_compiler_from = get(b:, 'pandoc_compiler_from', s:PandocFiletype(&filetype))
|
silent! function s:PandocLang()
|
||||||
let b:pandoc_compiler_lang = get(b:, 'pandoc_compiler_lang', &spell ? matchstr(&spelllang, '^\a\a') : '')
|
let lang = get(b:, 'pandoc_compiler_lang',
|
||||||
|
\ &spell ? matchstr(&spelllang, '^\a\a') : '')
|
||||||
|
if lang ==# 'en' | let lang = '' | endif
|
||||||
|
return empty(lang) ? '' : '--metadata lang='..lang
|
||||||
|
endfunction
|
||||||
|
|
||||||
execute 'CompilerSet makeprg=pandoc'..escape(
|
execute 'CompilerSet makeprg=pandoc'..escape(
|
||||||
\ ' --standalone' .
|
\ ' --standalone'..
|
||||||
\ (b:pandoc_compiler_from ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
|
\ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
|
||||||
\ '' : ' --metadata title=%:t:r:S') .
|
\ '' : ' --metadata title=%:t:r:S')..
|
||||||
\ (empty(b:pandoc_compiler_lang) ?
|
\ ' '..s:PandocLang()..
|
||||||
\ '' : ' --metadata lang='..b:pandoc_compiler_lang) .
|
\ ' --from='..s:PandocFiletype(&filetype)..
|
||||||
\ ' --from='..b:pandoc_compiler_from .
|
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', ''))..
|
||||||
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', '')) .
|
|
||||||
\ ' --output %:r:S.$* -- %:S', ' ')
|
\ ' --output %:r:S.$* -- %:S', ' ')
|
||||||
CompilerSet errorformat=\"%f\",\ line\ %l:\ %m
|
CompilerSet errorformat=\"%f\",\ line\ %l:\ %m
|
||||||
|
|
||||||
|
3
runtime/doc/builtin.txt
generated
3
runtime/doc/builtin.txt
generated
@ -6201,6 +6201,9 @@ search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) *search()*
|
|||||||
The value must not be negative. A zero value is like not
|
The value must not be negative. A zero value is like not
|
||||||
giving the argument.
|
giving the argument.
|
||||||
|
|
||||||
|
Note: the timeout is only considered when searching, not
|
||||||
|
while evaluating the {skip} expression.
|
||||||
|
|
||||||
If the {skip} expression is given it is evaluated with the
|
If the {skip} expression is given it is evaluated with the
|
||||||
cursor positioned on the start of a match. If it evaluates to
|
cursor positioned on the start of a match. If it evaluates to
|
||||||
non-zero this match is skipped. This can be used, for
|
non-zero this match is skipped. This can be used, for
|
||||||
|
@ -2230,6 +2230,12 @@ vim.tbl_count({t}) *vim.tbl_count()*
|
|||||||
vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()*
|
vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()*
|
||||||
Merges recursively two or more tables.
|
Merges recursively two or more tables.
|
||||||
|
|
||||||
|
Only values that are empty tables or tables that are not |lua-list|s
|
||||||
|
(indexed by consecutive integers starting from 1) are merged recursively.
|
||||||
|
This is useful for merging nested tables like default and user
|
||||||
|
configurations where lists should be treated as literals (i.e., are
|
||||||
|
overwritten instead of merged).
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {behavior} (`'error'|'keep'|'force'`) Decides what to do if a key is
|
• {behavior} (`'error'|'keep'|'force'`) Decides what to do if a key is
|
||||||
found in more than one map:
|
found in more than one map:
|
||||||
@ -2553,7 +2559,7 @@ vim.ui.input({opts}, {on_confirm}) *vim.ui.input()*
|
|||||||
typed (it might be an empty string if nothing was
|
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.
|
||||||
@ -2564,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
|
||||||
@ -2573,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.
|
||||||
|
@ -189,11 +189,15 @@ TREESITTER
|
|||||||
|
|
||||||
TUI
|
TUI
|
||||||
|
|
||||||
• TODO
|
• |log| messages written by the builtin UI client (TUI, |--remote-ui|) are
|
||||||
|
now prefixed with "ui" instead of "?".
|
||||||
|
|
||||||
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*
|
||||||
@ -214,9 +218,6 @@ These existing features changed their behavior.
|
|||||||
more emoji characters than before, including those encoded with multiple
|
more emoji characters than before, including those encoded with multiple
|
||||||
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
|
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
|
||||||
|
|
||||||
• |vim.tbl_deep_extend()| no longer ignores any values for which |vim.isarray()|
|
|
||||||
returns `true`.
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
REMOVED FEATURES *news-removed*
|
REMOVED FEATURES *news-removed*
|
||||||
|
|
||||||
|
@ -1129,9 +1129,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
list:{n} Adds an additional indent for lines that match a
|
list:{n} Adds an additional indent for lines that match a
|
||||||
numbered or bulleted list (using the
|
numbered or bulleted list (using the
|
||||||
'formatlistpat' setting).
|
'formatlistpat' setting).
|
||||||
list:-1 Uses the length of a match with 'formatlistpat'
|
|
||||||
for indentation.
|
|
||||||
(default: 0)
|
(default: 0)
|
||||||
|
list:-1 Uses the width of a match with 'formatlistpat' for
|
||||||
|
indentation.
|
||||||
column:{n} Indent at column {n}. Will overrule the other
|
column:{n} Indent at column {n}. Will overrule the other
|
||||||
sub-options. Note: an additional indent may be
|
sub-options. Note: an additional indent may be
|
||||||
added for the 'showbreak' setting.
|
added for the 'showbreak' setting.
|
||||||
@ -6713,7 +6713,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
global
|
global
|
||||||
When on, the title of the window will be set to the value of
|
When on, the title of the window will be set to the value of
|
||||||
'titlestring' (if it is not empty), or to:
|
'titlestring' (if it is not empty), or to:
|
||||||
filename [+=-] (path) - NVIM
|
filename [+=-] (path) - Nvim
|
||||||
Where:
|
Where:
|
||||||
filename the name of the file being edited
|
filename the name of the file being edited
|
||||||
- indicates the file cannot be modified, 'ma' off
|
- indicates the file cannot be modified, 'ma' off
|
||||||
@ -6721,7 +6721,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
= indicates the file is read-only
|
= indicates the file is read-only
|
||||||
=+ indicates the file is read-only and modified
|
=+ indicates the file is read-only and modified
|
||||||
(path) is the path of the file being edited
|
(path) is the path of the file being edited
|
||||||
- NVIM the server name |v:servername| or "NVIM"
|
- Nvim the server name |v:servername| or "Nvim"
|
||||||
|
|
||||||
*'titlelen'*
|
*'titlelen'*
|
||||||
'titlelen' number (default 85)
|
'titlelen' number (default 85)
|
||||||
|
@ -1262,6 +1262,7 @@ not "b:current_compiler". What the command actually does is the following:
|
|||||||
|
|
||||||
For writing a compiler plugin, see |write-compiler-plugin|.
|
For writing a compiler plugin, see |write-compiler-plugin|.
|
||||||
|
|
||||||
|
Use the |compiler-make| plugin to undo the effect of a compiler plugin.
|
||||||
|
|
||||||
DOTNET *compiler-dotnet*
|
DOTNET *compiler-dotnet*
|
||||||
|
|
||||||
@ -1277,7 +1278,6 @@ Example: limit output to only display errors, and suppress the project name: >
|
|||||||
let dotnet_show_project_file = v:false
|
let dotnet_show_project_file = v:false
|
||||||
compiler dotnet
|
compiler dotnet
|
||||||
<
|
<
|
||||||
|
|
||||||
GCC *quickfix-gcc* *compiler-gcc*
|
GCC *quickfix-gcc* *compiler-gcc*
|
||||||
|
|
||||||
There's one variable you can set for the GCC compiler:
|
There's one variable you can set for the GCC compiler:
|
||||||
@ -1294,6 +1294,24 @@ Commonly used compiler options can be added to 'makeprg' by setting the
|
|||||||
g:javac_makeprg_params variable. For example: >
|
g:javac_makeprg_params variable. For example: >
|
||||||
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
|
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
|
||||||
<
|
<
|
||||||
|
GNU MAKE *compiler-make*
|
||||||
|
|
||||||
|
Since the default make program is "make", the compiler plugin for make,
|
||||||
|
:compiler make, will reset the 'makeprg' and 'errorformat' option to
|
||||||
|
the default values and unlet any variables that may have been set by a
|
||||||
|
previous compiler plugin.
|
||||||
|
|
||||||
|
GROFF *quickfix-groff* *compiler-groff*
|
||||||
|
|
||||||
|
The GROFF compiler plugin uses the mom macro set (documented in the groff_mom
|
||||||
|
manpage) as input and expects that the output file type extension is passed to
|
||||||
|
make, say :make html or :make pdf.
|
||||||
|
|
||||||
|
Additional arguments can be passed to groff by setting them in
|
||||||
|
`b:groff_compiler_args` or `g:groff_compiler_args`. The `language` argument
|
||||||
|
passed to groff is set using 'spelllang'; it can be overridden by setting
|
||||||
|
`b:groff_compiler_lang`. The default enconding is `UTF-8` and can be changed
|
||||||
|
by setting `b:groff_compiler_encoding` or `g:groff_compiler_encoding`.
|
||||||
|
|
||||||
PANDOC *quickfix-pandoc* *compiler-pandoc*
|
PANDOC *quickfix-pandoc* *compiler-pandoc*
|
||||||
|
|
||||||
@ -1307,8 +1325,7 @@ Additional arguments can be passed to pandoc:
|
|||||||
|
|
||||||
The `--from` argument is an educated guess using the buffer file type;
|
The `--from` argument is an educated guess using the buffer file type;
|
||||||
it can be overridden by setting `b:pandoc_compiler_from`.
|
it can be overridden by setting `b:pandoc_compiler_from`.
|
||||||
Likewise the `--metadata lang` argument is set using `&spelllang`;
|
The `--metadata lang` argument is set using 'spelllang';
|
||||||
it can be overridden by setting `b:pandoc_compiler_lang`.
|
|
||||||
If `--from=markdown` is assumed and no title set in a title header or
|
If `--from=markdown` is assumed and no title set in a title header or
|
||||||
YAML block, then the filename (without extension) is used as the title.
|
YAML block, then the filename (without extension) is used as the title.
|
||||||
|
|
||||||
|
@ -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: >
|
||||||
|
@ -53,11 +53,17 @@ active yes yes 'a'
|
|||||||
hidden no yes 'h'
|
hidden no yes 'h'
|
||||||
inactive no no ' '
|
inactive no no ' '
|
||||||
|
|
||||||
Note: All CTRL-W commands can also be executed with |:wincmd|, for those
|
*buffer-reuse*
|
||||||
places where a Normal mode command can't be used or is inconvenient.
|
Each buffer has a unique number and the number will not change within a Vim
|
||||||
|
session. The |bufnr()| and |bufname()| functions can be used to convert
|
||||||
|
between a buffer name and the buffer number. There is one exception: if a new
|
||||||
|
empty buffer is created and it is not modified, the buffer will be re-used
|
||||||
|
when loading another file into that buffer. This also means the buffer number
|
||||||
|
will not change.
|
||||||
|
|
||||||
The main Vim window can hold several split windows. There are also tab pages
|
The main Vim window can hold several split windows. There are also tab pages
|
||||||
|tab-page|, each of which can hold multiple windows.
|
|tab-page|, each of which can hold multiple windows.
|
||||||
|
|
||||||
*window-ID* *winid* *windowid*
|
*window-ID* *winid* *windowid*
|
||||||
Each window has a unique identifier called the window ID. This identifier
|
Each window has a unique identifier called the window ID. This identifier
|
||||||
will not change within a Vim session. The |win_getid()| and |win_id2tabwin()|
|
will not change within a Vim session. The |win_getid()| and |win_id2tabwin()|
|
||||||
@ -69,9 +75,6 @@ across tabs. For most functions that take a window ID or a window number, the
|
|||||||
window number only applies to the current tab, while the window ID can refer
|
window number only applies to the current tab, while the window ID can refer
|
||||||
to a window in any tab.
|
to a window in any tab.
|
||||||
|
|
||||||
Each buffer has a unique number and the number will not change within a Vim
|
|
||||||
session. The |bufnr()| and |bufname()| functions can be used to convert
|
|
||||||
between a buffer name and the buffer number.
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
2. Starting Vim *windows-starting*
|
2. Starting Vim *windows-starting*
|
||||||
@ -468,6 +471,10 @@ These commands can also be executed with ":wincmd":
|
|||||||
:exe nr .. "wincmd w"
|
:exe nr .. "wincmd w"
|
||||||
< This goes to window "nr".
|
< This goes to window "nr".
|
||||||
|
|
||||||
|
Note: All CTRL-W commands can also be executed with |:wincmd|, for those
|
||||||
|
places where a Normal mode command can't be used or is inconvenient (e.g.
|
||||||
|
in a browser-based terminal).
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
5. Moving windows around *window-moving*
|
5. Moving windows around *window-moving*
|
||||||
|
|
||||||
|
3
runtime/ftplugin/dot.lua
Normal file
3
runtime/ftplugin/dot.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vim.bo.commentstring = '// %s'
|
||||||
|
|
||||||
|
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'
|
3
runtime/ftplugin/faust.lua
Normal file
3
runtime/ftplugin/faust.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vim.bo.commentstring = '// %s'
|
||||||
|
|
||||||
|
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'
|
@ -2,8 +2,9 @@
|
|||||||
" Filename: spec.vim
|
" Filename: spec.vim
|
||||||
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
|
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
|
||||||
" Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014)
|
" Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014)
|
||||||
" Last Change: Mon Jun 01 21:15 MSK 2015 Igor Gnatenko
|
" Last Change: 2015 Jun 01
|
||||||
" Update by Zdenek Dohnal, 2022 May 17
|
" Update by Zdenek Dohnal, 2022 May 17
|
||||||
|
" 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537
|
||||||
|
|
||||||
if exists("b:did_ftplugin")
|
if exists("b:did_ftplugin")
|
||||||
finish
|
finish
|
||||||
@ -66,9 +67,11 @@ if !exists("*s:SpecChangelog")
|
|||||||
endif
|
endif
|
||||||
let line = 0
|
let line = 0
|
||||||
let name = ""
|
let name = ""
|
||||||
|
let epoch = ""
|
||||||
let ver = ""
|
let ver = ""
|
||||||
let rel = ""
|
let rel = ""
|
||||||
let nameline = -1
|
let nameline = -1
|
||||||
|
let epochline = -1
|
||||||
let verline = -1
|
let verline = -1
|
||||||
let relline = -1
|
let relline = -1
|
||||||
let chgline = -1
|
let chgline = -1
|
||||||
@ -77,6 +80,9 @@ if !exists("*s:SpecChangelog")
|
|||||||
if name == "" && linestr =~? '^Name:'
|
if name == "" && linestr =~? '^Name:'
|
||||||
let nameline = line
|
let nameline = line
|
||||||
let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
||||||
|
elseif epoch == "" && linestr =~? '^Epoch:'
|
||||||
|
let epochline = line
|
||||||
|
let epoch = substitute(strpart(linestr,6), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
||||||
elseif ver == "" && linestr =~? '^Version:'
|
elseif ver == "" && linestr =~? '^Version:'
|
||||||
let verline = line
|
let verline = line
|
||||||
let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
||||||
@ -93,6 +99,7 @@ if !exists("*s:SpecChangelog")
|
|||||||
if nameline != -1 && verline != -1 && relline != -1
|
if nameline != -1 && verline != -1 && relline != -1
|
||||||
let include_release_info = exists("g:spec_chglog_release_info")
|
let include_release_info = exists("g:spec_chglog_release_info")
|
||||||
let name = s:ParseRpmVars(name, nameline)
|
let name = s:ParseRpmVars(name, nameline)
|
||||||
|
let epoch = s:ParseRpmVars(epoch, epochline)
|
||||||
let ver = s:ParseRpmVars(ver, verline)
|
let ver = s:ParseRpmVars(ver, verline)
|
||||||
let rel = s:ParseRpmVars(rel, relline)
|
let rel = s:ParseRpmVars(rel, relline)
|
||||||
else
|
else
|
||||||
@ -117,6 +124,9 @@ if !exists("*s:SpecChangelog")
|
|||||||
if chgline != -1
|
if chgline != -1
|
||||||
let tmptime = v:lc_time
|
let tmptime = v:lc_time
|
||||||
language time C
|
language time C
|
||||||
|
if strlen(epoch)
|
||||||
|
let ver = epoch.":".ver
|
||||||
|
endif
|
||||||
let parsed_format = "* ".strftime(format)." - ".ver."-".rel
|
let parsed_format = "* ".strftime(format)." - ".ver."-".rel
|
||||||
execute "language time" tmptime
|
execute "language time" tmptime
|
||||||
let release_info = "+ ".name."-".ver."-".rel
|
let release_info = "+ ".name."-".ver."-".rel
|
||||||
|
3
runtime/ftplugin/stata.lua
Normal file
3
runtime/ftplugin/stata.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vim.bo.commentstring = '// %s'
|
||||||
|
|
||||||
|
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'
|
3
runtime/ftplugin/supercollider.lua
Normal file
3
runtime/ftplugin/supercollider.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vim.bo.commentstring = '// %s'
|
||||||
|
|
||||||
|
vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<'
|
3
runtime/ftplugin/swift.lua
Normal file
3
runtime/ftplugin/swift.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vim.bo.commentstring = '// %s'
|
||||||
|
|
||||||
|
vim.b.undo_ftplugin = vim.b.undo_ftplugin .. ' | setl commentstring<'
|
@ -1293,9 +1293,25 @@ local function opt_to_global_state(opt, title)
|
|||||||
local fonts = {}
|
local fonts = {}
|
||||||
if opt.font then
|
if opt.font then
|
||||||
fonts = type(opt.font) == 'string' and { opt.font } or opt.font --[[@as (string[])]]
|
fonts = type(opt.font) == 'string' and { opt.font } or opt.font --[[@as (string[])]]
|
||||||
elseif vim.o.guifont:match('^[^:]+') then
|
for i, v in pairs(fonts) do
|
||||||
table.insert(fonts, vim.o.guifont:match('^[^:]+'))
|
fonts[i] = ('"%s"'):format(v)
|
||||||
end
|
end
|
||||||
|
elseif vim.o.guifont:match('^[^:]+') then
|
||||||
|
-- Example:
|
||||||
|
-- Input: "Font,Escape\,comma, Ignore space after comma"
|
||||||
|
-- Output: { "Font","Escape,comma","Ignore space after comma" }
|
||||||
|
local prev = ''
|
||||||
|
for name in vim.gsplit(vim.o.guifont:match('^[^:]+'), ',', { trimempty = true }) do
|
||||||
|
if vim.endswith(name, '\\') then
|
||||||
|
prev = prev .. vim.trim(name:sub(1, -2) .. ',')
|
||||||
|
elseif vim.trim(name) ~= '' then
|
||||||
|
table.insert(fonts, ('"%s%s"'):format(prev, vim.trim(name)))
|
||||||
|
prev = ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Generic family names (monospace here) must not be quoted
|
||||||
|
-- because the browser recognizes them as font families.
|
||||||
table.insert(fonts, 'monospace')
|
table.insert(fonts, 'monospace')
|
||||||
--- @type vim.tohtml.state.global
|
--- @type vim.tohtml.state.global
|
||||||
local state = {
|
local state = {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -97,37 +97,13 @@ do
|
|||||||
|
|
||||||
--- Map |gx| to call |vim.ui.open| on the <cfile> at cursor.
|
--- Map |gx| to call |vim.ui.open| on the <cfile> at cursor.
|
||||||
do
|
do
|
||||||
local function do_open(uri)
|
|
||||||
local cmd, err = vim.ui.open(uri)
|
|
||||||
local rv = cmd and cmd:wait(1000) or nil
|
|
||||||
if cmd and rv and rv.code ~= 0 then
|
|
||||||
err = ('vim.ui.open: command %s (%d): %s'):format(
|
|
||||||
(rv.code == 124 and 'timeout' or 'failed'),
|
|
||||||
rv.code,
|
|
||||||
vim.inspect(cmd.cmd)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
return err
|
|
||||||
end
|
|
||||||
|
|
||||||
local gx_desc =
|
local gx_desc =
|
||||||
'Opens filepath or URI under cursor with the system handler (file explorer, web browser, …)'
|
'Opens filepath or URI under cursor with the system handler (file explorer, web browser, …)'
|
||||||
vim.keymap.set({ 'n' }, 'gx', function()
|
vim.keymap.set({ 'n' }, 'gx', function()
|
||||||
for _, url in ipairs(require('vim.ui')._get_urls()) do
|
vim.ui.open()
|
||||||
local err = do_open(url)
|
|
||||||
if err then
|
|
||||||
vim.notify(err, vim.log.levels.ERROR)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end, { desc = gx_desc })
|
end, { desc = gx_desc })
|
||||||
vim.keymap.set({ 'x' }, 'gx', function()
|
vim.keymap.set({ 'x' }, 'gx', function()
|
||||||
local lines =
|
vim.ui.open()
|
||||||
vim.fn.getregion(vim.fn.getpos('.'), vim.fn.getpos('v'), { type = vim.fn.mode() })
|
|
||||||
-- Trim whitespace on each line and concatenate.
|
|
||||||
local err = do_open(table.concat(vim.iter(lines):map(vim.trim):totable()))
|
|
||||||
if err then
|
|
||||||
vim.notify(err, vim.log.levels.ERROR)
|
|
||||||
end
|
|
||||||
end, { desc = gx_desc })
|
end, { desc = gx_desc })
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -213,7 +189,6 @@ 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
|
||||||
@ -229,7 +204,10 @@ do
|
|||||||
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 +218,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 +229,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
|
||||||
|
8
runtime/lua/vim/_meta/options.lua
generated
8
runtime/lua/vim/_meta/options.lua
generated
@ -558,9 +558,9 @@ vim.wo.bri = vim.wo.breakindent
|
|||||||
--- list:{n} Adds an additional indent for lines that match a
|
--- list:{n} Adds an additional indent for lines that match a
|
||||||
--- numbered or bulleted list (using the
|
--- numbered or bulleted list (using the
|
||||||
--- 'formatlistpat' setting).
|
--- 'formatlistpat' setting).
|
||||||
--- list:-1 Uses the length of a match with 'formatlistpat'
|
|
||||||
--- for indentation.
|
|
||||||
--- (default: 0)
|
--- (default: 0)
|
||||||
|
--- list:-1 Uses the width of a match with 'formatlistpat' for
|
||||||
|
--- indentation.
|
||||||
--- column:{n} Indent at column {n}. Will overrule the other
|
--- column:{n} Indent at column {n}. Will overrule the other
|
||||||
--- sub-options. Note: an additional indent may be
|
--- sub-options. Note: an additional indent may be
|
||||||
--- added for the 'showbreak' setting.
|
--- added for the 'showbreak' setting.
|
||||||
@ -7255,7 +7255,7 @@ vim.go.tm = vim.go.timeoutlen
|
|||||||
|
|
||||||
--- When on, the title of the window will be set to the value of
|
--- When on, the title of the window will be set to the value of
|
||||||
--- 'titlestring' (if it is not empty), or to:
|
--- 'titlestring' (if it is not empty), or to:
|
||||||
--- filename [+=-] (path) - NVIM
|
--- filename [+=-] (path) - Nvim
|
||||||
--- Where:
|
--- Where:
|
||||||
--- filename the name of the file being edited
|
--- filename the name of the file being edited
|
||||||
--- - indicates the file cannot be modified, 'ma' off
|
--- - indicates the file cannot be modified, 'ma' off
|
||||||
@ -7263,7 +7263,7 @@ vim.go.tm = vim.go.timeoutlen
|
|||||||
--- = indicates the file is read-only
|
--- = indicates the file is read-only
|
||||||
--- =+ indicates the file is read-only and modified
|
--- =+ indicates the file is read-only and modified
|
||||||
--- (path) is the path of the file being edited
|
--- (path) is the path of the file being edited
|
||||||
--- - NVIM the server name `v:servername` or "NVIM"
|
--- - Nvim the server name `v:servername` or "Nvim"
|
||||||
---
|
---
|
||||||
--- @type boolean
|
--- @type boolean
|
||||||
vim.o.title = false
|
vim.o.title = false
|
||||||
|
17
runtime/lua/vim/_meta/vimfn.lua
generated
17
runtime/lua/vim/_meta/vimfn.lua
generated
@ -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
|
||||||
|
|
||||||
@ -7421,6 +7421,9 @@ function vim.fn.screenstring(row, col) end
|
|||||||
--- The value must not be negative. A zero value is like not
|
--- The value must not be negative. A zero value is like not
|
||||||
--- giving the argument.
|
--- giving the argument.
|
||||||
---
|
---
|
||||||
|
--- Note: the timeout is only considered when searching, not
|
||||||
|
--- while evaluating the {skip} expression.
|
||||||
|
---
|
||||||
--- If the {skip} expression is given it is evaluated with the
|
--- If the {skip} expression is given it is evaluated with the
|
||||||
--- cursor positioned on the start of a match. If it evaluates to
|
--- cursor positioned on the start of a match. If it evaluates to
|
||||||
--- non-zero this match is skipped. This can be used, for
|
--- non-zero this match is skipped. This can be used, for
|
||||||
|
@ -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',
|
||||||
@ -1164,15 +1129,11 @@ local extension = {
|
|||||||
svelte = 'svelte',
|
svelte = 'svelte',
|
||||||
svg = 'svg',
|
svg = 'svg',
|
||||||
swift = 'swift',
|
swift = 'swift',
|
||||||
|
swiftinterface = 'swift',
|
||||||
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',
|
||||||
|
@ -285,8 +285,8 @@ local path2name = function(path)
|
|||||||
-- Remove everything up to the last /lua/ folder
|
-- Remove everything up to the last /lua/ folder
|
||||||
path = path:gsub('^.*/lua/', '')
|
path = path:gsub('^.*/lua/', '')
|
||||||
|
|
||||||
-- Remove the filename (health.lua)
|
-- Remove the filename (health.lua) or (health/init.lua)
|
||||||
path = vim.fs.dirname(path)
|
path = vim.fs.dirname(path:gsub('/init%.lua$', ''))
|
||||||
|
|
||||||
-- Change slashes to dots
|
-- Change slashes to dots
|
||||||
path = path:gsub('/', '.')
|
path = path:gsub('/', '.')
|
||||||
|
@ -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
|
||||||
|
@ -43,17 +43,16 @@ function M.on_inlayhint(err, result, ctx, _)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
local bufnr = assert(ctx.bufnr)
|
local bufnr = assert(ctx.bufnr)
|
||||||
if util.buf_versions[bufnr] ~= ctx.version then
|
if
|
||||||
|
util.buf_versions[bufnr] ~= ctx.version
|
||||||
|
or not result
|
||||||
|
or not api.nvim_buf_is_loaded(bufnr)
|
||||||
|
or not bufstates[bufnr].enabled
|
||||||
|
then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local client_id = ctx.client_id
|
local client_id = ctx.client_id
|
||||||
if not result then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local bufstate = bufstates[bufnr]
|
local bufstate = bufstates[bufnr]
|
||||||
if not bufstate.enabled then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not (bufstate.client_hints and bufstate.version) then
|
if not (bufstate.client_hints and bufstate.version) then
|
||||||
bufstate.client_hints = vim.defaulttable()
|
bufstate.client_hints = vim.defaulttable()
|
||||||
bufstate.version = ctx.version
|
bufstate.version = ctx.version
|
||||||
@ -77,12 +76,7 @@ function M.on_inlayhint(err, result, ctx, _)
|
|||||||
local col = position.character
|
local col = position.character
|
||||||
if col > 0 then
|
if col > 0 then
|
||||||
local line = lines[position.line + 1] or ''
|
local line = lines[position.line + 1] or ''
|
||||||
local ok, convert_result
|
return util._str_byteindex_enc(line, col, client.offset_encoding)
|
||||||
ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding)
|
|
||||||
if ok then
|
|
||||||
return convert_result
|
|
||||||
end
|
|
||||||
return math.min(#line, col)
|
|
||||||
end
|
end
|
||||||
return col
|
return col
|
||||||
end
|
end
|
||||||
|
@ -140,12 +140,7 @@ local function tokens_to_ranges(data, bufnr, client, request)
|
|||||||
local function _get_byte_pos(col)
|
local function _get_byte_pos(col)
|
||||||
if col > 0 then
|
if col > 0 then
|
||||||
local buf_line = lines[line + 1] or ''
|
local buf_line = lines[line + 1] or ''
|
||||||
local ok, result
|
return util._str_byteindex_enc(buf_line, col, client.offset_encoding)
|
||||||
ok, result = pcall(util._str_byteindex_enc, buf_line, col, client.offset_encoding)
|
|
||||||
if ok then
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
return math.min(#buf_line, col)
|
|
||||||
end
|
end
|
||||||
return col
|
return col
|
||||||
end
|
end
|
||||||
|
@ -119,6 +119,7 @@ end
|
|||||||
---@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
|
---@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
|
||||||
---@return integer `encoding` index of `index` in `line`
|
---@return integer `encoding` index of `index` in `line`
|
||||||
function M._str_utfindex_enc(line, index, encoding)
|
function M._str_utfindex_enc(line, index, encoding)
|
||||||
|
local len32, len16 = vim.str_utfindex(line)
|
||||||
if not encoding then
|
if not encoding then
|
||||||
encoding = 'utf-16'
|
encoding = 'utf-16'
|
||||||
end
|
end
|
||||||
@ -129,9 +130,15 @@ function M._str_utfindex_enc(line, index, encoding)
|
|||||||
return #line
|
return #line
|
||||||
end
|
end
|
||||||
elseif encoding == 'utf-16' then
|
elseif encoding == 'utf-16' then
|
||||||
|
if not index or index > len16 then
|
||||||
|
return len16
|
||||||
|
end
|
||||||
local _, col16 = vim.str_utfindex(line, index)
|
local _, col16 = vim.str_utfindex(line, index)
|
||||||
return col16
|
return col16
|
||||||
elseif encoding == 'utf-32' then
|
elseif encoding == 'utf-32' then
|
||||||
|
if not index or index > len32 then
|
||||||
|
return len32
|
||||||
|
end
|
||||||
local col32, _ = vim.str_utfindex(line, index)
|
local col32, _ = vim.str_utfindex(line, index)
|
||||||
return col32
|
return col32
|
||||||
else
|
else
|
||||||
@ -147,6 +154,12 @@ 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 = #line
|
||||||
|
if index > len then
|
||||||
|
-- LSP spec: if character > line length, default to the line length.
|
||||||
|
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
|
||||||
|
return len
|
||||||
|
end
|
||||||
if not encoding then
|
if not encoding then
|
||||||
encoding = 'utf-16'
|
encoding = 'utf-16'
|
||||||
end
|
end
|
||||||
@ -154,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)
|
||||||
@ -165,9 +178,6 @@ function M._str_byteindex_enc(line, index, encoding)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local _str_utfindex_enc = M._str_utfindex_enc
|
|
||||||
local _str_byteindex_enc = M._str_byteindex_enc
|
|
||||||
|
|
||||||
--- Replaces text in a range with new text.
|
--- Replaces text in a range with new text.
|
||||||
---
|
---
|
||||||
--- CAUTION: Changes in-place!
|
--- CAUTION: Changes in-place!
|
||||||
@ -334,12 +344,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
|
|||||||
-- character
|
-- character
|
||||||
if col > 0 then
|
if col > 0 then
|
||||||
local line = get_line(bufnr, position.line) or ''
|
local line = get_line(bufnr, position.line) or ''
|
||||||
local ok, result
|
return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16')
|
||||||
ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding)
|
|
||||||
if ok then
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
return math.min(#line, col)
|
|
||||||
end
|
end
|
||||||
return col
|
return col
|
||||||
end
|
end
|
||||||
@ -436,14 +441,15 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
|
|||||||
e.end_col = last_line_len
|
e.end_col = last_line_len
|
||||||
has_eol_text_edit = true
|
has_eol_text_edit = true
|
||||||
else
|
else
|
||||||
-- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
|
-- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length and the
|
||||||
-- replacement text ends with a newline We can likely assume that the replacement is assumed
|
-- replacement text ends with a newline We can likely assume that the replacement is assumed
|
||||||
-- to be meant to replace the newline with another newline and we need to make sure this
|
-- to be meant to replace the newline with another newline and we need to make sure this
|
||||||
-- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
|
-- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
|
||||||
-- in the file some servers (clangd on windows) will include that character in the line
|
-- in the file some servers (clangd on windows) will include that character in the line
|
||||||
-- while nvim_buf_set_text doesn't count it as part of the line.
|
-- while nvim_buf_set_text doesn't count it as part of the line.
|
||||||
if
|
if
|
||||||
e.end_col > last_line_len
|
e.end_col >= last_line_len
|
||||||
|
and text_edit.range['end'].character > e.end_col
|
||||||
and #text_edit.newText > 0
|
and #text_edit.newText > 0
|
||||||
and string.sub(text_edit.newText, -1) == '\n'
|
and string.sub(text_edit.newText, -1) == '\n'
|
||||||
then
|
then
|
||||||
@ -1795,17 +1801,9 @@ function M.locations_to_items(locations, offset_encoding)
|
|||||||
local row = pos.line
|
local row = pos.line
|
||||||
local end_row = end_pos.line
|
local end_row = end_pos.line
|
||||||
local line = lines[row] or ''
|
local line = lines[row] or ''
|
||||||
local line_len = vim.fn.strcharlen(line)
|
|
||||||
local end_line = lines[end_row] or ''
|
local end_line = lines[end_row] or ''
|
||||||
local end_line_len = vim.fn.strcharlen(end_line)
|
local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
|
||||||
-- LSP spec: if character > line length, default to the line length.
|
local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
|
||||||
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
|
|
||||||
local col = pos.character <= line_len
|
|
||||||
and M._str_byteindex_enc(line, pos.character, offset_encoding)
|
|
||||||
or line_len
|
|
||||||
local end_col = end_pos.character <= end_line_len
|
|
||||||
and M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
|
|
||||||
or end_line_len
|
|
||||||
|
|
||||||
table.insert(items, {
|
table.insert(items, {
|
||||||
filename = filename,
|
filename = filename,
|
||||||
@ -1935,7 +1933,7 @@ local function make_position_param(window, offset_encoding)
|
|||||||
return { line = 0, character = 0 }
|
return { line = 0, character = 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
col = _str_utfindex_enc(line, col, offset_encoding)
|
col = M._str_utfindex_enc(line, col, offset_encoding)
|
||||||
|
|
||||||
return { line = row, character = col }
|
return { line = row, character = col }
|
||||||
end
|
end
|
||||||
@ -2117,11 +2115,7 @@ function M.character_offset(buf, row, col, offset_encoding)
|
|||||||
)
|
)
|
||||||
offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding
|
offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding
|
||||||
end
|
end
|
||||||
-- If the col is past the EOL, use the line length.
|
return M._str_utfindex_enc(line, col, offset_encoding)
|
||||||
if col > #line then
|
|
||||||
return _str_utfindex_enc(line, nil, offset_encoding)
|
|
||||||
end
|
|
||||||
return _str_utfindex_enc(line, col, offset_encoding)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Helper function to return nested values in language server settings
|
--- Helper function to return nested values in language server settings
|
||||||
|
@ -354,6 +354,12 @@ function vim.tbl_isempty(t)
|
|||||||
return next(t) == nil
|
return next(t) == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- We only merge empty tables or tables that are not list-like (indexed by consecutive integers
|
||||||
|
--- starting from 1)
|
||||||
|
local function can_merge(v)
|
||||||
|
return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.islist(v))
|
||||||
|
end
|
||||||
|
|
||||||
--- Recursive worker for tbl_extend
|
--- Recursive worker for tbl_extend
|
||||||
--- @param behavior 'error'|'keep'|'force'
|
--- @param behavior 'error'|'keep'|'force'
|
||||||
--- @param deep_extend boolean
|
--- @param deep_extend boolean
|
||||||
@ -368,7 +374,7 @@ local function tbl_extend_rec(behavior, deep_extend, ...)
|
|||||||
local tbl = select(i, ...) --[[@as table<any,any>]]
|
local tbl = select(i, ...) --[[@as table<any,any>]]
|
||||||
if tbl then
|
if tbl then
|
||||||
for k, v in pairs(tbl) do
|
for k, v in pairs(tbl) do
|
||||||
if deep_extend and type(v) == 'table' and type(ret[k]) == 'table' then
|
if deep_extend and can_merge(v) and can_merge(ret[k]) then
|
||||||
ret[k] = tbl_extend_rec(behavior, true, ret[k], v)
|
ret[k] = tbl_extend_rec(behavior, true, ret[k], v)
|
||||||
elseif behavior ~= 'force' and ret[k] ~= nil then
|
elseif behavior ~= 'force' and ret[k] ~= nil then
|
||||||
if behavior == 'error' then
|
if behavior == 'error' then
|
||||||
@ -421,6 +427,11 @@ end
|
|||||||
|
|
||||||
--- Merges recursively two or more tables.
|
--- Merges recursively two or more tables.
|
||||||
---
|
---
|
||||||
|
--- Only values that are empty tables or tables that are not |lua-list|s (indexed by consecutive
|
||||||
|
--- integers starting from 1) are merged recursively. This is useful for merging nested tables
|
||||||
|
--- like default and user configurations where lists should be treated as literals (i.e., are
|
||||||
|
--- overwritten instead of merged).
|
||||||
|
---
|
||||||
---@see |vim.tbl_extend()|
|
---@see |vim.tbl_extend()|
|
||||||
---
|
---
|
||||||
---@generic T1: table
|
---@generic T1: table
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
@ -124,47 +126,89 @@ end
|
|||||||
--- end
|
--- end
|
||||||
--- ```
|
--- ```
|
||||||
---
|
---
|
||||||
---@param path string Path or URL to open
|
---@param path? string Path or URL to open, or `nil` to get path or URL at cursor.
|
||||||
|
---@param opt? { cmd?: string[] } Options
|
||||||
|
--- - cmd string[]|nil Command used to open the path or URL.
|
||||||
---
|
---
|
||||||
---@return vim.SystemObj|nil # Command object, or nil if not found.
|
---@return 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', true },
|
||||||
})
|
})
|
||||||
local is_uri = path:match('%w+:')
|
|
||||||
if not is_uri then
|
|
||||||
path = vim.fs.normalize(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
local cmd --- @type string[]
|
opt = opt or {}
|
||||||
local opts --- @type vim.SystemOpts
|
local function do_open(uri)
|
||||||
|
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[] ]], { uri })
|
||||||
if vim.fn.has('mac') == 1 then
|
elseif vim.fn.has('mac') == 1 then
|
||||||
cmd = { 'open', path }
|
cmd = { 'open', uri }
|
||||||
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
|
||||||
cmd = { 'rundll32', 'url.dll,FileProtocolHandler', path }
|
cmd = { 'rundll32', 'url.dll,FileProtocolHandler', uri }
|
||||||
else
|
else
|
||||||
return nil, 'vim.ui.open: rundll32 not found'
|
return nil, 'vim.ui.open: rundll32 not found'
|
||||||
end
|
end
|
||||||
elseif vim.fn.executable('wslview') == 1 then
|
|
||||||
cmd = { 'wslview', path }
|
|
||||||
elseif vim.fn.executable('explorer.exe') == 1 then
|
|
||||||
cmd = { 'explorer.exe', path }
|
|
||||||
elseif vim.fn.executable('xdg-open') == 1 then
|
elseif vim.fn.executable('xdg-open') == 1 then
|
||||||
cmd = { 'xdg-open', path }
|
cmd = { 'xdg-open', uri }
|
||||||
opts.stdout = false
|
job_opt.stdout = false
|
||||||
opts.stderr = false
|
job_opt.stderr = false
|
||||||
|
elseif vim.fn.executable('wslview') == 1 then
|
||||||
|
cmd = { 'wslview', uri }
|
||||||
|
elseif vim.fn.executable('explorer.exe') == 1 then
|
||||||
|
cmd = { 'explorer.exe', uri }
|
||||||
else
|
else
|
||||||
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
|
||||||
|
|
||||||
|
local function do_open2(uri)
|
||||||
|
local cmd, err = do_open(uri)
|
||||||
|
-- wait() terminates the process if necessary (avoids stale processes), and allows us to show an
|
||||||
|
-- error message if needed.
|
||||||
|
local rv = cmd and cmd:wait(1000) or nil
|
||||||
|
if cmd and rv and rv.code ~= 0 then
|
||||||
|
err = ('vim.ui.open: command %s (%d): %s'):format(
|
||||||
|
(rv.code == 124 and 'timeout' or 'failed'),
|
||||||
|
rv.code,
|
||||||
|
vim.inspect(cmd.cmd)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
return err
|
||||||
|
end
|
||||||
|
|
||||||
|
if path then
|
||||||
|
local is_uri = path:match('%w+:')
|
||||||
|
if not is_uri then
|
||||||
|
path = vim.fs.normalize(path)
|
||||||
|
end
|
||||||
|
return do_open(path)
|
||||||
|
else -- DWIM mode: get the URL or path from the cursor position, and show error.
|
||||||
|
local visual = not not vim.fn.mode():match('[vV\22]')
|
||||||
|
if visual then
|
||||||
|
local lines =
|
||||||
|
vim.fn.getregion(vim.fn.getpos('.'), vim.fn.getpos('v'), { type = vim.fn.mode() })
|
||||||
|
-- Trim whitespace on each line and concatenate.
|
||||||
|
local err = do_open2(table.concat(vim.iter(lines):map(vim.trim):totable()))
|
||||||
|
if err then
|
||||||
|
vim.notify(err, vim.log.levels.ERROR)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for _, url in ipairs(M._get_urls()) do
|
||||||
|
local err = do_open2(url)
|
||||||
|
if err then
|
||||||
|
vim.notify(err, vim.log.levels.ERROR)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns all URLs at cursor, if any.
|
--- Returns all URLs at cursor, if any.
|
||||||
|
@ -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(),
|
||||||
[[
|
[[
|
||||||
|
@ -45,6 +45,11 @@
|
|||||||
(link_destination) @_url
|
(link_destination) @_url
|
||||||
(#set! @_label url @_url))
|
(#set! @_label url @_url))
|
||||||
|
|
||||||
|
(image
|
||||||
|
(image_description) @_label
|
||||||
|
(link_destination) @_url
|
||||||
|
(#set! @_label url @_url))
|
||||||
|
|
||||||
; Conceal image links
|
; Conceal image links
|
||||||
(image
|
(image
|
||||||
[
|
[
|
||||||
|
@ -33,7 +33,10 @@
|
|||||||
")"
|
")"
|
||||||
] @punctuation.bracket
|
] @punctuation.bracket
|
||||||
|
|
||||||
":" @punctuation.delimiter
|
[
|
||||||
|
":"
|
||||||
|
"/"
|
||||||
|
] @punctuation.delimiter
|
||||||
|
|
||||||
[
|
[
|
||||||
"@"
|
"@"
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
" Vim syntax file
|
" Vim syntax file
|
||||||
" Language: Configuration File (ini file) for MSDOS/MS Windows
|
" Language: Configuration File (ini file) for MSDOS/MS Windows
|
||||||
" Version: 2.3
|
" Version: 2.4
|
||||||
" Original Author: Sean M. McKee <mckee@misslink.net>
|
" Original Author: Sean M. McKee <mckee@misslink.net>
|
||||||
" Previous Maintainer: Nima Talebi <nima@it.net.au>
|
" Previous Maintainer: Nima Talebi <nima@it.net.au>
|
||||||
" Current Maintainer: Hong Xu <hong@topbug.net>
|
" Current Maintainer: Hong Xu <hong@topbug.net>
|
||||||
" Homepage: http://www.vim.org/scripts/script.php?script_id=3747
|
" Homepage: http://www.vim.org/scripts/script.php?script_id=3747
|
||||||
" Repository: https://github.com/xuhdev/syntax-dosini.vim
|
" Repository: https://github.com/xuhdev/syntax-dosini.vim
|
||||||
" Last Change: 2023 Aug 20
|
" Last Change: 2024 Sept 08
|
||||||
|
|
||||||
|
|
||||||
" quit when a syntax file was already loaded
|
" quit when a syntax file was already loaded
|
||||||
@ -27,7 +27,7 @@ syn match dosiniNumber "=\zs\s*\d\+\s*$"
|
|||||||
syn match dosiniNumber "=\zs\s*\d*\.\d\+\s*$"
|
syn match dosiniNumber "=\zs\s*\d*\.\d\+\s*$"
|
||||||
syn match dosiniNumber "=\zs\s*\d\+e[+-]\=\d\+\s*$"
|
syn match dosiniNumber "=\zs\s*\d\+e[+-]\=\d\+\s*$"
|
||||||
syn region dosiniHeader start="^\s*\[" end="\]"
|
syn region dosiniHeader start="^\s*\[" end="\]"
|
||||||
syn match dosiniComment "^[#;].*$"
|
syn match dosiniComment "^[#;].*$" contains=@Spell
|
||||||
syn region dosiniSection start="\s*\[.*\]" end="\ze\s*\[.*\]" fold
|
syn region dosiniSection start="\s*\[.*\]" end="\ze\s*\[.*\]" fold
|
||||||
\ contains=dosiniLabel,dosiniValue,dosiniNumber,dosiniHeader,dosiniComment
|
\ contains=dosiniLabel,dosiniValue,dosiniNumber,dosiniHeader,dosiniComment
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
" Interactive Data Language syntax file (IDL, too [:-)]
|
" Interactive Data Language syntax file (IDL, too [:-)]
|
||||||
" Maintainer: Aleksandar Jelenak <ajelenak AT yahoo.com>
|
" Maintainer: Aleksandar Jelenak <ajelenak AT yahoo.com>
|
||||||
" Last change: 2011 Apr 11
|
" Created By: Hermann Rochholz <Hermann.Rochholz AT gmx.de>
|
||||||
" Created by: Hermann Rochholz <Hermann.Rochholz AT gmx.de>
|
" Last Change: 2011 Apr 11
|
||||||
|
" 2024 Sep 10 by Vim Project: update syntax script, #15419
|
||||||
|
|
||||||
" Remove any old syntax stuff hanging around
|
" Remove any old syntax stuff hanging around
|
||||||
" quit when a syntax file was already loaded
|
" quit when a syntax file was already loaded
|
||||||
@ -16,7 +17,7 @@ syn match idlangStatement "^\s*function\s"
|
|||||||
syn keyword idlangStatement return continue mod do break
|
syn keyword idlangStatement return continue mod do break
|
||||||
syn keyword idlangStatement compile_opt forward_function goto
|
syn keyword idlangStatement compile_opt forward_function goto
|
||||||
syn keyword idlangStatement begin common end of
|
syn keyword idlangStatement begin common end of
|
||||||
syn keyword idlangStatement inherits on_ioerror begin
|
syn keyword idlangStatement inherits on_error on_ioerror begin
|
||||||
|
|
||||||
syn keyword idlangConditional if else then for while case switch
|
syn keyword idlangConditional if else then for while case switch
|
||||||
syn keyword idlangConditional endcase endelse endfor endswitch
|
syn keyword idlangConditional endcase endelse endfor endswitch
|
||||||
@ -82,7 +83,7 @@ syn keyword idlangRoutine CALL_EXTERNAL CALL_FUNCTION CALL_METHOD
|
|||||||
syn keyword idlangRoutine CALL_PROCEDURE CATCH CD CEIL CHEBYSHEV CHECK_MATH
|
syn keyword idlangRoutine CALL_PROCEDURE CATCH CD CEIL CHEBYSHEV CHECK_MATH
|
||||||
syn keyword idlangRoutine CHISQR_CVF CHISQR_PDF CHOLDC CHOLSOL CINDGEN
|
syn keyword idlangRoutine CHISQR_CVF CHISQR_PDF CHOLDC CHOLSOL CINDGEN
|
||||||
syn keyword idlangRoutine CIR_3PNT CLOSE CLUST_WTS CLUSTER COLOR_CONVERT
|
syn keyword idlangRoutine CIR_3PNT CLOSE CLUST_WTS CLUSTER COLOR_CONVERT
|
||||||
syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT COMMON
|
syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT
|
||||||
syn keyword idlangRoutine COMPLEX COMPLEXARR COMPLEXROUND
|
syn keyword idlangRoutine COMPLEX COMPLEXARR COMPLEXROUND
|
||||||
syn keyword idlangRoutine COMPUTE_MESH_NORMALS COND CONGRID CONJ
|
syn keyword idlangRoutine COMPUTE_MESH_NORMALS COND CONGRID CONJ
|
||||||
syn keyword idlangRoutine CONSTRAINED_MIN CONTOUR CONVERT_COORD CONVOL
|
syn keyword idlangRoutine CONSTRAINED_MIN CONTOUR CONVERT_COORD CONVOL
|
||||||
@ -98,7 +99,7 @@ syn keyword idlangRoutine CW_PALETTE_EDITOR_GET CW_PALETTE_EDITOR_SET
|
|||||||
syn keyword idlangRoutine CW_PDMENU CW_RGBSLIDER CW_TMPL CW_ZOOM DBLARR
|
syn keyword idlangRoutine CW_PDMENU CW_RGBSLIDER CW_TMPL CW_ZOOM DBLARR
|
||||||
syn keyword idlangRoutine DCINDGEN DCOMPLEX DCOMPLEXARR DEFINE_KEY DEFROI
|
syn keyword idlangRoutine DCINDGEN DCOMPLEX DCOMPLEXARR DEFINE_KEY DEFROI
|
||||||
syn keyword idlangRoutine DEFSYSV DELETE_SYMBOL DELLOG DELVAR DERIV DERIVSIG
|
syn keyword idlangRoutine DEFSYSV DELETE_SYMBOL DELLOG DELVAR DERIV DERIVSIG
|
||||||
syn keyword idlangRoutine DETERM DEVICE DFPMIN DIALOG_MESSAGE
|
syn keyword idlangRoutine DETERM DEVICE DFPMIN DIAG_MATRIX DIALOG_MESSAGE
|
||||||
syn keyword idlangRoutine DIALOG_PICKFILE DIALOG_PRINTERSETUP
|
syn keyword idlangRoutine DIALOG_PICKFILE DIALOG_PRINTERSETUP
|
||||||
syn keyword idlangRoutine DIALOG_PRINTJOB DIALOG_READ_IMAGE
|
syn keyword idlangRoutine DIALOG_PRINTJOB DIALOG_READ_IMAGE
|
||||||
syn keyword idlangRoutine DIALOG_WRITE_IMAGE DIGITAL_FILTER DILATE DINDGEN
|
syn keyword idlangRoutine DIALOG_WRITE_IMAGE DIGITAL_FILTER DILATE DINDGEN
|
||||||
@ -155,7 +156,7 @@ syn keyword idlangRoutine MPEG_PUT MPEG_SAVE MSG_CAT_CLOSE MSG_CAT_COMPILE
|
|||||||
syn keyword idlangRoutine MSG_CAT_OPEN MULTI N_ELEMENTS N_PARAMS N_TAGS
|
syn keyword idlangRoutine MSG_CAT_OPEN MULTI N_ELEMENTS N_PARAMS N_TAGS
|
||||||
syn keyword idlangRoutine NEWTON NORM OBJ_CLASS OBJ_DESTROY OBJ_ISA OBJ_NEW
|
syn keyword idlangRoutine NEWTON NORM OBJ_CLASS OBJ_DESTROY OBJ_ISA OBJ_NEW
|
||||||
syn keyword idlangRoutine OBJ_VALID OBJARR ON_ERROR ON_IOERROR ONLINE_HELP
|
syn keyword idlangRoutine OBJ_VALID OBJARR ON_ERROR ON_IOERROR ONLINE_HELP
|
||||||
syn keyword idlangRoutine OPEN OPENR OPENW OPLOT OPLOTERR P_CORRELATE
|
syn keyword idlangRoutine OPEN OPENR OPENW OPENU OPLOT OPLOTERR P_CORRELATE
|
||||||
syn keyword idlangRoutine PARTICLE_TRACE PCOMP PLOT PLOT_3DBOX PLOT_FIELD
|
syn keyword idlangRoutine PARTICLE_TRACE PCOMP PLOT PLOT_3DBOX PLOT_FIELD
|
||||||
syn keyword idlangRoutine PLOTERR PLOTS PNT_LINE POINT_LUN POLAR_CONTOUR
|
syn keyword idlangRoutine PLOTERR PLOTS PNT_LINE POINT_LUN POLAR_CONTOUR
|
||||||
syn keyword idlangRoutine POLAR_SURFACE POLY POLY_2D POLY_AREA POLY_FIT
|
syn keyword idlangRoutine POLAR_SURFACE POLY POLY_2D POLY_AREA POLY_FIT
|
||||||
|
@ -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 Aug 26
|
" 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.
|
||||||
|
|
||||||
@ -157,13 +157,20 @@ endif
|
|||||||
" testing in a project without attendant confusion for IDEs, with the
|
" testing in a project without attendant confusion for IDEs, with the
|
||||||
" ".java\=" extension used for a production version and an arbitrary
|
" ".java\=" extension used for a production version and an arbitrary
|
||||||
" extension used for a testing version.
|
" extension used for a testing version.
|
||||||
if fnamemodify(bufname("%"), ":t") =~ '^module-info\%(\.class\>\)\@!'
|
if fnamemodify(bufname("%"), ":t") =~ '^module-info\>\%(\.class\>\)\@!'
|
||||||
syn keyword javaModuleStorageClass module transitive
|
syn keyword javaModuleStorageClass module transitive
|
||||||
syn keyword javaModuleStmt open requires exports opens uses provides
|
syn keyword javaModuleStmt open requires exports opens uses provides
|
||||||
syn keyword javaModuleExternal to with
|
syn keyword javaModuleExternal to with
|
||||||
hi def link javaModuleStorageClass StorageClass
|
hi def link javaModuleStorageClass StorageClass
|
||||||
hi def link javaModuleStmt Statement
|
hi def link javaModuleStmt Statement
|
||||||
hi def link javaModuleExternal Include
|
hi def link javaModuleExternal Include
|
||||||
|
|
||||||
|
if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
|
||||||
|
syn match javaDocProvidesTag contained "@provides\_s\+\S\+" contains=javaDocParam
|
||||||
|
syn match javaDocUsesTag contained "@uses\_s\+\S\+" contains=javaDocParam
|
||||||
|
hi def link javaDocProvidesTag Special
|
||||||
|
hi def link javaDocUsesTag Special
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Fancy parameterised types (JLS-17, §4.5).
|
" Fancy parameterised types (JLS-17, §4.5).
|
||||||
@ -335,29 +342,99 @@ if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
|
|||||||
call s:ReportOnce(v:exception)
|
call s:ReportOnce(v:exception)
|
||||||
endtry
|
endtry
|
||||||
|
|
||||||
syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag,javaTodo,javaCommentError,javaSpaceError,@Spell fold
|
syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,@javaDocTags,javaTodo,javaCommentError,javaSpaceError,@Spell fold
|
||||||
exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag'
|
exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags'
|
||||||
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag
|
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
|
||||||
syn region javaDocTags contained start="{@\%(li\%(teral\|nk\%(plain\)\=\)\|inherit[Dd]oc\|doc[rR]oot\|value\)\>" end="}"
|
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@summary\>\)\@=" matchgroup=javaCommentTitle end="}" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
|
||||||
syn match javaDocTags contained "@\%(param\|exception\|throws\|since\)\s\+\S\+" contains=javaDocParam
|
" The members of javaDocTags are sub-grouped according to the Java
|
||||||
syn match javaDocParam contained "\s\S\+"
|
" version of their introduction, and sub-group members in turn are
|
||||||
syn match javaDocTags contained "@\%(version\|author\|return\|deprecated\|serial\%(Field\|Data\)\=\)\>"
|
" arranged in alphabetical order, so that future newer members can
|
||||||
syn region javaDocSeeTag contained matchgroup=javaDocTags start="@see\s\+" matchgroup=NONE end="\_."re=e-1 contains=javaDocSeeTagParam
|
" be pre-sorted and appended without disturbing the current member
|
||||||
syn match javaDocSeeTagParam contained @"\_[^"]\+"\|<a\s\+\_.\{-}</a>\|\%(\k\|\.\)*\%(#\k\+\%((\_[^)]*)\)\=\)\=@ contains=@javaHtml extend
|
" placement.
|
||||||
|
" Since they only have significance in javaCommentTitle, neither
|
||||||
|
" javaDocSummaryTag nor javaDocReturnTitleTag are defined.
|
||||||
|
syn cluster javaDocTags contains=javaDocAuthorTag,javaDocDeprecatedTag,javaDocExceptionTag,javaDocParamTag,javaDocReturnTag,javaDocSeeTag,javaDocVersionTag,javaDocSinceTag,javaDocLinkTag,javaDocSerialTag,javaDocSerialDataTag,javaDocSerialFieldTag,javaDocThrowsTag,javaDocDocRootTag,javaDocInheritDocTag,javaDocLinkplainTag,javaDocValueTag,javaDocCodeTag,javaDocLiteralTag,javaDocHiddenTag,javaDocIndexTag,javaDocProvidesTag,javaDocUsesTag,javaDocSystemPropertyTag,javaDocSnippetTag,javaDocSpecTag
|
||||||
|
|
||||||
|
" Anticipate non-standard inline tags in {@return} and {@summary}.
|
||||||
|
syn region javaTitleSkipBlock contained transparent start="{\%(@\%(return\|summary\)\>\)\@!" end="}"
|
||||||
|
syn match javaDocDocRootTag contained "{@docRoot}"
|
||||||
|
syn match javaDocInheritDocTag contained "{@inheritDoc}"
|
||||||
|
syn region javaIndexSkipBlock contained transparent start="{\%(@index\>\)\@!" end="}" contains=javaIndexSkipBlock,javaDocIndexTag
|
||||||
|
syn region javaDocIndexTag contained start="{@index\>" end="}" contains=javaDocIndexTag,javaIndexSkipBlock
|
||||||
|
syn region javaLinkSkipBlock contained transparent start="{\%(@link\>\)\@!" end="}" contains=javaLinkSkipBlock,javaDocLinkTag
|
||||||
|
syn region javaDocLinkTag contained start="{@link\>" end="}" contains=javaDocLinkTag,javaLinkSkipBlock
|
||||||
|
syn region javaLinkplainSkipBlock contained transparent start="{\%(@linkplain\>\)\@!" end="}" contains=javaLinkplainSkipBlock,javaDocLinkplainTag
|
||||||
|
syn region javaDocLinkplainTag contained start="{@linkplain\>" end="}" contains=javaDocLinkplainTag,javaLinkplainSkipBlock
|
||||||
|
syn region javaLiteralSkipBlock contained transparent start="{\%(@literal\>\)\@!" end="}" contains=javaLiteralSkipBlock,javaDocLiteralTag
|
||||||
|
syn region javaDocLiteralTag contained start="{@literal\>" end="}" contains=javaDocLiteralTag,javaLiteralSkipBlock
|
||||||
|
syn region javaSystemPropertySkipBlock contained transparent start="{\%(@systemProperty\>\)\@!" end="}" contains=javaSystemPropertySkipBlock,javaDocSystemPropertyTag
|
||||||
|
syn region javaDocSystemPropertyTag contained start="{@systemProperty\>" end="}" contains=javaDocSystemPropertyTag,javaSystemPropertySkipBlock
|
||||||
|
syn region javaValueSkipBlock contained transparent start="{\%(@value\>\)\@!" end="}" contains=javaValueSkipBlock,javaDocValueTag
|
||||||
|
syn region javaDocValueTag contained start="{@value\>" end="}" contains=javaDocValueTag,javaValueSkipBlock
|
||||||
|
|
||||||
|
syn match javaDocParam contained "\s\zs\S\+"
|
||||||
|
syn match javaDocExceptionTag contained "@exception\s\+\S\+" contains=javaDocParam
|
||||||
|
syn match javaDocParamTag contained "@param\s\+\S\+" contains=javaDocParam
|
||||||
|
syn match javaDocSinceTag contained "@since\s\+\S\+" contains=javaDocParam
|
||||||
|
syn match javaDocThrowsTag contained "@throws\s\+\S\+" contains=javaDocParam
|
||||||
|
syn match javaDocSpecTag contained "@spec\_s\+\S\+\ze\_s\+\S\+" contains=javaDocParam
|
||||||
|
|
||||||
|
syn match javaDocAuthorTag contained "@author\>"
|
||||||
|
syn match javaDocDeprecatedTag contained "@deprecated\>"
|
||||||
|
syn match javaDocHiddenTag contained "@hidden\>"
|
||||||
|
syn match javaDocReturnTag contained "@return\>"
|
||||||
|
syn match javaDocSerialTag contained "@serial\>"
|
||||||
|
syn match javaDocSerialDataTag contained "@serialData\>"
|
||||||
|
syn match javaDocSerialFieldTag contained "@serialField\>"
|
||||||
|
syn match javaDocVersionTag contained "@version\>"
|
||||||
|
|
||||||
|
syn match javaDocSeeTag contained "@see\>" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTagStar skipwhite skipempty
|
||||||
|
syn match javaDocSeeTagStar contained "^\s*\*\+\%(\s*{\=@\|/\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3 skipwhite skipempty
|
||||||
|
syn match javaDocSeeTag1 contained @"\_[^"]\+"@
|
||||||
|
syn match javaDocSeeTag2 contained @<a\s\+\_.\{-}</a>@ contains=@javaHtml extend
|
||||||
|
syn match javaDocSeeTag3 contained @["< \t]\@!\%(\k\|[/.]\)*\%(##\=\k\+\%((\_[^)]*)\)\=\)\=@ nextgroup=javaDocSeeTag3Label skipwhite skipempty
|
||||||
|
syn match javaDocSeeTag3Label contained @\k\%(\k\+\s*\)*$@
|
||||||
|
|
||||||
syn region javaCodeSkipBlock contained transparent start="{\%(@code\>\)\@!" end="}" contains=javaCodeSkipBlock,javaDocCodeTag
|
syn region javaCodeSkipBlock contained transparent start="{\%(@code\>\)\@!" end="}" contains=javaCodeSkipBlock,javaDocCodeTag
|
||||||
syn region javaDocCodeTag contained start="{@code\>" end="}" contains=javaDocCodeTag,javaCodeSkipBlock
|
syn region javaDocCodeTag contained start="{@code\>" end="}" contains=javaDocCodeTag,javaCodeSkipBlock
|
||||||
|
|
||||||
exec 'syn region javaDocSnippetTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(class\|file\|id\|lang\|region\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/:$/ end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.\\/-]\|\k\)\+\)/ nextgroup=javaDocSnippetTagAttr skipwhite skipnl'
|
exec 'syn region javaDocSnippetTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(class\|file\|id\|lang\|region\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/:$/ end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.\\/-]\|\k\)\+\)/ nextgroup=javaDocSnippetTagAttr skipwhite skipnl'
|
||||||
syn region javaSnippetSkipBlock contained transparent start="{\%(@snippet\>\)\@!" end="}" contains=javaSnippetSkipBlock,javaDocSnippetTag,javaCommentMarkupTag
|
syn region javaSnippetSkipBlock contained transparent start="{\%(@snippet\>\)\@!" end="}" contains=javaSnippetSkipBlock,javaDocSnippetTag,javaCommentMarkupTag
|
||||||
syn region javaDocSnippetTag contained start="{@snippet\>" end="}" contains=javaDocSnippetTag,javaSnippetSkipBlock,javaDocSnippetTagAttr,javaCommentMarkupTag
|
syn region javaDocSnippetTag contained start="{@snippet\>" end="}" contains=javaDocSnippetTag,javaSnippetSkipBlock,javaDocSnippetTagAttr,javaCommentMarkupTag
|
||||||
|
|
||||||
syntax case match
|
syntax case match
|
||||||
hi def link javaDocComment Comment
|
hi def link javaDocComment Comment
|
||||||
|
hi def link javaDocSeeTagStar javaDocComment
|
||||||
hi def link javaCommentTitle SpecialComment
|
hi def link javaCommentTitle SpecialComment
|
||||||
hi def link javaDocTags Special
|
|
||||||
hi def link javaDocCodeTag Special
|
|
||||||
hi def link javaDocSnippetTag Special
|
|
||||||
hi def link javaDocSeeTagParam Function
|
|
||||||
hi def link javaDocParam Function
|
hi def link javaDocParam Function
|
||||||
|
|
||||||
|
hi def link javaDocAuthorTag Special
|
||||||
|
hi def link javaDocCodeTag Special
|
||||||
|
hi def link javaDocDeprecatedTag Special
|
||||||
|
hi def link javaDocDocRootTag Special
|
||||||
|
hi def link javaDocExceptionTag Special
|
||||||
|
hi def link javaDocHiddenTag Special
|
||||||
|
hi def link javaDocIndexTag Special
|
||||||
|
hi def link javaDocInheritDocTag Special
|
||||||
|
hi def link javaDocLinkTag Special
|
||||||
|
hi def link javaDocLinkplainTag Special
|
||||||
|
hi def link javaDocLiteralTag Special
|
||||||
|
hi def link javaDocParamTag Special
|
||||||
|
hi def link javaDocReturnTag Special
|
||||||
|
hi def link javaDocSeeTag Special
|
||||||
|
hi def link javaDocSeeTag1 String
|
||||||
|
hi def link javaDocSeeTag2 Special
|
||||||
|
hi def link javaDocSeeTag3 Function
|
||||||
|
hi def link javaDocSerialTag Special
|
||||||
|
hi def link javaDocSerialDataTag Special
|
||||||
|
hi def link javaDocSerialFieldTag Special
|
||||||
|
hi def link javaDocSinceTag Special
|
||||||
|
hi def link javaDocSnippetTag Special
|
||||||
|
hi def link javaDocSpecTag Special
|
||||||
|
hi def link javaDocSystemPropertyTag Special
|
||||||
|
hi def link javaDocThrowsTag Special
|
||||||
|
hi def link javaDocValueTag Special
|
||||||
|
hi def link javaDocVersionTag Special
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" match the special comment /**/
|
" match the special comment /**/
|
||||||
@ -586,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
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
|
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
|
||||||
" Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014)
|
" Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014)
|
||||||
" Last Change: 2020 May 25
|
" Last Change: 2020 May 25
|
||||||
|
" 2024 Sep 10 by Vim Project: add file triggers support, #15569
|
||||||
|
|
||||||
" quit when a syntax file was already loaded
|
" quit when a syntax file was already loaded
|
||||||
if exists("b:current_syntax")
|
if exists("b:current_syntax")
|
||||||
@ -111,7 +112,7 @@ syn region specDescriptionArea matchgroup=specSection start='^%description' end=
|
|||||||
syn region specPackageArea matchgroup=specSection start='^%package' end='^%'me=e-1 contains=specPackageOpts,specPreAmble,specComment
|
syn region specPackageArea matchgroup=specSection start='^%package' end='^%'me=e-1 contains=specPackageOpts,specPreAmble,specComment
|
||||||
|
|
||||||
"%% Scripts Section %%
|
"%% Scripts Section %%
|
||||||
syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2
|
syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\|filetriggerin\|filetriggerun\|filetriggerpostun\|transfiletriggerin\|transfiletriggerun\|transfiletriggerpostun\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2
|
||||||
|
|
||||||
"%% Changelog Section %%
|
"%% Changelog Section %%
|
||||||
syn region specChangelogArea matchgroup=specSection start='^%changelog' end='^%'me=e-1 contains=specEmail,specURL,specWeekday,specMonth,specNumber,specComment,specLicense
|
syn region specChangelogArea matchgroup=specSection start='^%changelog' end='^%'me=e-1 contains=specEmail,specURL,specWeekday,specMonth,specNumber,specComment,specLicense
|
||||||
|
@ -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
|
||||||
" =====
|
" =====
|
||||||
|
@ -81,6 +81,14 @@ local function get_dependency(dependency_name)
|
|||||||
repo = 'luvit/luv',
|
repo = 'luvit/luv',
|
||||||
symbol = 'LUV',
|
symbol = 'LUV',
|
||||||
},
|
},
|
||||||
|
['unibilium'] = {
|
||||||
|
repo = 'neovim/unibilium',
|
||||||
|
symbol = 'UNIBILIUM',
|
||||||
|
},
|
||||||
|
['utf8proc'] = {
|
||||||
|
repo = 'JuliaStrings/utf8proc',
|
||||||
|
symbol = 'UTF8PROC',
|
||||||
|
},
|
||||||
['tree-sitter'] = {
|
['tree-sitter'] = {
|
||||||
repo = 'tree-sitter/tree-sitter',
|
repo = 'tree-sitter/tree-sitter',
|
||||||
symbol = 'TREESITTER',
|
symbol = 'TREESITTER',
|
||||||
@ -90,11 +98,11 @@ local function get_dependency(dependency_name)
|
|||||||
symbol = 'TREESITTER_C',
|
symbol = 'TREESITTER_C',
|
||||||
},
|
},
|
||||||
['tree-sitter-lua'] = {
|
['tree-sitter-lua'] = {
|
||||||
repo = 'MunifTanjim/tree-sitter-lua',
|
repo = 'tree-sitter-grammars/tree-sitter-lua',
|
||||||
symbol = 'TREESITTER_LUA',
|
symbol = 'TREESITTER_LUA',
|
||||||
},
|
},
|
||||||
['tree-sitter-vim'] = {
|
['tree-sitter-vim'] = {
|
||||||
repo = 'neovim/tree-sitter-vim',
|
repo = 'tree-sitter-grammars/tree-sitter-vim',
|
||||||
symbol = 'TREESITTER_VIM',
|
symbol = 'TREESITTER_VIM',
|
||||||
},
|
},
|
||||||
['tree-sitter-vimdoc'] = {
|
['tree-sitter-vimdoc'] = {
|
||||||
@ -102,9 +110,21 @@ local function get_dependency(dependency_name)
|
|||||||
symbol = 'TREESITTER_VIMDOC',
|
symbol = 'TREESITTER_VIMDOC',
|
||||||
},
|
},
|
||||||
['tree-sitter-query'] = {
|
['tree-sitter-query'] = {
|
||||||
repo = 'nvim-treesitter/tree-sitter-query',
|
repo = 'tree-sitter-grammars/tree-sitter-query',
|
||||||
symbol = 'TREESITTER_QUERY',
|
symbol = 'TREESITTER_QUERY',
|
||||||
},
|
},
|
||||||
|
['tree-sitter-markdown'] = {
|
||||||
|
repo = 'tree-sitter-grammars/tree-sitter-markdown',
|
||||||
|
symbol = 'TREESITTER_MARKDOWN',
|
||||||
|
},
|
||||||
|
['wasmtime'] = {
|
||||||
|
repo = 'bytecodealliance/wasmtime',
|
||||||
|
symbol = 'WASMTIME',
|
||||||
|
},
|
||||||
|
['uncrustify'] = {
|
||||||
|
repo = 'uncrustify/uncrustify',
|
||||||
|
symbol = 'UNCRUSTIFY',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
local dependency = dependency_table[dependency_name]
|
local dependency = dependency_table[dependency_name]
|
||||||
if dependency == nil then
|
if dependency == nil then
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 = [
|
||||||
|
@ -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()
|
||||||
|
@ -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"
|
||||||
|
@ -3338,7 +3338,7 @@ void maketitle(void)
|
|||||||
|
|
||||||
#define SPACE_FOR_FNAME (sizeof(buf) - 100)
|
#define SPACE_FOR_FNAME (sizeof(buf) - 100)
|
||||||
#define SPACE_FOR_DIR (sizeof(buf) - 20)
|
#define SPACE_FOR_DIR (sizeof(buf) - 20)
|
||||||
#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM".
|
#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - Nvim".
|
||||||
char *buf_p = buf;
|
char *buf_p = buf;
|
||||||
if (curbuf->b_fname == NULL) {
|
if (curbuf->b_fname == NULL) {
|
||||||
const size_t size = xstrlcpy(buf_p, _("[No Name]"),
|
const size_t size = xstrlcpy(buf_p, _("[No Name]"),
|
||||||
@ -3412,7 +3412,7 @@ void maketitle(void)
|
|||||||
|
|
||||||
append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)));
|
append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)));
|
||||||
|
|
||||||
xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf)));
|
xstrlcat(buf_p, " - Nvim", (sizeof(buf) - (size_t)(buf_p - buf)));
|
||||||
|
|
||||||
if (maxlen > 0) {
|
if (maxlen > 0) {
|
||||||
// Make it shorter by removing a bit in the middle.
|
// Make it shorter by removing a bit in the middle.
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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));
|
||||||
|
@ -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 = {
|
||||||
@ -8927,6 +8927,9 @@ M.funcs = {
|
|||||||
The value must not be negative. A zero value is like not
|
The value must not be negative. A zero value is like not
|
||||||
giving the argument.
|
giving the argument.
|
||||||
|
|
||||||
|
Note: the timeout is only considered when searching, not
|
||||||
|
while evaluating the {skip} expression.
|
||||||
|
|
||||||
If the {skip} expression is given it is evaluated with the
|
If the {skip} expression is given it is evaluated with the
|
||||||
cursor positioned on the start of a match. If it evaluates to
|
cursor positioned on the start of a match. If it evaluates to
|
||||||
non-zero this match is skipped. This can be used, for
|
non-zero this match is skipped. This can be used, for
|
||||||
|
@ -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,12 +3796,12 @@ 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,7 +4144,7 @@ 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.
|
||||||
@ -7641,7 +7641,7 @@ static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const void *iter = NULL;
|
const void *iter = NULL;
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname(false);
|
||||||
do {
|
do {
|
||||||
size_t dir_len;
|
size_t dir_len;
|
||||||
const char *dir;
|
const char *dir;
|
||||||
@ -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);
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
@ -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
|
@ -16,15 +16,14 @@ struct loop {
|
|||||||
uv_loop_t uv;
|
uv_loop_t uv;
|
||||||
MultiQueue *events;
|
MultiQueue *events;
|
||||||
MultiQueue *thread_events;
|
MultiQueue *thread_events;
|
||||||
// Immediate events:
|
// Immediate events.
|
||||||
// "Processed after exiting uv_run() (to avoid recursion), but before
|
// - "Processed after exiting `uv_run()` (to avoid recursion), but before returning from
|
||||||
// returning from loop_poll_events()." 502aee690c98
|
// `loop_poll_events()`." 502aee690c98
|
||||||
// Practical consequence (for main_loop): these events are processed by
|
// - Practical consequence (for `main_loop`):
|
||||||
// state_enter()..os_inchar()
|
// - these are processed by `state_enter()..input_get()` whereas "regular" events
|
||||||
// whereas "regular" events (main_loop.events) are processed by
|
// (`main_loop.events`) are processed by `state_enter()..VimState.execute()`
|
||||||
// state_enter()..VimState.execute()
|
// - `state_enter()..input_get()` can be "too early" if you want the event to trigger UI
|
||||||
// But state_enter()..os_inchar() can be "too early" if you want the event
|
// updates and other user-activity-related side-effects.
|
||||||
// to trigger UI updates and other user-activity-related side-effects.
|
|
||||||
MultiQueue *fast_events;
|
MultiQueue *fast_events;
|
||||||
|
|
||||||
// used by process/job-control subsystem
|
// used by process/job-control subsystem
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -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
|
@ -94,14 +94,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
|
|||||||
stream->events = NULL;
|
stream->events = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream)
|
void stream_may_close(Stream *stream, bool rstream)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
|
if (stream->closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
assert(!stream->closed);
|
assert(!stream->closed);
|
||||||
DLOG("closing Stream: %p", (void *)stream);
|
DLOG("closing Stream: %p", (void *)stream);
|
||||||
stream->closed = true;
|
stream->closed = true;
|
||||||
stream->close_cb = on_stream_close;
|
stream->close_cb = NULL;
|
||||||
stream->close_cb_data = data;
|
stream->close_cb_data = NULL;
|
||||||
|
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
if (UV_TTY == uv_guess_handle(stream->fd)) {
|
if (UV_TTY == uv_guess_handle(stream->fd)) {
|
||||||
@ -115,13 +118,6 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_may_close(Stream *stream, bool rstream)
|
|
||||||
{
|
|
||||||
if (!stream->closed) {
|
|
||||||
stream_close(stream, NULL, NULL, rstream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void stream_close_handle(Stream *stream, bool rstream)
|
void stream_close_handle(Stream *stream, bool rstream)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
|
@ -3264,18 +3264,12 @@ static void vim_mktempdir(void)
|
|||||||
char tmp[TEMP_FILE_PATH_MAXLEN];
|
char tmp[TEMP_FILE_PATH_MAXLEN];
|
||||||
char path[TEMP_FILE_PATH_MAXLEN];
|
char path[TEMP_FILE_PATH_MAXLEN];
|
||||||
char user[40] = { 0 };
|
char user[40] = { 0 };
|
||||||
char appname[40] = { 0 };
|
|
||||||
|
|
||||||
os_get_username(user, sizeof(user));
|
os_get_username(user, sizeof(user));
|
||||||
// Usernames may contain slashes! #19240
|
// Usernames may contain slashes! #19240
|
||||||
memchrsub(user, '/', '_', sizeof(user));
|
memchrsub(user, '/', '_', sizeof(user));
|
||||||
memchrsub(user, '\\', '_', sizeof(user));
|
memchrsub(user, '\\', '_', sizeof(user));
|
||||||
|
|
||||||
// Appname may be a relative path, replace slashes to make it name-like.
|
|
||||||
xstrlcpy(appname, get_appname(), sizeof(appname));
|
|
||||||
memchrsub(appname, '/', '%', sizeof(appname));
|
|
||||||
memchrsub(appname, '\\', '%', sizeof(appname));
|
|
||||||
|
|
||||||
// Make sure the umask doesn't remove the executable bit.
|
// Make sure the umask doesn't remove the executable bit.
|
||||||
// "repl" has been reported to use "0177".
|
// "repl" has been reported to use "0177".
|
||||||
mode_t umask_save = umask(0077);
|
mode_t umask_save = umask(0077);
|
||||||
@ -3283,14 +3277,15 @@ static void vim_mktempdir(void)
|
|||||||
// Expand environment variables, leave room for "/tmp/nvim.<user>/XXXXXX/999999999".
|
// Expand environment variables, leave room for "/tmp/nvim.<user>/XXXXXX/999999999".
|
||||||
expand_env((char *)temp_dirs[i], tmp, TEMP_FILE_PATH_MAXLEN - 64);
|
expand_env((char *)temp_dirs[i], tmp, TEMP_FILE_PATH_MAXLEN - 64);
|
||||||
if (!os_isdir(tmp)) {
|
if (!os_isdir(tmp)) {
|
||||||
|
if (strequal("$TMPDIR", temp_dirs[i])) {
|
||||||
|
WLOG("$TMPDIR tempdir not a directory (or does not exist): %s", tmp);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
|
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
|
||||||
add_pathsep(tmp);
|
add_pathsep(tmp);
|
||||||
|
xstrlcat(tmp, "nvim.", sizeof(tmp));
|
||||||
xstrlcat(tmp, appname, sizeof(tmp));
|
|
||||||
xstrlcat(tmp, ".", sizeof(tmp));
|
|
||||||
xstrlcat(tmp, user, sizeof(tmp));
|
xstrlcat(tmp, user, sizeof(tmp));
|
||||||
os_mkdir(tmp, 0700); // Always create, to avoid a race.
|
os_mkdir(tmp, 0700); // Always create, to avoid a race.
|
||||||
bool owned = os_file_owned(tmp);
|
bool owned = os_file_owned(tmp);
|
||||||
|
@ -1858,7 +1858,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
|
|||||||
if (!char_avail()) {
|
if (!char_avail()) {
|
||||||
// Flush screen updates before blocking.
|
// Flush screen updates before blocking.
|
||||||
ui_flush();
|
ui_flush();
|
||||||
os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
||||||
if (!multiqueue_empty(main_loop.events)) {
|
if (!multiqueue_empty(main_loop.events)) {
|
||||||
state_handle_k_event();
|
state_handle_k_event();
|
||||||
continue;
|
continue;
|
||||||
@ -2981,7 +2981,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time)
|
|||||||
uint8_t dum[DUM_LEN + 1];
|
uint8_t dum[DUM_LEN + 1];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
len = os_inchar(dum, DUM_LEN, 0, 0, NULL);
|
len = input_get(dum, DUM_LEN, 0, 0, NULL);
|
||||||
if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) {
|
if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2997,7 +2997,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time)
|
|||||||
|
|
||||||
// Fill up to a third of the buffer, because each character may be
|
// Fill up to a third of the buffer, because each character may be
|
||||||
// tripled below.
|
// tripled below.
|
||||||
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
|
len = input_get(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the typebuf was changed further down, it is like nothing was added by
|
// If the typebuf was changed further down, it is like nothing was added by
|
||||||
|
@ -370,12 +370,15 @@ void update_window_hl(win_T *wp, bool invalid)
|
|||||||
|
|
||||||
// determine window specific background set in 'winhighlight'
|
// determine window specific background set in 'winhighlight'
|
||||||
bool float_win = wp->w_floating && !wp->w_config.external;
|
bool float_win = wp->w_floating && !wp->w_config.external;
|
||||||
if (float_win && hl_def[HLF_NFLOAT] != 0) {
|
if (float_win && hl_def[HLF_NFLOAT] != 0 && ns_id > 0) {
|
||||||
wp->w_hl_attr_normal = hl_def[HLF_NFLOAT];
|
wp->w_hl_attr_normal = hl_def[HLF_NFLOAT];
|
||||||
} else if (hl_def[HLF_COUNT] > 0) {
|
} else if (hl_def[HLF_COUNT] > 0) {
|
||||||
wp->w_hl_attr_normal = hl_def[HLF_COUNT];
|
wp->w_hl_attr_normal = hl_def[HLF_COUNT];
|
||||||
|
} else if (float_win) {
|
||||||
|
wp->w_hl_attr_normal = HL_ATTR(HLF_NFLOAT) > 0
|
||||||
|
? HL_ATTR(HLF_NFLOAT) : highlight_attr[HLF_NFLOAT];
|
||||||
} else {
|
} else {
|
||||||
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
|
wp->w_hl_attr_normal = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wp->w_floating) {
|
if (wp->w_floating) {
|
||||||
|
@ -891,7 +891,17 @@ int get_breakindent_win(win_T *wp, char *line)
|
|||||||
if (wp->w_briopt_list > 0) {
|
if (wp->w_briopt_list > 0) {
|
||||||
prev_list += wp->w_briopt_list;
|
prev_list += wp->w_briopt_list;
|
||||||
} else {
|
} else {
|
||||||
prev_indent = (int)(*regmatch.endp - *regmatch.startp);
|
char *ptr = *regmatch.startp;
|
||||||
|
char *end_ptr = *regmatch.endp;
|
||||||
|
int indent = 0;
|
||||||
|
// Compute the width of the matched text.
|
||||||
|
// Use win_chartabsize() so that TAB size is correct,
|
||||||
|
// while wrapping is ignored.
|
||||||
|
while (ptr < end_ptr) {
|
||||||
|
indent += win_chartabsize(wp, ptr, indent);
|
||||||
|
MB_PTR_ADV(ptr);
|
||||||
|
}
|
||||||
|
prev_indent = indent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vim_regfree(regmatch.regprog);
|
vim_regfree(regmatch.regprog);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
/// @param[in] str Prompt: question to ask user. Is always followed by
|
/// @param[in] str Prompt: question to ask user. Is always followed by
|
||||||
/// " (y/n)?".
|
/// " (y/n)?".
|
||||||
/// @param[in] direct Determines what function to use to get user input. If
|
/// @param[in] direct Determines what function to use to get user input. If
|
||||||
/// true then os_inchar() will be used, otherwise vgetc().
|
/// true then input_get() will be used, otherwise vgetc().
|
||||||
/// I.e. when direct is true then characters are obtained
|
/// I.e. when direct is true then characters are obtained
|
||||||
/// directly from the user without buffers involved.
|
/// directly from the user without buffers involved.
|
||||||
///
|
///
|
||||||
@ -111,7 +111,7 @@ int get_keystroke(MultiQueue *events)
|
|||||||
|
|
||||||
// First time: blocking wait. Second time: wait up to 100ms for a
|
// First time: blocking wait. Second time: wait up to 100ms for a
|
||||||
// terminal code to complete.
|
// terminal code to complete.
|
||||||
n = os_inchar(buf + len, maxlen, len == 0 ? -1 : 100, 0, events);
|
n = input_get(buf + len, maxlen, len == 0 ? -1 : 100, 0, events);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
// Replace zero and K_SPECIAL by a special key code.
|
// Replace zero and K_SPECIAL by a special key code.
|
||||||
n = fix_input_buffer(buf + len, n);
|
n = fix_input_buffer(buf + len, n);
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "nvim/os/stdpaths_defs.h"
|
#include "nvim/os/stdpaths_defs.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
#include "nvim/path.h"
|
#include "nvim/path.h"
|
||||||
|
#include "nvim/ui_client.h"
|
||||||
|
|
||||||
/// Cached location of the expanded log file path decided by log_path_init().
|
/// Cached location of the expanded log file path decided by log_path_init().
|
||||||
static char log_file_path[MAXPATHL + 1] = { 0 };
|
static char log_file_path[MAXPATHL + 1] = { 0 };
|
||||||
@ -322,20 +323,28 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
|
|||||||
millis = (int)curtime.tv_usec / 1000;
|
millis = (int)curtime.tv_usec / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ui = !!ui_client_channel_id; // Running as a UI client (--remote-ui).
|
||||||
|
|
||||||
|
// Regenerate the name when:
|
||||||
|
// - UI client (to ensure "ui" is in the name)
|
||||||
|
// - not set yet
|
||||||
|
// - no v:servername yet
|
||||||
|
bool regen = ui || name[0] == NUL || name[0] == '?';
|
||||||
|
|
||||||
// Get a name for this Nvim instance.
|
// Get a name for this Nvim instance.
|
||||||
// TODO(justinmk): expose this as v:name ?
|
// TODO(justinmk): expose this as v:name ?
|
||||||
if (name[0] == NUL) {
|
if (regen) {
|
||||||
// Parent servername.
|
// Parent servername ($NVIM).
|
||||||
const char *parent = path_tail(os_getenv(ENV_NVIM));
|
const char *parent = path_tail(os_getenv(ENV_NVIM));
|
||||||
// Servername. Empty until starting=false.
|
// Servername. Empty until starting=false.
|
||||||
const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER));
|
const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER));
|
||||||
if (parent[0] != NUL) {
|
if (parent[0] != NUL) {
|
||||||
snprintf(name, sizeof(name), "%s/c", parent); // "/c" indicates child.
|
snprintf(name, sizeof(name), ui ? "ui/c/%s" : "c/%s", parent); // "c/" = child of $NVIM.
|
||||||
} else if (serv[0] != NUL) {
|
} else if (serv[0] != NUL) {
|
||||||
snprintf(name, sizeof(name), "%s", serv);
|
snprintf(name, sizeof(name), ui ? "ui/%s" : "%s", serv);
|
||||||
} else {
|
} else {
|
||||||
int64_t pid = os_get_pid();
|
int64_t pid = os_get_pid();
|
||||||
snprintf(name, sizeof(name), "?.%-5" PRId64, pid);
|
snprintf(name, sizeof(name), "%s.%-5" PRId64, ui ? "ui" : "?", pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,10 +357,6 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
|
|||||||
log_levels[log_level], date_time, millis, name,
|
log_levels[log_level], date_time, millis, name,
|
||||||
(context == NULL ? "" : context),
|
(context == NULL ? "" : context),
|
||||||
func_name, line_num);
|
func_name, line_num);
|
||||||
if (name[0] == '?') {
|
|
||||||
// No v:servername yet. Clear `name` so that the next log can try again.
|
|
||||||
name[0] = NUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -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();
|
||||||
@ -266,7 +266,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (argc > 1 && STRICMP(argv[1], "-ll") == 0) {
|
if (argc > 1 && STRICMP(argv[1], "-ll") == 0) {
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
print_mainerr(err_arg_missing, argv[1]);
|
print_mainerr(err_arg_missing, argv[1], NULL);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
nlua_run_script(argv, argc, 3);
|
nlua_run_script(argv, argc, 3);
|
||||||
@ -357,10 +357,8 @@ int main(int argc, char **argv)
|
|||||||
assert(!ui_client_channel_id && !use_builtin_ui);
|
assert(!ui_client_channel_id && !use_builtin_ui);
|
||||||
// Nvim server...
|
// Nvim server...
|
||||||
|
|
||||||
int listen_rv = server_init(params.listen_addr);
|
if (!server_init(params.listen_addr)) {
|
||||||
if (listen_rv != 0) {
|
mainerr(IObuff, NULL, NULL);
|
||||||
mainerr("Failed to --listen", listen_rv < 0
|
|
||||||
? os_strerror(listen_rv) : (listen_rv == 1 ? "empty address" : NULL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TIME_MSG("expanding arguments");
|
TIME_MSG("expanding arguments");
|
||||||
@ -1053,7 +1051,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
// "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
|
// "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
|
||||||
if (argv[0][0] == '+' && !had_minmin) {
|
if (argv[0][0] == '+' && !had_minmin) {
|
||||||
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
||||||
mainerr(err_extra_cmd, NULL);
|
mainerr(err_extra_cmd, NULL, NULL);
|
||||||
}
|
}
|
||||||
argv_idx = -1; // skip to next argument
|
argv_idx = -1; // skip to next argument
|
||||||
if (argv[0][1] == NUL) {
|
if (argv[0][1] == NUL) {
|
||||||
@ -1074,7 +1072,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
parmp->no_swap_file = true;
|
parmp->no_swap_file = true;
|
||||||
} else {
|
} else {
|
||||||
if (parmp->edit_type > EDIT_STDIN) {
|
if (parmp->edit_type > EDIT_STDIN) {
|
||||||
mainerr(err_too_many_args, argv[0]);
|
mainerr(err_too_many_args, argv[0], NULL);
|
||||||
}
|
}
|
||||||
parmp->had_stdin_file = true;
|
parmp->had_stdin_file = true;
|
||||||
parmp->edit_type = EDIT_STDIN;
|
parmp->edit_type = EDIT_STDIN;
|
||||||
@ -1137,7 +1135,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
nlua_disable_preload = true;
|
nlua_disable_preload = true;
|
||||||
} else {
|
} else {
|
||||||
if (argv[0][argv_idx]) {
|
if (argv[0][argv_idx]) {
|
||||||
mainerr(err_opt_unknown, argv[0]);
|
mainerr(err_opt_unknown, argv[0], NULL);
|
||||||
}
|
}
|
||||||
had_minmin = true;
|
had_minmin = true;
|
||||||
}
|
}
|
||||||
@ -1211,7 +1209,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
break;
|
break;
|
||||||
case 'q': // "-q" QuickFix mode
|
case 'q': // "-q" QuickFix mode
|
||||||
if (parmp->edit_type != EDIT_NONE) {
|
if (parmp->edit_type != EDIT_NONE) {
|
||||||
mainerr(err_too_many_args, argv[0]);
|
mainerr(err_too_many_args, argv[0], NULL);
|
||||||
}
|
}
|
||||||
parmp->edit_type = EDIT_QF;
|
parmp->edit_type = EDIT_QF;
|
||||||
if (argv[0][argv_idx]) { // "-q{errorfile}"
|
if (argv[0][argv_idx]) { // "-q{errorfile}"
|
||||||
@ -1240,7 +1238,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
break;
|
break;
|
||||||
case 't': // "-t {tag}" or "-t{tag}" jump to tag
|
case 't': // "-t {tag}" or "-t{tag}" jump to tag
|
||||||
if (parmp->edit_type != EDIT_NONE) {
|
if (parmp->edit_type != EDIT_NONE) {
|
||||||
mainerr(err_too_many_args, argv[0]);
|
mainerr(err_too_many_args, argv[0], NULL);
|
||||||
}
|
}
|
||||||
parmp->edit_type = EDIT_TAG;
|
parmp->edit_type = EDIT_TAG;
|
||||||
if (argv[0][argv_idx]) { // "-t{tag}"
|
if (argv[0][argv_idx]) { // "-t{tag}"
|
||||||
@ -1274,7 +1272,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
case 'c': // "-c{command}" or "-c {command}" exec command
|
case 'c': // "-c{command}" or "-c {command}" exec command
|
||||||
if (argv[0][argv_idx] != NUL) {
|
if (argv[0][argv_idx] != NUL) {
|
||||||
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
||||||
mainerr(err_extra_cmd, NULL);
|
mainerr(err_extra_cmd, NULL, NULL);
|
||||||
}
|
}
|
||||||
parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
|
parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
|
||||||
argv_idx = -1;
|
argv_idx = -1;
|
||||||
@ -1291,19 +1289,19 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
mainerr(err_opt_unknown, argv[0]);
|
mainerr(err_opt_unknown, argv[0], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle option arguments with argument.
|
// Handle option arguments with argument.
|
||||||
if (want_argument) {
|
if (want_argument) {
|
||||||
// Check for garbage immediately after the option letter.
|
// Check for garbage immediately after the option letter.
|
||||||
if (argv[0][argv_idx] != NUL) {
|
if (argv[0][argv_idx] != NUL) {
|
||||||
mainerr(err_opt_garbage, argv[0]);
|
mainerr(err_opt_garbage, argv[0], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
argc--;
|
argc--;
|
||||||
if (argc < 1 && c != 'S') { // -S has an optional argument
|
if (argc < 1 && c != 'S') { // -S has an optional argument
|
||||||
mainerr(err_arg_missing, argv[0]);
|
mainerr(err_arg_missing, argv[0], NULL);
|
||||||
}
|
}
|
||||||
argv++;
|
argv++;
|
||||||
argv_idx = -1;
|
argv_idx = -1;
|
||||||
@ -1312,7 +1310,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
case 'c': // "-c {command}" execute command
|
case 'c': // "-c {command}" execute command
|
||||||
case 'S': // "-S {file}" execute Vim script
|
case 'S': // "-S {file}" execute Vim script
|
||||||
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
||||||
mainerr(err_extra_cmd, NULL);
|
mainerr(err_extra_cmd, NULL, NULL);
|
||||||
}
|
}
|
||||||
if (c == 'S') {
|
if (c == 'S') {
|
||||||
char *a;
|
char *a;
|
||||||
@ -1343,7 +1341,7 @@ static void command_line_scan(mparm_T *parmp)
|
|||||||
if (strequal(argv[-1], "--cmd")) {
|
if (strequal(argv[-1], "--cmd")) {
|
||||||
// "--cmd {command}" execute command
|
// "--cmd {command}" execute command
|
||||||
if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
|
if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
|
||||||
mainerr(err_extra_cmd, NULL);
|
mainerr(err_extra_cmd, NULL, NULL);
|
||||||
}
|
}
|
||||||
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
|
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
|
||||||
} else if (strequal(argv[-1], "--listen")) {
|
} else if (strequal(argv[-1], "--listen")) {
|
||||||
@ -1425,7 +1423,7 @@ scripterror:
|
|||||||
|
|
||||||
// Check for only one type of editing.
|
// Check for only one type of editing.
|
||||||
if (parmp->edit_type > EDIT_STDIN) {
|
if (parmp->edit_type > EDIT_STDIN) {
|
||||||
mainerr(err_too_many_args, argv[0]);
|
mainerr(err_too_many_args, argv[0], NULL);
|
||||||
}
|
}
|
||||||
parmp->edit_type = EDIT_FILE;
|
parmp->edit_type = EDIT_FILE;
|
||||||
|
|
||||||
@ -1472,7 +1470,7 @@ scripterror:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (embedded_mode && (silent_mode || parmp->luaf)) {
|
if (embedded_mode && (silent_mode || parmp->luaf)) {
|
||||||
mainerr(_("--embed conflicts with -es/-Es/-l"), NULL);
|
mainerr(_("--embed conflicts with -es/-Es/-l"), NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a "+123" or "-c" command, set v:swapcommand to the first one.
|
// If there is a "+123" or "-c" command, set v:swapcommand to the first one.
|
||||||
@ -2135,28 +2133,30 @@ static int execute_env(char *env)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints the following then exits:
|
/// Prints a message of the form "{msg1}: {msg2}: {msg3}", then exits with code 1.
|
||||||
/// - An error message `errstr`
|
|
||||||
/// - A string `str` if not null
|
|
||||||
///
|
///
|
||||||
/// @param errstr string containing an error message
|
/// @param msg1 error message
|
||||||
/// @param str string to append to the primary error message, or NULL
|
/// @param msg2 extra message, or NULL
|
||||||
static void mainerr(const char *errstr, const char *str)
|
/// @param msg3 extra message, or NULL
|
||||||
|
static void mainerr(const char *msg1, const char *msg2, const char *msg3)
|
||||||
FUNC_ATTR_NORETURN
|
FUNC_ATTR_NORETURN
|
||||||
{
|
{
|
||||||
print_mainerr(errstr, str);
|
print_mainerr(msg1, msg2, msg3);
|
||||||
os_exit(1);
|
os_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_mainerr(const char *errstr, const char *str)
|
static void print_mainerr(const char *msg1, const char *msg2, const char *msg3)
|
||||||
{
|
{
|
||||||
char *prgname = path_tail(argv0);
|
char *prgname = path_tail(argv0);
|
||||||
|
|
||||||
signal_stop(); // kill us with CTRL-C here, if you like
|
signal_stop(); // kill us with CTRL-C here, if you like
|
||||||
|
|
||||||
fprintf(stderr, "%s: %s", prgname, _(errstr));
|
fprintf(stderr, "%s: %s", prgname, _(msg1));
|
||||||
if (str != NULL) {
|
if (msg2 != NULL) {
|
||||||
fprintf(stderr, ": \"%s\"", str);
|
fprintf(stderr, ": \"%s\"", msg2);
|
||||||
|
}
|
||||||
|
if (msg3 != NULL) {
|
||||||
|
fprintf(stderr, ": \"%s\"", msg3);
|
||||||
}
|
}
|
||||||
fprintf(stderr, _("\nMore info with \""));
|
fprintf(stderr, _("\nMore info with \""));
|
||||||
fprintf(stderr, "%s -h\"\n", prgname);
|
fprintf(stderr, "%s -h\"\n", prgname);
|
||||||
@ -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"));
|
||||||
}
|
}
|
||||||
|
@ -2925,17 +2925,17 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
emsg(_(e_listreq));
|
emsg(_(e_listreq));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const list_T *const l = argvars[0].vval.v_list;
|
const list_T *const l = argvars[0].vval.v_list;
|
||||||
if (tv_list_len(l) == 0) {
|
cw_interval_T *table = NULL;
|
||||||
|
const size_t table_size = (size_t)tv_list_len(l);
|
||||||
|
if (table_size == 0) {
|
||||||
// Clearing the table.
|
// Clearing the table.
|
||||||
xfree(cw_table);
|
goto update;
|
||||||
cw_table = NULL;
|
|
||||||
cw_table_size = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: use list_T instead of listitem_T so that TV_LIST_ITEM_NEXT can be used properly below.
|
// Note: use list_T instead of listitem_T so that TV_LIST_ITEM_NEXT can be used properly below.
|
||||||
const list_T **ptrs = xmalloc(sizeof(const list_T *) * (size_t)tv_list_len(l));
|
const list_T **ptrs = xmalloc(sizeof(const list_T *) * table_size);
|
||||||
|
|
||||||
// Check that all entries are a list with three numbers, the range is
|
// Check that all entries are a list with three numbers, the range is
|
||||||
// valid and the cell width is valid.
|
// valid and the cell width is valid.
|
||||||
@ -2987,12 +2987,12 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Sort the list on the first number.
|
// Sort the list on the first number.
|
||||||
qsort((void *)ptrs, (size_t)tv_list_len(l), sizeof(const list_T *), tv_nr_compare);
|
qsort((void *)ptrs, table_size, sizeof(const list_T *), tv_nr_compare);
|
||||||
|
|
||||||
cw_interval_T *table = xmalloc(sizeof(cw_interval_T) * (size_t)tv_list_len(l));
|
table = xmalloc(sizeof(cw_interval_T) * table_size);
|
||||||
|
|
||||||
// Store the items in the new table.
|
// Store the items in the new table.
|
||||||
for (item = 0; item < tv_list_len(l); item++) {
|
for (item = 0; (size_t)item < table_size; item++) {
|
||||||
const list_T *const li_l = ptrs[item];
|
const list_T *const li_l = ptrs[item];
|
||||||
const listitem_T *lili = tv_list_first(li_l);
|
const listitem_T *lili = tv_list_first(li_l);
|
||||||
const varnumber_T n1 = TV_LIST_ITEM_TV(lili)->vval.v_number;
|
const varnumber_T n1 = TV_LIST_ITEM_TV(lili)->vval.v_number;
|
||||||
@ -3011,10 +3011,12 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
|
|
||||||
xfree((void *)ptrs);
|
xfree((void *)ptrs);
|
||||||
|
|
||||||
|
update:
|
||||||
|
;
|
||||||
cw_interval_T *const cw_table_save = cw_table;
|
cw_interval_T *const cw_table_save = cw_table;
|
||||||
const size_t cw_table_size_save = cw_table_size;
|
const size_t cw_table_size_save = cw_table_size;
|
||||||
cw_table = table;
|
cw_table = table;
|
||||||
cw_table_size = (size_t)tv_list_len(l);
|
cw_table_size = table_size;
|
||||||
|
|
||||||
// Check that the new value does not conflict with 'listchars' or
|
// Check that the new value does not conflict with 'listchars' or
|
||||||
// 'fillchars'.
|
// 'fillchars'.
|
||||||
@ -3028,7 +3030,6 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
xfree(cw_table_save);
|
xfree(cw_table_save);
|
||||||
done:
|
|
||||||
changed_window_setting_all();
|
changed_window_setting_all();
|
||||||
redraw_all_later(UPD_NOT_VALID);
|
redraw_all_later(UPD_NOT_VALID);
|
||||||
}
|
}
|
||||||
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
/// HACK: os/input.c drains this queue immediately before blocking for input.
|
/// HACK: os/input.c drains this queue immediately before blocking for input.
|
||||||
/// Events on this queue are async-safe, but they need the resolved state
|
/// Events on this queue are async-safe, but they need the resolved state
|
||||||
/// of os_inchar(), so they are processed "just-in-time".
|
/// of input_get(), so they are processed "just-in-time".
|
||||||
EXTERN MultiQueue *ch_before_blocking_events INIT( = NULL);
|
EXTERN MultiQueue *ch_before_blocking_events INIT( = NULL);
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
#include "nvim/event/socket.h"
|
#include "nvim/event/socket.h"
|
||||||
#include "nvim/garray.h"
|
#include "nvim/garray.h"
|
||||||
#include "nvim/garray_defs.h"
|
#include "nvim/garray_defs.h"
|
||||||
|
#include "nvim/globals.h"
|
||||||
#include "nvim/log.h"
|
#include "nvim/log.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/msgpack_rpc/server.h"
|
#include "nvim/msgpack_rpc/server.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/stdpaths_defs.h"
|
#include "nvim/os/stdpaths_defs.h"
|
||||||
|
#include "nvim/types_defs.h"
|
||||||
|
|
||||||
#define MAX_CONNECTIONS 32
|
#define MAX_CONNECTIONS 32
|
||||||
#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
|
#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
|
||||||
@ -27,37 +29,31 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE;
|
|||||||
# include "msgpack_rpc/server.c.generated.h"
|
# include "msgpack_rpc/server.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Initializes the module
|
/// Initializes resources, handles `--listen`, starts the primary server at v:servername.
|
||||||
///
|
///
|
||||||
/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
|
/// @returns true on success, false on fatal error (message stored in IObuff)
|
||||||
int server_init(const char *listen_addr)
|
bool server_init(const char *listen_addr)
|
||||||
{
|
{
|
||||||
|
bool ok = true;
|
||||||
bool must_free = false;
|
bool must_free = false;
|
||||||
|
TriState user_arg = kTrue; // User-provided --listen arg.
|
||||||
ga_init(&watchers, sizeof(SocketWatcher *), 1);
|
ga_init(&watchers, sizeof(SocketWatcher *), 1);
|
||||||
|
|
||||||
// $NVIM_LISTEN_ADDRESS (deprecated)
|
// $NVIM_LISTEN_ADDRESS (deprecated)
|
||||||
if ((!listen_addr || listen_addr[0] == '\0') && os_env_exists(ENV_LISTEN)) {
|
if ((!listen_addr || listen_addr[0] == '\0') && os_env_exists(ENV_LISTEN)) {
|
||||||
|
user_arg = kFalse; // User-provided env var.
|
||||||
listen_addr = os_getenv(ENV_LISTEN);
|
listen_addr = os_getenv(ENV_LISTEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!listen_addr || listen_addr[0] == '\0') {
|
if (!listen_addr || listen_addr[0] == '\0') {
|
||||||
|
user_arg = kNone; // Autogenerated server address.
|
||||||
listen_addr = server_address_new(NULL);
|
listen_addr = server_address_new(NULL);
|
||||||
must_free = true;
|
must_free = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!listen_addr) {
|
|
||||||
abort(); // Cannot happen.
|
|
||||||
}
|
|
||||||
|
|
||||||
int rv = server_start(listen_addr);
|
int rv = server_start(listen_addr);
|
||||||
|
|
||||||
if (os_env_exists(ENV_LISTEN)) {
|
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
|
||||||
// Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be
|
|
||||||
// leaked to child jobs or :terminal.
|
|
||||||
os_unsetenv(ENV_LISTEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(justinmk): this is for logging_spec. Can remove this after nvim_log #7062 is merged.
|
|
||||||
if (os_env_exists("__NVIM_TEST_LOG")) {
|
if (os_env_exists("__NVIM_TEST_LOG")) {
|
||||||
ELOG("test log message");
|
ELOG("test log message");
|
||||||
}
|
}
|
||||||
@ -66,7 +62,28 @@ int server_init(const char *listen_addr)
|
|||||||
xfree((char *)listen_addr);
|
xfree((char *)listen_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
if (rv == 0 || user_arg == kNone) {
|
||||||
|
// The autogenerated servername can fail if the user has a broken $XDG_RUNTIME_DIR. #30282
|
||||||
|
// But that is not fatal (startup will continue, logged in $NVIM_LOGFILE, empty v:servername).
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)snprintf(IObuff, IOSIZE,
|
||||||
|
user_arg ==
|
||||||
|
kTrue ? "Failed to --listen: %s: \"%s\""
|
||||||
|
: "Failed $NVIM_LISTEN_ADDRESS: %s: \"%s\"",
|
||||||
|
rv < 0 ? os_strerror(rv) : (rv == 1 ? "empty address" : "?"),
|
||||||
|
listen_addr);
|
||||||
|
ok = false;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (os_env_exists(ENV_LISTEN)) {
|
||||||
|
// Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be
|
||||||
|
// leaked to child jobs or :terminal.
|
||||||
|
os_unsetenv(ENV_LISTEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Teardown a single server
|
/// Teardown a single server
|
||||||
@ -97,17 +114,19 @@ void server_teardown(void)
|
|||||||
/// - Windows: "\\.\pipe\<name>.<pid>.<counter>"
|
/// - Windows: "\\.\pipe\<name>.<pid>.<counter>"
|
||||||
/// - Other: "/tmp/nvim.user/xxx/<name>.<pid>.<counter>"
|
/// - Other: "/tmp/nvim.user/xxx/<name>.<pid>.<counter>"
|
||||||
char *server_address_new(const char *name)
|
char *server_address_new(const char *name)
|
||||||
|
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
static uint32_t count = 0;
|
static uint32_t count = 0;
|
||||||
char fmt[ADDRESS_MAX_SIZE];
|
char fmt[ADDRESS_MAX_SIZE];
|
||||||
const char *appname = get_appname();
|
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
|
(void)get_appname(true);
|
||||||
int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
|
int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
|
||||||
name ? name : appname, os_get_pid(), count++);
|
name ? name : NameBuff, os_get_pid(), count++);
|
||||||
#else
|
#else
|
||||||
char *dir = stdpaths_get_xdg_var(kXDGRuntimeDir);
|
char *dir = stdpaths_get_xdg_var(kXDGRuntimeDir);
|
||||||
|
(void)get_appname(true);
|
||||||
int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
|
int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
|
||||||
dir, name ? name : appname, os_get_pid(), count++);
|
dir, name ? name : NameBuff, os_get_pid(), count++);
|
||||||
xfree(dir);
|
xfree(dir);
|
||||||
#endif
|
#endif
|
||||||
if ((size_t)r >= sizeof(fmt)) {
|
if ((size_t)r >= sizeof(fmt)) {
|
||||||
|
@ -6597,11 +6597,11 @@ static void nv_open(cmdarg_T *cap)
|
|||||||
static void nv_event(cmdarg_T *cap)
|
static void nv_event(cmdarg_T *cap)
|
||||||
{
|
{
|
||||||
// Garbage collection should have been executed before blocking for events in
|
// Garbage collection should have been executed before blocking for events in
|
||||||
// the `os_inchar` in `state_enter`, but we also disable it here in case the
|
// the `input_get` in `state_enter`, but we also disable it here in case the
|
||||||
// `os_inchar` branch was not executed (!multiqueue_empty(loop.events), which
|
// `input_get` branch was not executed (!multiqueue_empty(loop.events), which
|
||||||
// could have `may_garbage_collect` set to true in `normal_check`).
|
// could have `may_garbage_collect` set to true in `normal_check`).
|
||||||
//
|
//
|
||||||
// That is because here we may run code that calls `os_inchar`
|
// That is because here we may run code that calls `input_get`
|
||||||
// later(`f_confirm` or `get_keystroke` for example), but in these cases it is
|
// later(`f_confirm` or `get_keystroke` for example), but in these cases it is
|
||||||
// not safe to perform garbage collection because there could be unreferenced
|
// not safe to perform garbage collection because there could be unreferenced
|
||||||
// lists or dicts being used.
|
// lists or dicts being used.
|
||||||
|
@ -210,39 +210,53 @@ static void set_init_default_backupskip(void)
|
|||||||
OptIndex opt_idx = kOptBackupskip;
|
OptIndex opt_idx = kOptBackupskip;
|
||||||
|
|
||||||
ga_init(&ga, 1, 100);
|
ga_init(&ga, 1, 100);
|
||||||
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
|
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
|
||||||
bool mustfree = true;
|
bool mustfree = true;
|
||||||
char *p;
|
char *p;
|
||||||
|
size_t plen;
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
if (*names[n] == NUL) {
|
if (*names[i] == NUL) {
|
||||||
# ifdef __APPLE__
|
# ifdef __APPLE__
|
||||||
p = "/private/tmp";
|
p = "/private/tmp";
|
||||||
|
plen = STRLEN_LITERAL("/private/tmp");
|
||||||
# else
|
# else
|
||||||
p = "/tmp";
|
p = "/tmp";
|
||||||
|
plen = STRLEN_LITERAL("/tmp");
|
||||||
# endif
|
# endif
|
||||||
mustfree = false;
|
mustfree = false;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
p = vim_getenv(names[n]);
|
p = vim_getenv(names[i]);
|
||||||
|
plen = 0; // will be calcuated below
|
||||||
}
|
}
|
||||||
if (p != NULL && *p != NUL) {
|
if (p != NULL && *p != NUL) {
|
||||||
// First time count the NUL, otherwise count the ','.
|
bool has_trailing_path_sep = false;
|
||||||
const size_t len = strlen(p) + 3;
|
|
||||||
char *item = xmalloc(len);
|
if (plen == 0) {
|
||||||
xstrlcpy(item, p, len);
|
// the value was retrieved from the environment
|
||||||
add_pathsep(item);
|
plen = strlen(p);
|
||||||
xstrlcat(item, "*", len);
|
// does the value include a trailing path separator?
|
||||||
if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
|
if (after_pathsep(p, p + plen)) {
|
||||||
== NULL) {
|
has_trailing_path_sep = true;
|
||||||
ga_grow(&ga, (int)len);
|
|
||||||
if (!GA_EMPTY(&ga)) {
|
|
||||||
strcat(ga.ga_data, ",");
|
|
||||||
}
|
}
|
||||||
strcat(ga.ga_data, p);
|
}
|
||||||
add_pathsep(ga.ga_data);
|
|
||||||
strcat(ga.ga_data, "*");
|
// item size needs to be large enough to include "/*" and a trailing NUL
|
||||||
ga.ga_len += (int)len;
|
// note: the value (and therefore plen) may already include a path separator
|
||||||
|
size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2;
|
||||||
|
char *item = xmalloc(itemsize);
|
||||||
|
// add a preceeding comma as a separator after the first item
|
||||||
|
size_t itemseplen = (ga.ga_len == 0) ? 0 : 1;
|
||||||
|
|
||||||
|
size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p,
|
||||||
|
has_trailing_path_sep ? "" : PATHSEPSTR);
|
||||||
|
|
||||||
|
if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) {
|
||||||
|
ga_grow(&ga, (int)(itemseplen + itemlen + 1));
|
||||||
|
ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len,
|
||||||
|
itemseplen + itemlen + 1,
|
||||||
|
"%s%s", (itemseplen > 0) ? "," : "", item);
|
||||||
}
|
}
|
||||||
xfree(item);
|
xfree(item);
|
||||||
}
|
}
|
||||||
@ -526,7 +540,8 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
|
|||||||
|
|
||||||
/// For an option value that contains comma separated items, find "newval" in
|
/// For an option value that contains comma separated items, find "newval" in
|
||||||
/// "origval". Return NULL if not found.
|
/// "origval". Return NULL if not found.
|
||||||
static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
|
static char *find_dup_item(char *origval, const char *newval, const size_t newvallen,
|
||||||
|
uint32_t flags)
|
||||||
FUNC_ATTR_NONNULL_ARG(2)
|
FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
if (origval == NULL) {
|
if (origval == NULL) {
|
||||||
@ -535,11 +550,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
|
|||||||
|
|
||||||
int bs = 0;
|
int bs = 0;
|
||||||
|
|
||||||
const size_t newlen = strlen(newval);
|
|
||||||
for (char *s = origval; *s != NUL; s++) {
|
for (char *s = origval; *s != NUL; s++) {
|
||||||
if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
|
if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
|
||||||
&& strncmp(s, newval, newlen) == 0
|
&& strncmp(s, newval, newvallen) == 0
|
||||||
&& (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) {
|
&& (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
// Count backslashes. Only a comma with an even number of backslashes
|
// Count backslashes. Only a comma with an even number of backslashes
|
||||||
@ -697,10 +711,10 @@ void set_helplang_default(const char *lang)
|
|||||||
}
|
}
|
||||||
p_hlg = xmemdupz(lang, lang_len);
|
p_hlg = xmemdupz(lang, lang_len);
|
||||||
// zh_CN becomes "cn", zh_TW becomes "tw".
|
// zh_CN becomes "cn", zh_TW becomes "tw".
|
||||||
if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) {
|
if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) {
|
||||||
p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]);
|
p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]);
|
||||||
p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]);
|
p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]);
|
||||||
} else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') {
|
} else if (lang_len && *p_hlg == 'C') {
|
||||||
// any C like setting, such as C.UTF-8, becomes "en"
|
// any C like setting, such as C.UTF-8, becomes "en"
|
||||||
p_hlg[0] = 'e';
|
p_hlg[0] = 'e';
|
||||||
p_hlg[1] = 'n';
|
p_hlg[1] = 'n';
|
||||||
@ -950,7 +964,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
if (op == OP_REMOVING || (flags & P_NODUP)) {
|
if (op == OP_REMOVING || (flags & P_NODUP)) {
|
||||||
len = (int)strlen(newval);
|
len = (int)strlen(newval);
|
||||||
s = find_dup_item(origval, newval, flags);
|
s = find_dup_item(origval, newval, (size_t)len, flags);
|
||||||
|
|
||||||
// do not add if already there
|
// do not add if already there
|
||||||
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
|
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
|
||||||
@ -1464,11 +1478,10 @@ int do_set(char *arg, int opt_flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errmsg != NULL) {
|
if (errmsg != NULL) {
|
||||||
xstrlcpy(IObuff, _(errmsg), IOSIZE);
|
int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2;
|
||||||
int i = (int)strlen(IObuff) + 2;
|
|
||||||
if (i + (arg - startarg) < IOSIZE) {
|
if (i + (arg - startarg) < IOSIZE) {
|
||||||
// append the argument with the error
|
// append the argument with the error
|
||||||
xstrlcat(IObuff, ": ", IOSIZE);
|
xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2));
|
||||||
assert(arg >= startarg);
|
assert(arg >= startarg);
|
||||||
memmove(IObuff + i, startarg, (size_t)(arg - startarg));
|
memmove(IObuff + i, startarg, (size_t)(arg - startarg));
|
||||||
IObuff[i + (arg - startarg)] = NUL;
|
IObuff[i + (arg - startarg)] = NUL;
|
||||||
@ -5431,7 +5444,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
|
|||||||
xp->xp_pattern = arg;
|
xp->xp_pattern = arg;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char *p = arg + strlen(arg) - 1;
|
char *const argend = arg + strlen(arg);
|
||||||
|
char *p = argend - 1;
|
||||||
if (*p == ' ' && *(p - 1) != '\\') {
|
if (*p == ' ' && *(p - 1) != '\\') {
|
||||||
xp->xp_pattern = p + 1;
|
xp->xp_pattern = p + 1;
|
||||||
return;
|
return;
|
||||||
@ -5618,7 +5632,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
|
|||||||
// Triple-backslashed escaped file names (e.g. 'path') can also be
|
// Triple-backslashed escaped file names (e.g. 'path') can also be
|
||||||
// delimited by space.
|
// delimited by space.
|
||||||
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
|
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
|
||||||
for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) {
|
for (p = argend - 1; p > xp->xp_pattern; p--) {
|
||||||
// count number of backslashes before ' ' or ','
|
// count number of backslashes before ' ' or ','
|
||||||
if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
|
if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
|
||||||
char *s = p;
|
char *s = p;
|
||||||
@ -5642,7 +5656,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
|
|||||||
// An option that is a list of single-character flags should always start
|
// An option that is a list of single-character flags should always start
|
||||||
// at the end as we don't complete words.
|
// at the end as we don't complete words.
|
||||||
if (flags & P_FLAGLIST) {
|
if (flags & P_FLAGLIST) {
|
||||||
xp->xp_pattern = arg + strlen(arg);
|
xp->xp_pattern = argend;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some options can either be using file/dir expansions, or custom value
|
// Some options can either be using file/dir expansions, or custom value
|
||||||
@ -5952,7 +5966,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
|
|||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
(*matches)[count++] = xstrdup(option_val);
|
(*matches)[count++] = xmemdupz(option_val, num_flags);
|
||||||
|
|
||||||
if (num_flags > 1) {
|
if (num_flags > 1) {
|
||||||
// If more than one flags, split the flags up and expose each
|
// If more than one flags, split the flags up and expose each
|
||||||
|
@ -761,9 +761,9 @@ return {
|
|||||||
list:{n} Adds an additional indent for lines that match a
|
list:{n} Adds an additional indent for lines that match a
|
||||||
numbered or bulleted list (using the
|
numbered or bulleted list (using the
|
||||||
'formatlistpat' setting).
|
'formatlistpat' setting).
|
||||||
list:-1 Uses the length of a match with 'formatlistpat'
|
|
||||||
for indentation.
|
|
||||||
(default: 0)
|
(default: 0)
|
||||||
|
list:-1 Uses the width of a match with 'formatlistpat' for
|
||||||
|
indentation.
|
||||||
column:{n} Indent at column {n}. Will overrule the other
|
column:{n} Indent at column {n}. Will overrule the other
|
||||||
sub-options. Note: an additional indent may be
|
sub-options. Note: an additional indent may be
|
||||||
added for the 'showbreak' setting.
|
added for the 'showbreak' setting.
|
||||||
@ -9047,7 +9047,7 @@ return {
|
|||||||
desc = [=[
|
desc = [=[
|
||||||
When on, the title of the window will be set to the value of
|
When on, the title of the window will be set to the value of
|
||||||
'titlestring' (if it is not empty), or to:
|
'titlestring' (if it is not empty), or to:
|
||||||
filename [+=-] (path) - NVIM
|
filename [+=-] (path) - Nvim
|
||||||
Where:
|
Where:
|
||||||
filename the name of the file being edited
|
filename the name of the file being edited
|
||||||
- indicates the file cannot be modified, 'ma' off
|
- indicates the file cannot be modified, 'ma' off
|
||||||
@ -9055,11 +9055,11 @@ return {
|
|||||||
= indicates the file is read-only
|
= indicates the file is read-only
|
||||||
=+ indicates the file is read-only and modified
|
=+ indicates the file is read-only and modified
|
||||||
(path) is the path of the file being edited
|
(path) is the path of the file being edited
|
||||||
- NVIM the server name |v:servername| or "NVIM"
|
- Nvim the server name |v:servername| or "Nvim"
|
||||||
]=],
|
]=],
|
||||||
full_name = 'title',
|
full_name = 'title',
|
||||||
scope = { 'global' },
|
scope = { 'global' },
|
||||||
short_desc = N_('Vim set the title of the window'),
|
short_desc = N_('set the title of the window'),
|
||||||
type = 'boolean',
|
type = 'boolean',
|
||||||
varname = 'p_title',
|
varname = 'p_title',
|
||||||
},
|
},
|
||||||
|
@ -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)
|
||||||
|
@ -33,12 +33,6 @@
|
|||||||
#define READ_BUFFER_SIZE 0xfff
|
#define READ_BUFFER_SIZE 0xfff
|
||||||
#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
|
#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
kInputNone,
|
|
||||||
kInputAvail,
|
|
||||||
kInputEof,
|
|
||||||
} InbufPollResult;
|
|
||||||
|
|
||||||
static RStream read_stream = { .s.closed = true }; // Input before UI starts.
|
static RStream read_stream = { .s.closed = true }; // Input before UI starts.
|
||||||
static char input_buffer[INPUT_BUFFER_SIZE];
|
static char input_buffer[INPUT_BUFFER_SIZE];
|
||||||
static char *input_read_pos = input_buffer;
|
static char *input_read_pos = input_buffer;
|
||||||
@ -84,57 +78,76 @@ static void cursorhold_event(void **argv)
|
|||||||
static void create_cursorhold_event(bool events_enabled)
|
static void create_cursorhold_event(bool events_enabled)
|
||||||
{
|
{
|
||||||
// If events are enabled and the queue has any items, this function should not
|
// If events are enabled and the queue has any items, this function should not
|
||||||
// have been called (inbuf_poll would return kInputAvail).
|
// have been called (`inbuf_poll` would return `kTrue`).
|
||||||
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
|
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
|
||||||
// `state_check` callback for the states where it can be triggered.
|
// `state_check` callback for the states where it can be triggered.
|
||||||
assert(!events_enabled || multiqueue_empty(main_loop.events));
|
assert(!events_enabled || multiqueue_empty(main_loop.events));
|
||||||
multiqueue_put(main_loop.events, cursorhold_event, NULL);
|
multiqueue_put(main_loop.events, cursorhold_event, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restart_cursorhold_wait(int tb_change_cnt)
|
static void reset_cursorhold_wait(int tb_change_cnt)
|
||||||
{
|
{
|
||||||
cursorhold_time = 0;
|
cursorhold_time = 0;
|
||||||
cursorhold_tb_change_cnt = tb_change_cnt;
|
cursorhold_tb_change_cnt = tb_change_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Low level input function
|
/// Reads OS input into `buf`, and consumes pending events while waiting (if `ms != 0`).
|
||||||
///
|
///
|
||||||
/// Wait until either the input buffer is non-empty or, if `events` is not NULL
|
/// - Consumes available input received from the OS.
|
||||||
/// until `events` is non-empty.
|
/// - Consumes pending events.
|
||||||
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
|
/// - Manages CursorHold events.
|
||||||
|
/// - Handles EOF conditions.
|
||||||
|
///
|
||||||
|
/// Originally based on the Vim `mch_inchar` function.
|
||||||
|
///
|
||||||
|
/// @param buf Buffer to store consumed input.
|
||||||
|
/// @param maxlen Maximum bytes to read into `buf`, or 0 to skip reading.
|
||||||
|
/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
|
||||||
|
/// @param tb_change_cnt Used to detect when typeahead changes.
|
||||||
|
/// @param events (optional) Events to process.
|
||||||
|
/// @return Bytes read into buf, or 0 if no input was read
|
||||||
|
int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
|
||||||
{
|
{
|
||||||
// This check is needed so that feeding typeahead from RPC can prevent CursorHold.
|
// This check is needed so that feeding typeahead from RPC can prevent CursorHold.
|
||||||
if (tb_change_cnt != cursorhold_tb_change_cnt) {
|
if (tb_change_cnt != cursorhold_tb_change_cnt) {
|
||||||
restart_cursorhold_wait(tb_change_cnt);
|
reset_cursorhold_wait(tb_change_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxlen && input_available()) {
|
#define TRY_READ() \
|
||||||
restart_cursorhold_wait(tb_change_cnt);
|
do { \
|
||||||
size_t to_read = MIN((size_t)maxlen, input_available());
|
if (maxlen && input_available()) { \
|
||||||
memcpy(buf, input_read_pos, to_read);
|
reset_cursorhold_wait(tb_change_cnt); \
|
||||||
input_read_pos += to_read;
|
assert(maxlen >= 0); \
|
||||||
return (int)to_read;
|
size_t to_read = MIN((size_t)maxlen, input_available()); \
|
||||||
}
|
memcpy(buf, input_read_pos, to_read); \
|
||||||
|
input_read_pos += to_read; \
|
||||||
|
/* This is safe because INPUT_BUFFER_SIZE fits in an int. */ \
|
||||||
|
assert(to_read <= INT_MAX); \
|
||||||
|
return (int)to_read; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
TRY_READ();
|
||||||
|
|
||||||
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
|
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
|
||||||
if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
|
if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
|
||||||
ctrl_c_interrupts = false;
|
ctrl_c_interrupts = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
InbufPollResult result;
|
TriState result; ///< inbuf_poll result.
|
||||||
if (ms >= 0) {
|
if (ms >= 0) {
|
||||||
if ((result = inbuf_poll(ms, events)) == kInputNone) {
|
if ((result = inbuf_poll(ms, events)) == kFalse) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint64_t wait_start = os_hrtime();
|
uint64_t wait_start = os_hrtime();
|
||||||
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
|
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
|
||||||
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
|
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) {
|
||||||
if (read_stream.s.closed && silent_mode) {
|
if (read_stream.s.closed && silent_mode) {
|
||||||
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
|
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
|
||||||
read_error_exit();
|
read_error_exit();
|
||||||
}
|
}
|
||||||
restart_cursorhold_wait(tb_change_cnt);
|
reset_cursorhold_wait(tb_change_cnt);
|
||||||
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
|
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
|
||||||
create_cursorhold_event(events == main_loop.events);
|
create_cursorhold_event(events == main_loop.events);
|
||||||
} else {
|
} else {
|
||||||
@ -153,32 +166,26 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxlen && input_available()) {
|
TRY_READ();
|
||||||
restart_cursorhold_wait(tb_change_cnt);
|
|
||||||
// Safe to convert `to_read` to int, it will never overflow since
|
|
||||||
// INPUT_BUFFER_SIZE fits in an int
|
|
||||||
size_t to_read = MIN((size_t)maxlen, input_available());
|
|
||||||
memcpy(buf, input_read_pos, to_read);
|
|
||||||
input_read_pos += to_read;
|
|
||||||
return (int)to_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are events, return the keys directly
|
// If there are events, return the keys directly
|
||||||
if (maxlen && pending_events(events)) {
|
if (maxlen && pending_events(events)) {
|
||||||
return push_event_key(buf, maxlen);
|
return push_event_key(buf, maxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == kInputEof) {
|
if (result == kNone) {
|
||||||
read_error_exit();
|
read_error_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#undef TRY_READ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a character is available for reading
|
// Check if a character is available for reading
|
||||||
bool os_char_avail(void)
|
bool os_char_avail(void)
|
||||||
{
|
{
|
||||||
return inbuf_poll(0, NULL) == kInputAvail;
|
return inbuf_poll(0, NULL) == kTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
|
/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
|
||||||
@ -463,15 +470,22 @@ bool input_blocking(void)
|
|||||||
return blocking;
|
return blocking;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a replacement for the old `WaitForChar` function in os_unix.c
|
/// Checks for (but does not read) available input, and consumes `main_loop.events` while waiting.
|
||||||
static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
|
///
|
||||||
|
/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
|
||||||
|
/// @param events (optional) Queue to check for pending events.
|
||||||
|
/// @return TriState:
|
||||||
|
/// - kTrue: Input/events available
|
||||||
|
/// - kFalse: No input/events
|
||||||
|
/// - kNone: EOF reached on the input stream
|
||||||
|
static TriState inbuf_poll(int ms, MultiQueue *events)
|
||||||
{
|
{
|
||||||
if (os_input_ready(events)) {
|
if (os_input_ready(events)) {
|
||||||
return kInputAvail;
|
return kTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_profiling == PROF_YES && ms) {
|
if (do_profiling == PROF_YES && ms) {
|
||||||
prof_inchar_enter();
|
prof_input_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) {
|
if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) {
|
||||||
@ -479,20 +493,18 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
|
|||||||
blocking = true;
|
blocking = true;
|
||||||
multiqueue_process_events(ch_before_blocking_events);
|
multiqueue_process_events(ch_before_blocking_events);
|
||||||
}
|
}
|
||||||
DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL,
|
DLOG("blocking... events=%s", !!events ? "true" : "false");
|
||||||
events && !multiqueue_empty(events));
|
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, os_input_ready(events) || input_eof);
|
||||||
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms,
|
|
||||||
os_input_ready(events) || input_eof);
|
|
||||||
blocking = false;
|
blocking = false;
|
||||||
|
|
||||||
if (do_profiling == PROF_YES && ms) {
|
if (do_profiling == PROF_YES && ms) {
|
||||||
prof_inchar_exit();
|
prof_input_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os_input_ready(events)) {
|
if (os_input_ready(events)) {
|
||||||
return kInputAvail;
|
return kTrue;
|
||||||
}
|
}
|
||||||
return input_eof ? kInputEof : kInputNone;
|
return input_eof ? kNone : kFalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
|
static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
|
||||||
@ -533,8 +545,8 @@ static void process_ctrl_c(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function used to push bytes from the 'event' key sequence partially
|
/// Pushes bytes from the "event" key sequence (KE_EVENT) partially between calls to input_get when
|
||||||
// between calls to os_inchar when maxlen < 3
|
/// `maxlen < 3`.
|
||||||
static int push_event_key(uint8_t *buf, int maxlen)
|
static int push_event_key(uint8_t *buf, int maxlen)
|
||||||
{
|
{
|
||||||
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
|
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
|
||||||
|
@ -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)
|
@ -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
|
@ -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
7
src/nvim/os/pty_proc.h
Normal 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
|
@ -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;
|
@ -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
|
@ -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;
|
||||||
}
|
}
|
@ -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
|
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef MSWIN
|
|
||||||
# include "nvim/os/pty_process_win.h"
|
|
||||||
#else
|
|
||||||
# include "nvim/os/pty_process_unix.h"
|
|
||||||
#endif
|
|
@ -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);
|
||||||
@ -1292,7 +1292,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
|
|||||||
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
|
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
|
||||||
uv_err_name(status));
|
uv_err_name(status));
|
||||||
}
|
}
|
||||||
stream_close(stream, NULL, NULL, false);
|
stream_may_close(stream, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
|
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
|
||||||
|
@ -63,22 +63,32 @@ static const char *const xdg_defaults[] = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Get the value of $NVIM_APPNAME or "nvim" if not set.
|
/// Gets the value of $NVIM_APPNAME, or "nvim" if not set.
|
||||||
|
///
|
||||||
|
/// @param namelike Write "name-like" value (no path separators) in `NameBuff`.
|
||||||
///
|
///
|
||||||
/// @return $NVIM_APPNAME value
|
/// @return $NVIM_APPNAME value
|
||||||
const char *get_appname(void)
|
const char *get_appname(bool namelike)
|
||||||
{
|
{
|
||||||
const char *env_val = os_getenv("NVIM_APPNAME");
|
const char *env_val = os_getenv("NVIM_APPNAME");
|
||||||
if (env_val == NULL || *env_val == NUL) {
|
if (env_val == NULL || *env_val == NUL) {
|
||||||
env_val = "nvim";
|
env_val = "nvim";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (namelike) {
|
||||||
|
// Appname may be a relative path, replace slashes to make it name-like.
|
||||||
|
xstrlcpy(NameBuff, env_val, sizeof(NameBuff));
|
||||||
|
memchrsub(NameBuff, '/', '-', sizeof(NameBuff));
|
||||||
|
memchrsub(NameBuff, '\\', '-', sizeof(NameBuff));
|
||||||
|
}
|
||||||
|
|
||||||
return env_val;
|
return env_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that APPNAME is valid. Must be a name or relative path.
|
/// Ensure that APPNAME is valid. Must be a name or relative path.
|
||||||
bool appname_is_valid(void)
|
bool appname_is_valid(void)
|
||||||
{
|
{
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname(false);
|
||||||
if (path_is_absolute(appname)
|
if (path_is_absolute(appname)
|
||||||
// TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
|
// TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
|
||||||
|| strequal(appname, "/")
|
|| strequal(appname, "/")
|
||||||
@ -193,7 +203,7 @@ char *get_xdg_home(const XDGVarType idx)
|
|||||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
char *dir = stdpaths_get_xdg_var(idx);
|
char *dir = stdpaths_get_xdg_var(idx);
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname(false);
|
||||||
size_t appname_len = strlen(appname);
|
size_t appname_len = strlen(appname);
|
||||||
assert(appname_len < (IOSIZE - sizeof("-data")));
|
assert(appname_len < (IOSIZE - sizeof("-data")));
|
||||||
|
|
||||||
|
@ -383,19 +383,19 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg)
|
|||||||
xp->xp_context = EXPAND_NOTHING;
|
xp->xp_context = EXPAND_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static proftime_T inchar_time;
|
static proftime_T wait_time;
|
||||||
|
|
||||||
/// Called when starting to wait for the user to type a character.
|
/// Called when starting to wait for the user to type a character.
|
||||||
void prof_inchar_enter(void)
|
void prof_input_start(void)
|
||||||
{
|
{
|
||||||
inchar_time = profile_start();
|
wait_time = profile_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when finished waiting for the user to type a character.
|
/// Called when finished waiting for the user to type a character.
|
||||||
void prof_inchar_exit(void)
|
void prof_input_end(void)
|
||||||
{
|
{
|
||||||
inchar_time = profile_end(inchar_time);
|
wait_time = profile_end(wait_time);
|
||||||
profile_set_wait(profile_add(profile_get_wait(), inchar_time));
|
profile_set_wait(profile_add(profile_get_wait(), wait_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return true when a function defined in the current script should be
|
/// @return true when a function defined in the current script should be
|
||||||
@ -950,8 +950,8 @@ void time_msg(const char *mesg, const proftime_T *start)
|
|||||||
/// Initializes the `time_fd` stream for the --startuptime report.
|
/// 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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1559,7 +1559,7 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val, const ch
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
const void *iter = NULL;
|
const void *iter = NULL;
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname(false);
|
||||||
const size_t appname_len = strlen(appname);
|
const size_t appname_len = strlen(appname);
|
||||||
do {
|
do {
|
||||||
size_t dir_len;
|
size_t dir_len;
|
||||||
@ -1626,7 +1626,7 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_
|
|||||||
if (!after_pathsep(dest - 1, dest)) {
|
if (!after_pathsep(dest - 1, dest)) {
|
||||||
*dest++ = PATHSEP;
|
*dest++ = PATHSEP;
|
||||||
}
|
}
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname(false);
|
||||||
size_t appname_len = strlen(appname);
|
size_t appname_len = strlen(appname);
|
||||||
assert(appname_len < (IOSIZE - sizeof("-data")));
|
assert(appname_len < (IOSIZE - sizeof("-data")));
|
||||||
xmemcpyz(IObuff, appname, appname_len);
|
xmemcpyz(IObuff, appname, appname_len);
|
||||||
@ -1697,7 +1697,7 @@ char *runtimepath_default(bool clean_arg)
|
|||||||
size_t config_len = 0;
|
size_t config_len = 0;
|
||||||
size_t vimruntime_len = 0;
|
size_t vimruntime_len = 0;
|
||||||
size_t libdir_len = 0;
|
size_t libdir_len = 0;
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname(false);
|
||||||
size_t appname_len = strlen(appname);
|
size_t appname_len = strlen(appname);
|
||||||
if (data_home != NULL) {
|
if (data_home != NULL) {
|
||||||
data_len = strlen(data_home);
|
data_len = strlen(data_home);
|
||||||
|
@ -74,10 +74,9 @@ getkey:
|
|||||||
}
|
}
|
||||||
// Flush screen updates before blocking.
|
// Flush screen updates before blocking.
|
||||||
ui_flush();
|
ui_flush();
|
||||||
// Call `os_inchar` directly to block for events or user input without
|
// Call `input_get` directly to block for events or user input without consuming anything from
|
||||||
// consuming anything from `input_buffer`(os/input.c) or calling the
|
// `os/input.c:input_buffer` or calling the mapping engine.
|
||||||
// mapping engine.
|
input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
||||||
os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
|
||||||
// If an event was put into the queue, we send K_EVENT directly.
|
// If an event was put into the queue, we send K_EVENT directly.
|
||||||
if (!input_available() && !multiqueue_empty(main_loop.events)) {
|
if (!input_available() && !multiqueue_empty(main_loop.events)) {
|
||||||
key = K_EVENT;
|
key = K_EVENT;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "nvim/memory_defs.h"
|
#include "nvim/memory_defs.h"
|
||||||
#include "nvim/msgpack_rpc/channel.h"
|
#include "nvim/msgpack_rpc/channel.h"
|
||||||
#include "nvim/msgpack_rpc/channel_defs.h"
|
#include "nvim/msgpack_rpc/channel_defs.h"
|
||||||
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/os_defs.h"
|
#include "nvim/os/os_defs.h"
|
||||||
#include "nvim/tui/tui.h"
|
#include "nvim/tui/tui.h"
|
||||||
#include "nvim/tui/tui_defs.h"
|
#include "nvim/tui/tui_defs.h"
|
||||||
@ -126,6 +127,11 @@ void ui_client_run(bool remote_ui)
|
|||||||
|
|
||||||
ui_client_attach(width, height, term, rgb);
|
ui_client_attach(width, height, term, rgb);
|
||||||
|
|
||||||
|
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
|
||||||
|
if (os_env_exists("__NVIM_TEST_LOG")) {
|
||||||
|
ELOG("test log message");
|
||||||
|
}
|
||||||
|
|
||||||
// os_exit() will be invoked when the client channel detaches
|
// os_exit() will be invoked when the client channel detaches
|
||||||
while (true) {
|
while (true) {
|
||||||
LOOP_PROCESS_EVENTS(&main_loop, resize_events, -1);
|
LOOP_PROCESS_EVENTS(&main_loop, resize_events, -1);
|
||||||
|
@ -14,7 +14,7 @@ EXTERN size_t grid_line_buf_size INIT( = 0);
|
|||||||
EXTERN schar_T *grid_line_buf_char INIT( = NULL);
|
EXTERN schar_T *grid_line_buf_char INIT( = NULL);
|
||||||
EXTERN sattr_T *grid_line_buf_attr INIT( = NULL);
|
EXTERN sattr_T *grid_line_buf_attr INIT( = NULL);
|
||||||
|
|
||||||
// ID of the ui client channel. If zero, the client is not running.
|
// Client-side UI channel. Zero during early startup or if not a (--remote-ui) UI client.
|
||||||
EXTERN uint64_t ui_client_channel_id INIT( = 0);
|
EXTERN uint64_t ui_client_channel_id INIT( = 0);
|
||||||
|
|
||||||
// exit status from embedded nvim process
|
// exit status from embedded nvim process
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user