mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
Compare commits
43 Commits
17de3a2144
...
dc39e9f0e2
Author | SHA1 | Date | |
---|---|---|---|
|
dc39e9f0e2 | ||
|
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 | ||
|
8a3bc607d6 |
@ -7,8 +7,8 @@ LUAJIT_SHA256 2b5514bd6a6573cb6111b43d013e952cbaf46762d14ebe26c872ddb80b5a84e0
|
||||
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
|
||||
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
|
||||
|
||||
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/d72c3598e7ac5d1ebf86ee268b8b4ed95c0fa628.tar.gz
|
||||
UNIBILIUM_SHA256 9c4747c862ab5e3076dcf8fa8f0ea7a6b50f20ec5905618b9536655596797487
|
||||
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/ab28a2ddb86a144194a798bcf1fef1ab4f981ab7.tar.gz
|
||||
UNIBILIUM_SHA256 7c0386fc48452632868e0dcb8e7ed140d67a3da79e39ceee54c1ba7a495ad625
|
||||
|
||||
LUV_URL https://github.com/luvit/luv/releases/download/1.48.0-2/luv-1.48.0-2.tar.gz
|
||||
LUV_SHA256 2c3a1ddfebb4f6550293a40ee789f7122e97647eede51511f57203de48c03b7a
|
||||
@ -38,18 +38,18 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
|
||||
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/3de4596fbe28956855df2ecb3c11c0bbc3535838.tar.gz
|
||||
UTF8PROC_SHA256 fb4a16bb659b58afb7f921fcc8928d0b3c1fcab135366c8a4f9ca7de1b1cfada
|
||||
|
||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.21.3.tar.gz
|
||||
TREESITTER_C_SHA256 75a3780df6114cd37496761c4a7c9fd900c78bee3a2707f590d78c0ca3a24368
|
||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.1.0.tar.gz
|
||||
TREESITTER_LUA_SHA256 230cfcbfa74ed1f7b8149e9a1f34c2efc4c589a71fe0f5dc8560622f8020d722
|
||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.0.tar.gz
|
||||
TREESITTER_C_SHA256 ee58c925e2e507c23d735aad46bf7fb0af31ca06d6f4f41bc008216d9232b0cb
|
||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.2.0.tar.gz
|
||||
TREESITTER_LUA_SHA256 6c41227cd0a59047b19d31f0031d4d901f08bfd78d6fc7f55c89e5b8374c794e
|
||||
TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz
|
||||
TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5
|
||||
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.0.tar.gz
|
||||
TREESITTER_VIMDOC_SHA256 a639bf92bf57bfa1cdc90ca16af27bfaf26a9779064776dd4be34c1ef1453f6c
|
||||
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz
|
||||
TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e
|
||||
TREESITTER_MARKDOWN_URL https://github.com/MDeiml/tree-sitter-markdown/archive/v0.2.3.tar.gz
|
||||
TREESITTER_MARKDOWN_SHA256 4909d6023643f1afc3ab219585d4035b7403f3a17849782ab803c5f73c8a31d5
|
||||
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.3.2.tar.gz
|
||||
TREESITTER_MARKDOWN_SHA256 5dac48a6d971eb545aab665d59a18180d21963afc781bbf40f9077c06cb82ae5
|
||||
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.23.0.tar.gz
|
||||
TREESITTER_SHA256 6403b361b0014999e96f61b9c84d6950d42f0c7d6e806be79382e0232e48a11b
|
||||
|
||||
|
@ -4,6 +4,8 @@ They are used with the ":compiler" command.
|
||||
These scripts usually set options, for example 'errorformat'.
|
||||
See ":help write-compiler-plugin".
|
||||
|
||||
To undo the effect of a compiler plugin, use the make compiler plugin.
|
||||
|
||||
If you want to write your own compiler plugin, have a look at the other files
|
||||
for how to do it, the format is simple.
|
||||
|
||||
|
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
|
||||
" Compiler: Pandoc
|
||||
" Maintainer: Konfekt
|
||||
" Last Change: 2024 Aug 20
|
||||
" Last Change: 2024 Sep 8
|
||||
"
|
||||
" Expects output file extension, say `:make html` or `:make pdf`.
|
||||
" Passes additional arguments to pandoc, say `:make html --self-contained`.
|
||||
" Adjust command-line flags by buffer-local/global variable
|
||||
" b/g:pandoc_compiler_args which defaults to empty.
|
||||
|
||||
if exists("current_compiler")
|
||||
finish
|
||||
@ -40,18 +42,21 @@ silent! function s:PandocFiletype(filetype) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let b:pandoc_compiler_from = get(b:, 'pandoc_compiler_from', s:PandocFiletype(&filetype))
|
||||
let b:pandoc_compiler_lang = get(b:, 'pandoc_compiler_lang', &spell ? matchstr(&spelllang, '^\a\a') : '')
|
||||
silent! function s:PandocLang()
|
||||
let lang = get(b:, 'pandoc_compiler_lang',
|
||||
\ &spell ? matchstr(&spelllang, '^\a\a') : '')
|
||||
if lang ==# 'en' | let lang = '' | endif
|
||||
return empty(lang) ? '' : '--metadata lang='..lang
|
||||
endfunction
|
||||
|
||||
execute 'CompilerSet makeprg=pandoc'..escape(
|
||||
\ ' --standalone' .
|
||||
\ (b:pandoc_compiler_from ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
|
||||
\ '' : ' --metadata title=%:t:r:S') .
|
||||
\ (empty(b:pandoc_compiler_lang) ?
|
||||
\ '' : ' --metadata lang='..b:pandoc_compiler_lang) .
|
||||
\ ' --from='..b:pandoc_compiler_from .
|
||||
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', '')) .
|
||||
\ ' --output %:r:S.$* -- %:S', ' ')
|
||||
\ ' --standalone'..
|
||||
\ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
|
||||
\ '' : ' --metadata title=%:t:r:S')..
|
||||
\ ' '..s:PandocLang()..
|
||||
\ ' --from='..s:PandocFiletype(&filetype)..
|
||||
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', ''))..
|
||||
\ ' --output %:r:S.$* -- %:S', ' ')
|
||||
CompilerSet errorformat=\"%f\",\ line\ %l:\ %m
|
||||
|
||||
let &cpo = s:keepcpo
|
||||
|
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
|
||||
giving the argument.
|
||||
|
||||
Note: the timeout is only considered when searching, not
|
||||
while evaluating the {skip} expression.
|
||||
|
||||
If the {skip} expression is given it is evaluated with the
|
||||
cursor positioned on the start of a match. If it evaluates to
|
||||
non-zero this match is skipped. This can be used, for
|
||||
|
@ -526,28 +526,32 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
*vim.diagnostic.Opts.Signs*
|
||||
|
||||
Fields: ~
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual text
|
||||
for diagnostics matching the given severity
|
||||
|diagnostic-severity|
|
||||
• {priority}? (`integer`, default: `10`) Base priority to use for
|
||||
signs. When {severity_sort} is used, the priority of a
|
||||
sign is adjusted based on its severity. Otherwise, all
|
||||
signs use the same priority.
|
||||
• {text}? (`table<vim.diagnostic.Severity,string>`) A table mapping
|
||||
|diagnostic-severity| to the sign text to display in the
|
||||
sign column. The default is to use `"E"`, `"W"`, `"I"`,
|
||||
and `"H"` for errors, warnings, information, and hints,
|
||||
respectively. Example: >lua
|
||||
vim.diagnostic.config({
|
||||
signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } }
|
||||
})
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual
|
||||
text for diagnostics matching the given severity
|
||||
|diagnostic-severity|
|
||||
• {priority}? (`integer`, default: `10`) Base priority to use for
|
||||
signs. When {severity_sort} is used, the priority of a
|
||||
sign is adjusted based on its severity. Otherwise, all
|
||||
signs use the same priority.
|
||||
• {text}? (`table<vim.diagnostic.Severity,string>`) A table
|
||||
mapping |diagnostic-severity| to the sign text to
|
||||
display in the sign column. The default is to use
|
||||
`"E"`, `"W"`, `"I"`, and `"H"` for errors, warnings,
|
||||
information, and hints, respectively. Example: >lua
|
||||
vim.diagnostic.config({
|
||||
signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } }
|
||||
})
|
||||
<
|
||||
• {numhl}? (`table<vim.diagnostic.Severity,string>`) A table mapping
|
||||
|diagnostic-severity| to the highlight group used for the
|
||||
line number where the sign is placed.
|
||||
• {linehl}? (`table<vim.diagnostic.Severity,string>`) A table mapping
|
||||
|diagnostic-severity| to the highlight group used for the
|
||||
whole line the sign is placed in.
|
||||
• {numhl}? (`table<vim.diagnostic.Severity,string>`) A table
|
||||
mapping |diagnostic-severity| to the highlight group
|
||||
used for the line number where the sign is placed.
|
||||
• {linehl}? (`table<vim.diagnostic.Severity,string>`) A table
|
||||
mapping |diagnostic-severity| to the highlight group
|
||||
used for the whole line the sign is placed in.
|
||||
• {cursorlinehl} (`table<vim.diagnostic.Severity,string>`) A table
|
||||
mapping |diagnostic-severity| to the highlight group
|
||||
used for the highlight the sign column text when
|
||||
cursor is on target line and 'cursorline' is enabled.
|
||||
|
||||
*vim.diagnostic.Opts.Underline*
|
||||
|
||||
|
@ -2230,6 +2230,12 @@ vim.tbl_count({t}) *vim.tbl_count()*
|
||||
vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()*
|
||||
Merges recursively two or more tables.
|
||||
|
||||
Only values that are empty tables or tables that are not |lua-list|s
|
||||
(indexed by consecutive integers starting from 1) are merged recursively.
|
||||
This is useful for merging nested tables like default and user
|
||||
configurations where lists should be treated as literals (i.e., are
|
||||
overwritten instead of merged).
|
||||
|
||||
Parameters: ~
|
||||
• {behavior} (`'error'|'keep'|'force'`) Decides what to do if a key is
|
||||
found in more than one map:
|
||||
|
@ -189,7 +189,8 @@ TREESITTER
|
||||
|
||||
TUI
|
||||
|
||||
• TODO
|
||||
• |log| messages written by the builtin UI client (TUI, |--remote-ui|) are
|
||||
now prefixed with "ui" instead of "?".
|
||||
|
||||
UI
|
||||
|
||||
@ -214,9 +215,6 @@ These existing features changed their behavior.
|
||||
more emoji characters than before, including those encoded with multiple
|
||||
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
|
||||
|
||||
• |vim.tbl_deep_extend()| no longer ignores any values for which |vim.isarray()|
|
||||
returns `true`.
|
||||
|
||||
==============================================================================
|
||||
REMOVED FEATURES *news-removed*
|
||||
|
||||
|
@ -6713,7 +6713,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
global
|
||||
When on, the title of the window will be set to the value of
|
||||
'titlestring' (if it is not empty), or to:
|
||||
filename [+=-] (path) - NVIM
|
||||
filename [+=-] (path) - Nvim
|
||||
Where:
|
||||
filename the name of the file being edited
|
||||
- indicates the file cannot be modified, 'ma' off
|
||||
@ -6721,7 +6721,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
= indicates the file is read-only
|
||||
=+ indicates the file is read-only and modified
|
||||
(path) is the path of the file being edited
|
||||
- NVIM the server name |v:servername| or "NVIM"
|
||||
- Nvim the server name |v:servername| or "Nvim"
|
||||
|
||||
*'titlelen'*
|
||||
'titlelen' number (default 85)
|
||||
|
@ -1262,6 +1262,7 @@ not "b:current_compiler". What the command actually does is the following:
|
||||
|
||||
For writing a compiler plugin, see |write-compiler-plugin|.
|
||||
|
||||
Use the |compiler-make| plugin to undo the effect of a compiler plugin.
|
||||
|
||||
DOTNET *compiler-dotnet*
|
||||
|
||||
@ -1277,7 +1278,6 @@ Example: limit output to only display errors, and suppress the project name: >
|
||||
let dotnet_show_project_file = v:false
|
||||
compiler dotnet
|
||||
<
|
||||
|
||||
GCC *quickfix-gcc* *compiler-gcc*
|
||||
|
||||
There's one variable you can set for the GCC compiler:
|
||||
@ -1294,6 +1294,24 @@ Commonly used compiler options can be added to 'makeprg' by setting the
|
||||
g:javac_makeprg_params variable. For example: >
|
||||
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
|
||||
<
|
||||
GNU MAKE *compiler-make*
|
||||
|
||||
Since the default make program is "make", the compiler plugin for make,
|
||||
:compiler make, will reset the 'makeprg' and 'errorformat' option to
|
||||
the default values and unlet any variables that may have been set by a
|
||||
previous compiler plugin.
|
||||
|
||||
GROFF *quickfix-groff* *compiler-groff*
|
||||
|
||||
The GROFF compiler plugin uses the mom macro set (documented in the groff_mom
|
||||
manpage) as input and expects that the output file type extension is passed to
|
||||
make, say :make html or :make pdf.
|
||||
|
||||
Additional arguments can be passed to groff by setting them in
|
||||
`b:groff_compiler_args` or `g:groff_compiler_args`. The `language` argument
|
||||
passed to groff is set using 'spelllang'; it can be overridden by setting
|
||||
`b:groff_compiler_lang`. The default enconding is `UTF-8` and can be changed
|
||||
by setting `b:groff_compiler_encoding` or `g:groff_compiler_encoding`.
|
||||
|
||||
PANDOC *quickfix-pandoc* *compiler-pandoc*
|
||||
|
||||
@ -1307,8 +1325,7 @@ Additional arguments can be passed to pandoc:
|
||||
|
||||
The `--from` argument is an educated guess using the buffer file type;
|
||||
it can be overridden by setting `b:pandoc_compiler_from`.
|
||||
Likewise the `--metadata lang` argument is set using `&spelllang`;
|
||||
it can be overridden by setting `b:pandoc_compiler_lang`.
|
||||
The `--metadata lang` argument is set using 'spelllang';
|
||||
If `--from=markdown` is assumed and no title set in a title header or
|
||||
YAML block, then the filename (without extension) is used as the title.
|
||||
|
||||
|
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
|
||||
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
|
||||
" Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014)
|
||||
" Last Change: Mon Jun 01 21:15 MSK 2015 Igor Gnatenko
|
||||
" Update by Zdenek Dohnal, 2022 May 17
|
||||
" Last Change: 2015 Jun 01
|
||||
" Update by Zdenek Dohnal, 2022 May 17
|
||||
" 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@ -66,9 +67,11 @@ if !exists("*s:SpecChangelog")
|
||||
endif
|
||||
let line = 0
|
||||
let name = ""
|
||||
let epoch = ""
|
||||
let ver = ""
|
||||
let rel = ""
|
||||
let nameline = -1
|
||||
let epochline = -1
|
||||
let verline = -1
|
||||
let relline = -1
|
||||
let chgline = -1
|
||||
@ -77,6 +80,9 @@ if !exists("*s:SpecChangelog")
|
||||
if name == "" && linestr =~? '^Name:'
|
||||
let nameline = line
|
||||
let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
||||
elseif epoch == "" && linestr =~? '^Epoch:'
|
||||
let epochline = line
|
||||
let epoch = substitute(strpart(linestr,6), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
||||
elseif ver == "" && linestr =~? '^Version:'
|
||||
let verline = line
|
||||
let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
|
||||
@ -93,6 +99,7 @@ if !exists("*s:SpecChangelog")
|
||||
if nameline != -1 && verline != -1 && relline != -1
|
||||
let include_release_info = exists("g:spec_chglog_release_info")
|
||||
let name = s:ParseRpmVars(name, nameline)
|
||||
let epoch = s:ParseRpmVars(epoch, epochline)
|
||||
let ver = s:ParseRpmVars(ver, verline)
|
||||
let rel = s:ParseRpmVars(rel, relline)
|
||||
else
|
||||
@ -117,6 +124,9 @@ if !exists("*s:SpecChangelog")
|
||||
if chgline != -1
|
||||
let tmptime = v:lc_time
|
||||
language time C
|
||||
if strlen(epoch)
|
||||
let ver = epoch.":".ver
|
||||
endif
|
||||
let parsed_format = "* ".strftime(format)." - ".ver."-".rel
|
||||
execute "language time" tmptime
|
||||
let release_info = "+ ".name."-".ver."-".rel
|
||||
|
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 = {}
|
||||
if opt.font then
|
||||
fonts = type(opt.font) == 'string' and { opt.font } or opt.font --[[@as (string[])]]
|
||||
for i, v in pairs(fonts) do
|
||||
fonts[i] = ('"%s"'):format(v)
|
||||
end
|
||||
elseif vim.o.guifont:match('^[^:]+') then
|
||||
table.insert(fonts, vim.o.guifont:match('^[^:]+'))
|
||||
-- Example:
|
||||
-- Input: "Font,Escape\,comma, Ignore space after comma"
|
||||
-- Output: { "Font","Escape,comma","Ignore space after comma" }
|
||||
local prev = ''
|
||||
for name in vim.gsplit(vim.o.guifont:match('^[^:]+'), ',', { trimempty = true }) do
|
||||
if vim.endswith(name, '\\') then
|
||||
prev = prev .. vim.trim(name:sub(1, -2) .. ',')
|
||||
elseif vim.trim(name) ~= '' then
|
||||
table.insert(fonts, ('"%s%s"'):format(prev, vim.trim(name)))
|
||||
prev = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Generic family names (monospace here) must not be quoted
|
||||
-- because the browser recognizes them as font families.
|
||||
table.insert(fonts, 'monospace')
|
||||
--- @type vim.tohtml.state.global
|
||||
local state = {
|
||||
|
4
runtime/lua/vim/_meta/options.lua
generated
4
runtime/lua/vim/_meta/options.lua
generated
@ -7255,7 +7255,7 @@ vim.go.tm = vim.go.timeoutlen
|
||||
|
||||
--- When on, the title of the window will be set to the value of
|
||||
--- 'titlestring' (if it is not empty), or to:
|
||||
--- filename [+=-] (path) - NVIM
|
||||
--- filename [+=-] (path) - Nvim
|
||||
--- Where:
|
||||
--- filename the name of the file being edited
|
||||
--- - indicates the file cannot be modified, 'ma' off
|
||||
@ -7263,7 +7263,7 @@ vim.go.tm = vim.go.timeoutlen
|
||||
--- = indicates the file is read-only
|
||||
--- =+ indicates the file is read-only and modified
|
||||
--- (path) is the path of the file being edited
|
||||
--- - NVIM the server name `v:servername` or "NVIM"
|
||||
--- - Nvim the server name `v:servername` or "Nvim"
|
||||
---
|
||||
--- @type boolean
|
||||
vim.o.title = false
|
||||
|
3
runtime/lua/vim/_meta/vimfn.lua
generated
3
runtime/lua/vim/_meta/vimfn.lua
generated
@ -7421,6 +7421,9 @@ function vim.fn.screenstring(row, col) end
|
||||
--- The value must not be negative. A zero value is like not
|
||||
--- giving the argument.
|
||||
---
|
||||
--- Note: the timeout is only considered when searching, not
|
||||
--- while evaluating the {skip} expression.
|
||||
---
|
||||
--- If the {skip} expression is given it is evaluated with the
|
||||
--- cursor positioned on the start of a match. If it evaluates to
|
||||
--- non-zero this match is skipped. This can be used, for
|
||||
|
@ -243,6 +243,10 @@ local M = {}
|
||||
--- A table mapping |diagnostic-severity| to the highlight group used for the
|
||||
--- whole line the sign is placed in.
|
||||
--- @field linehl? table<vim.diagnostic.Severity,string>
|
||||
---
|
||||
--- A table mapping |diagnostic-severity| to the highlight group used for the
|
||||
--- highlight the sign column text when cursor is on target line and 'cursorline' is enabled.
|
||||
--- @field cursorlinehl table<vim.diagnostic.Severity,string>
|
||||
|
||||
--- @class vim.diagnostic.Opts.Jump
|
||||
---
|
||||
@ -1447,6 +1451,7 @@ M.handlers.signs = {
|
||||
|
||||
local numhl = opts.signs.numhl or {}
|
||||
local linehl = opts.signs.linehl or {}
|
||||
local curlinehl = opts.signs.cursorlinehl or {}
|
||||
|
||||
local line_count = api.nvim_buf_line_count(bufnr)
|
||||
|
||||
@ -1457,6 +1462,7 @@ M.handlers.signs = {
|
||||
sign_hl_group = sign_highlight_map[diagnostic.severity],
|
||||
number_hl_group = numhl[diagnostic.severity],
|
||||
line_hl_group = linehl[diagnostic.severity],
|
||||
cursorline_hl_group = vim.wo.cursorline and curlinehl[diagnostic.severity] or nil,
|
||||
priority = get_priority(diagnostic.severity),
|
||||
})
|
||||
end
|
||||
|
@ -1164,6 +1164,7 @@ local extension = {
|
||||
svelte = 'svelte',
|
||||
svg = 'svg',
|
||||
swift = 'swift',
|
||||
swiftinterface = 'swift',
|
||||
swig = 'swig',
|
||||
swg = 'swig',
|
||||
sys = detect.sys,
|
||||
|
@ -285,8 +285,8 @@ local path2name = function(path)
|
||||
-- Remove everything up to the last /lua/ folder
|
||||
path = path:gsub('^.*/lua/', '')
|
||||
|
||||
-- Remove the filename (health.lua)
|
||||
path = vim.fs.dirname(path)
|
||||
-- Remove the filename (health.lua) or (health/init.lua)
|
||||
path = vim.fs.dirname(path:gsub('/init%.lua$', ''))
|
||||
|
||||
-- Change slashes to dots
|
||||
path = path:gsub('/', '.')
|
||||
|
@ -43,17 +43,16 @@ function M.on_inlayhint(err, result, ctx, _)
|
||||
return
|
||||
end
|
||||
local bufnr = assert(ctx.bufnr)
|
||||
if util.buf_versions[bufnr] ~= ctx.version then
|
||||
if
|
||||
util.buf_versions[bufnr] ~= ctx.version
|
||||
or not result
|
||||
or not api.nvim_buf_is_loaded(bufnr)
|
||||
or not bufstates[bufnr].enabled
|
||||
then
|
||||
return
|
||||
end
|
||||
local client_id = ctx.client_id
|
||||
if not result then
|
||||
return
|
||||
end
|
||||
local bufstate = bufstates[bufnr]
|
||||
if not bufstate.enabled then
|
||||
return
|
||||
end
|
||||
if not (bufstate.client_hints and bufstate.version) then
|
||||
bufstate.client_hints = vim.defaulttable()
|
||||
bufstate.version = ctx.version
|
||||
@ -77,12 +76,7 @@ function M.on_inlayhint(err, result, ctx, _)
|
||||
local col = position.character
|
||||
if col > 0 then
|
||||
local line = lines[position.line + 1] or ''
|
||||
local ok, convert_result
|
||||
ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding)
|
||||
if ok then
|
||||
return convert_result
|
||||
end
|
||||
return math.min(#line, col)
|
||||
return util._str_byteindex_enc(line, col, client.offset_encoding)
|
||||
end
|
||||
return col
|
||||
end
|
||||
|
@ -140,12 +140,7 @@ local function tokens_to_ranges(data, bufnr, client, request)
|
||||
local function _get_byte_pos(col)
|
||||
if col > 0 then
|
||||
local buf_line = lines[line + 1] or ''
|
||||
local ok, result
|
||||
ok, result = pcall(util._str_byteindex_enc, buf_line, col, client.offset_encoding)
|
||||
if ok then
|
||||
return result
|
||||
end
|
||||
return math.min(#buf_line, col)
|
||||
return util._str_byteindex_enc(buf_line, col, client.offset_encoding)
|
||||
end
|
||||
return col
|
||||
end
|
||||
|
@ -119,6 +119,7 @@ end
|
||||
---@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
|
||||
---@return integer `encoding` index of `index` in `line`
|
||||
function M._str_utfindex_enc(line, index, encoding)
|
||||
local len32, len16 = vim.str_utfindex(line)
|
||||
if not encoding then
|
||||
encoding = 'utf-16'
|
||||
end
|
||||
@ -129,9 +130,15 @@ function M._str_utfindex_enc(line, index, encoding)
|
||||
return #line
|
||||
end
|
||||
elseif encoding == 'utf-16' then
|
||||
if not index or index > len16 then
|
||||
return len16
|
||||
end
|
||||
local _, col16 = vim.str_utfindex(line, index)
|
||||
return col16
|
||||
elseif encoding == 'utf-32' then
|
||||
if not index or index > len32 then
|
||||
return len32
|
||||
end
|
||||
local col32, _ = vim.str_utfindex(line, index)
|
||||
return col32
|
||||
else
|
||||
@ -147,6 +154,12 @@ end
|
||||
---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
|
||||
---@return integer byte (utf-8) index of `encoding` index `index` in `line`
|
||||
function M._str_byteindex_enc(line, index, encoding)
|
||||
local len = vim.fn.strlen(line)
|
||||
if index > len then
|
||||
-- LSP spec: if character > line length, default to the line length.
|
||||
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
|
||||
return len
|
||||
end
|
||||
if not encoding then
|
||||
encoding = 'utf-16'
|
||||
end
|
||||
@ -165,9 +178,6 @@ function M._str_byteindex_enc(line, index, encoding)
|
||||
end
|
||||
end
|
||||
|
||||
local _str_utfindex_enc = M._str_utfindex_enc
|
||||
local _str_byteindex_enc = M._str_byteindex_enc
|
||||
|
||||
--- Replaces text in a range with new text.
|
||||
---
|
||||
--- CAUTION: Changes in-place!
|
||||
@ -334,12 +344,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
|
||||
-- character
|
||||
if col > 0 then
|
||||
local line = get_line(bufnr, position.line) or ''
|
||||
local ok, result
|
||||
ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding)
|
||||
if ok then
|
||||
return result
|
||||
end
|
||||
return math.min(#line, col)
|
||||
return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16')
|
||||
end
|
||||
return col
|
||||
end
|
||||
@ -436,14 +441,15 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
|
||||
e.end_col = last_line_len
|
||||
has_eol_text_edit = true
|
||||
else
|
||||
-- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
|
||||
-- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length and the
|
||||
-- replacement text ends with a newline We can likely assume that the replacement is assumed
|
||||
-- to be meant to replace the newline with another newline and we need to make sure this
|
||||
-- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
|
||||
-- in the file some servers (clangd on windows) will include that character in the line
|
||||
-- while nvim_buf_set_text doesn't count it as part of the line.
|
||||
if
|
||||
e.end_col > last_line_len
|
||||
e.end_col >= last_line_len
|
||||
and text_edit.range['end'].character > e.end_col
|
||||
and #text_edit.newText > 0
|
||||
and string.sub(text_edit.newText, -1) == '\n'
|
||||
then
|
||||
@ -1795,17 +1801,9 @@ function M.locations_to_items(locations, offset_encoding)
|
||||
local row = pos.line
|
||||
local end_row = end_pos.line
|
||||
local line = lines[row] or ''
|
||||
local line_len = vim.fn.strcharlen(line)
|
||||
local end_line = lines[end_row] or ''
|
||||
local end_line_len = vim.fn.strcharlen(end_line)
|
||||
-- LSP spec: if character > line length, default to the line length.
|
||||
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
|
||||
local col = pos.character <= line_len
|
||||
and M._str_byteindex_enc(line, pos.character, offset_encoding)
|
||||
or line_len
|
||||
local end_col = end_pos.character <= end_line_len
|
||||
and M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
|
||||
or end_line_len
|
||||
local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
|
||||
local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
|
||||
|
||||
table.insert(items, {
|
||||
filename = filename,
|
||||
@ -1935,7 +1933,7 @@ local function make_position_param(window, offset_encoding)
|
||||
return { line = 0, character = 0 }
|
||||
end
|
||||
|
||||
col = _str_utfindex_enc(line, col, offset_encoding)
|
||||
col = M._str_utfindex_enc(line, col, offset_encoding)
|
||||
|
||||
return { line = row, character = col }
|
||||
end
|
||||
@ -2117,11 +2115,7 @@ function M.character_offset(buf, row, col, offset_encoding)
|
||||
)
|
||||
offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding
|
||||
end
|
||||
-- If the col is past the EOL, use the line length.
|
||||
if col > #line then
|
||||
return _str_utfindex_enc(line, nil, offset_encoding)
|
||||
end
|
||||
return _str_utfindex_enc(line, col, offset_encoding)
|
||||
return M._str_utfindex_enc(line, col, offset_encoding)
|
||||
end
|
||||
|
||||
--- Helper function to return nested values in language server settings
|
||||
|
@ -354,6 +354,12 @@ function vim.tbl_isempty(t)
|
||||
return next(t) == nil
|
||||
end
|
||||
|
||||
--- We only merge empty tables or tables that are not list-like (indexed by consecutive integers
|
||||
--- starting from 1)
|
||||
local function can_merge(v)
|
||||
return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.islist(v))
|
||||
end
|
||||
|
||||
--- Recursive worker for tbl_extend
|
||||
--- @param behavior 'error'|'keep'|'force'
|
||||
--- @param deep_extend boolean
|
||||
@ -368,7 +374,7 @@ local function tbl_extend_rec(behavior, deep_extend, ...)
|
||||
local tbl = select(i, ...) --[[@as table<any,any>]]
|
||||
if tbl then
|
||||
for k, v in pairs(tbl) do
|
||||
if deep_extend and type(v) == 'table' and type(ret[k]) == 'table' then
|
||||
if deep_extend and can_merge(v) and can_merge(ret[k]) then
|
||||
ret[k] = tbl_extend_rec(behavior, true, ret[k], v)
|
||||
elseif behavior ~= 'force' and ret[k] ~= nil then
|
||||
if behavior == 'error' then
|
||||
@ -421,6 +427,11 @@ end
|
||||
|
||||
--- Merges recursively two or more tables.
|
||||
---
|
||||
--- Only values that are empty tables or tables that are not |lua-list|s (indexed by consecutive
|
||||
--- integers starting from 1) are merged recursively. This is useful for merging nested tables
|
||||
--- like default and user configurations where lists should be treated as literals (i.e., are
|
||||
--- overwritten instead of merged).
|
||||
---
|
||||
---@see |vim.tbl_extend()|
|
||||
---
|
||||
---@generic T1: table
|
||||
|
@ -45,6 +45,11 @@
|
||||
(link_destination) @_url
|
||||
(#set! @_label url @_url))
|
||||
|
||||
(image
|
||||
(image_description) @_label
|
||||
(link_destination) @_url
|
||||
(#set! @_label url @_url))
|
||||
|
||||
; Conceal image links
|
||||
(image
|
||||
[
|
||||
|
@ -33,7 +33,10 @@
|
||||
")"
|
||||
] @punctuation.bracket
|
||||
|
||||
":" @punctuation.delimiter
|
||||
[
|
||||
":"
|
||||
"/"
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
"@"
|
||||
|
@ -1,12 +1,12 @@
|
||||
" Vim syntax file
|
||||
" Language: Configuration File (ini file) for MSDOS/MS Windows
|
||||
" Version: 2.3
|
||||
" Version: 2.4
|
||||
" Original Author: Sean M. McKee <mckee@misslink.net>
|
||||
" Previous Maintainer: Nima Talebi <nima@it.net.au>
|
||||
" Current Maintainer: Hong Xu <hong@topbug.net>
|
||||
" Homepage: http://www.vim.org/scripts/script.php?script_id=3747
|
||||
" Repository: https://github.com/xuhdev/syntax-dosini.vim
|
||||
" Last Change: 2023 Aug 20
|
||||
" Last Change: 2024 Sept 08
|
||||
|
||||
|
||||
" quit when a syntax file was already loaded
|
||||
@ -27,7 +27,7 @@ syn match dosiniNumber "=\zs\s*\d\+\s*$"
|
||||
syn match dosiniNumber "=\zs\s*\d*\.\d\+\s*$"
|
||||
syn match dosiniNumber "=\zs\s*\d\+e[+-]\=\d\+\s*$"
|
||||
syn region dosiniHeader start="^\s*\[" end="\]"
|
||||
syn match dosiniComment "^[#;].*$"
|
||||
syn match dosiniComment "^[#;].*$" contains=@Spell
|
||||
syn region dosiniSection start="\s*\[.*\]" end="\ze\s*\[.*\]" fold
|
||||
\ contains=dosiniLabel,dosiniValue,dosiniNumber,dosiniHeader,dosiniComment
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
" Interactive Data Language syntax file (IDL, too [:-)]
|
||||
" Maintainer: Aleksandar Jelenak <ajelenak AT yahoo.com>
|
||||
" Last change: 2011 Apr 11
|
||||
" Created by: Hermann Rochholz <Hermann.Rochholz AT gmx.de>
|
||||
" Created By: Hermann Rochholz <Hermann.Rochholz AT gmx.de>
|
||||
" Last Change: 2011 Apr 11
|
||||
" 2024 Sep 10 by Vim Project: update syntax script, #15419
|
||||
|
||||
" Remove any old syntax stuff hanging around
|
||||
" quit when a syntax file was already loaded
|
||||
@ -16,7 +17,7 @@ syn match idlangStatement "^\s*function\s"
|
||||
syn keyword idlangStatement return continue mod do break
|
||||
syn keyword idlangStatement compile_opt forward_function goto
|
||||
syn keyword idlangStatement begin common end of
|
||||
syn keyword idlangStatement inherits on_ioerror begin
|
||||
syn keyword idlangStatement inherits on_error on_ioerror begin
|
||||
|
||||
syn keyword idlangConditional if else then for while case switch
|
||||
syn keyword idlangConditional endcase endelse endfor endswitch
|
||||
@ -82,7 +83,7 @@ syn keyword idlangRoutine CALL_EXTERNAL CALL_FUNCTION CALL_METHOD
|
||||
syn keyword idlangRoutine CALL_PROCEDURE CATCH CD CEIL CHEBYSHEV CHECK_MATH
|
||||
syn keyword idlangRoutine CHISQR_CVF CHISQR_PDF CHOLDC CHOLSOL CINDGEN
|
||||
syn keyword idlangRoutine CIR_3PNT CLOSE CLUST_WTS CLUSTER COLOR_CONVERT
|
||||
syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT COMMON
|
||||
syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT
|
||||
syn keyword idlangRoutine COMPLEX COMPLEXARR COMPLEXROUND
|
||||
syn keyword idlangRoutine COMPUTE_MESH_NORMALS COND CONGRID CONJ
|
||||
syn keyword idlangRoutine CONSTRAINED_MIN CONTOUR CONVERT_COORD CONVOL
|
||||
@ -98,7 +99,7 @@ syn keyword idlangRoutine CW_PALETTE_EDITOR_GET CW_PALETTE_EDITOR_SET
|
||||
syn keyword idlangRoutine CW_PDMENU CW_RGBSLIDER CW_TMPL CW_ZOOM DBLARR
|
||||
syn keyword idlangRoutine DCINDGEN DCOMPLEX DCOMPLEXARR DEFINE_KEY DEFROI
|
||||
syn keyword idlangRoutine DEFSYSV DELETE_SYMBOL DELLOG DELVAR DERIV DERIVSIG
|
||||
syn keyword idlangRoutine DETERM DEVICE DFPMIN DIALOG_MESSAGE
|
||||
syn keyword idlangRoutine DETERM DEVICE DFPMIN DIAG_MATRIX DIALOG_MESSAGE
|
||||
syn keyword idlangRoutine DIALOG_PICKFILE DIALOG_PRINTERSETUP
|
||||
syn keyword idlangRoutine DIALOG_PRINTJOB DIALOG_READ_IMAGE
|
||||
syn keyword idlangRoutine DIALOG_WRITE_IMAGE DIGITAL_FILTER DILATE DINDGEN
|
||||
@ -155,7 +156,7 @@ syn keyword idlangRoutine MPEG_PUT MPEG_SAVE MSG_CAT_CLOSE MSG_CAT_COMPILE
|
||||
syn keyword idlangRoutine MSG_CAT_OPEN MULTI N_ELEMENTS N_PARAMS N_TAGS
|
||||
syn keyword idlangRoutine NEWTON NORM OBJ_CLASS OBJ_DESTROY OBJ_ISA OBJ_NEW
|
||||
syn keyword idlangRoutine OBJ_VALID OBJARR ON_ERROR ON_IOERROR ONLINE_HELP
|
||||
syn keyword idlangRoutine OPEN OPENR OPENW OPLOT OPLOTERR P_CORRELATE
|
||||
syn keyword idlangRoutine OPEN OPENR OPENW OPENU OPLOT OPLOTERR P_CORRELATE
|
||||
syn keyword idlangRoutine PARTICLE_TRACE PCOMP PLOT PLOT_3DBOX PLOT_FIELD
|
||||
syn keyword idlangRoutine PLOTERR PLOTS PNT_LINE POINT_LUN POLAR_CONTOUR
|
||||
syn keyword idlangRoutine POLAR_SURFACE POLY POLY_2D POLY_AREA POLY_FIT
|
||||
|
@ -3,7 +3,7 @@
|
||||
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
|
||||
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
|
||||
" Repository: https://github.com/zzzyxwvut/java-vim.git
|
||||
" Last Change: 2024 Aug 26
|
||||
" Last Change: 2024 Sep 10
|
||||
|
||||
" Please check :help java.vim for comments on some of the options available.
|
||||
|
||||
@ -157,13 +157,20 @@ endif
|
||||
" testing in a project without attendant confusion for IDEs, with the
|
||||
" ".java\=" extension used for a production version and an arbitrary
|
||||
" extension used for a testing version.
|
||||
if fnamemodify(bufname("%"), ":t") =~ '^module-info\%(\.class\>\)\@!'
|
||||
if fnamemodify(bufname("%"), ":t") =~ '^module-info\>\%(\.class\>\)\@!'
|
||||
syn keyword javaModuleStorageClass module transitive
|
||||
syn keyword javaModuleStmt open requires exports opens uses provides
|
||||
syn keyword javaModuleExternal to with
|
||||
hi def link javaModuleStorageClass StorageClass
|
||||
hi def link javaModuleStmt Statement
|
||||
hi def link javaModuleExternal Include
|
||||
|
||||
if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
|
||||
syn match javaDocProvidesTag contained "@provides\_s\+\S\+" contains=javaDocParam
|
||||
syn match javaDocUsesTag contained "@uses\_s\+\S\+" contains=javaDocParam
|
||||
hi def link javaDocProvidesTag Special
|
||||
hi def link javaDocUsesTag Special
|
||||
endif
|
||||
endif
|
||||
|
||||
" Fancy parameterised types (JLS-17, §4.5).
|
||||
@ -335,29 +342,99 @@ if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
|
||||
call s:ReportOnce(v:exception)
|
||||
endtry
|
||||
|
||||
syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag,javaTodo,javaCommentError,javaSpaceError,@Spell fold
|
||||
exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag'
|
||||
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag
|
||||
syn region javaDocTags contained start="{@\%(li\%(teral\|nk\%(plain\)\=\)\|inherit[Dd]oc\|doc[rR]oot\|value\)\>" end="}"
|
||||
syn match javaDocTags contained "@\%(param\|exception\|throws\|since\)\s\+\S\+" contains=javaDocParam
|
||||
syn match javaDocParam contained "\s\S\+"
|
||||
syn match javaDocTags contained "@\%(version\|author\|return\|deprecated\|serial\%(Field\|Data\)\=\)\>"
|
||||
syn region javaDocSeeTag contained matchgroup=javaDocTags start="@see\s\+" matchgroup=NONE end="\_."re=e-1 contains=javaDocSeeTagParam
|
||||
syn match javaDocSeeTagParam contained @"\_[^"]\+"\|<a\s\+\_.\{-}</a>\|\%(\k\|\.\)*\%(#\k\+\%((\_[^)]*)\)\=\)\=@ contains=@javaHtml extend
|
||||
syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,@javaDocTags,javaTodo,javaCommentError,javaSpaceError,@Spell fold
|
||||
exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags'
|
||||
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
|
||||
syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@summary\>\)\@=" matchgroup=javaCommentTitle end="}" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
|
||||
" The members of javaDocTags are sub-grouped according to the Java
|
||||
" version of their introduction, and sub-group members in turn are
|
||||
" arranged in alphabetical order, so that future newer members can
|
||||
" be pre-sorted and appended without disturbing the current member
|
||||
" placement.
|
||||
" Since they only have significance in javaCommentTitle, neither
|
||||
" javaDocSummaryTag nor javaDocReturnTitleTag are defined.
|
||||
syn cluster javaDocTags contains=javaDocAuthorTag,javaDocDeprecatedTag,javaDocExceptionTag,javaDocParamTag,javaDocReturnTag,javaDocSeeTag,javaDocVersionTag,javaDocSinceTag,javaDocLinkTag,javaDocSerialTag,javaDocSerialDataTag,javaDocSerialFieldTag,javaDocThrowsTag,javaDocDocRootTag,javaDocInheritDocTag,javaDocLinkplainTag,javaDocValueTag,javaDocCodeTag,javaDocLiteralTag,javaDocHiddenTag,javaDocIndexTag,javaDocProvidesTag,javaDocUsesTag,javaDocSystemPropertyTag,javaDocSnippetTag,javaDocSpecTag
|
||||
|
||||
" Anticipate non-standard inline tags in {@return} and {@summary}.
|
||||
syn region javaTitleSkipBlock contained transparent start="{\%(@\%(return\|summary\)\>\)\@!" end="}"
|
||||
syn match javaDocDocRootTag contained "{@docRoot}"
|
||||
syn match javaDocInheritDocTag contained "{@inheritDoc}"
|
||||
syn region javaIndexSkipBlock contained transparent start="{\%(@index\>\)\@!" end="}" contains=javaIndexSkipBlock,javaDocIndexTag
|
||||
syn region javaDocIndexTag contained start="{@index\>" end="}" contains=javaDocIndexTag,javaIndexSkipBlock
|
||||
syn region javaLinkSkipBlock contained transparent start="{\%(@link\>\)\@!" end="}" contains=javaLinkSkipBlock,javaDocLinkTag
|
||||
syn region javaDocLinkTag contained start="{@link\>" end="}" contains=javaDocLinkTag,javaLinkSkipBlock
|
||||
syn region javaLinkplainSkipBlock contained transparent start="{\%(@linkplain\>\)\@!" end="}" contains=javaLinkplainSkipBlock,javaDocLinkplainTag
|
||||
syn region javaDocLinkplainTag contained start="{@linkplain\>" end="}" contains=javaDocLinkplainTag,javaLinkplainSkipBlock
|
||||
syn region javaLiteralSkipBlock contained transparent start="{\%(@literal\>\)\@!" end="}" contains=javaLiteralSkipBlock,javaDocLiteralTag
|
||||
syn region javaDocLiteralTag contained start="{@literal\>" end="}" contains=javaDocLiteralTag,javaLiteralSkipBlock
|
||||
syn region javaSystemPropertySkipBlock contained transparent start="{\%(@systemProperty\>\)\@!" end="}" contains=javaSystemPropertySkipBlock,javaDocSystemPropertyTag
|
||||
syn region javaDocSystemPropertyTag contained start="{@systemProperty\>" end="}" contains=javaDocSystemPropertyTag,javaSystemPropertySkipBlock
|
||||
syn region javaValueSkipBlock contained transparent start="{\%(@value\>\)\@!" end="}" contains=javaValueSkipBlock,javaDocValueTag
|
||||
syn region javaDocValueTag contained start="{@value\>" end="}" contains=javaDocValueTag,javaValueSkipBlock
|
||||
|
||||
syn match javaDocParam contained "\s\zs\S\+"
|
||||
syn match javaDocExceptionTag contained "@exception\s\+\S\+" contains=javaDocParam
|
||||
syn match javaDocParamTag contained "@param\s\+\S\+" contains=javaDocParam
|
||||
syn match javaDocSinceTag contained "@since\s\+\S\+" contains=javaDocParam
|
||||
syn match javaDocThrowsTag contained "@throws\s\+\S\+" contains=javaDocParam
|
||||
syn match javaDocSpecTag contained "@spec\_s\+\S\+\ze\_s\+\S\+" contains=javaDocParam
|
||||
|
||||
syn match javaDocAuthorTag contained "@author\>"
|
||||
syn match javaDocDeprecatedTag contained "@deprecated\>"
|
||||
syn match javaDocHiddenTag contained "@hidden\>"
|
||||
syn match javaDocReturnTag contained "@return\>"
|
||||
syn match javaDocSerialTag contained "@serial\>"
|
||||
syn match javaDocSerialDataTag contained "@serialData\>"
|
||||
syn match javaDocSerialFieldTag contained "@serialField\>"
|
||||
syn match javaDocVersionTag contained "@version\>"
|
||||
|
||||
syn match javaDocSeeTag contained "@see\>" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTagStar skipwhite skipempty
|
||||
syn match javaDocSeeTagStar contained "^\s*\*\+\%(\s*{\=@\|/\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3 skipwhite skipempty
|
||||
syn match javaDocSeeTag1 contained @"\_[^"]\+"@
|
||||
syn match javaDocSeeTag2 contained @<a\s\+\_.\{-}</a>@ contains=@javaHtml extend
|
||||
syn match javaDocSeeTag3 contained @["< \t]\@!\%(\k\|[/.]\)*\%(##\=\k\+\%((\_[^)]*)\)\=\)\=@ nextgroup=javaDocSeeTag3Label skipwhite skipempty
|
||||
syn match javaDocSeeTag3Label contained @\k\%(\k\+\s*\)*$@
|
||||
|
||||
syn region javaCodeSkipBlock contained transparent start="{\%(@code\>\)\@!" end="}" contains=javaCodeSkipBlock,javaDocCodeTag
|
||||
syn region javaDocCodeTag contained start="{@code\>" end="}" contains=javaDocCodeTag,javaCodeSkipBlock
|
||||
|
||||
exec 'syn region javaDocSnippetTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(class\|file\|id\|lang\|region\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/:$/ end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.\\/-]\|\k\)\+\)/ nextgroup=javaDocSnippetTagAttr skipwhite skipnl'
|
||||
syn region javaSnippetSkipBlock contained transparent start="{\%(@snippet\>\)\@!" end="}" contains=javaSnippetSkipBlock,javaDocSnippetTag,javaCommentMarkupTag
|
||||
syn region javaDocSnippetTag contained start="{@snippet\>" end="}" contains=javaDocSnippetTag,javaSnippetSkipBlock,javaDocSnippetTagAttr,javaCommentMarkupTag
|
||||
|
||||
syntax case match
|
||||
hi def link javaDocComment Comment
|
||||
hi def link javaDocSeeTagStar javaDocComment
|
||||
hi def link javaCommentTitle SpecialComment
|
||||
hi def link javaDocTags Special
|
||||
hi def link javaDocCodeTag Special
|
||||
hi def link javaDocSnippetTag Special
|
||||
hi def link javaDocSeeTagParam Function
|
||||
hi def link javaDocParam Function
|
||||
|
||||
hi def link javaDocAuthorTag Special
|
||||
hi def link javaDocCodeTag Special
|
||||
hi def link javaDocDeprecatedTag Special
|
||||
hi def link javaDocDocRootTag Special
|
||||
hi def link javaDocExceptionTag Special
|
||||
hi def link javaDocHiddenTag Special
|
||||
hi def link javaDocIndexTag Special
|
||||
hi def link javaDocInheritDocTag Special
|
||||
hi def link javaDocLinkTag Special
|
||||
hi def link javaDocLinkplainTag Special
|
||||
hi def link javaDocLiteralTag Special
|
||||
hi def link javaDocParamTag Special
|
||||
hi def link javaDocReturnTag Special
|
||||
hi def link javaDocSeeTag Special
|
||||
hi def link javaDocSeeTag1 String
|
||||
hi def link javaDocSeeTag2 Special
|
||||
hi def link javaDocSeeTag3 Function
|
||||
hi def link javaDocSerialTag Special
|
||||
hi def link javaDocSerialDataTag Special
|
||||
hi def link javaDocSerialFieldTag Special
|
||||
hi def link javaDocSinceTag Special
|
||||
hi def link javaDocSnippetTag Special
|
||||
hi def link javaDocSpecTag Special
|
||||
hi def link javaDocSystemPropertyTag Special
|
||||
hi def link javaDocThrowsTag Special
|
||||
hi def link javaDocValueTag Special
|
||||
hi def link javaDocVersionTag Special
|
||||
endif
|
||||
|
||||
" match the special comment /**/
|
||||
|
@ -4,6 +4,7 @@
|
||||
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
|
||||
" Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014)
|
||||
" Last Change: 2020 May 25
|
||||
" 2024 Sep 10 by Vim Project: add file triggers support, #15569
|
||||
|
||||
" quit when a syntax file was already loaded
|
||||
if exists("b:current_syntax")
|
||||
@ -111,7 +112,7 @@ syn region specDescriptionArea matchgroup=specSection start='^%description' end=
|
||||
syn region specPackageArea matchgroup=specSection start='^%package' end='^%'me=e-1 contains=specPackageOpts,specPreAmble,specComment
|
||||
|
||||
"%% Scripts Section %%
|
||||
syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2
|
||||
syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\|filetriggerin\|filetriggerun\|filetriggerpostun\|transfiletriggerin\|transfiletriggerun\|transfiletriggerpostun\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2
|
||||
|
||||
"%% Changelog Section %%
|
||||
syn region specChangelogArea matchgroup=specSection start='^%changelog' end='^%'me=e-1 contains=specEmail,specURL,specWeekday,specMonth,specNumber,specComment,specLicense
|
||||
|
@ -81,6 +81,14 @@ local function get_dependency(dependency_name)
|
||||
repo = 'luvit/luv',
|
||||
symbol = 'LUV',
|
||||
},
|
||||
['unibilium'] = {
|
||||
repo = 'neovim/unibilium',
|
||||
symbol = 'UNIBILIUM',
|
||||
},
|
||||
['utf8proc'] = {
|
||||
repo = 'JuliaStrings/utf8proc',
|
||||
symbol = 'UTF8PROC',
|
||||
},
|
||||
['tree-sitter'] = {
|
||||
repo = 'tree-sitter/tree-sitter',
|
||||
symbol = 'TREESITTER',
|
||||
@ -90,11 +98,11 @@ local function get_dependency(dependency_name)
|
||||
symbol = 'TREESITTER_C',
|
||||
},
|
||||
['tree-sitter-lua'] = {
|
||||
repo = 'MunifTanjim/tree-sitter-lua',
|
||||
repo = 'tree-sitter-grammars/tree-sitter-lua',
|
||||
symbol = 'TREESITTER_LUA',
|
||||
},
|
||||
['tree-sitter-vim'] = {
|
||||
repo = 'neovim/tree-sitter-vim',
|
||||
repo = 'tree-sitter-grammars/tree-sitter-vim',
|
||||
symbol = 'TREESITTER_VIM',
|
||||
},
|
||||
['tree-sitter-vimdoc'] = {
|
||||
@ -102,9 +110,21 @@ local function get_dependency(dependency_name)
|
||||
symbol = 'TREESITTER_VIMDOC',
|
||||
},
|
||||
['tree-sitter-query'] = {
|
||||
repo = 'nvim-treesitter/tree-sitter-query',
|
||||
repo = 'tree-sitter-grammars/tree-sitter-query',
|
||||
symbol = 'TREESITTER_QUERY',
|
||||
},
|
||||
['tree-sitter-markdown'] = {
|
||||
repo = 'tree-sitter-grammars/tree-sitter-markdown',
|
||||
symbol = 'TREESITTER_MARKDOWN',
|
||||
},
|
||||
['wasmtime'] = {
|
||||
repo = 'bytecodealliance/wasmtime',
|
||||
symbol = 'WASMTIME',
|
||||
},
|
||||
['uncrustify'] = {
|
||||
repo = 'uncrustify/uncrustify',
|
||||
symbol = 'UNCRUSTIFY',
|
||||
},
|
||||
}
|
||||
local dependency = dependency_table[dependency_name]
|
||||
if dependency == nil then
|
||||
|
@ -3338,7 +3338,7 @@ void maketitle(void)
|
||||
|
||||
#define SPACE_FOR_FNAME (sizeof(buf) - 100)
|
||||
#define SPACE_FOR_DIR (sizeof(buf) - 20)
|
||||
#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM".
|
||||
#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - Nvim".
|
||||
char *buf_p = buf;
|
||||
if (curbuf->b_fname == NULL) {
|
||||
const size_t size = xstrlcpy(buf_p, _("[No Name]"),
|
||||
@ -3412,7 +3412,7 @@ void maketitle(void)
|
||||
|
||||
append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)));
|
||||
|
||||
xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf)));
|
||||
xstrlcat(buf_p, " - Nvim", (sizeof(buf) - (size_t)(buf_p - buf)));
|
||||
|
||||
if (maxlen > 0) {
|
||||
// Make it shorter by removing a bit in the middle.
|
||||
|
@ -8927,6 +8927,9 @@ M.funcs = {
|
||||
The value must not be negative. A zero value is like not
|
||||
giving the argument.
|
||||
|
||||
Note: the timeout is only considered when searching, not
|
||||
while evaluating the {skip} expression.
|
||||
|
||||
If the {skip} expression is given it is evaluated with the
|
||||
cursor positioned on the start of a match. If it evaluates to
|
||||
non-zero this match is skipped. This can be used, for
|
||||
|
@ -7641,7 +7641,7 @@ static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
|
||||
return;
|
||||
}
|
||||
const void *iter = NULL;
|
||||
const char *appname = get_appname();
|
||||
const char *appname = get_appname(false);
|
||||
do {
|
||||
size_t dir_len;
|
||||
const char *dir;
|
||||
|
@ -16,15 +16,14 @@ struct loop {
|
||||
uv_loop_t uv;
|
||||
MultiQueue *events;
|
||||
MultiQueue *thread_events;
|
||||
// Immediate events:
|
||||
// "Processed after exiting uv_run() (to avoid recursion), but before
|
||||
// returning from loop_poll_events()." 502aee690c98
|
||||
// Practical consequence (for main_loop): these events are processed by
|
||||
// state_enter()..os_inchar()
|
||||
// whereas "regular" events (main_loop.events) are processed by
|
||||
// state_enter()..VimState.execute()
|
||||
// But state_enter()..os_inchar() can be "too early" if you want the event
|
||||
// to trigger UI updates and other user-activity-related side-effects.
|
||||
// Immediate events.
|
||||
// - "Processed after exiting `uv_run()` (to avoid recursion), but before returning from
|
||||
// `loop_poll_events()`." 502aee690c98
|
||||
// - Practical consequence (for `main_loop`):
|
||||
// - these are processed by `state_enter()..input_get()` whereas "regular" events
|
||||
// (`main_loop.events`) are processed by `state_enter()..VimState.execute()`
|
||||
// - `state_enter()..input_get()` can be "too early" if you want the event to trigger UI
|
||||
// updates and other user-activity-related side-effects.
|
||||
MultiQueue *fast_events;
|
||||
|
||||
// used by process/job-control subsystem
|
||||
|
@ -94,14 +94,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
|
||||
stream->events = NULL;
|
||||
}
|
||||
|
||||
void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream)
|
||||
void stream_may_close(Stream *stream, bool rstream)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
if (stream->closed) {
|
||||
return;
|
||||
}
|
||||
assert(!stream->closed);
|
||||
DLOG("closing Stream: %p", (void *)stream);
|
||||
stream->closed = true;
|
||||
stream->close_cb = on_stream_close;
|
||||
stream->close_cb_data = data;
|
||||
stream->close_cb = NULL;
|
||||
stream->close_cb_data = NULL;
|
||||
|
||||
#ifdef MSWIN
|
||||
if (UV_TTY == uv_guess_handle(stream->fd)) {
|
||||
@ -115,13 +118,6 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, b
|
||||
}
|
||||
}
|
||||
|
||||
void stream_may_close(Stream *stream, bool rstream)
|
||||
{
|
||||
if (!stream->closed) {
|
||||
stream_close(stream, NULL, NULL, rstream);
|
||||
}
|
||||
}
|
||||
|
||||
void stream_close_handle(Stream *stream, bool rstream)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
|
@ -3264,18 +3264,12 @@ static void vim_mktempdir(void)
|
||||
char tmp[TEMP_FILE_PATH_MAXLEN];
|
||||
char path[TEMP_FILE_PATH_MAXLEN];
|
||||
char user[40] = { 0 };
|
||||
char appname[40] = { 0 };
|
||||
|
||||
os_get_username(user, sizeof(user));
|
||||
// Usernames may contain slashes! #19240
|
||||
memchrsub(user, '/', '_', sizeof(user));
|
||||
memchrsub(user, '\\', '_', sizeof(user));
|
||||
|
||||
// Appname may be a relative path, replace slashes to make it name-like.
|
||||
xstrlcpy(appname, get_appname(), sizeof(appname));
|
||||
memchrsub(appname, '/', '%', sizeof(appname));
|
||||
memchrsub(appname, '\\', '%', sizeof(appname));
|
||||
|
||||
// Make sure the umask doesn't remove the executable bit.
|
||||
// "repl" has been reported to use "0177".
|
||||
mode_t umask_save = umask(0077);
|
||||
@ -3283,14 +3277,15 @@ static void vim_mktempdir(void)
|
||||
// Expand environment variables, leave room for "/tmp/nvim.<user>/XXXXXX/999999999".
|
||||
expand_env((char *)temp_dirs[i], tmp, TEMP_FILE_PATH_MAXLEN - 64);
|
||||
if (!os_isdir(tmp)) {
|
||||
if (strequal("$TMPDIR", temp_dirs[i])) {
|
||||
WLOG("$TMPDIR tempdir not a directory (or does not exist): %s", tmp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
|
||||
add_pathsep(tmp);
|
||||
|
||||
xstrlcat(tmp, appname, sizeof(tmp));
|
||||
xstrlcat(tmp, ".", sizeof(tmp));
|
||||
xstrlcat(tmp, "nvim.", sizeof(tmp));
|
||||
xstrlcat(tmp, user, sizeof(tmp));
|
||||
os_mkdir(tmp, 0700); // Always create, to avoid a race.
|
||||
bool owned = os_file_owned(tmp);
|
||||
|
@ -1858,7 +1858,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
|
||||
if (!char_avail()) {
|
||||
// Flush screen updates before blocking.
|
||||
ui_flush();
|
||||
os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
||||
input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
||||
if (!multiqueue_empty(main_loop.events)) {
|
||||
state_handle_k_event();
|
||||
continue;
|
||||
@ -2981,7 +2981,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time)
|
||||
uint8_t dum[DUM_LEN + 1];
|
||||
|
||||
while (true) {
|
||||
len = os_inchar(dum, DUM_LEN, 0, 0, NULL);
|
||||
len = input_get(dum, DUM_LEN, 0, 0, NULL);
|
||||
if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) {
|
||||
break;
|
||||
}
|
||||
@ -2997,7 +2997,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time)
|
||||
|
||||
// Fill up to a third of the buffer, because each character may be
|
||||
// tripled below.
|
||||
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
|
||||
len = input_get(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
|
||||
}
|
||||
|
||||
// If the typebuf was changed further down, it is like nothing was added by
|
||||
|
@ -370,12 +370,15 @@ void update_window_hl(win_T *wp, bool invalid)
|
||||
|
||||
// determine window specific background set in 'winhighlight'
|
||||
bool float_win = wp->w_floating && !wp->w_config.external;
|
||||
if (float_win && hl_def[HLF_NFLOAT] != 0) {
|
||||
if (float_win && hl_def[HLF_NFLOAT] != 0 && ns_id > 0) {
|
||||
wp->w_hl_attr_normal = hl_def[HLF_NFLOAT];
|
||||
} else if (hl_def[HLF_COUNT] > 0) {
|
||||
wp->w_hl_attr_normal = hl_def[HLF_COUNT];
|
||||
} else if (float_win) {
|
||||
wp->w_hl_attr_normal = HL_ATTR(HLF_NFLOAT) > 0
|
||||
? HL_ATTR(HLF_NFLOAT) : highlight_attr[HLF_NFLOAT];
|
||||
} else {
|
||||
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
|
||||
wp->w_hl_attr_normal = 0;
|
||||
}
|
||||
|
||||
if (wp->w_floating) {
|
||||
|
@ -37,7 +37,7 @@
|
||||
/// @param[in] str Prompt: question to ask user. Is always followed by
|
||||
/// " (y/n)?".
|
||||
/// @param[in] direct Determines what function to use to get user input. If
|
||||
/// true then os_inchar() will be used, otherwise vgetc().
|
||||
/// true then input_get() will be used, otherwise vgetc().
|
||||
/// I.e. when direct is true then characters are obtained
|
||||
/// directly from the user without buffers involved.
|
||||
///
|
||||
@ -111,7 +111,7 @@ int get_keystroke(MultiQueue *events)
|
||||
|
||||
// First time: blocking wait. Second time: wait up to 100ms for a
|
||||
// terminal code to complete.
|
||||
n = os_inchar(buf + len, maxlen, len == 0 ? -1 : 100, 0, events);
|
||||
n = input_get(buf + len, maxlen, len == 0 ? -1 : 100, 0, events);
|
||||
if (n > 0) {
|
||||
// Replace zero and K_SPECIAL by a special key code.
|
||||
n = fix_input_buffer(buf + len, n);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "nvim/os/stdpaths_defs.h"
|
||||
#include "nvim/os/time.h"
|
||||
#include "nvim/path.h"
|
||||
#include "nvim/ui_client.h"
|
||||
|
||||
/// Cached location of the expanded log file path decided by log_path_init().
|
||||
static char log_file_path[MAXPATHL + 1] = { 0 };
|
||||
@ -322,20 +323,28 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
|
||||
millis = (int)curtime.tv_usec / 1000;
|
||||
}
|
||||
|
||||
bool ui = !!ui_client_channel_id; // Running as a UI client (--remote-ui).
|
||||
|
||||
// Regenerate the name when:
|
||||
// - UI client (to ensure "ui" is in the name)
|
||||
// - not set yet
|
||||
// - no v:servername yet
|
||||
bool regen = ui || name[0] == NUL || name[0] == '?';
|
||||
|
||||
// Get a name for this Nvim instance.
|
||||
// TODO(justinmk): expose this as v:name ?
|
||||
if (name[0] == NUL) {
|
||||
// Parent servername.
|
||||
if (regen) {
|
||||
// Parent servername ($NVIM).
|
||||
const char *parent = path_tail(os_getenv(ENV_NVIM));
|
||||
// Servername. Empty until starting=false.
|
||||
const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER));
|
||||
if (parent[0] != NUL) {
|
||||
snprintf(name, sizeof(name), "%s/c", parent); // "/c" indicates child.
|
||||
snprintf(name, sizeof(name), ui ? "ui/c/%s" : "c/%s", parent); // "c/" = child of $NVIM.
|
||||
} else if (serv[0] != NUL) {
|
||||
snprintf(name, sizeof(name), "%s", serv);
|
||||
snprintf(name, sizeof(name), ui ? "ui/%s" : "%s", serv);
|
||||
} else {
|
||||
int64_t pid = os_get_pid();
|
||||
snprintf(name, sizeof(name), "?.%-5" PRId64, pid);
|
||||
snprintf(name, sizeof(name), "%s.%-5" PRId64, ui ? "ui" : "?", pid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,10 +357,6 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
|
||||
log_levels[log_level], date_time, millis, name,
|
||||
(context == NULL ? "" : context),
|
||||
func_name, line_num);
|
||||
if (name[0] == '?') {
|
||||
// No v:servername yet. Clear `name` so that the next log can try again.
|
||||
name[0] = NUL;
|
||||
}
|
||||
|
||||
if (rv < 0) {
|
||||
return false;
|
||||
|
@ -266,7 +266,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (argc > 1 && STRICMP(argv[1], "-ll") == 0) {
|
||||
if (argc == 2) {
|
||||
print_mainerr(err_arg_missing, argv[1]);
|
||||
print_mainerr(err_arg_missing, argv[1], NULL);
|
||||
exit(1);
|
||||
}
|
||||
nlua_run_script(argv, argc, 3);
|
||||
@ -357,10 +357,8 @@ int main(int argc, char **argv)
|
||||
assert(!ui_client_channel_id && !use_builtin_ui);
|
||||
// Nvim server...
|
||||
|
||||
int listen_rv = server_init(params.listen_addr);
|
||||
if (listen_rv != 0) {
|
||||
mainerr("Failed to --listen", listen_rv < 0
|
||||
? os_strerror(listen_rv) : (listen_rv == 1 ? "empty address" : NULL));
|
||||
if (!server_init(params.listen_addr)) {
|
||||
mainerr(IObuff, NULL, NULL);
|
||||
}
|
||||
|
||||
TIME_MSG("expanding arguments");
|
||||
@ -1053,7 +1051,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
// "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
|
||||
if (argv[0][0] == '+' && !had_minmin) {
|
||||
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
||||
mainerr(err_extra_cmd, NULL);
|
||||
mainerr(err_extra_cmd, NULL, NULL);
|
||||
}
|
||||
argv_idx = -1; // skip to next argument
|
||||
if (argv[0][1] == NUL) {
|
||||
@ -1074,7 +1072,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
parmp->no_swap_file = true;
|
||||
} else {
|
||||
if (parmp->edit_type > EDIT_STDIN) {
|
||||
mainerr(err_too_many_args, argv[0]);
|
||||
mainerr(err_too_many_args, argv[0], NULL);
|
||||
}
|
||||
parmp->had_stdin_file = true;
|
||||
parmp->edit_type = EDIT_STDIN;
|
||||
@ -1137,7 +1135,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
nlua_disable_preload = true;
|
||||
} else {
|
||||
if (argv[0][argv_idx]) {
|
||||
mainerr(err_opt_unknown, argv[0]);
|
||||
mainerr(err_opt_unknown, argv[0], NULL);
|
||||
}
|
||||
had_minmin = true;
|
||||
}
|
||||
@ -1211,7 +1209,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
break;
|
||||
case 'q': // "-q" QuickFix mode
|
||||
if (parmp->edit_type != EDIT_NONE) {
|
||||
mainerr(err_too_many_args, argv[0]);
|
||||
mainerr(err_too_many_args, argv[0], NULL);
|
||||
}
|
||||
parmp->edit_type = EDIT_QF;
|
||||
if (argv[0][argv_idx]) { // "-q{errorfile}"
|
||||
@ -1240,7 +1238,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
break;
|
||||
case 't': // "-t {tag}" or "-t{tag}" jump to tag
|
||||
if (parmp->edit_type != EDIT_NONE) {
|
||||
mainerr(err_too_many_args, argv[0]);
|
||||
mainerr(err_too_many_args, argv[0], NULL);
|
||||
}
|
||||
parmp->edit_type = EDIT_TAG;
|
||||
if (argv[0][argv_idx]) { // "-t{tag}"
|
||||
@ -1274,7 +1272,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
case 'c': // "-c{command}" or "-c {command}" exec command
|
||||
if (argv[0][argv_idx] != NUL) {
|
||||
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
||||
mainerr(err_extra_cmd, NULL);
|
||||
mainerr(err_extra_cmd, NULL, NULL);
|
||||
}
|
||||
parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
|
||||
argv_idx = -1;
|
||||
@ -1291,19 +1289,19 @@ static void command_line_scan(mparm_T *parmp)
|
||||
break;
|
||||
|
||||
default:
|
||||
mainerr(err_opt_unknown, argv[0]);
|
||||
mainerr(err_opt_unknown, argv[0], NULL);
|
||||
}
|
||||
|
||||
// Handle option arguments with argument.
|
||||
if (want_argument) {
|
||||
// Check for garbage immediately after the option letter.
|
||||
if (argv[0][argv_idx] != NUL) {
|
||||
mainerr(err_opt_garbage, argv[0]);
|
||||
mainerr(err_opt_garbage, argv[0], NULL);
|
||||
}
|
||||
|
||||
argc--;
|
||||
if (argc < 1 && c != 'S') { // -S has an optional argument
|
||||
mainerr(err_arg_missing, argv[0]);
|
||||
mainerr(err_arg_missing, argv[0], NULL);
|
||||
}
|
||||
argv++;
|
||||
argv_idx = -1;
|
||||
@ -1312,7 +1310,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
case 'c': // "-c {command}" execute command
|
||||
case 'S': // "-S {file}" execute Vim script
|
||||
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
||||
mainerr(err_extra_cmd, NULL);
|
||||
mainerr(err_extra_cmd, NULL, NULL);
|
||||
}
|
||||
if (c == 'S') {
|
||||
char *a;
|
||||
@ -1343,7 +1341,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
if (strequal(argv[-1], "--cmd")) {
|
||||
// "--cmd {command}" execute command
|
||||
if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
|
||||
mainerr(err_extra_cmd, NULL);
|
||||
mainerr(err_extra_cmd, NULL, NULL);
|
||||
}
|
||||
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
|
||||
} else if (strequal(argv[-1], "--listen")) {
|
||||
@ -1425,7 +1423,7 @@ scripterror:
|
||||
|
||||
// Check for only one type of editing.
|
||||
if (parmp->edit_type > EDIT_STDIN) {
|
||||
mainerr(err_too_many_args, argv[0]);
|
||||
mainerr(err_too_many_args, argv[0], NULL);
|
||||
}
|
||||
parmp->edit_type = EDIT_FILE;
|
||||
|
||||
@ -1472,7 +1470,7 @@ scripterror:
|
||||
}
|
||||
|
||||
if (embedded_mode && (silent_mode || parmp->luaf)) {
|
||||
mainerr(_("--embed conflicts with -es/-Es/-l"), NULL);
|
||||
mainerr(_("--embed conflicts with -es/-Es/-l"), NULL, NULL);
|
||||
}
|
||||
|
||||
// If there is a "+123" or "-c" command, set v:swapcommand to the first one.
|
||||
@ -2135,28 +2133,30 @@ static int execute_env(char *env)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Prints the following then exits:
|
||||
/// - An error message `errstr`
|
||||
/// - A string `str` if not null
|
||||
/// Prints a message of the form "{msg1}: {msg2}: {msg3}", then exits with code 1.
|
||||
///
|
||||
/// @param errstr string containing an error message
|
||||
/// @param str string to append to the primary error message, or NULL
|
||||
static void mainerr(const char *errstr, const char *str)
|
||||
/// @param msg1 error message
|
||||
/// @param msg2 extra message, or NULL
|
||||
/// @param msg3 extra message, or NULL
|
||||
static void mainerr(const char *msg1, const char *msg2, const char *msg3)
|
||||
FUNC_ATTR_NORETURN
|
||||
{
|
||||
print_mainerr(errstr, str);
|
||||
print_mainerr(msg1, msg2, msg3);
|
||||
os_exit(1);
|
||||
}
|
||||
|
||||
static void print_mainerr(const char *errstr, const char *str)
|
||||
static void print_mainerr(const char *msg1, const char *msg2, const char *msg3)
|
||||
{
|
||||
char *prgname = path_tail(argv0);
|
||||
|
||||
signal_stop(); // kill us with CTRL-C here, if you like
|
||||
|
||||
fprintf(stderr, "%s: %s", prgname, _(errstr));
|
||||
if (str != NULL) {
|
||||
fprintf(stderr, ": \"%s\"", str);
|
||||
fprintf(stderr, "%s: %s", prgname, _(msg1));
|
||||
if (msg2 != NULL) {
|
||||
fprintf(stderr, ": \"%s\"", msg2);
|
||||
}
|
||||
if (msg3 != NULL) {
|
||||
fprintf(stderr, ": \"%s\"", msg3);
|
||||
}
|
||||
fprintf(stderr, _("\nMore info with \""));
|
||||
fprintf(stderr, "%s -h\"\n", prgname);
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
/// HACK: os/input.c drains this queue immediately before blocking for input.
|
||||
/// Events on this queue are async-safe, but they need the resolved state
|
||||
/// of os_inchar(), so they are processed "just-in-time".
|
||||
/// of input_get(), so they are processed "just-in-time".
|
||||
EXTERN MultiQueue *ch_before_blocking_events INIT( = NULL);
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
|
@ -11,12 +11,14 @@
|
||||
#include "nvim/event/socket.h"
|
||||
#include "nvim/garray.h"
|
||||
#include "nvim/garray_defs.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/log.h"
|
||||
#include "nvim/main.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/msgpack_rpc/server.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/stdpaths_defs.h"
|
||||
#include "nvim/types_defs.h"
|
||||
|
||||
#define MAX_CONNECTIONS 32
|
||||
#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
|
||||
@ -27,37 +29,31 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE;
|
||||
# include "msgpack_rpc/server.c.generated.h"
|
||||
#endif
|
||||
|
||||
/// Initializes the module
|
||||
/// Initializes resources, handles `--listen`, starts the primary server at v:servername.
|
||||
///
|
||||
/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
|
||||
int server_init(const char *listen_addr)
|
||||
/// @returns true on success, false on fatal error (message stored in IObuff)
|
||||
bool server_init(const char *listen_addr)
|
||||
{
|
||||
bool ok = true;
|
||||
bool must_free = false;
|
||||
TriState user_arg = kTrue; // User-provided --listen arg.
|
||||
ga_init(&watchers, sizeof(SocketWatcher *), 1);
|
||||
|
||||
// $NVIM_LISTEN_ADDRESS (deprecated)
|
||||
if ((!listen_addr || listen_addr[0] == '\0') && os_env_exists(ENV_LISTEN)) {
|
||||
user_arg = kFalse; // User-provided env var.
|
||||
listen_addr = os_getenv(ENV_LISTEN);
|
||||
}
|
||||
|
||||
if (!listen_addr || listen_addr[0] == '\0') {
|
||||
user_arg = kNone; // Autogenerated server address.
|
||||
listen_addr = server_address_new(NULL);
|
||||
must_free = true;
|
||||
}
|
||||
|
||||
if (!listen_addr) {
|
||||
abort(); // Cannot happen.
|
||||
}
|
||||
|
||||
int rv = server_start(listen_addr);
|
||||
|
||||
if (os_env_exists(ENV_LISTEN)) {
|
||||
// Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be
|
||||
// leaked to child jobs or :terminal.
|
||||
os_unsetenv(ENV_LISTEN);
|
||||
}
|
||||
|
||||
// TODO(justinmk): this is for logging_spec. Can remove this after nvim_log #7062 is merged.
|
||||
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
|
||||
if (os_env_exists("__NVIM_TEST_LOG")) {
|
||||
ELOG("test log message");
|
||||
}
|
||||
@ -66,7 +62,28 @@ int server_init(const char *listen_addr)
|
||||
xfree((char *)listen_addr);
|
||||
}
|
||||
|
||||
return rv;
|
||||
if (rv == 0 || user_arg == kNone) {
|
||||
// The autogenerated servername can fail if the user has a broken $XDG_RUNTIME_DIR. #30282
|
||||
// But that is not fatal (startup will continue, logged in $NVIM_LOGFILE, empty v:servername).
|
||||
goto end;
|
||||
}
|
||||
|
||||
(void)snprintf(IObuff, IOSIZE,
|
||||
user_arg ==
|
||||
kTrue ? "Failed to --listen: %s: \"%s\""
|
||||
: "Failed $NVIM_LISTEN_ADDRESS: %s: \"%s\"",
|
||||
rv < 0 ? os_strerror(rv) : (rv == 1 ? "empty address" : "?"),
|
||||
listen_addr);
|
||||
ok = false;
|
||||
|
||||
end:
|
||||
if (os_env_exists(ENV_LISTEN)) {
|
||||
// Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be
|
||||
// leaked to child jobs or :terminal.
|
||||
os_unsetenv(ENV_LISTEN);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/// Teardown a single server
|
||||
@ -97,17 +114,19 @@ void server_teardown(void)
|
||||
/// - Windows: "\\.\pipe\<name>.<pid>.<counter>"
|
||||
/// - Other: "/tmp/nvim.user/xxx/<name>.<pid>.<counter>"
|
||||
char *server_address_new(const char *name)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
static uint32_t count = 0;
|
||||
char fmt[ADDRESS_MAX_SIZE];
|
||||
const char *appname = get_appname();
|
||||
#ifdef MSWIN
|
||||
(void)get_appname(true);
|
||||
int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
|
||||
name ? name : appname, os_get_pid(), count++);
|
||||
name ? name : NameBuff, os_get_pid(), count++);
|
||||
#else
|
||||
char *dir = stdpaths_get_xdg_var(kXDGRuntimeDir);
|
||||
(void)get_appname(true);
|
||||
int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
|
||||
dir, name ? name : appname, os_get_pid(), count++);
|
||||
dir, name ? name : NameBuff, os_get_pid(), count++);
|
||||
xfree(dir);
|
||||
#endif
|
||||
if ((size_t)r >= sizeof(fmt)) {
|
||||
|
@ -6597,11 +6597,11 @@ static void nv_open(cmdarg_T *cap)
|
||||
static void nv_event(cmdarg_T *cap)
|
||||
{
|
||||
// Garbage collection should have been executed before blocking for events in
|
||||
// the `os_inchar` in `state_enter`, but we also disable it here in case the
|
||||
// `os_inchar` branch was not executed (!multiqueue_empty(loop.events), which
|
||||
// the `input_get` in `state_enter`, but we also disable it here in case the
|
||||
// `input_get` branch was not executed (!multiqueue_empty(loop.events), which
|
||||
// could have `may_garbage_collect` set to true in `normal_check`).
|
||||
//
|
||||
// That is because here we may run code that calls `os_inchar`
|
||||
// That is because here we may run code that calls `input_get`
|
||||
// later(`f_confirm` or `get_keystroke` for example), but in these cases it is
|
||||
// not safe to perform garbage collection because there could be unreferenced
|
||||
// lists or dicts being used.
|
||||
|
@ -210,39 +210,53 @@ static void set_init_default_backupskip(void)
|
||||
OptIndex opt_idx = kOptBackupskip;
|
||||
|
||||
ga_init(&ga, 1, 100);
|
||||
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
|
||||
bool mustfree = true;
|
||||
char *p;
|
||||
size_t plen;
|
||||
#ifdef UNIX
|
||||
if (*names[n] == NUL) {
|
||||
if (*names[i] == NUL) {
|
||||
# ifdef __APPLE__
|
||||
p = "/private/tmp";
|
||||
plen = STRLEN_LITERAL("/private/tmp");
|
||||
# else
|
||||
p = "/tmp";
|
||||
plen = STRLEN_LITERAL("/tmp");
|
||||
# endif
|
||||
mustfree = false;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
p = vim_getenv(names[n]);
|
||||
p = vim_getenv(names[i]);
|
||||
plen = 0; // will be calcuated below
|
||||
}
|
||||
if (p != NULL && *p != NUL) {
|
||||
// First time count the NUL, otherwise count the ','.
|
||||
const size_t len = strlen(p) + 3;
|
||||
char *item = xmalloc(len);
|
||||
xstrlcpy(item, p, len);
|
||||
add_pathsep(item);
|
||||
xstrlcat(item, "*", len);
|
||||
if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
|
||||
== NULL) {
|
||||
ga_grow(&ga, (int)len);
|
||||
if (!GA_EMPTY(&ga)) {
|
||||
strcat(ga.ga_data, ",");
|
||||
bool has_trailing_path_sep = false;
|
||||
|
||||
if (plen == 0) {
|
||||
// the value was retrieved from the environment
|
||||
plen = strlen(p);
|
||||
// does the value include a trailing path separator?
|
||||
if (after_pathsep(p, p + plen)) {
|
||||
has_trailing_path_sep = true;
|
||||
}
|
||||
strcat(ga.ga_data, p);
|
||||
add_pathsep(ga.ga_data);
|
||||
strcat(ga.ga_data, "*");
|
||||
ga.ga_len += (int)len;
|
||||
}
|
||||
|
||||
// item size needs to be large enough to include "/*" and a trailing NUL
|
||||
// note: the value (and therefore plen) may already include a path separator
|
||||
size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2;
|
||||
char *item = xmalloc(itemsize);
|
||||
// add a preceeding comma as a separator after the first item
|
||||
size_t itemseplen = (ga.ga_len == 0) ? 0 : 1;
|
||||
|
||||
size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p,
|
||||
has_trailing_path_sep ? "" : PATHSEPSTR);
|
||||
|
||||
if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) {
|
||||
ga_grow(&ga, (int)(itemseplen + itemlen + 1));
|
||||
ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len,
|
||||
itemseplen + itemlen + 1,
|
||||
"%s%s", (itemseplen > 0) ? "," : "", item);
|
||||
}
|
||||
xfree(item);
|
||||
}
|
||||
@ -526,7 +540,8 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
|
||||
|
||||
/// For an option value that contains comma separated items, find "newval" in
|
||||
/// "origval". Return NULL if not found.
|
||||
static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
|
||||
static char *find_dup_item(char *origval, const char *newval, const size_t newvallen,
|
||||
uint32_t flags)
|
||||
FUNC_ATTR_NONNULL_ARG(2)
|
||||
{
|
||||
if (origval == NULL) {
|
||||
@ -535,11 +550,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
|
||||
|
||||
int bs = 0;
|
||||
|
||||
const size_t newlen = strlen(newval);
|
||||
for (char *s = origval; *s != NUL; s++) {
|
||||
if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
|
||||
&& strncmp(s, newval, newlen) == 0
|
||||
&& (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) {
|
||||
&& strncmp(s, newval, newvallen) == 0
|
||||
&& (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) {
|
||||
return s;
|
||||
}
|
||||
// Count backslashes. Only a comma with an even number of backslashes
|
||||
@ -697,10 +711,10 @@ void set_helplang_default(const char *lang)
|
||||
}
|
||||
p_hlg = xmemdupz(lang, lang_len);
|
||||
// zh_CN becomes "cn", zh_TW becomes "tw".
|
||||
if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) {
|
||||
if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) {
|
||||
p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]);
|
||||
p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]);
|
||||
} else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') {
|
||||
} else if (lang_len && *p_hlg == 'C') {
|
||||
// any C like setting, such as C.UTF-8, becomes "en"
|
||||
p_hlg[0] = 'e';
|
||||
p_hlg[1] = 'n';
|
||||
@ -950,7 +964,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void
|
||||
int len = 0;
|
||||
if (op == OP_REMOVING || (flags & P_NODUP)) {
|
||||
len = (int)strlen(newval);
|
||||
s = find_dup_item(origval, newval, flags);
|
||||
s = find_dup_item(origval, newval, (size_t)len, flags);
|
||||
|
||||
// do not add if already there
|
||||
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
|
||||
@ -1464,11 +1478,10 @@ int do_set(char *arg, int opt_flags)
|
||||
}
|
||||
|
||||
if (errmsg != NULL) {
|
||||
xstrlcpy(IObuff, _(errmsg), IOSIZE);
|
||||
int i = (int)strlen(IObuff) + 2;
|
||||
int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2;
|
||||
if (i + (arg - startarg) < IOSIZE) {
|
||||
// append the argument with the error
|
||||
xstrlcat(IObuff, ": ", IOSIZE);
|
||||
xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2));
|
||||
assert(arg >= startarg);
|
||||
memmove(IObuff + i, startarg, (size_t)(arg - startarg));
|
||||
IObuff[i + (arg - startarg)] = NUL;
|
||||
@ -5431,7 +5444,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
|
||||
xp->xp_pattern = arg;
|
||||
return;
|
||||
}
|
||||
char *p = arg + strlen(arg) - 1;
|
||||
char *const argend = arg + strlen(arg);
|
||||
char *p = argend - 1;
|
||||
if (*p == ' ' && *(p - 1) != '\\') {
|
||||
xp->xp_pattern = p + 1;
|
||||
return;
|
||||
@ -5618,7 +5632,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
|
||||
// Triple-backslashed escaped file names (e.g. 'path') can also be
|
||||
// delimited by space.
|
||||
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
|
||||
for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) {
|
||||
for (p = argend - 1; p > xp->xp_pattern; p--) {
|
||||
// count number of backslashes before ' ' or ','
|
||||
if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
|
||||
char *s = p;
|
||||
@ -5642,7 +5656,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
|
||||
// An option that is a list of single-character flags should always start
|
||||
// at the end as we don't complete words.
|
||||
if (flags & P_FLAGLIST) {
|
||||
xp->xp_pattern = arg + strlen(arg);
|
||||
xp->xp_pattern = argend;
|
||||
}
|
||||
|
||||
// Some options can either be using file/dir expansions, or custom value
|
||||
@ -5952,7 +5966,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
|
||||
|
||||
int count = 0;
|
||||
|
||||
(*matches)[count++] = xstrdup(option_val);
|
||||
(*matches)[count++] = xmemdupz(option_val, num_flags);
|
||||
|
||||
if (num_flags > 1) {
|
||||
// If more than one flags, split the flags up and expose each
|
||||
|
@ -9047,7 +9047,7 @@ return {
|
||||
desc = [=[
|
||||
When on, the title of the window will be set to the value of
|
||||
'titlestring' (if it is not empty), or to:
|
||||
filename [+=-] (path) - NVIM
|
||||
filename [+=-] (path) - Nvim
|
||||
Where:
|
||||
filename the name of the file being edited
|
||||
- indicates the file cannot be modified, 'ma' off
|
||||
@ -9055,11 +9055,11 @@ return {
|
||||
= indicates the file is read-only
|
||||
=+ indicates the file is read-only and modified
|
||||
(path) is the path of the file being edited
|
||||
- NVIM the server name |v:servername| or "NVIM"
|
||||
- Nvim the server name |v:servername| or "Nvim"
|
||||
]=],
|
||||
full_name = 'title',
|
||||
scope = { 'global' },
|
||||
short_desc = N_('Vim set the title of the window'),
|
||||
short_desc = N_('set the title of the window'),
|
||||
type = 'boolean',
|
||||
varname = 'p_title',
|
||||
},
|
||||
|
@ -33,12 +33,6 @@
|
||||
#define READ_BUFFER_SIZE 0xfff
|
||||
#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
|
||||
|
||||
typedef enum {
|
||||
kInputNone,
|
||||
kInputAvail,
|
||||
kInputEof,
|
||||
} InbufPollResult;
|
||||
|
||||
static RStream read_stream = { .s.closed = true }; // Input before UI starts.
|
||||
static char input_buffer[INPUT_BUFFER_SIZE];
|
||||
static char *input_read_pos = input_buffer;
|
||||
@ -84,57 +78,76 @@ static void cursorhold_event(void **argv)
|
||||
static void create_cursorhold_event(bool events_enabled)
|
||||
{
|
||||
// If events are enabled and the queue has any items, this function should not
|
||||
// have been called (inbuf_poll would return kInputAvail).
|
||||
// have been called (`inbuf_poll` would return `kTrue`).
|
||||
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
|
||||
// `state_check` callback for the states where it can be triggered.
|
||||
assert(!events_enabled || multiqueue_empty(main_loop.events));
|
||||
multiqueue_put(main_loop.events, cursorhold_event, NULL);
|
||||
}
|
||||
|
||||
static void restart_cursorhold_wait(int tb_change_cnt)
|
||||
static void reset_cursorhold_wait(int tb_change_cnt)
|
||||
{
|
||||
cursorhold_time = 0;
|
||||
cursorhold_tb_change_cnt = tb_change_cnt;
|
||||
}
|
||||
|
||||
/// Low level input function
|
||||
/// Reads OS input into `buf`, and consumes pending events while waiting (if `ms != 0`).
|
||||
///
|
||||
/// Wait until either the input buffer is non-empty or, if `events` is not NULL
|
||||
/// until `events` is non-empty.
|
||||
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
|
||||
/// - Consumes available input received from the OS.
|
||||
/// - Consumes pending events.
|
||||
/// - Manages CursorHold events.
|
||||
/// - Handles EOF conditions.
|
||||
///
|
||||
/// Originally based on the Vim `mch_inchar` function.
|
||||
///
|
||||
/// @param buf Buffer to store consumed input.
|
||||
/// @param maxlen Maximum bytes to read into `buf`, or 0 to skip reading.
|
||||
/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
|
||||
/// @param tb_change_cnt Used to detect when typeahead changes.
|
||||
/// @param events (optional) Events to process.
|
||||
/// @return Bytes read into buf, or 0 if no input was read
|
||||
int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
|
||||
{
|
||||
// This check is needed so that feeding typeahead from RPC can prevent CursorHold.
|
||||
if (tb_change_cnt != cursorhold_tb_change_cnt) {
|
||||
restart_cursorhold_wait(tb_change_cnt);
|
||||
reset_cursorhold_wait(tb_change_cnt);
|
||||
}
|
||||
|
||||
if (maxlen && input_available()) {
|
||||
restart_cursorhold_wait(tb_change_cnt);
|
||||
size_t to_read = MIN((size_t)maxlen, input_available());
|
||||
memcpy(buf, input_read_pos, to_read);
|
||||
input_read_pos += to_read;
|
||||
return (int)to_read;
|
||||
}
|
||||
#define TRY_READ() \
|
||||
do { \
|
||||
if (maxlen && input_available()) { \
|
||||
reset_cursorhold_wait(tb_change_cnt); \
|
||||
assert(maxlen >= 0); \
|
||||
size_t to_read = MIN((size_t)maxlen, input_available()); \
|
||||
memcpy(buf, input_read_pos, to_read); \
|
||||
input_read_pos += to_read; \
|
||||
/* This is safe because INPUT_BUFFER_SIZE fits in an int. */ \
|
||||
assert(to_read <= INT_MAX); \
|
||||
return (int)to_read; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
TRY_READ();
|
||||
|
||||
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
|
||||
if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
|
||||
ctrl_c_interrupts = false;
|
||||
}
|
||||
|
||||
InbufPollResult result;
|
||||
TriState result; ///< inbuf_poll result.
|
||||
if (ms >= 0) {
|
||||
if ((result = inbuf_poll(ms, events)) == kInputNone) {
|
||||
if ((result = inbuf_poll(ms, events)) == kFalse) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
uint64_t wait_start = os_hrtime();
|
||||
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
|
||||
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
|
||||
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) {
|
||||
if (read_stream.s.closed && silent_mode) {
|
||||
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
|
||||
read_error_exit();
|
||||
}
|
||||
restart_cursorhold_wait(tb_change_cnt);
|
||||
reset_cursorhold_wait(tb_change_cnt);
|
||||
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
|
||||
create_cursorhold_event(events == main_loop.events);
|
||||
} else {
|
||||
@ -153,32 +166,26 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (maxlen && input_available()) {
|
||||
restart_cursorhold_wait(tb_change_cnt);
|
||||
// Safe to convert `to_read` to int, it will never overflow since
|
||||
// INPUT_BUFFER_SIZE fits in an int
|
||||
size_t to_read = MIN((size_t)maxlen, input_available());
|
||||
memcpy(buf, input_read_pos, to_read);
|
||||
input_read_pos += to_read;
|
||||
return (int)to_read;
|
||||
}
|
||||
TRY_READ();
|
||||
|
||||
// If there are events, return the keys directly
|
||||
if (maxlen && pending_events(events)) {
|
||||
return push_event_key(buf, maxlen);
|
||||
}
|
||||
|
||||
if (result == kInputEof) {
|
||||
if (result == kNone) {
|
||||
read_error_exit();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#undef TRY_READ
|
||||
}
|
||||
|
||||
// Check if a character is available for reading
|
||||
bool os_char_avail(void)
|
||||
{
|
||||
return inbuf_poll(0, NULL) == kInputAvail;
|
||||
return inbuf_poll(0, NULL) == kTrue;
|
||||
}
|
||||
|
||||
/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
|
||||
@ -463,15 +470,22 @@ bool input_blocking(void)
|
||||
return blocking;
|
||||
}
|
||||
|
||||
// This is a replacement for the old `WaitForChar` function in os_unix.c
|
||||
static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
|
||||
/// Checks for (but does not read) available input, and consumes `main_loop.events` while waiting.
|
||||
///
|
||||
/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
|
||||
/// @param events (optional) Queue to check for pending events.
|
||||
/// @return TriState:
|
||||
/// - kTrue: Input/events available
|
||||
/// - kFalse: No input/events
|
||||
/// - kNone: EOF reached on the input stream
|
||||
static TriState inbuf_poll(int ms, MultiQueue *events)
|
||||
{
|
||||
if (os_input_ready(events)) {
|
||||
return kInputAvail;
|
||||
return kTrue;
|
||||
}
|
||||
|
||||
if (do_profiling == PROF_YES && ms) {
|
||||
prof_inchar_enter();
|
||||
prof_input_start();
|
||||
}
|
||||
|
||||
if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) {
|
||||
@ -479,20 +493,18 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
|
||||
blocking = true;
|
||||
multiqueue_process_events(ch_before_blocking_events);
|
||||
}
|
||||
DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL,
|
||||
events && !multiqueue_empty(events));
|
||||
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms,
|
||||
os_input_ready(events) || input_eof);
|
||||
DLOG("blocking... events=%s", !!events ? "true" : "false");
|
||||
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, os_input_ready(events) || input_eof);
|
||||
blocking = false;
|
||||
|
||||
if (do_profiling == PROF_YES && ms) {
|
||||
prof_inchar_exit();
|
||||
prof_input_end();
|
||||
}
|
||||
|
||||
if (os_input_ready(events)) {
|
||||
return kInputAvail;
|
||||
return kTrue;
|
||||
}
|
||||
return input_eof ? kInputEof : kInputNone;
|
||||
return input_eof ? kNone : kFalse;
|
||||
}
|
||||
|
||||
static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
|
||||
@ -533,8 +545,8 @@ static void process_ctrl_c(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function used to push bytes from the 'event' key sequence partially
|
||||
// between calls to os_inchar when maxlen < 3
|
||||
/// Pushes bytes from the "event" key sequence (KE_EVENT) partially between calls to input_get when
|
||||
/// `maxlen < 3`.
|
||||
static int push_event_key(uint8_t *buf, int maxlen)
|
||||
{
|
||||
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
|
||||
|
@ -1292,7 +1292,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
|
||||
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
|
||||
uv_err_name(status));
|
||||
}
|
||||
stream_close(stream, NULL, NULL, false);
|
||||
stream_may_close(stream, false);
|
||||
}
|
||||
|
||||
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
|
||||
|
@ -63,22 +63,32 @@ static const char *const xdg_defaults[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Get the value of $NVIM_APPNAME or "nvim" if not set.
|
||||
/// Gets the value of $NVIM_APPNAME, or "nvim" if not set.
|
||||
///
|
||||
/// @param namelike Write "name-like" value (no path separators) in `NameBuff`.
|
||||
///
|
||||
/// @return $NVIM_APPNAME value
|
||||
const char *get_appname(void)
|
||||
const char *get_appname(bool namelike)
|
||||
{
|
||||
const char *env_val = os_getenv("NVIM_APPNAME");
|
||||
if (env_val == NULL || *env_val == NUL) {
|
||||
env_val = "nvim";
|
||||
}
|
||||
|
||||
if (namelike) {
|
||||
// Appname may be a relative path, replace slashes to make it name-like.
|
||||
xstrlcpy(NameBuff, env_val, sizeof(NameBuff));
|
||||
memchrsub(NameBuff, '/', '-', sizeof(NameBuff));
|
||||
memchrsub(NameBuff, '\\', '-', sizeof(NameBuff));
|
||||
}
|
||||
|
||||
return env_val;
|
||||
}
|
||||
|
||||
/// Ensure that APPNAME is valid. Must be a name or relative path.
|
||||
bool appname_is_valid(void)
|
||||
{
|
||||
const char *appname = get_appname();
|
||||
const char *appname = get_appname(false);
|
||||
if (path_is_absolute(appname)
|
||||
// TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
|
||||
|| strequal(appname, "/")
|
||||
@ -193,7 +203,7 @@ char *get_xdg_home(const XDGVarType idx)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
char *dir = stdpaths_get_xdg_var(idx);
|
||||
const char *appname = get_appname();
|
||||
const char *appname = get_appname(false);
|
||||
size_t appname_len = strlen(appname);
|
||||
assert(appname_len < (IOSIZE - sizeof("-data")));
|
||||
|
||||
|
@ -383,19 +383,19 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg)
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
}
|
||||
|
||||
static proftime_T inchar_time;
|
||||
static proftime_T wait_time;
|
||||
|
||||
/// Called when starting to wait for the user to type a character.
|
||||
void prof_inchar_enter(void)
|
||||
void prof_input_start(void)
|
||||
{
|
||||
inchar_time = profile_start();
|
||||
wait_time = profile_start();
|
||||
}
|
||||
|
||||
/// Called when finished waiting for the user to type a character.
|
||||
void prof_inchar_exit(void)
|
||||
void prof_input_end(void)
|
||||
{
|
||||
inchar_time = profile_end(inchar_time);
|
||||
profile_set_wait(profile_add(profile_get_wait(), inchar_time));
|
||||
wait_time = profile_end(wait_time);
|
||||
profile_set_wait(profile_add(profile_get_wait(), wait_time));
|
||||
}
|
||||
|
||||
/// @return true when a function defined in the current script should be
|
||||
|
@ -1559,7 +1559,7 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val, const ch
|
||||
return dest;
|
||||
}
|
||||
const void *iter = NULL;
|
||||
const char *appname = get_appname();
|
||||
const char *appname = get_appname(false);
|
||||
const size_t appname_len = strlen(appname);
|
||||
do {
|
||||
size_t dir_len;
|
||||
@ -1626,7 +1626,7 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_
|
||||
if (!after_pathsep(dest - 1, dest)) {
|
||||
*dest++ = PATHSEP;
|
||||
}
|
||||
const char *appname = get_appname();
|
||||
const char *appname = get_appname(false);
|
||||
size_t appname_len = strlen(appname);
|
||||
assert(appname_len < (IOSIZE - sizeof("-data")));
|
||||
xmemcpyz(IObuff, appname, appname_len);
|
||||
@ -1697,7 +1697,7 @@ char *runtimepath_default(bool clean_arg)
|
||||
size_t config_len = 0;
|
||||
size_t vimruntime_len = 0;
|
||||
size_t libdir_len = 0;
|
||||
const char *appname = get_appname();
|
||||
const char *appname = get_appname(false);
|
||||
size_t appname_len = strlen(appname);
|
||||
if (data_home != NULL) {
|
||||
data_len = strlen(data_home);
|
||||
|
@ -74,10 +74,9 @@ getkey:
|
||||
}
|
||||
// Flush screen updates before blocking.
|
||||
ui_flush();
|
||||
// Call `os_inchar` directly to block for events or user input without
|
||||
// consuming anything from `input_buffer`(os/input.c) or calling the
|
||||
// mapping engine.
|
||||
os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
||||
// Call `input_get` directly to block for events or user input without consuming anything from
|
||||
// `os/input.c:input_buffer` or calling the mapping engine.
|
||||
input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
|
||||
// If an event was put into the queue, we send K_EVENT directly.
|
||||
if (!input_available() && !multiqueue_empty(main_loop.events)) {
|
||||
key = K_EVENT;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nvim/memory_defs.h"
|
||||
#include "nvim/msgpack_rpc/channel.h"
|
||||
#include "nvim/msgpack_rpc/channel_defs.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/os_defs.h"
|
||||
#include "nvim/tui/tui.h"
|
||||
#include "nvim/tui/tui_defs.h"
|
||||
@ -126,6 +127,11 @@ void ui_client_run(bool remote_ui)
|
||||
|
||||
ui_client_attach(width, height, term, rgb);
|
||||
|
||||
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
|
||||
if (os_env_exists("__NVIM_TEST_LOG")) {
|
||||
ELOG("test log message");
|
||||
}
|
||||
|
||||
// os_exit() will be invoked when the client channel detaches
|
||||
while (true) {
|
||||
LOOP_PROCESS_EVENTS(&main_loop, resize_events, -1);
|
||||
|
@ -14,7 +14,7 @@ EXTERN size_t grid_line_buf_size INIT( = 0);
|
||||
EXTERN schar_T *grid_line_buf_char INIT( = NULL);
|
||||
EXTERN sattr_T *grid_line_buf_attr INIT( = NULL);
|
||||
|
||||
// ID of the ui client channel. If zero, the client is not running.
|
||||
// Client-side UI channel. Zero during early startup or if not a (--remote-ui) UI client.
|
||||
EXTERN uint64_t ui_client_channel_id INIT( = 0);
|
||||
|
||||
// exit status from embedded nvim process
|
||||
|
@ -3201,7 +3201,7 @@ describe('API', function()
|
||||
end)
|
||||
|
||||
describe('nvim_get_runtime_file', function()
|
||||
local p = n.alter_slashes
|
||||
local p = t.fix_slashes
|
||||
it('can find files', function()
|
||||
eq({}, api.nvim_get_runtime_file('bork.borkbork', false))
|
||||
eq({}, api.nvim_get_runtime_file('bork.borkbork', true))
|
||||
@ -3210,36 +3210,36 @@ describe('API', function()
|
||||
local val = api.nvim_get_runtime_file('autoload/remote/*.vim', true)
|
||||
eq(2, #val)
|
||||
if endswith(val[1], 'define.vim') then
|
||||
ok(endswith(val[1], p 'autoload/remote/define.vim'))
|
||||
ok(endswith(val[2], p 'autoload/remote/host.vim'))
|
||||
ok(endswith(p(val[1]), 'autoload/remote/define.vim'))
|
||||
ok(endswith(p(val[2]), 'autoload/remote/host.vim'))
|
||||
else
|
||||
ok(endswith(val[1], p 'autoload/remote/host.vim'))
|
||||
ok(endswith(val[2], p 'autoload/remote/define.vim'))
|
||||
ok(endswith(p(val[1]), 'autoload/remote/host.vim'))
|
||||
ok(endswith(p(val[2]), 'autoload/remote/define.vim'))
|
||||
end
|
||||
val = api.nvim_get_runtime_file('autoload/remote/*.vim', false)
|
||||
eq(1, #val)
|
||||
ok(
|
||||
endswith(val[1], p 'autoload/remote/define.vim')
|
||||
or endswith(val[1], p 'autoload/remote/host.vim')
|
||||
endswith(p(val[1]), 'autoload/remote/define.vim')
|
||||
or endswith(p(val[1]), 'autoload/remote/host.vim')
|
||||
)
|
||||
|
||||
val = api.nvim_get_runtime_file('lua', true)
|
||||
eq(1, #val)
|
||||
ok(endswith(val[1], p 'lua'))
|
||||
ok(endswith(p(val[1]), 'lua'))
|
||||
|
||||
val = api.nvim_get_runtime_file('lua/vim', true)
|
||||
eq(1, #val)
|
||||
ok(endswith(val[1], p 'lua/vim'))
|
||||
ok(endswith(p(val[1]), 'lua/vim'))
|
||||
end)
|
||||
|
||||
it('can find directories', function()
|
||||
local val = api.nvim_get_runtime_file('lua/', true)
|
||||
eq(1, #val)
|
||||
ok(endswith(val[1], p 'lua/'))
|
||||
ok(endswith(p(val[1]), 'lua/'))
|
||||
|
||||
val = api.nvim_get_runtime_file('lua/vim/', true)
|
||||
eq(1, #val)
|
||||
ok(endswith(val[1], p 'lua/vim/'))
|
||||
ok(endswith(p(val[1]), 'lua/vim/'))
|
||||
|
||||
eq({}, api.nvim_get_runtime_file('foobarlang/', true))
|
||||
end)
|
||||
|
@ -9,7 +9,7 @@ local request = n.request
|
||||
local is_os = t.is_os
|
||||
|
||||
describe('autocmd DirChanged and DirChangedPre', function()
|
||||
local curdir = vim.uv.cwd():gsub('\\', '/')
|
||||
local curdir = t.fix_slashes(vim.uv.cwd())
|
||||
local dirs = {
|
||||
curdir .. '/Xtest-functional-autocmd-dirchanged.dir1',
|
||||
curdir .. '/Xtest-functional-autocmd-dirchanged.dir2',
|
||||
|
@ -321,11 +321,11 @@ end)
|
||||
describe('tmpdir', function()
|
||||
local tmproot_pat = [=[.*[/\\]nvim%.[^/\\]+]=]
|
||||
local testlog = 'Xtest_tmpdir_log'
|
||||
local os_tmpdir
|
||||
local os_tmpdir ---@type string
|
||||
|
||||
before_each(function()
|
||||
-- Fake /tmp dir so that we can mess it up.
|
||||
os_tmpdir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX')
|
||||
os_tmpdir = assert(vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX'))
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
@ -414,15 +414,4 @@ describe('tmpdir', function()
|
||||
rm_tmpdir()
|
||||
eq('E5431: tempdir disappeared (3 times)', api.nvim_get_vvar('errmsg'))
|
||||
end)
|
||||
|
||||
it('$NVIM_APPNAME relative path', function()
|
||||
clear({
|
||||
env = {
|
||||
NVIM_APPNAME = 'a/b',
|
||||
NVIM_LOG_FILE = testlog,
|
||||
TMPDIR = os_tmpdir,
|
||||
},
|
||||
})
|
||||
matches([=[.*[/\\]a%%b%.[^/\\]+]=], fn.tempname())
|
||||
end)
|
||||
end)
|
||||
|
@ -1,5 +1,6 @@
|
||||
local t = require('test.testutil')
|
||||
local n = require('test.functional.testnvim')()
|
||||
local tt = require('test.functional.terminal.testutil')
|
||||
|
||||
local assert_log = t.assert_log
|
||||
local clear = n.clear
|
||||
@ -29,10 +30,54 @@ describe('log', function()
|
||||
assert(request('nvim__stats').log_skip <= 13)
|
||||
end)
|
||||
|
||||
it('messages are formatted with name or test id', function()
|
||||
it('TUI client name is "ui"', function()
|
||||
local function setup(env)
|
||||
clear()
|
||||
-- Start Nvim with builtin UI.
|
||||
local screen = tt.setup_child_nvim({
|
||||
'-u',
|
||||
'NONE',
|
||||
'-i',
|
||||
'NONE',
|
||||
'--cmd',
|
||||
n.nvim_set,
|
||||
}, {
|
||||
env = env,
|
||||
})
|
||||
screen:expect([[
|
||||
{1: } |
|
||||
~ |*4
|
||||
|
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
end
|
||||
|
||||
-- Without $NVIM parent.
|
||||
setup({
|
||||
NVIM = '',
|
||||
NVIM_LISTEN_ADDRESS = '',
|
||||
NVIM_LOG_FILE = testlog,
|
||||
__NVIM_TEST_LOG = '1',
|
||||
})
|
||||
-- Example:
|
||||
-- ERR 2024-09-11T16:40:02.421 ui.47056 ui_client_run:165: test log message
|
||||
assert_log(' ui%.%d+% +ui_client_run:%d+: test log message', testlog, 100)
|
||||
|
||||
-- With $NVIM parent.
|
||||
setup({
|
||||
NVIM_LOG_FILE = testlog,
|
||||
__NVIM_TEST_LOG = '1',
|
||||
})
|
||||
-- Example:
|
||||
-- ERR 2024-09-11T16:41:17.539 ui/c/T2.47826.0 ui_client_run:165: test log message
|
||||
local tid = _G._nvim_test_id
|
||||
assert_log(' ui/c/' .. tid .. '%.%d+%.%d +ui_client_run:%d+: test log message', testlog, 100)
|
||||
end)
|
||||
|
||||
it('formats messages with session name or test id', function()
|
||||
-- Examples:
|
||||
-- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message
|
||||
-- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message
|
||||
-- ERR 2024-09-11T16:44:33.794 T3.49429.0 server_init:58: test log message
|
||||
-- ERR 2024-09-11T16:44:33.823 c/T3.49429.0 server_init:58: test log message
|
||||
|
||||
clear({
|
||||
env = {
|
||||
@ -47,10 +92,10 @@ describe('log', function()
|
||||
|
||||
exec_lua([[
|
||||
local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict())
|
||||
vim.fn.jobwait({ j1 }, 10000)
|
||||
vim.fn.jobwait({ j1 }, 5000)
|
||||
]])
|
||||
|
||||
-- Child Nvim spawned by jobstart() appends "/c" to parent name.
|
||||
assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100)
|
||||
-- Child Nvim spawned by jobstart() prepends "c/" to parent name.
|
||||
assert_log('c/' .. tid .. '%.%d+%.%d +server_init:%d+: test log message', testlog, 100)
|
||||
end)
|
||||
end)
|
||||
|
@ -41,6 +41,21 @@ describe('server', function()
|
||||
end
|
||||
end)
|
||||
|
||||
it('broken $XDG_RUNTIME_DIR is not fatal #30282', function()
|
||||
clear {
|
||||
args_rm = { '--listen' },
|
||||
env = { NVIM_LOG_FILE = testlog, XDG_RUNTIME_DIR = '/non-existent-dir/subdir//' },
|
||||
}
|
||||
|
||||
if is_os('win') then
|
||||
-- Windows pipes have a special namespace and thus aren't decided by $XDG_RUNTIME_DIR.
|
||||
matches('nvim', api.nvim_get_vvar('servername'))
|
||||
else
|
||||
eq('', api.nvim_get_vvar('servername'))
|
||||
t.assert_log('Failed to start server%: no such file or directory', testlog, 100)
|
||||
end
|
||||
end)
|
||||
|
||||
it('serverstart(), serverstop() does not set $NVIM', function()
|
||||
clear()
|
||||
local s = eval('serverstart()')
|
||||
@ -139,7 +154,7 @@ describe('server', function()
|
||||
clear_serverlist()
|
||||
|
||||
-- Address without slashes is a "name" which is appended to a generated path. #8519
|
||||
matches([[.*[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4'))
|
||||
matches([[[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4'))
|
||||
clear_serverlist()
|
||||
|
||||
eq('Vim:Failed to start server: invalid argument', pcall_err(fn.serverstart, '127.0.0.1:65536')) -- invalid port
|
||||
@ -175,56 +190,79 @@ describe('server', function()
|
||||
end)
|
||||
|
||||
describe('startup --listen', function()
|
||||
-- Tests Nvim output when failing to start, with and without "--headless".
|
||||
-- TODO(justinmk): clear() should have a way to get stdout if Nvim fails to start.
|
||||
local function _test(args, env, expected)
|
||||
local function run(cmd)
|
||||
return n.exec_lua(function(cmd_, env_)
|
||||
return vim
|
||||
.system(cmd_, {
|
||||
text = true,
|
||||
env = vim.tbl_extend(
|
||||
'force',
|
||||
-- Avoid noise in the logs; we expect failures for these tests.
|
||||
{ NVIM_LOG_FILE = testlog },
|
||||
env_ or {}
|
||||
),
|
||||
})
|
||||
:wait()
|
||||
end, cmd, env) --[[@as vim.SystemCompleted]]
|
||||
end
|
||||
|
||||
local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args)
|
||||
local r = run(cmd)
|
||||
eq(1, r.code)
|
||||
matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' '))
|
||||
|
||||
if is_os('win') then
|
||||
return -- On Windows, output without --headless is garbage.
|
||||
end
|
||||
table.remove(cmd, 3) -- Remove '--headless'.
|
||||
assert(not vim.tbl_contains(cmd, '--headless'))
|
||||
r = run(cmd)
|
||||
eq(1, r.code)
|
||||
matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' '))
|
||||
end
|
||||
|
||||
it('validates', function()
|
||||
clear { env = { NVIM_LOG_FILE = testlog } }
|
||||
|
||||
-- Tests args with and without "--headless".
|
||||
local function _test(args, expected)
|
||||
local function run(cmd)
|
||||
return n.exec_lua(function(cmd_)
|
||||
return vim
|
||||
.system(cmd_, {
|
||||
text = true,
|
||||
env = {
|
||||
-- Avoid noise in the logs; we expect failures for these tests.
|
||||
NVIM_LOG_FILE = testlog,
|
||||
},
|
||||
})
|
||||
:wait()
|
||||
end, cmd) --[[@as vim.SystemCompleted]]
|
||||
end
|
||||
|
||||
local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args)
|
||||
local r = run(cmd)
|
||||
eq(1, r.code)
|
||||
matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' '))
|
||||
|
||||
if is_os('win') then
|
||||
return -- On Windows, output without --headless is garbage.
|
||||
end
|
||||
table.remove(cmd, 3) -- Remove '--headless'.
|
||||
assert(not vim.tbl_contains(cmd, '--headless'))
|
||||
r = run(cmd)
|
||||
eq(1, r.code)
|
||||
matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' '))
|
||||
end
|
||||
local in_use = n.eval('v:servername') ---@type string Address already used by another server.
|
||||
|
||||
t.assert_nolog('Failed to start server', testlog, 100)
|
||||
t.assert_nolog('Host lookup failed', testlog, 100)
|
||||
|
||||
_test({ '--listen' }, 'nvim.*: Argument missing after: "%-%-listen"')
|
||||
_test({ '--listen2' }, 'nvim.*: Garbage after option argument: "%-%-listen2"')
|
||||
_test({ '--listen', n.eval('v:servername') }, 'nvim.*: Failed to %-%-listen: ".* already .*"')
|
||||
_test({ '--listen', '/' }, 'nvim.*: Failed to %-%-listen: ".*"')
|
||||
_test({ '--listen' }, nil, 'nvim.*: Argument missing after: "%-%-listen"')
|
||||
_test({ '--listen2' }, nil, 'nvim.*: Garbage after option argument: "%-%-listen2"')
|
||||
_test(
|
||||
{ '--listen', in_use },
|
||||
nil,
|
||||
('nvim.*: Failed to %%-%%-listen: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use))
|
||||
)
|
||||
_test({ '--listen', '/' }, nil, 'nvim.*: Failed to %-%-listen: [^:]+: "/"')
|
||||
_test(
|
||||
{ '--listen', 'https://example.com' },
|
||||
('nvim.*: Failed to %%-%%-listen: "%s"'):format(
|
||||
nil,
|
||||
('nvim.*: Failed to %%-%%-listen: %s: "https://example.com"'):format(
|
||||
is_os('mac') and 'unknown node or service' or 'service not available for socket type'
|
||||
)
|
||||
)
|
||||
|
||||
t.assert_log('Failed to start server', testlog, 100)
|
||||
t.assert_log('Host lookup failed', testlog, 100)
|
||||
|
||||
_test(
|
||||
{},
|
||||
{ NVIM_LISTEN_ADDRESS = in_use },
|
||||
('nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use))
|
||||
)
|
||||
_test({}, { NVIM_LISTEN_ADDRESS = '/' }, 'nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+: "/"')
|
||||
_test(
|
||||
{},
|
||||
{ NVIM_LISTEN_ADDRESS = 'https://example.com' },
|
||||
('nvim.*: Failed $NVIM_LISTEN_ADDRESS: %s: "https://example.com"'):format(
|
||||
is_os('mac') and 'unknown node or service' or 'service not available for socket type'
|
||||
)
|
||||
)
|
||||
end)
|
||||
|
||||
it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
|
||||
@ -235,6 +273,6 @@ describe('startup --listen', function()
|
||||
|
||||
-- Address without slashes is a "name" which is appended to a generated path. #8519
|
||||
clear({ args = { '--listen', 'test-name' } })
|
||||
matches([[.*[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername'))
|
||||
matches([[[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername'))
|
||||
end)
|
||||
end)
|
@ -27,7 +27,6 @@ local sleep = vim.uv.sleep
|
||||
local startswith = vim.startswith
|
||||
local write_file = t.write_file
|
||||
local api = n.api
|
||||
local alter_slashes = n.alter_slashes
|
||||
local is_os = t.is_os
|
||||
local dedent = t.dedent
|
||||
local tbl_map = vim.tbl_map
|
||||
@ -40,22 +39,15 @@ local testlog = 'Xtest-startupspec-log'
|
||||
describe('startup', function()
|
||||
it('--clean', function()
|
||||
clear()
|
||||
ok(
|
||||
string.find(
|
||||
alter_slashes(api.nvim_get_option_value('runtimepath', {})),
|
||||
fn.stdpath('config'),
|
||||
1,
|
||||
true
|
||||
) ~= nil
|
||||
matches(
|
||||
vim.pesc(t.fix_slashes(fn.stdpath('config'))),
|
||||
t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
)
|
||||
|
||||
clear('--clean')
|
||||
ok(
|
||||
string.find(
|
||||
alter_slashes(api.nvim_get_option_value('runtimepath', {})),
|
||||
fn.stdpath('config'),
|
||||
1,
|
||||
true
|
||||
) == nil
|
||||
not t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
:match(vim.pesc(t.fix_slashes(fn.stdpath('config'))))
|
||||
)
|
||||
end)
|
||||
|
||||
|
@ -170,7 +170,7 @@ describe(':mksession', function()
|
||||
skip(is_os('win'), 'causes rmdir() to fail')
|
||||
|
||||
local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
|
||||
cwd_dir = cwd_dir:gsub([[\]], '/') -- :mksession always uses unix slashes.
|
||||
cwd_dir = t.fix_slashes(cwd_dir) -- :mksession always uses unix slashes.
|
||||
local session_path = cwd_dir .. '/' .. session_file
|
||||
|
||||
command('cd ' .. tab_dir)
|
||||
|
@ -2347,6 +2347,7 @@ describe('vim.diagnostic', function()
|
||||
-- Legacy signs for diagnostics were deprecated in 0.10 and will be removed in 0.12
|
||||
eq(0, n.fn.has('nvim-0.12'))
|
||||
|
||||
n.command('set cursorline')
|
||||
n.command('sign define DiagnosticSignError text= texthl= linehl=ErrorMsg numhl=ErrorMsg')
|
||||
n.command('sign define DiagnosticSignWarn text= texthl= linehl=WarningMsg numhl=WarningMsg')
|
||||
n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined')
|
||||
@ -2354,7 +2355,7 @@ describe('vim.diagnostic', function()
|
||||
|
||||
local result = exec_lua(function()
|
||||
vim.diagnostic.config({
|
||||
signs = true,
|
||||
signs = { cursorlinehl = { 'DiagnosticError', 'DiagnosticWarn' } },
|
||||
})
|
||||
|
||||
local diagnostics = {
|
||||
@ -2382,6 +2383,7 @@ describe('vim.diagnostic', function()
|
||||
text = s[4].sign_text or '',
|
||||
numhl = s[4].number_hl_group,
|
||||
linehl = s[4].line_hl_group,
|
||||
culhl = s[4].cursorline_hl_group,
|
||||
}
|
||||
end
|
||||
return result
|
||||
@ -2393,6 +2395,7 @@ describe('vim.diagnostic', function()
|
||||
text = '',
|
||||
numhl = 'ErrorMsg',
|
||||
linehl = 'ErrorMsg',
|
||||
culhl = 'DiagnosticError',
|
||||
}, result[1])
|
||||
|
||||
eq({
|
||||
@ -2401,6 +2404,7 @@ describe('vim.diagnostic', function()
|
||||
text = '',
|
||||
numhl = 'WarningMsg',
|
||||
linehl = 'WarningMsg',
|
||||
culhl = 'DiagnosticWarn',
|
||||
}, result[2])
|
||||
end)
|
||||
end)
|
||||
|
@ -217,7 +217,7 @@ describe('URI methods', function()
|
||||
]],
|
||||
file
|
||||
)
|
||||
local expected_uri = 'file:///' .. file:gsub('\\', '/')
|
||||
local expected_uri = 'file:///' .. t.fix_slashes(file)
|
||||
eq(expected_uri, exec_lua(test_case))
|
||||
os.remove(file)
|
||||
end)
|
||||
|
@ -1071,12 +1071,11 @@ describe('lua stdlib', function()
|
||||
]])
|
||||
)
|
||||
|
||||
-- Fix github issue #23654
|
||||
ok(exec_lua([[
|
||||
local a = { sub = { [1] = 'a' } }
|
||||
local b = { sub = { b = 'a' } }
|
||||
local a = { sub = { 'a', 'b' } }
|
||||
local b = { sub = { 'b', 'c' } }
|
||||
local c = vim.tbl_deep_extend('force', a, b)
|
||||
return vim.deep_equal(c, { sub = { [1] = 'a', b = 'a' } })
|
||||
return vim.deep_equal(c, { sub = { 'b', 'c' } })
|
||||
]]))
|
||||
|
||||
matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]]))
|
||||
|
@ -22,7 +22,7 @@ describe("'autochdir'", function()
|
||||
end)
|
||||
|
||||
it('is not overwritten by getwinvar() call #17609', function()
|
||||
local curdir = vim.uv.cwd():gsub('\\', '/')
|
||||
local curdir = t.fix_slashes(vim.uv.cwd())
|
||||
local dir_a = curdir .. '/Xtest-functional-options-autochdir.dir_a'
|
||||
local dir_b = curdir .. '/Xtest-functional-options-autochdir.dir_b'
|
||||
mkdir(dir_a)
|
||||
|
@ -23,7 +23,6 @@ local insert = n.insert
|
||||
local neq = t.neq
|
||||
local mkdir = t.mkdir
|
||||
local rmdir = n.rmdir
|
||||
local alter_slashes = n.alter_slashes
|
||||
local tbl_contains = vim.tbl_contains
|
||||
local expect_exit = n.expect_exit
|
||||
local check_close = n.check_close
|
||||
@ -262,7 +261,7 @@ describe('startup defaults', function()
|
||||
NVIM_LOG_FILE = '', -- Empty is invalid.
|
||||
},
|
||||
})
|
||||
eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
|
||||
eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE')))
|
||||
end)
|
||||
|
||||
it('defaults to stdpath("log")/log if invalid', function()
|
||||
@ -273,7 +272,7 @@ describe('startup defaults', function()
|
||||
NVIM_LOG_FILE = '.', -- Any directory is invalid.
|
||||
},
|
||||
})
|
||||
eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
|
||||
eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE')))
|
||||
-- Avoid "failed to open $NVIM_LOG_FILE" noise in test output.
|
||||
expect_exit(command, 'qall!')
|
||||
end)
|
||||
@ -383,69 +382,69 @@ describe('XDG defaults', function()
|
||||
|
||||
eq(
|
||||
(
|
||||
(
|
||||
t.fix_slashes(
|
||||
root_path
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. (',' .. root_path .. '/c/nvim')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. (',' .. root_path .. '/C/nvim/site')
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. (',' .. root_path .. '/C/nvim/site/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. (',' .. root_path .. '/c/nvim/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim/after'
|
||||
):gsub('\\', '/')
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. (',' .. root_path .. '/c/nvim')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. (',' .. root_path .. '/C/nvim/site')
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. (',' .. root_path .. '/C/nvim/site/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. (',' .. root_path .. '/c/nvim/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim/after'
|
||||
)
|
||||
),
|
||||
(api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
)
|
||||
command('set runtimepath&')
|
||||
command('set backupdir&')
|
||||
@ -454,85 +453,85 @@ describe('XDG defaults', function()
|
||||
command('set viewdir&')
|
||||
eq(
|
||||
(
|
||||
(
|
||||
t.fix_slashes(
|
||||
root_path
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. (',' .. root_path .. '/c/nvim')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. (',' .. root_path .. '/C/nvim/site')
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. (',' .. root_path .. '/C/nvim/site/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. (',' .. root_path .. '/c/nvim/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim/after'
|
||||
):gsub('\\', '/')
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim'
|
||||
.. (',' .. root_path .. '/c/nvim')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site'
|
||||
.. (',' .. root_path .. '/C/nvim/site')
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. (',' .. root_path .. '/C/nvim/site/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/B'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/A'):rep(2048)
|
||||
.. '/nvim/site/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/X'):rep(4096)
|
||||
.. '/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. (',' .. root_path .. '/c/nvim/after')
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/b'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/a'):rep(2048)
|
||||
.. '/nvim/after'
|
||||
.. ','
|
||||
.. root_path
|
||||
.. ('/x'):rep(4096)
|
||||
.. '/nvim/after'
|
||||
)
|
||||
),
|
||||
(api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
)
|
||||
eq(
|
||||
'.,' .. root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/backup//',
|
||||
(api.nvim_get_option_value('backupdir', {}):gsub('\\', '/'))
|
||||
t.fix_slashes(api.nvim_get_option_value('backupdir', {}))
|
||||
)
|
||||
eq(
|
||||
root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//',
|
||||
(api.nvim_get_option_value('directory', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('directory', {}))
|
||||
)
|
||||
eq(
|
||||
root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//',
|
||||
(api.nvim_get_option_value('undodir', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('undodir', {}))
|
||||
)
|
||||
eq(
|
||||
root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//',
|
||||
(api.nvim_get_option_value('viewdir', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('viewdir', {}))
|
||||
)
|
||||
end)
|
||||
end)
|
||||
@ -574,26 +573,26 @@ describe('XDG defaults', function()
|
||||
local vimruntime, libdir = vimruntime_and_libdir()
|
||||
eq(
|
||||
(
|
||||
(
|
||||
t.fix_slashes(
|
||||
'$XDG_DATA_HOME/nvim'
|
||||
.. ',$XDG_DATA_DIRS/nvim'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site'
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. ',$XDG_DATA_DIRS/nvim/after'
|
||||
.. ',$XDG_DATA_HOME/nvim/after'
|
||||
):gsub('\\', '/')
|
||||
.. ',$XDG_DATA_DIRS/nvim'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site'
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. ',$XDG_DATA_DIRS/nvim/after'
|
||||
.. ',$XDG_DATA_HOME/nvim/after'
|
||||
)
|
||||
),
|
||||
(api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
)
|
||||
command('set runtimepath&')
|
||||
command('set backupdir&')
|
||||
@ -602,8 +601,47 @@ describe('XDG defaults', function()
|
||||
command('set viewdir&')
|
||||
eq(
|
||||
(
|
||||
(
|
||||
t.fix_slashes(
|
||||
'$XDG_DATA_HOME/nvim'
|
||||
.. ',$XDG_DATA_DIRS/nvim'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site'
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. ',$XDG_DATA_DIRS/nvim/after'
|
||||
.. ',$XDG_DATA_HOME/nvim/after'
|
||||
)
|
||||
),
|
||||
t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
)
|
||||
eq(
|
||||
('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
|
||||
t.fix_slashes(api.nvim_get_option_value('backupdir', {}))
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
|
||||
t.fix_slashes(api.nvim_get_option_value('directory', {}))
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
|
||||
t.fix_slashes(api.nvim_get_option_value('undodir', {}))
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
|
||||
t.fix_slashes(api.nvim_get_option_value('viewdir', {}))
|
||||
)
|
||||
command('set all&')
|
||||
eq(
|
||||
t.fix_slashes(
|
||||
'$XDG_DATA_HOME/nvim'
|
||||
.. ',$XDG_DATA_DIRS/nvim'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
@ -619,63 +657,24 @@ describe('XDG defaults', function()
|
||||
.. '/site/after'
|
||||
.. ',$XDG_DATA_DIRS/nvim/after'
|
||||
.. ',$XDG_DATA_HOME/nvim/after'
|
||||
):gsub('\\', '/')
|
||||
),
|
||||
(api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
|
||||
)
|
||||
eq(
|
||||
('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
|
||||
api.nvim_get_option_value('backupdir', {}):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('backupdir', {}))
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
|
||||
api.nvim_get_option_value('directory', {}):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('directory', {}))
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
|
||||
api.nvim_get_option_value('undodir', {}):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('undodir', {}))
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
|
||||
api.nvim_get_option_value('viewdir', {}):gsub('\\', '/')
|
||||
)
|
||||
command('set all&')
|
||||
eq(
|
||||
(
|
||||
'$XDG_DATA_HOME/nvim'
|
||||
.. ',$XDG_DATA_DIRS/nvim'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site'
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site'
|
||||
.. ','
|
||||
.. vimruntime
|
||||
.. ','
|
||||
.. libdir
|
||||
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
|
||||
.. ',$XDG_CONFIG_HOME/'
|
||||
.. data_dir
|
||||
.. '/site/after'
|
||||
.. ',$XDG_DATA_DIRS/nvim/after'
|
||||
.. ',$XDG_DATA_HOME/nvim/after'
|
||||
):gsub('\\', '/'),
|
||||
(api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
|
||||
)
|
||||
eq(
|
||||
('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
|
||||
api.nvim_get_option_value('backupdir', {}):gsub('\\', '/')
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
|
||||
api.nvim_get_option_value('directory', {}):gsub('\\', '/')
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
|
||||
api.nvim_get_option_value('undodir', {}):gsub('\\', '/')
|
||||
)
|
||||
eq(
|
||||
('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
|
||||
api.nvim_get_option_value('viewdir', {}):gsub('\\', '/')
|
||||
t.fix_slashes(api.nvim_get_option_value('viewdir', {}))
|
||||
)
|
||||
eq(nil, (fn.tempname()):match('XDG_RUNTIME_DIR'))
|
||||
end)
|
||||
@ -915,7 +914,7 @@ describe('stdpath()', function()
|
||||
assert_alive() -- Check for crash. #8393
|
||||
end)
|
||||
|
||||
it('supports $NVIM_APPNAME', function()
|
||||
it('$NVIM_APPNAME', function()
|
||||
local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106)
|
||||
clear({ env = { NVIM_APPNAME = appname, NVIM_LOG_FILE = testlog } })
|
||||
eq(appname, fn.fnamemodify(fn.stdpath('config'), ':t'))
|
||||
@ -939,7 +938,7 @@ describe('stdpath()', function()
|
||||
local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } })
|
||||
return vim.fn.jobwait({ child }, %d)[1]
|
||||
]],
|
||||
alter_slashes(testAppname),
|
||||
testAppname,
|
||||
3000
|
||||
)
|
||||
eq(expected_exitcode, exec_lua(lua_code))
|
||||
@ -957,24 +956,43 @@ describe('stdpath()', function()
|
||||
test_appname('a/b\\c', 0)
|
||||
end)
|
||||
|
||||
it('$NVIM_APPNAME relative path', function()
|
||||
local tmpdir = t.tmpname(false)
|
||||
t.mkdir(tmpdir)
|
||||
|
||||
clear({
|
||||
args_rm = { '--listen' },
|
||||
env = {
|
||||
NVIM_APPNAME = 'relative/appname',
|
||||
NVIM_LOG_FILE = testlog,
|
||||
TMPDIR = tmpdir,
|
||||
},
|
||||
})
|
||||
|
||||
t.matches(vim.pesc(tmpdir), t.fix_slashes(fn.tempname()))
|
||||
t.assert_nolog('tempdir', testlog, 100)
|
||||
t.assert_nolog('TMPDIR', testlog, 100)
|
||||
t.matches([=[[/\\]relative%-appname.[^/\\]+]=], api.nvim_get_vvar('servername'))
|
||||
end)
|
||||
|
||||
describe('returns a String', function()
|
||||
describe('with "config"', function()
|
||||
it('knows XDG_CONFIG_HOME', function()
|
||||
clear({
|
||||
env = {
|
||||
XDG_CONFIG_HOME = alter_slashes('/home/docwhat/.config'),
|
||||
XDG_CONFIG_HOME = '/home/docwhat/.config',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('/home/docwhat/.config/nvim'), fn.stdpath('config'))
|
||||
eq('/home/docwhat/.config/nvim', t.fix_slashes(fn.stdpath('config')))
|
||||
end)
|
||||
|
||||
it('handles changes during runtime', function()
|
||||
clear({ env = {
|
||||
XDG_CONFIG_HOME = alter_slashes('/home/original'),
|
||||
XDG_CONFIG_HOME = '/home/original',
|
||||
} })
|
||||
eq(alter_slashes('/home/original/nvim'), fn.stdpath('config'))
|
||||
command("let $XDG_CONFIG_HOME='" .. alter_slashes('/home/new') .. "'")
|
||||
eq(alter_slashes('/home/new/nvim'), fn.stdpath('config'))
|
||||
eq('/home/original/nvim', t.fix_slashes(fn.stdpath('config')))
|
||||
command("let $XDG_CONFIG_HOME='/home/new'")
|
||||
eq('/home/new/nvim', t.fix_slashes(fn.stdpath('config')))
|
||||
end)
|
||||
|
||||
it("doesn't expand $VARIABLES", function()
|
||||
@ -984,32 +1002,32 @@ describe('stdpath()', function()
|
||||
VARIABLES = 'this-should-not-happen',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('config'))
|
||||
eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('config')))
|
||||
end)
|
||||
|
||||
it("doesn't expand ~/", function()
|
||||
clear({ env = {
|
||||
XDG_CONFIG_HOME = alter_slashes('~/frobnitz'),
|
||||
XDG_CONFIG_HOME = '~/frobnitz',
|
||||
} })
|
||||
eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('config'))
|
||||
eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('config')))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with "data"', function()
|
||||
it('knows XDG_DATA_HOME', function()
|
||||
clear({ env = {
|
||||
XDG_DATA_HOME = alter_slashes('/home/docwhat/.local'),
|
||||
XDG_DATA_HOME = '/home/docwhat/.local',
|
||||
} })
|
||||
eq(alter_slashes('/home/docwhat/.local/' .. datadir), fn.stdpath('data'))
|
||||
eq('/home/docwhat/.local/' .. datadir, t.fix_slashes(fn.stdpath('data')))
|
||||
end)
|
||||
|
||||
it('handles changes during runtime', function()
|
||||
clear({ env = {
|
||||
XDG_DATA_HOME = alter_slashes('/home/original'),
|
||||
XDG_DATA_HOME = '/home/original',
|
||||
} })
|
||||
eq(alter_slashes('/home/original/' .. datadir), fn.stdpath('data'))
|
||||
command("let $XDG_DATA_HOME='" .. alter_slashes('/home/new') .. "'")
|
||||
eq(alter_slashes('/home/new/' .. datadir), fn.stdpath('data'))
|
||||
eq('/home/original/' .. datadir, t.fix_slashes(fn.stdpath('data')))
|
||||
command("let $XDG_DATA_HOME='/home/new'")
|
||||
eq('/home/new/' .. datadir, t.fix_slashes(fn.stdpath('data')))
|
||||
end)
|
||||
|
||||
it("doesn't expand $VARIABLES", function()
|
||||
@ -1019,14 +1037,14 @@ describe('stdpath()', function()
|
||||
VARIABLES = 'this-should-not-happen',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('$VARIABLES/' .. datadir), fn.stdpath('data'))
|
||||
eq('$VARIABLES/' .. datadir, t.fix_slashes(fn.stdpath('data')))
|
||||
end)
|
||||
|
||||
it("doesn't expand ~/", function()
|
||||
clear({ env = {
|
||||
XDG_DATA_HOME = alter_slashes('~/frobnitz'),
|
||||
XDG_DATA_HOME = '~/frobnitz',
|
||||
} })
|
||||
eq(alter_slashes('~/frobnitz/' .. datadir), fn.stdpath('data'))
|
||||
eq('~/frobnitz/' .. datadir, t.fix_slashes(fn.stdpath('data')))
|
||||
end)
|
||||
end)
|
||||
|
||||
@ -1034,19 +1052,19 @@ describe('stdpath()', function()
|
||||
it('knows XDG_STATE_HOME', function()
|
||||
clear({
|
||||
env = {
|
||||
XDG_STATE_HOME = alter_slashes('/home/docwhat/.local'),
|
||||
XDG_STATE_HOME = '/home/docwhat/.local',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('/home/docwhat/.local/' .. statedir), fn.stdpath('state'))
|
||||
eq('/home/docwhat/.local/' .. statedir, t.fix_slashes(fn.stdpath('state')))
|
||||
end)
|
||||
|
||||
it('handles changes during runtime', function()
|
||||
clear({ env = {
|
||||
XDG_STATE_HOME = alter_slashes('/home/original'),
|
||||
XDG_STATE_HOME = '/home/original',
|
||||
} })
|
||||
eq(alter_slashes('/home/original/' .. statedir), fn.stdpath('state'))
|
||||
command("let $XDG_STATE_HOME='" .. alter_slashes('/home/new') .. "'")
|
||||
eq(alter_slashes('/home/new/' .. statedir), fn.stdpath('state'))
|
||||
eq('/home/original/' .. statedir, t.fix_slashes(fn.stdpath('state')))
|
||||
command("let $XDG_STATE_HOME='" .. '/home/new' .. "'")
|
||||
eq('/home/new/' .. statedir, t.fix_slashes(fn.stdpath('state')))
|
||||
end)
|
||||
|
||||
it("doesn't expand $VARIABLES", function()
|
||||
@ -1056,14 +1074,14 @@ describe('stdpath()', function()
|
||||
VARIABLES = 'this-should-not-happen',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('$VARIABLES/' .. statedir), fn.stdpath('state'))
|
||||
eq('$VARIABLES/' .. statedir, t.fix_slashes(fn.stdpath('state')))
|
||||
end)
|
||||
|
||||
it("doesn't expand ~/", function()
|
||||
clear({ env = {
|
||||
XDG_STATE_HOME = alter_slashes('~/frobnitz'),
|
||||
XDG_STATE_HOME = '~/frobnitz',
|
||||
} })
|
||||
eq(alter_slashes('~/frobnitz/' .. statedir), fn.stdpath('state'))
|
||||
eq('~/frobnitz/' .. statedir, t.fix_slashes(fn.stdpath('state')))
|
||||
end)
|
||||
end)
|
||||
|
||||
@ -1071,19 +1089,19 @@ describe('stdpath()', function()
|
||||
it('knows XDG_CACHE_HOME', function()
|
||||
clear({
|
||||
env = {
|
||||
XDG_CACHE_HOME = alter_slashes('/home/docwhat/.cache'),
|
||||
XDG_CACHE_HOME = '/home/docwhat/.cache',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('/home/docwhat/.cache/nvim'), fn.stdpath('cache'))
|
||||
eq('/home/docwhat/.cache/nvim', t.fix_slashes(fn.stdpath('cache')))
|
||||
end)
|
||||
|
||||
it('handles changes during runtime', function()
|
||||
clear({ env = {
|
||||
XDG_CACHE_HOME = alter_slashes('/home/original'),
|
||||
XDG_CACHE_HOME = '/home/original',
|
||||
} })
|
||||
eq(alter_slashes('/home/original/nvim'), fn.stdpath('cache'))
|
||||
command("let $XDG_CACHE_HOME='" .. alter_slashes('/home/new') .. "'")
|
||||
eq(alter_slashes('/home/new/nvim'), fn.stdpath('cache'))
|
||||
eq('/home/original/nvim', t.fix_slashes(fn.stdpath('cache')))
|
||||
command("let $XDG_CACHE_HOME='" .. '/home/new' .. "'")
|
||||
eq('/home/new/nvim', t.fix_slashes(fn.stdpath('cache')))
|
||||
end)
|
||||
|
||||
it("doesn't expand $VARIABLES", function()
|
||||
@ -1093,14 +1111,14 @@ describe('stdpath()', function()
|
||||
VARIABLES = 'this-should-not-happen',
|
||||
},
|
||||
})
|
||||
eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('cache'))
|
||||
eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('cache')))
|
||||
end)
|
||||
|
||||
it("doesn't expand ~/", function()
|
||||
clear({ env = {
|
||||
XDG_CACHE_HOME = alter_slashes('~/frobnitz'),
|
||||
XDG_CACHE_HOME = '~/frobnitz',
|
||||
} })
|
||||
eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('cache'))
|
||||
eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('cache')))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
@ -1114,6 +1132,7 @@ describe('stdpath()', function()
|
||||
HOMEDRIVE = 'C:',
|
||||
HOMEPATH = '\\Users\\docwhat',
|
||||
LOCALAPPDATA = 'C:\\Users\\docwhat\\AppData\\Local',
|
||||
NVIM_LOG_FILE = testlog,
|
||||
TEMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp',
|
||||
TMPDIR = 'C:\\Users\\docwhat\\AppData\\Local\\Temp',
|
||||
TMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp',
|
||||
@ -1124,6 +1143,7 @@ describe('stdpath()', function()
|
||||
HOMEDRIVE = 'HOMEDRIVE-should-be-ignored',
|
||||
HOMEPATH = 'HOMEPATH-should-be-ignored',
|
||||
LOCALAPPDATA = 'LOCALAPPDATA-should-be-ignored',
|
||||
NVIM_LOG_FILE = testlog,
|
||||
TEMP = 'TEMP-should-be-ignored',
|
||||
TMPDIR = 'TMPDIR-should-be-ignored',
|
||||
TMP = 'TMP-should-be-ignored',
|
||||
@ -1147,12 +1167,18 @@ describe('stdpath()', function()
|
||||
describe(msg, function()
|
||||
it('set via system', function()
|
||||
set_paths_via_system(env_var_name, paths)
|
||||
eq(expected_paths, fn.stdpath(stdpath_arg))
|
||||
eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg)))
|
||||
if not is_os('win') then
|
||||
assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100)
|
||||
end
|
||||
end)
|
||||
|
||||
it('set at runtime', function()
|
||||
set_paths_at_runtime(env_var_name, paths)
|
||||
eq(expected_paths, fn.stdpath(stdpath_arg))
|
||||
eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg)))
|
||||
if not is_os('win') then
|
||||
assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
@ -1163,10 +1189,10 @@ describe('stdpath()', function()
|
||||
'config_dirs',
|
||||
'XDG_CONFIG_DIRS',
|
||||
{
|
||||
alter_slashes('/home/docwhat/.config'),
|
||||
t.fix_slashes('/home/docwhat/.config'),
|
||||
},
|
||||
{
|
||||
alter_slashes('/home/docwhat/.config/nvim'),
|
||||
t.fix_slashes('/home/docwhat/.config/nvim'),
|
||||
}
|
||||
)
|
||||
|
||||
@ -1175,12 +1201,12 @@ describe('stdpath()', function()
|
||||
'config_dirs',
|
||||
'XDG_CONFIG_DIRS',
|
||||
{
|
||||
alter_slashes('/home/docwhat/.config'),
|
||||
alter_slashes('/etc/config'),
|
||||
t.fix_slashes('/home/docwhat/.config'),
|
||||
t.fix_slashes('/etc/config'),
|
||||
},
|
||||
{
|
||||
alter_slashes('/home/docwhat/.config/nvim'),
|
||||
alter_slashes('/etc/config/nvim'),
|
||||
t.fix_slashes('/home/docwhat/.config/nvim'),
|
||||
t.fix_slashes('/etc/config/nvim'),
|
||||
}
|
||||
)
|
||||
|
||||
@ -1190,25 +1216,25 @@ describe('stdpath()', function()
|
||||
'XDG_CONFIG_DIRS',
|
||||
{ '$HOME', '$TMP' },
|
||||
{
|
||||
alter_slashes('$HOME/nvim'),
|
||||
alter_slashes('$TMP/nvim'),
|
||||
t.fix_slashes('$HOME/nvim'),
|
||||
t.fix_slashes('$TMP/nvim'),
|
||||
}
|
||||
)
|
||||
|
||||
behaves_like_dir_list_env("doesn't expand ~/", 'config_dirs', 'XDG_CONFIG_DIRS', {
|
||||
alter_slashes('~/.oldconfig'),
|
||||
alter_slashes('~/.olderconfig'),
|
||||
t.fix_slashes('~/.oldconfig'),
|
||||
t.fix_slashes('~/.olderconfig'),
|
||||
}, {
|
||||
alter_slashes('~/.oldconfig/nvim'),
|
||||
alter_slashes('~/.olderconfig/nvim'),
|
||||
t.fix_slashes('~/.oldconfig/nvim'),
|
||||
t.fix_slashes('~/.olderconfig/nvim'),
|
||||
})
|
||||
end)
|
||||
|
||||
describe('with "data_dirs"', function()
|
||||
behaves_like_dir_list_env('knows XDG_DATA_DIRS with one path', 'data_dirs', 'XDG_DATA_DIRS', {
|
||||
alter_slashes('/home/docwhat/.data'),
|
||||
t.fix_slashes('/home/docwhat/.data'),
|
||||
}, {
|
||||
alter_slashes('/home/docwhat/.data/nvim'),
|
||||
t.fix_slashes('/home/docwhat/.data/nvim'),
|
||||
})
|
||||
|
||||
behaves_like_dir_list_env(
|
||||
@ -1216,12 +1242,12 @@ describe('stdpath()', function()
|
||||
'data_dirs',
|
||||
'XDG_DATA_DIRS',
|
||||
{
|
||||
alter_slashes('/home/docwhat/.data'),
|
||||
alter_slashes('/etc/local'),
|
||||
t.fix_slashes('/home/docwhat/.data'),
|
||||
t.fix_slashes('/etc/local'),
|
||||
},
|
||||
{
|
||||
alter_slashes('/home/docwhat/.data/nvim'),
|
||||
alter_slashes('/etc/local/nvim'),
|
||||
t.fix_slashes('/home/docwhat/.data/nvim'),
|
||||
t.fix_slashes('/etc/local/nvim'),
|
||||
}
|
||||
)
|
||||
|
||||
@ -1231,17 +1257,17 @@ describe('stdpath()', function()
|
||||
'XDG_DATA_DIRS',
|
||||
{ '$HOME', '$TMP' },
|
||||
{
|
||||
alter_slashes('$HOME/nvim'),
|
||||
alter_slashes('$TMP/nvim'),
|
||||
t.fix_slashes('$HOME/nvim'),
|
||||
t.fix_slashes('$TMP/nvim'),
|
||||
}
|
||||
)
|
||||
|
||||
behaves_like_dir_list_env("doesn't expand ~/", 'data_dirs', 'XDG_DATA_DIRS', {
|
||||
alter_slashes('~/.oldconfig'),
|
||||
alter_slashes('~/.olderconfig'),
|
||||
t.fix_slashes('~/.oldconfig'),
|
||||
t.fix_slashes('~/.olderconfig'),
|
||||
}, {
|
||||
alter_slashes('~/.oldconfig/nvim'),
|
||||
alter_slashes('~/.olderconfig/nvim'),
|
||||
t.fix_slashes('~/.oldconfig/nvim'),
|
||||
t.fix_slashes('~/.olderconfig/nvim'),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -40,11 +40,22 @@ describe(':checkhealth', function()
|
||||
matches('ERROR $VIM .* zub', curbuf_contents())
|
||||
end)
|
||||
|
||||
it('completions can be listed via getcompletion()', function()
|
||||
clear()
|
||||
it('getcompletion()', function()
|
||||
clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
|
||||
|
||||
eq('vim.deprecated', getcompletion('vim', 'checkhealth')[1])
|
||||
eq('vim.provider', getcompletion('vim.prov', 'checkhealth')[1])
|
||||
eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
|
||||
|
||||
-- "test_plug/health/init.lua" should complete as "test_plug", not "test_plug.health". #30342
|
||||
eq({
|
||||
'test_plug',
|
||||
'test_plug.full_render',
|
||||
'test_plug.submodule',
|
||||
'test_plug.submodule_empty',
|
||||
'test_plug.success1',
|
||||
'test_plug.success2',
|
||||
}, getcompletion('test_plug', 'checkhealth'))
|
||||
end)
|
||||
|
||||
it('completion checks for vim.health._complete() return type #28456', function()
|
||||
@ -57,11 +68,9 @@ describe(':checkhealth', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('health.vim', function()
|
||||
describe('vim.health', function()
|
||||
before_each(function()
|
||||
clear { args = { '-u', 'NORC' } }
|
||||
-- Provides healthcheck functions
|
||||
command('set runtimepath+=test/functional/fixtures')
|
||||
clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
|
||||
end)
|
||||
|
||||
describe(':checkhealth', function()
|
||||
@ -207,9 +216,7 @@ end)
|
||||
|
||||
describe(':checkhealth window', function()
|
||||
before_each(function()
|
||||
clear { args = { '-u', 'NORC' } }
|
||||
-- Provides healthcheck functions
|
||||
command('set runtimepath+=test/functional/fixtures')
|
||||
clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
|
||||
command('set nofoldenable nowrap laststatus=0')
|
||||
end)
|
||||
|
||||
|
@ -3607,21 +3607,21 @@ describe('LSP', function()
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
},
|
||||
selectionRange = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
},
|
||||
uri = 'file:///home/jiangyinzuo/hello.cpp',
|
||||
@ -3651,21 +3651,21 @@ describe('LSP', function()
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
},
|
||||
selectionRange = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
},
|
||||
uri = 'file:///home/jiangyinzuo/hello.cpp',
|
||||
@ -3679,7 +3679,15 @@ describe('LSP', function()
|
||||
})
|
||||
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
|
||||
local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
|
||||
handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
|
||||
'class B : public A{};',
|
||||
'class C : public B{};',
|
||||
'class D1 : public C{};',
|
||||
'class D2 : public C{};',
|
||||
'class E : public D1, D2 {};',
|
||||
})
|
||||
handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
|
||||
return vim.fn.getqflist()
|
||||
end)
|
||||
|
||||
@ -3689,7 +3697,7 @@ describe('LSP', function()
|
||||
col = 7,
|
||||
end_col = 0,
|
||||
end_lnum = 0,
|
||||
lnum = 10,
|
||||
lnum = 4,
|
||||
module = '',
|
||||
nr = 0,
|
||||
pattern = '',
|
||||
@ -3703,7 +3711,7 @@ describe('LSP', function()
|
||||
col = 7,
|
||||
end_col = 0,
|
||||
end_lnum = 0,
|
||||
lnum = 9,
|
||||
lnum = 3,
|
||||
module = '',
|
||||
nr = 0,
|
||||
pattern = '',
|
||||
@ -3763,7 +3771,15 @@ describe('LSP', function()
|
||||
})
|
||||
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
|
||||
local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
|
||||
handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
|
||||
'package mylist;',
|
||||
'',
|
||||
'public class MyList {',
|
||||
' static class Inner extends MyList{}',
|
||||
'~}',
|
||||
})
|
||||
handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
|
||||
return vim.fn.getqflist()
|
||||
end)
|
||||
|
||||
@ -3840,21 +3856,21 @@ describe('LSP', function()
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
},
|
||||
selectionRange = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 9,
|
||||
line = 3,
|
||||
},
|
||||
},
|
||||
uri = 'file:///home/jiangyinzuo/hello.cpp',
|
||||
@ -3884,21 +3900,21 @@ describe('LSP', function()
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
},
|
||||
selectionRange = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 8,
|
||||
line = 2,
|
||||
},
|
||||
},
|
||||
uri = 'file:///home/jiangyinzuo/hello.cpp',
|
||||
@ -3912,7 +3928,16 @@ describe('LSP', function()
|
||||
})
|
||||
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
|
||||
local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
|
||||
handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
|
||||
'class B : public A{};',
|
||||
'class C : public B{};',
|
||||
'class D1 : public C{};',
|
||||
'class D2 : public C{};',
|
||||
'class E : public D1, D2 {};',
|
||||
})
|
||||
|
||||
handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
|
||||
return vim.fn.getqflist()
|
||||
end)
|
||||
|
||||
@ -3922,7 +3947,7 @@ describe('LSP', function()
|
||||
col = 7,
|
||||
end_col = 0,
|
||||
end_lnum = 0,
|
||||
lnum = 10,
|
||||
lnum = 4,
|
||||
module = '',
|
||||
nr = 0,
|
||||
pattern = '',
|
||||
@ -3936,7 +3961,7 @@ describe('LSP', function()
|
||||
col = 7,
|
||||
end_col = 0,
|
||||
end_lnum = 0,
|
||||
lnum = 9,
|
||||
lnum = 3,
|
||||
module = '',
|
||||
nr = 0,
|
||||
pattern = '',
|
||||
@ -3996,7 +4021,15 @@ describe('LSP', function()
|
||||
})
|
||||
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
|
||||
local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
|
||||
handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
|
||||
'package mylist;',
|
||||
'',
|
||||
'public class MyList {',
|
||||
' static class Inner extends MyList{}',
|
||||
'~}',
|
||||
})
|
||||
handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
|
||||
return vim.fn.getqflist()
|
||||
end)
|
||||
|
||||
|
@ -136,6 +136,50 @@ local function run_tohtml_and_assert(screen, func)
|
||||
screen:expect({ grid = expected.grid, attr_ids = expected.attr_ids })
|
||||
end
|
||||
|
||||
---@param guifont boolean
|
||||
local function test_generates_html(guifont, expect_font)
|
||||
insert([[line]])
|
||||
exec('set termguicolors')
|
||||
local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
|
||||
local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
|
||||
local tmpfile = t.tmpname()
|
||||
|
||||
exec_lua(
|
||||
[[
|
||||
local guifont, outfile = ...
|
||||
local html = (guifont
|
||||
and require('tohtml').tohtml(0,{title="title"})
|
||||
or require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }}))
|
||||
vim.fn.writefile(html, outfile)
|
||||
vim.cmd.split(outfile)
|
||||
]],
|
||||
guifont,
|
||||
tmpfile
|
||||
)
|
||||
|
||||
local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
|
||||
eq({
|
||||
'<!DOCTYPE html>',
|
||||
'<html>',
|
||||
'<head>',
|
||||
'<meta charset="UTF-8">',
|
||||
'<title>title</title>',
|
||||
('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
|
||||
'<style>',
|
||||
('* {font-family: %s,monospace}'):format(expect_font),
|
||||
('body {background-color: %s; color: %s}'):format(bg, fg),
|
||||
'</style>',
|
||||
'</head>',
|
||||
'<body style="display: flex">',
|
||||
'<pre>',
|
||||
'line',
|
||||
'',
|
||||
'</pre>',
|
||||
'</body>',
|
||||
'</html>',
|
||||
}, fn.readfile(out_file))
|
||||
end
|
||||
|
||||
describe(':TOhtml', function()
|
||||
--- @type test.functional.ui.screen
|
||||
local screen
|
||||
@ -146,41 +190,16 @@ describe(':TOhtml', function()
|
||||
exec('colorscheme default')
|
||||
end)
|
||||
|
||||
it('expected internal html generated', function()
|
||||
insert([[line]])
|
||||
exec('set termguicolors')
|
||||
local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
|
||||
local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
|
||||
exec_lua [[
|
||||
local outfile = vim.fn.tempname() .. '.html'
|
||||
local html = require('tohtml').tohtml(0,{title="title",font="dumyfont"})
|
||||
vim.fn.writefile(html, outfile)
|
||||
vim.cmd.split(outfile)
|
||||
]]
|
||||
local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
|
||||
eq({
|
||||
'<!DOCTYPE html>',
|
||||
'<html>',
|
||||
'<head>',
|
||||
'<meta charset="UTF-8">',
|
||||
'<title>title</title>',
|
||||
('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
|
||||
'<style>',
|
||||
'* {font-family: dumyfont,monospace}',
|
||||
('body {background-color: %s; color: %s}'):format(bg, fg),
|
||||
'</style>',
|
||||
'</head>',
|
||||
'<body style="display: flex">',
|
||||
'<pre>',
|
||||
'line',
|
||||
'',
|
||||
'</pre>',
|
||||
'</body>',
|
||||
'</html>',
|
||||
}, fn.readfile(out_file))
|
||||
it('generates html with given font', function()
|
||||
test_generates_html(false, '"dumyfont","anotherfont"')
|
||||
end)
|
||||
|
||||
it('expected internal html generated from range', function()
|
||||
it("generates html, respects 'guifont'", function()
|
||||
exec_lua [[vim.o.guifont='Font,Escape\\,comma, Ignore space after comma']]
|
||||
test_generates_html(true, '"Font","Escape,comma","Ignore space after comma"')
|
||||
end)
|
||||
|
||||
it('generates html from range', function()
|
||||
insert([[
|
||||
line1
|
||||
line2
|
||||
@ -218,7 +237,7 @@ describe(':TOhtml', function()
|
||||
}, fn.readfile(out_file))
|
||||
end)
|
||||
|
||||
it('highlight attributes generated', function()
|
||||
it('generates highlight attributes', function()
|
||||
--Make sure to uncomment the attribute in `html_syntax_match()`
|
||||
exec('hi LINE guisp=#00ff00 gui=' .. table.concat({
|
||||
'bold',
|
||||
|
@ -342,7 +342,7 @@ describe(':terminal buffer', function()
|
||||
command('wincmd p')
|
||||
|
||||
-- cwd will be inserted in a file URI, which cannot contain backs
|
||||
local cwd = fn.getcwd():gsub('\\', '/')
|
||||
local cwd = t.fix_slashes(fn.getcwd())
|
||||
local parent = cwd:match('^(.+/)')
|
||||
local expected = '\027]7;file://host' .. parent
|
||||
api.nvim_chan_send(term, string.format('%s\027\\', expected))
|
||||
|
@ -14,8 +14,7 @@ local is_os = t.is_os
|
||||
local ok = t.ok
|
||||
local sleep = uv.sleep
|
||||
|
||||
--- This module uses functions from the context of the test session, i.e. in the context of the
|
||||
--- nvim being tests.
|
||||
--- Functions executing in the current nvim session/process being tested.
|
||||
local M = {}
|
||||
|
||||
local runtime_set = 'set runtimepath^=./build/lib/nvim/'
|
||||
@ -903,26 +902,6 @@ function M.missing_provider(provider)
|
||||
assert(false, 'Unknown provider: ' .. provider)
|
||||
end
|
||||
|
||||
--- @param obj string|table
|
||||
--- @return any
|
||||
function M.alter_slashes(obj)
|
||||
if not is_os('win') then
|
||||
return obj
|
||||
end
|
||||
if type(obj) == 'string' then
|
||||
local ret = obj:gsub('/', '\\')
|
||||
return ret
|
||||
elseif type(obj) == 'table' then
|
||||
--- @cast obj table<any,any>
|
||||
local ret = {} --- @type table<any,any>
|
||||
for k, v in pairs(obj) do
|
||||
ret[k] = M.alter_slashes(v)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
assert(false, 'expected string or table of strings, got ' .. type(obj))
|
||||
end
|
||||
|
||||
local load_factor = 1
|
||||
if t.is_ci() then
|
||||
-- Compute load factor only once (but outside of any tests).
|
||||
|
@ -1344,6 +1344,53 @@ describe('float window', function()
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
--
|
||||
-- floating windows inherit NormalFloat from global-ns.
|
||||
--
|
||||
command('fclose')
|
||||
command('hi NormalFloat guibg=LightRed')
|
||||
api.nvim_open_win(0, false, { relative = 'win', row = 3, col = 3, width = 12, height = 3, style = 'minimal' })
|
||||
api.nvim_set_hl_ns(api.nvim_create_namespace('test1'))
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
[2:----------------------------------------]|*6
|
||||
[3:----------------------------------------]|
|
||||
## grid 2
|
||||
{14: 1 }^x |
|
||||
{14: 2 }y |
|
||||
{14: 3 } |
|
||||
{0:~ }|*3
|
||||
## grid 3
|
||||
|
|
||||
## grid 5
|
||||
{22:x }|
|
||||
{22:y }|
|
||||
{22: }|
|
||||
]], float_pos={
|
||||
[5] = {1002, "NW", 2, 3, 3, true, 50};
|
||||
}, win_viewport={
|
||||
[2] = {win = 1000, topline = 0, botline = 4, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
|
||||
[5] = {win = 1002, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
|
||||
}, win_viewport_margins={
|
||||
[2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 },
|
||||
[5] = { bottom = 0, left = 0, right = 0, top = 0, win = 1002 }
|
||||
}})
|
||||
else
|
||||
screen:expect({
|
||||
grid = [[
|
||||
{14: 1 }^x |
|
||||
{14: 2 }y |
|
||||
{14: 3 } |
|
||||
{0:~ }{22:x }{0: }|
|
||||
{0:~ }{22:y }{0: }|
|
||||
{0:~ }{22: }{0: }|
|
||||
|
|
||||
]]
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
it("can use 'minimal' style", function()
|
||||
|
@ -22,7 +22,7 @@ describe('title', function()
|
||||
end)
|
||||
|
||||
it('has correct default title with unnamed file', function()
|
||||
local expected = '[No Name] - NVIM'
|
||||
local expected = '[No Name] - Nvim'
|
||||
command('set title')
|
||||
screen:expect(function()
|
||||
eq(expected, screen.title)
|
||||
@ -30,7 +30,7 @@ describe('title', function()
|
||||
end)
|
||||
|
||||
it('has correct default title with named file', function()
|
||||
local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
|
||||
local expected = (is_os('win') and 'myfile (C:\\mydir) - Nvim' or 'myfile (/mydir) - Nvim')
|
||||
command('set title')
|
||||
command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
|
||||
screen:expect(function()
|
||||
@ -41,7 +41,7 @@ describe('title', function()
|
||||
describe('is not changed by', function()
|
||||
local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
|
||||
local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
|
||||
local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
|
||||
local expected = (is_os('win') and 'myfile1 (C:\\mydir) - Nvim' or 'myfile1 (/mydir) - Nvim')
|
||||
local buf2
|
||||
|
||||
before_each(function()
|
||||
|
@ -7,11 +7,10 @@ local fnamemodify = n.fn.fnamemodify
|
||||
local getcwd = n.fn.getcwd
|
||||
local command = n.command
|
||||
local write_file = t.write_file
|
||||
local alter_slashes = n.alter_slashes
|
||||
local is_os = t.is_os
|
||||
|
||||
local function eq_slashconvert(expected, got)
|
||||
eq(alter_slashes(expected), alter_slashes(got))
|
||||
eq(t.fix_slashes(expected), t.fix_slashes(got))
|
||||
end
|
||||
|
||||
describe('fnamemodify()', function()
|
||||
|
@ -710,7 +710,7 @@ func s:GetFilenameChecks() abort
|
||||
\ 'svg': ['file.svg'],
|
||||
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
|
||||
\ 'swayconfig': ['/home/user/.sway/config', '/home/user/.config/sway/config', '/etc/sway/config', '/etc/xdg/sway/config'],
|
||||
\ 'swift': ['file.swift'],
|
||||
\ 'swift': ['file.swift', 'file.swiftinterface'],
|
||||
\ 'swiftgyb': ['file.swift.gyb'],
|
||||
\ 'swig': ['file.swg', 'file.swig'],
|
||||
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'],
|
||||
|
@ -16,7 +16,7 @@ local function shell_quote(str)
|
||||
return str
|
||||
end
|
||||
|
||||
--- This module uses functions from the context of the test runner.
|
||||
--- Functions executing in the context of the test runner (not the current nvim test session).
|
||||
--- @class test.testutil
|
||||
local M = {
|
||||
paths = Paths,
|
||||
@ -42,6 +42,29 @@ function M.isdir(path)
|
||||
return stat.type == 'directory'
|
||||
end
|
||||
|
||||
--- (Only on Windows) Replaces yucky "\\" slashes with delicious "/" slashes in a string, or all
|
||||
--- string values in a table (recursively).
|
||||
---
|
||||
--- @param obj string|table
|
||||
--- @return any
|
||||
function M.fix_slashes(obj)
|
||||
if not M.is_os('win') then
|
||||
return obj
|
||||
end
|
||||
if type(obj) == 'string' then
|
||||
local ret = obj:gsub('\\', '/')
|
||||
return ret
|
||||
elseif type(obj) == 'table' then
|
||||
--- @cast obj table<any,any>
|
||||
local ret = {} --- @type table<any,any>
|
||||
for k, v in pairs(obj) do
|
||||
ret[k] = M.fix_slashes(v)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
assert(false, 'expected string or table of strings, got ' .. type(obj))
|
||||
end
|
||||
|
||||
--- @param ... string|string[]
|
||||
--- @return string
|
||||
function M.argss_to_cmd(...)
|
||||
|
975
test/unit/termkey_spec.lua
Normal file
975
test/unit/termkey_spec.lua
Normal file
@ -0,0 +1,975 @@
|
||||
local t = require('test.unit.testutil')
|
||||
local itp = t.gen_itp(it)
|
||||
local bit = require('bit')
|
||||
|
||||
--- @alias TermKeyKey {utf8: string, type: integer, modifiers: integer, code: {codepoint: integer, sym: any, number: integer}}
|
||||
|
||||
--- @class termkey
|
||||
--- @field TERMKEY_CANON_SPACESYMBOL integer
|
||||
--- @field TERMKEY_FLAG_SPACESYMBOL integer
|
||||
--- @field TERMKEY_FLAG_UTF8 integer
|
||||
--- @field TERMKEY_FORMAT_ALTISMETA integer
|
||||
--- @field TERMKEY_FORMAT_CARETCTRL integer
|
||||
--- @field TERMKEY_FORMAT_LONGMOD integer
|
||||
--- @field TERMKEY_FORMAT_LOWERMOD integer
|
||||
--- @field TERMKEY_FORMAT_LOWERSPACE integer
|
||||
--- @field TERMKEY_FORMAT_MOUSE_POS integer
|
||||
--- @field TERMKEY_FORMAT_SPACEMOD integer
|
||||
--- @field TERMKEY_FORMAT_WRAPBRACKET integer
|
||||
--- @field TERMKEY_KEYMOD_ALT integer
|
||||
--- @field TERMKEY_KEYMOD_CTRL integer
|
||||
--- @field TERMKEY_MOUSE_DRAG integer
|
||||
--- @field TERMKEY_MOUSE_PRESS integer
|
||||
--- @field TERMKEY_MOUSE_RELEASE integer
|
||||
--- @field TERMKEY_RES_AGAIN integer
|
||||
--- @field TERMKEY_RES_KEY integer
|
||||
--- @field TERMKEY_RES_NONE integer
|
||||
--- @field TERMKEY_SYM_DOWN integer
|
||||
--- @field TERMKEY_SYM_PAGEUP integer
|
||||
--- @field TERMKEY_SYM_SPACE integer
|
||||
--- @field TERMKEY_SYM_UNKNOWN integer
|
||||
--- @field TERMKEY_SYM_UP integer
|
||||
--- @field TERMKEY_TYPE_DCS integer
|
||||
--- @field TERMKEY_TYPE_FUNCTION integer
|
||||
--- @field TERMKEY_TYPE_KEYSYM integer
|
||||
--- @field TERMKEY_TYPE_MODEREPORT integer
|
||||
--- @field TERMKEY_TYPE_MOUSE integer
|
||||
--- @field TERMKEY_TYPE_OSC integer
|
||||
--- @field TERMKEY_TYPE_POSITION integer
|
||||
--- @field TERMKEY_TYPE_UNICODE integer
|
||||
--- @field TERMKEY_TYPE_UNKNOWN_CSI integer
|
||||
--- @field termkey_canonicalise fun(any, any):any
|
||||
--- @field termkey_destroy fun(any)
|
||||
--- @field termkey_get_buffer_remaining fun(any):integer
|
||||
--- @field termkey_get_buffer_size fun(any):integer
|
||||
--- @field termkey_get_canonflags fun(any):any
|
||||
--- @field termkey_get_keyname fun(any, any):any
|
||||
--- @field termkey_getkey fun(any, any):any
|
||||
--- @field termkey_getkey_force fun(any, any):any
|
||||
--- @field termkey_interpret_csi fun(any, any, any, any, any):any
|
||||
--- @field termkey_interpret_modereport fun(any, any, any, any, any):any
|
||||
--- @field termkey_interpret_mouse fun(any, any, TermKeyKey, integer, integer, integer):any
|
||||
--- @field termkey_interpret_position fun(any, any, any, any):any
|
||||
--- @field termkey_interpret_string fun(any, TermKeyKey, any):any
|
||||
--- @field termkey_lookup_keyname fun(any, any, any):any
|
||||
--- @field termkey_new_abstract fun(string, integer):any
|
||||
--- @field termkey_push_bytes fun(any, string, integer):integer
|
||||
--- @field termkey_set_buffer_size fun(any, integer):integer
|
||||
--- @field termkey_set_canonflags fun(any, any):any
|
||||
--- @field termkey_set_flags fun(any, integer)
|
||||
--- @field termkey_start fun(any):integer
|
||||
--- @field termkey_stop fun(any):integer
|
||||
--- @field termkey_strfkey fun(any, string, integer, any, any):integer
|
||||
local termkey = t.cimport(
|
||||
'./src/nvim/tui/termkey/termkey.h',
|
||||
'./src/nvim/tui/termkey/termkey-internal.h',
|
||||
'./src/nvim/tui/termkey/termkey_defs.h',
|
||||
'./src/nvim/tui/termkey/driver-csi.h'
|
||||
)
|
||||
|
||||
describe('termkey', function()
|
||||
itp('01base', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
t.neq(tk, nil)
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_size(tk), 256)
|
||||
t.eq(tk.is_started, 1) -- tk->is_started true after construction
|
||||
|
||||
termkey.termkey_stop(tk)
|
||||
t.neq(tk.is_started, 1) -- tk->is_started false after termkey_stop()
|
||||
|
||||
termkey.termkey_start(tk)
|
||||
t.eq(tk.is_started, 1) -- tk->is_started true after termkey_start()
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('02getkey', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free initially 256
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey yields RES_NONE when empty
|
||||
|
||||
t.eq(termkey.termkey_push_bytes(tk, 'h', 1), 1) -- push_bytes returns 1
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_remaining(tk), 255) -- buffer free 255 after push_bytes
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after h
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after h
|
||||
t.eq(key.code.codepoint, string.byte('h')) -- key.code.codepoint after h
|
||||
t.eq(key.modifiers, 0) -- key.modifiers after h
|
||||
t.eq(t.ffi.string(key.utf8), 'h') -- key.utf8 after h
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free 256 after getkey
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey yields RES_NONE a second time
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x01', 1)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after C-a
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after C-a
|
||||
t.eq(key.code.codepoint, string.byte('a')) -- key.code.codepoint after C-a
|
||||
t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_CTRL) -- key.modifiers after C-a
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\033OA', 3)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Up
|
||||
|
||||
-- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Up");
|
||||
-- is_int(key.code.sym, TERMKEY_SYM_UP, "key.code.sym after Up");
|
||||
t.eq(key.modifiers, 0) -- key.modifiers after Up
|
||||
|
||||
t.eq(termkey.termkey_push_bytes(tk, '\033O', 2), 2) -- push_bytes returns 2
|
||||
|
||||
-- is_int(termkey_get_buffer_remaining(tk), 254, "buffer free 254 after partial write");
|
||||
|
||||
-- is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN after partial write");
|
||||
|
||||
termkey.termkey_push_bytes(tk, 'C', 1)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Right completion
|
||||
|
||||
-- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Right");
|
||||
-- is_int(key.code.sym, TERMKEY_SYM_RIGHT, "key.code.sym after Right");
|
||||
-- is_int(key.modifiers, 0, "key.modifiers after Right");
|
||||
|
||||
-- is_int(termkey_get_buffer_remaining(tk), 256, "buffer free 256 after completion");
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\033[27;5u', 7)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Ctrl-Escape
|
||||
|
||||
-- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Ctrl-Escape");
|
||||
-- is_int(key.code.sym, TERMKEY_SYM_ESCAPE, "key.code.sym after Ctrl-Escape");
|
||||
-- is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after Ctrl-Escape");
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\0', 1)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Ctrl-Space
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after Ctrl-Space
|
||||
-- t.eq(key.code.codepoint, string.byte(' ')) -- key.code.codepoint after Ctrl-Space
|
||||
-- is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after Ctrl-Space");
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('03utf8', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', termkey.TERMKEY_FLAG_UTF8)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
|
||||
termkey.termkey_push_bytes(tk, 'a', 1)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY low ASCII
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type low ASCII
|
||||
t.eq(key.code.codepoint, string.byte('a')) -- key.code.codepoint low ASCII
|
||||
|
||||
-- 2-byte UTF-8 range is U+0080 to U+07FF (0xDF 0xBF)
|
||||
-- However, we'd best avoid the C1 range, so we'll start at U+00A0 (0xC2 0xA0)
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xC2\xA0', 2)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 low
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 2 low
|
||||
t.eq(key.code.codepoint, 0x00A0) -- key.code.codepoint UTF-8 2 low
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xDF\xBF', 2)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 high
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 2 high
|
||||
t.eq(key.code.codepoint, 0x07FF) -- key.code.codepoint UTF-8 2 high
|
||||
|
||||
-- 3-byte UTF-8 range is U+0800 (0xE0 0xA0 0x80) to U+FFFD (0xEF 0xBF 0xBD)
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xE0\xA0\x80', 3)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 low
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 3 low
|
||||
t.eq(key.code.codepoint, 0x0800) -- key.code.codepoint UTF-8 3 low
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xEF\xBF\xBD', 3)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 high
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 3 high
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 high
|
||||
|
||||
-- 4-byte UTF-8 range is U+10000 (0xF0 0x90 0x80 0x80) to U+10FFFF (0xF4 0x8F 0xBF 0xBF)
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xF0\x90\x80\x80', 4)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 low
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 4 low
|
||||
t.eq(key.code.codepoint, 0x10000) -- key.code.codepoint UTF-8 4 low
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xF4\x8F\xBF\xBF', 4)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 high
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 4 high
|
||||
t.eq(key.code.codepoint, 0x10FFFF) -- key.code.codepoint UTF-8 4 high
|
||||
|
||||
-- Invalid continuations
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xC2!', 2)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 invalid cont
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 2 invalid cont
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 invalid after
|
||||
t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 2 invalid after
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xE0!', 2)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid cont
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 invalid cont
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid after
|
||||
t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 3 invalid after
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xE0\xA0!', 3)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid cont 2
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 invalid cont 2
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid after
|
||||
t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 3 invalid after
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xF0!', 2)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after
|
||||
t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xF0\x90!', 3)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont 2
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont 2
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after
|
||||
t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xF0\x90\x80!', 4)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont 3
|
||||
t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont 3
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after
|
||||
t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after
|
||||
|
||||
-- Partials
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xC2', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 2 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xA0', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 partial
|
||||
t.eq(key.code.codepoint, 0x00A0) -- key.code.codepoint UTF-8 2 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xE0', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 3 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xA0', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 3 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x80', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 partial
|
||||
t.eq(key.code.codepoint, 0x0800) -- key.code.codepoint UTF-8 3 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\xF0', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x90', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x80', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x80', 1)
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 partial
|
||||
t.eq(key.code.codepoint, 0x10000) -- key.code.codepoint UTF-8 4 partial
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('04flags', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
|
||||
termkey.termkey_push_bytes(tk, ' ', 1)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after space
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after space
|
||||
t.eq(key.code.codepoint, string.byte(' ')) -- key.code.codepoint after space
|
||||
t.eq(key.modifiers, 0) -- key.modifiers after space
|
||||
|
||||
termkey.termkey_set_flags(tk, termkey.TERMKEY_FLAG_SPACESYMBOL)
|
||||
|
||||
termkey.termkey_push_bytes(tk, ' ', 1)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after space
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_KEYSYM) -- key.type after space with FLAG_SPACESYMBOL
|
||||
t.eq(key.code.sym, termkey.TERMKEY_SYM_SPACE) -- key.code.sym after space with FLAG_SPACESYMBOL
|
||||
t.eq(key.modifiers, 0) -- key.modifiers after space with FLAG_SPACESYMBOL
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('06buffer', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free initially 256
|
||||
t.eq(termkey.termkey_get_buffer_size(tk), 256) -- buffer size initially 256
|
||||
|
||||
t.eq(termkey.termkey_push_bytes(tk, 'h', 1), 1) -- push_bytes returns 1
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_remaining(tk), 255) -- buffer free 255 after push_bytes
|
||||
t.eq(termkey.termkey_get_buffer_size(tk), 256) -- buffer size 256 after push_bytes
|
||||
|
||||
t.eq(not not termkey.termkey_set_buffer_size(tk, 512), true) -- buffer set size OK
|
||||
|
||||
t.eq(termkey.termkey_get_buffer_remaining(tk), 511) -- buffer free 511 after push_bytes
|
||||
t.eq(termkey.termkey_get_buffer_size(tk), 512) -- buffer size 512 after push_bytes
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- buffered key still useable after resize
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
local function termkey_keyname2sym(tk, keyname)
|
||||
local sym = t.ffi.new('TermKeySym[1]')
|
||||
local endp = termkey.termkey_lookup_keyname(tk, keyname, sym)
|
||||
if endp == nil then
|
||||
return termkey.TERMKEY_SYM_UNKNOWN
|
||||
end
|
||||
return sym
|
||||
end
|
||||
|
||||
itp('10keyname', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
|
||||
local sym = termkey_keyname2sym(tk, 'SomeUnknownKey')
|
||||
t.eq(sym, termkey.TERMKEY_SYM_UNKNOWN) -- keyname2sym SomeUnknownKey
|
||||
|
||||
sym = termkey_keyname2sym(tk, 'Space')
|
||||
t.eq(sym[0], termkey.TERMKEY_SYM_SPACE) -- keyname2sym Space
|
||||
|
||||
local _end = termkey.termkey_lookup_keyname(tk, 'Up', sym)
|
||||
t.neq(_end, nil) -- termkey_get_keyname Up returns non-NULL
|
||||
t.eq(t.ffi.string(_end), '') -- termkey_get_keyname Up return points at endofstring
|
||||
t.eq(sym[0], termkey.TERMKEY_SYM_UP) -- termkey_get_keyname Up yields Up symbol
|
||||
|
||||
_end = termkey.termkey_lookup_keyname(tk, 'DownMore', sym)
|
||||
t.neq(_end, nil) -- termkey_get_keyname DownMore returns non-NULL
|
||||
t.eq(t.ffi.string(_end), 'More') -- termkey_get_keyname DownMore return points at More
|
||||
t.eq(sym[0], termkey.TERMKEY_SYM_DOWN) -- termkey_get_keyname DownMore yields Down symbol
|
||||
|
||||
_end = termkey.termkey_lookup_keyname(tk, 'SomeUnknownKey', sym)
|
||||
t.eq(_end, nil) -- termkey_get_keyname SomeUnknownKey returns NULL
|
||||
|
||||
t.eq(t.ffi.string(termkey.termkey_get_keyname(tk, termkey.TERMKEY_SYM_SPACE)), 'Space') -- "get_keyname SPACE");
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('11strfkey', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
---@type TermKeyKey
|
||||
local key = t.ffi.new(
|
||||
'TermKeyKey',
|
||||
{ type = termkey.TERMKEY_TYPE_UNICODE, code = { codepoint = string.byte('A') } }
|
||||
)
|
||||
local buffer = t.ffi.new('char[16]')
|
||||
|
||||
local len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 1) -- length for unicode/A/0
|
||||
t.eq(t.ffi.string(buffer), 'A') -- buffer for unicode/A/0
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_WRAPBRACKET
|
||||
)
|
||||
t.eq(len, 1) -- length for unicode/A/0 wrapbracket
|
||||
t.eq(t.ffi.string(buffer), 'A') -- buffer for unicode/A/0 wrapbracket
|
||||
|
||||
---@type TermKeyKey
|
||||
key = t.ffi.new('TermKeyKey', {
|
||||
type = termkey.TERMKEY_TYPE_UNICODE,
|
||||
code = { codepoint = string.byte('b') },
|
||||
modifiers = termkey.TERMKEY_KEYMOD_CTRL,
|
||||
})
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 3) -- length for unicode/b/CTRL
|
||||
t.eq(t.ffi.string(buffer), 'C-b') -- buffer for unicode/b/CTRL
|
||||
|
||||
len =
|
||||
termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, termkey.TERMKEY_FORMAT_LONGMOD)
|
||||
t.eq(len, 6) -- length for unicode/b/CTRL longmod
|
||||
t.eq(t.ffi.string(buffer), 'Ctrl-b') -- buffer for unicode/b/CTRL longmod
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_SPACEMOD)
|
||||
)
|
||||
t.eq(len, 6) -- length for unicode/b/CTRL longmod|spacemod
|
||||
t.eq(t.ffi.string(buffer), 'Ctrl b') -- buffer for unicode/b/CTRL longmod|spacemod
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_LOWERMOD)
|
||||
)
|
||||
t.eq(len, 6) -- length for unicode/b/CTRL longmod|lowermod
|
||||
t.eq(t.ffi.string(buffer), 'ctrl-b') -- buffer for unicode/b/CTRL longmod|lowermod
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
bit.bor(
|
||||
termkey.TERMKEY_FORMAT_LONGMOD,
|
||||
termkey.TERMKEY_FORMAT_SPACEMOD,
|
||||
termkey.TERMKEY_FORMAT_LOWERMOD
|
||||
)
|
||||
)
|
||||
t.eq(len, 6) -- length for unicode/b/CTRL longmod|spacemod|lowermode
|
||||
t.eq(t.ffi.string(buffer), 'ctrl b') -- buffer for unicode/b/CTRL longmod|spacemod|lowermode
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_CARETCTRL
|
||||
)
|
||||
t.eq(len, 2) -- length for unicode/b/CTRL caretctrl
|
||||
t.eq(t.ffi.string(buffer), '^B') -- buffer for unicode/b/CTRL caretctrl
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_WRAPBRACKET
|
||||
)
|
||||
t.eq(len, 5) -- length for unicode/b/CTRL wrapbracket
|
||||
t.eq(t.ffi.string(buffer), '<C-b>') -- buffer for unicode/b/CTRL wrapbracket
|
||||
|
||||
---@type TermKeyKey
|
||||
key = t.ffi.new('TermKeyKey', {
|
||||
type = termkey.TERMKEY_TYPE_UNICODE,
|
||||
code = { codepoint = string.byte('c') },
|
||||
modifiers = termkey.TERMKEY_KEYMOD_ALT,
|
||||
})
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 3) -- length for unicode/c/ALT
|
||||
t.eq(t.ffi.string(buffer), 'A-c') -- buffer for unicode/c/ALT
|
||||
|
||||
len =
|
||||
termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, termkey.TERMKEY_FORMAT_LONGMOD)
|
||||
t.eq(len, 5) -- length for unicode/c/ALT longmod
|
||||
t.eq(t.ffi.string(buffer), 'Alt-c') -- buffer for unicode/c/ALT longmod
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_ALTISMETA
|
||||
)
|
||||
t.eq(len, 3) -- length for unicode/c/ALT altismeta
|
||||
t.eq(t.ffi.string(buffer), 'M-c') -- buffer for unicode/c/ALT altismeta
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_ALTISMETA)
|
||||
)
|
||||
t.eq(len, 6) -- length for unicode/c/ALT longmod|altismeta
|
||||
t.eq(t.ffi.string(buffer), 'Meta-c') -- buffer for unicode/c/ALT longmod|altismeta
|
||||
|
||||
---@type TermKeyKey
|
||||
key = t.ffi.new(
|
||||
'TermKeyKey',
|
||||
{ type = termkey.TERMKEY_TYPE_KEYSYM, code = { sym = termkey.TERMKEY_SYM_UP } }
|
||||
)
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 2) -- length for sym/Up/0
|
||||
t.eq(t.ffi.string(buffer), 'Up') -- buffer for sym/Up/0
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_WRAPBRACKET
|
||||
)
|
||||
t.eq(len, 4) -- length for sym/Up/0 wrapbracket
|
||||
t.eq(t.ffi.string(buffer), '<Up>') -- buffer for sym/Up/0 wrapbracket
|
||||
|
||||
---@type TermKeyKey
|
||||
key = t.ffi.new(
|
||||
'TermKeyKey',
|
||||
{ type = termkey.TERMKEY_TYPE_KEYSYM, code = { sym = termkey.TERMKEY_SYM_PAGEUP } }
|
||||
)
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 6) -- length for sym/PageUp/0
|
||||
t.eq(t.ffi.string(buffer), 'PageUp') -- buffer for sym/PageUp/0
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_LOWERSPACE
|
||||
)
|
||||
t.eq(len, 7) -- length for sym/PageUp/0 lowerspace
|
||||
t.eq(t.ffi.string(buffer), 'page up') -- buffer for sym/PageUp/0 lowerspace
|
||||
|
||||
-- If size of buffer is too small, strfkey should return something consistent
|
||||
len = termkey.termkey_strfkey(tk, buffer, 4, key, 0)
|
||||
t.eq(len, 6) -- length for sym/PageUp/0
|
||||
t.eq(t.ffi.string(buffer), 'Pag') -- buffer of len 4 for sym/PageUp/0
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, 4, key, termkey.TERMKEY_FORMAT_LOWERSPACE)
|
||||
t.eq(len, 7) -- length for sym/PageUp/0 lowerspace
|
||||
t.eq(t.ffi.string(buffer), 'pag') -- buffer of len 4 for sym/PageUp/0 lowerspace
|
||||
|
||||
key = t.ffi.new('TermKeyKey', { type = termkey.TERMKEY_TYPE_FUNCTION, code = { number = 5 } }) ---@type TermKeyKey
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 2) -- length for func/5/0
|
||||
t.eq(t.ffi.string(buffer), 'F5') -- buffer for func/5/0
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_WRAPBRACKET
|
||||
)
|
||||
t.eq(len, 4) -- length for func/5/0 wrapbracket
|
||||
t.eq(t.ffi.string(buffer), '<F5>') -- buffer for func/5/0 wrapbracket
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_LOWERSPACE
|
||||
)
|
||||
t.eq(len, 2) -- length for func/5/0 lowerspace
|
||||
t.eq(t.ffi.string(buffer), 'f5') -- buffer for func/5/0 lowerspace
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('13cmpkey', function()
|
||||
local function termkey_keycmp(tk, key1, key2)
|
||||
termkey.termkey_canonicalise(tk, key1)
|
||||
termkey.termkey_canonicalise(tk, key2)
|
||||
|
||||
if key1.type ~= key2.type then
|
||||
return key1.type - key2.type
|
||||
end
|
||||
|
||||
if key1.type == termkey.TERMKEY_TYPE_UNICODE then
|
||||
if key1.code.codepoint ~= key2.code.codepoint then
|
||||
return key1.code.codepoint - key2.code.codepoint
|
||||
end
|
||||
end
|
||||
|
||||
return key1.modifiers - key2.modifiers
|
||||
end
|
||||
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
---@type TermKeyKey
|
||||
local key1 = t.ffi.new('TermKeyKey', {
|
||||
type = termkey.TERMKEY_TYPE_UNICODE,
|
||||
code = { codepoint = string.byte('A') },
|
||||
modifiers = 0,
|
||||
})
|
||||
---@type TermKeyKey
|
||||
local key2 = t.ffi.new('TermKeyKey', {
|
||||
type = termkey.TERMKEY_TYPE_UNICODE,
|
||||
code = { codepoint = string.byte('A') },
|
||||
modifiers = 0,
|
||||
})
|
||||
|
||||
t.eq(termkey_keycmp(tk, key1, key1), 0) -- cmpkey same structure
|
||||
t.eq(termkey_keycmp(tk, key1, key2), 0) -- cmpkey identical structure
|
||||
|
||||
key2.modifiers = termkey.TERMKEY_KEYMOD_CTRL
|
||||
|
||||
t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders CTRL after nomod
|
||||
t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders nomod before CTRL
|
||||
|
||||
key2.code.codepoint = string.byte('B')
|
||||
key2.modifiers = 0
|
||||
|
||||
t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders 'B' after 'A'
|
||||
t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders 'A' before 'B'
|
||||
|
||||
key1.modifiers = termkey.TERMKEY_KEYMOD_CTRL
|
||||
|
||||
t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders nomod 'B' after CTRL 'A'
|
||||
t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders CTRL 'A' before nomod 'B'
|
||||
|
||||
key2.type = termkey.TERMKEY_TYPE_KEYSYM
|
||||
key2.code.sym = termkey.TERMKEY_SYM_UP
|
||||
|
||||
t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders KEYSYM after UNICODE
|
||||
t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders UNICODE before KEYSYM
|
||||
|
||||
key1.type = termkey.TERMKEY_TYPE_KEYSYM
|
||||
key1.code.sym = termkey.TERMKEY_SYM_SPACE
|
||||
key1.modifiers = 0
|
||||
key2.type = termkey.TERMKEY_TYPE_UNICODE
|
||||
key2.code.codepoint = string.byte(' ')
|
||||
key2.modifiers = 0
|
||||
|
||||
t.eq(termkey_keycmp(tk, key1, key2), 0) -- cmpkey considers KEYSYM/SPACE and UNICODE/SP identical
|
||||
|
||||
termkey.termkey_set_canonflags(
|
||||
tk,
|
||||
bit.bor(termkey.termkey_get_canonflags(tk), termkey.TERMKEY_CANON_SPACESYMBOL)
|
||||
)
|
||||
t.eq(termkey_keycmp(tk, key1, key2), 0) -- "cmpkey considers KEYSYM/SPACE and UNICODE/SP identical under SPACESYMBOL");
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('30mouse', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey', { type = -1 }) ---@type TermKeyKey
|
||||
local ev = t.ffi.new('TermKeyMouseEvent[1]')
|
||||
local button = t.ffi.new('int[1]')
|
||||
local line = t.ffi.new('int[1]')
|
||||
local col = t.ffi.new('int[1]')
|
||||
local buffer = t.ffi.new('char[32]')
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[M !!', 6)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press
|
||||
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press
|
||||
t.eq(button[0], 1) -- mouse button for press
|
||||
t.eq(line[0], 1) -- mouse line for press
|
||||
t.eq(col[0], 1) -- mouse column for press
|
||||
t.eq(key.modifiers, 0) -- modifiers for press
|
||||
|
||||
local len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 13) -- string length for press
|
||||
t.eq(t.ffi.string(buffer), 'MousePress(1)') -- string buffer for press
|
||||
|
||||
len = termkey.termkey_strfkey(
|
||||
tk,
|
||||
buffer,
|
||||
t.ffi.sizeof(buffer),
|
||||
key,
|
||||
termkey.TERMKEY_FORMAT_MOUSE_POS
|
||||
)
|
||||
t.eq(len, 21) -- string length for press
|
||||
t.eq(t.ffi.string(buffer), 'MousePress(1) @ (1,1)') -- string buffer for press
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[M@"!', 6)
|
||||
|
||||
termkey.termkey_getkey(tk, key)
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_DRAG) -- mouse event for drag
|
||||
t.eq(button[0], 1) -- mouse button for drag
|
||||
t.eq(line[0], 1) -- mouse line for drag
|
||||
t.eq(col[0], 2) -- mouse column for drag
|
||||
t.eq(key.modifiers, 0) -- modifiers for press
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[M##!', 6)
|
||||
|
||||
termkey.termkey_getkey(tk, key)
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release
|
||||
t.eq(line[0], 1) -- mouse line for release
|
||||
t.eq(col[0], 3) -- mouse column for release
|
||||
t.eq(key.modifiers, 0) -- modifiers for press
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[M0++', 6)
|
||||
|
||||
termkey.termkey_getkey(tk, key)
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for Ctrl-press
|
||||
t.eq(button[0], 1) -- mouse button for Ctrl-press
|
||||
t.eq(line[0], 11) -- mouse line for Ctrl-press
|
||||
t.eq(col[0], 11) -- mouse column for Ctrl-press
|
||||
t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_CTRL) -- modifiers for Ctrl-press
|
||||
|
||||
len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
|
||||
t.eq(len, 15) -- string length for Ctrl-press
|
||||
t.eq(t.ffi.string(buffer), 'C-MousePress(1)') -- string buffer for Ctrl-press
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[M`!!', 6)
|
||||
|
||||
termkey.termkey_getkey(tk, key)
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for wheel down
|
||||
t.eq(button[0], 4) -- mouse button for wheel down
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[Mb!!', 6)
|
||||
|
||||
termkey.termkey_getkey(tk, key)
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for wheel left
|
||||
t.eq(button[0], 6) -- mouse button for wheel left
|
||||
|
||||
-- rxvt protocol
|
||||
termkey.termkey_push_bytes(tk, '\x1b[0;20;20M', 10)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press rxvt protocol
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press rxvt protocol
|
||||
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press rxvt protocol
|
||||
t.eq(button[0], 1) -- mouse button for press rxvt protocol
|
||||
t.eq(line[0], 20) -- mouse line for press rxvt protocol
|
||||
t.eq(col[0], 20) -- mouse column for press rxvt protocol
|
||||
t.eq(key.modifiers, 0) -- modifiers for press rxvt protocol
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[3;20;20M', 10)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse release rxvt protocol
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse release rxvt protocol
|
||||
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release rxvt protocol
|
||||
t.eq(line[0], 20) -- mouse line for release rxvt protocol
|
||||
t.eq(col[0], 20) -- mouse column for release rxvt protocol
|
||||
t.eq(key.modifiers, 0) -- modifiers for release rxvt protocol
|
||||
|
||||
-- SGR protocol
|
||||
termkey.termkey_push_bytes(tk, '\x1b[<0;30;30M', 11)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press SGR encoding
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press SGR encoding
|
||||
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press SGR
|
||||
t.eq(button[0], 1) -- mouse button for press SGR
|
||||
t.eq(line[0], 30) -- mouse line for press SGR
|
||||
t.eq(col[0], 30) -- mouse column for press SGR
|
||||
t.eq(key.modifiers, 0) -- modifiers for press SGR
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[<0;30;30m', 11)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse release SGR encoding
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse release SGR encoding
|
||||
|
||||
t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
|
||||
|
||||
t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release SGR
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[<0;500;300M', 13)
|
||||
|
||||
termkey.termkey_getkey(tk, key)
|
||||
termkey.termkey_interpret_mouse(tk, key, ev, button, line, col)
|
||||
|
||||
t.eq(line[0], 300) -- mouse line for press SGR wide
|
||||
t.eq(col[0], 500) -- mouse column for press SGR wide
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('31position', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
local line = t.ffi.new('int[1]')
|
||||
local col = t.ffi.new('int[1]')
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[?15;7R', 8)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for position report
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_POSITION) -- key.type for position report
|
||||
|
||||
t.eq(termkey.termkey_interpret_position(tk, key, line, col), termkey.TERMKEY_RES_KEY) -- interpret_position yields RES_KEY
|
||||
|
||||
t.eq(line[0], 15) -- line for position report
|
||||
t.eq(col[0], 7) -- column for position report
|
||||
|
||||
-- A plain CSI R is likely to be <F3> though.
|
||||
-- This is tricky :/
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[R', 3)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for <F3>
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_FUNCTION) -- key.type for <F3>
|
||||
t.eq(key.code.number, 3) -- key.code.number for <F3>
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('32modereport', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
local initial = t.ffi.new('int[1]')
|
||||
local mode = t.ffi.new('int[1]')
|
||||
local value = t.ffi.new('int[1]')
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[?1;2$y', 8)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mode report
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MODEREPORT) -- key.type for mode report
|
||||
|
||||
t.eq(
|
||||
termkey.termkey_interpret_modereport(tk, key, initial, mode, value),
|
||||
termkey.TERMKEY_RES_KEY
|
||||
) -- interpret_modereoprt yields RES_KEY
|
||||
|
||||
t.eq(initial[0], 63) -- initial indicator from mode report
|
||||
t.eq(mode[0], 1) -- mode number from mode report
|
||||
t.eq(value[0], 2) -- mode value from mode report
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[4;1$y', 7)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mode report
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_MODEREPORT) -- key.type for mode report
|
||||
|
||||
t.eq(
|
||||
termkey.termkey_interpret_modereport(tk, key, initial, mode, value),
|
||||
termkey.TERMKEY_RES_KEY
|
||||
) -- interpret_modereoprt yields RES_KEY
|
||||
|
||||
t.eq(initial[0], 0) -- initial indicator from mode report
|
||||
t.eq(mode[0], 4) -- mode number from mode report
|
||||
t.eq(value[0], 1) -- mode value from mode report
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('38csi', function()
|
||||
local tk = termkey.termkey_new_abstract('vt100', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
local args = t.ffi.new('TermKeyCsiParam[16]')
|
||||
local nargs = t.ffi.new('size_t[1]')
|
||||
local command = t.ffi.new('unsigned[1]')
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[5;25v', 7)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI v
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI
|
||||
|
||||
t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY
|
||||
|
||||
t.eq(nargs[0], 2) -- nargs for unknown CSI
|
||||
-- t.eq(args[0], 5) -- args[0] for unknown CSI
|
||||
-- t.eq(args[1], 25) -- args[1] for unknown CSI
|
||||
t.eq(command[0], 118) -- command for unknown CSI
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[?w', 4)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI ? w
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI
|
||||
t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY
|
||||
t.eq(command[0], bit.bor(bit.lshift(63, 8), 119)) -- command for unknown CSI
|
||||
|
||||
termkey.termkey_push_bytes(tk, '\x1b[?$x', 5)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI ? $x
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI
|
||||
t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY
|
||||
t.eq(command[0], bit.bor(bit.lshift(36, 16), bit.lshift(63, 8), 120)) -- command for unknown CSI
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
|
||||
itp('39dcs', function()
|
||||
local tk = termkey.termkey_new_abstract('xterm', 0)
|
||||
local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
|
||||
|
||||
-- 7bit DCS
|
||||
termkey.termkey_push_bytes(tk, '\x1bP1$r1 q\x1b\\', 10)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for DCS
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_DCS) -- key.type for DCS
|
||||
t.eq(key.modifiers, 0) -- key.modifiers for DCS
|
||||
|
||||
local str = t.ffi.new('const char*[1]')
|
||||
t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- termkey_interpret_string() gives string
|
||||
t.eq(t.ffi.string(str[0]), '1$r1 q') -- termkey_interpret_string() yields correct string
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey again yields RES_NONE
|
||||
|
||||
-- 8bit DCS
|
||||
termkey.termkey_push_bytes(tk, '\x901$r2 q\x9c', 8)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for DCS
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_DCS) -- key.type for DCS
|
||||
t.eq(key.modifiers, 0) -- key.modifiers for DCS
|
||||
|
||||
t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- "termkey_interpret_string() gives string");
|
||||
t.eq(t.ffi.string(str[0]), '1$r2 q') -- "termkey_interpret_string() yields correct string");
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- "getkey again yields RES_NONE");
|
||||
|
||||
-- 7bit OSC
|
||||
termkey.termkey_push_bytes(tk, '\x1b]15;abc\x1b\\', 10)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for OSC
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_OSC) -- key.type for OSC
|
||||
t.eq(key.modifiers, 0) -- key.modifiers for OSC
|
||||
|
||||
t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- "termkey_interpret_string() gives string");
|
||||
t.eq(t.ffi.string(str[0]), '15;abc') -- "termkey_interpret_string() yields correct string");
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey again yields RES_NONE
|
||||
|
||||
-- False alarm
|
||||
termkey.termkey_push_bytes(tk, '\x1bP', 2)
|
||||
|
||||
t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN for false alarm
|
||||
|
||||
t.eq(termkey.termkey_getkey_force(tk, key), termkey.TERMKEY_RES_KEY) -- getkey_force yields RES_KEY for false alarm
|
||||
|
||||
t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type for false alarm
|
||||
t.eq(key.code.codepoint, string.byte('P')) -- key.code.codepoint for false alarm
|
||||
t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_ALT) -- key.modifiers for false alarm
|
||||
|
||||
termkey.termkey_destroy(tk)
|
||||
end)
|
||||
end)
|
Loading…
Reference in New Issue
Block a user