mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
Compare commits
21 Commits
8a6c1f8339
...
9644e65493
Author | SHA1 | Date | |
---|---|---|---|
|
9644e65493 | ||
|
4c5bce9cb4 | ||
|
5d7853f229 | ||
|
f279d1ae33 | ||
|
9ddfcb64bf | ||
|
8e81212e15 | ||
|
648d6426c8 | ||
|
f0334c2c71 | ||
|
c8e3618e0e | ||
|
ed832b9ddf | ||
|
8a2aec9974 | ||
|
3a88113246 | ||
|
08153ddd1c | ||
|
003b8a251d | ||
|
0cfbc6eaff | ||
|
95b65a7554 | ||
|
e37404f7fe | ||
|
b40ec083ae | ||
|
d338ec9cb2 | ||
|
5ddf2ab768 | ||
|
169a159ccc |
@ -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:
|
||||
|
@ -42,6 +42,9 @@ DIAGNOSTICS
|
||||
|
||||
• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|
||||
|vim.diagnostic.jump()|.
|
||||
• Diagnostics are filtered by severity before being passed to a diagnostic
|
||||
handler |diagnostic-handlers|.
|
||||
|
||||
|
||||
EDITOR
|
||||
|
||||
@ -214,9 +217,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*
|
||||
|
||||
|
@ -53,11 +53,17 @@ active yes yes 'a'
|
||||
hidden no yes 'h'
|
||||
inactive no no ' '
|
||||
|
||||
Note: All CTRL-W commands can also be executed with |:wincmd|, for those
|
||||
places where a Normal mode command can't be used or is inconvenient.
|
||||
*buffer-reuse*
|
||||
Each buffer has a unique number and the number will not change within a Vim
|
||||
session. The |bufnr()| and |bufname()| functions can be used to convert
|
||||
between a buffer name and the buffer number. There is one exception: if a new
|
||||
empty buffer is created and it is not modified, the buffer will be re-used
|
||||
when loading another file into that buffer. This also means the buffer number
|
||||
will not change.
|
||||
|
||||
The main Vim window can hold several split windows. There are also tab pages
|
||||
|tab-page|, each of which can hold multiple windows.
|
||||
|
||||
*window-ID* *winid* *windowid*
|
||||
Each window has a unique identifier called the window ID. This identifier
|
||||
will not change within a Vim session. The |win_getid()| and |win_id2tabwin()|
|
||||
@ -69,9 +75,6 @@ across tabs. For most functions that take a window ID or a window number, the
|
||||
window number only applies to the current tab, while the window ID can refer
|
||||
to a window in any tab.
|
||||
|
||||
Each buffer has a unique number and the number will not change within a Vim
|
||||
session. The |bufnr()| and |bufname()| functions can be used to convert
|
||||
between a buffer name and the buffer number.
|
||||
|
||||
==============================================================================
|
||||
2. Starting Vim *windows-starting*
|
||||
@ -468,6 +471,10 @@ These commands can also be executed with ":wincmd":
|
||||
:exe nr .. "wincmd w"
|
||||
< This goes to window "nr".
|
||||
|
||||
Note: All CTRL-W commands can also be executed with |:wincmd|, for those
|
||||
places where a Normal mode command can't be used or is inconvenient (e.g.
|
||||
in a browser-based terminal).
|
||||
|
||||
==============================================================================
|
||||
5. Moving windows around *window-moving*
|
||||
|
||||
|
3
runtime/ftplugin/dot.lua
Normal file
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<'
|
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 = {
|
||||
|
@ -1366,10 +1366,6 @@ M.handlers.signs = {
|
||||
return
|
||||
end
|
||||
|
||||
if opts.signs and opts.signs.severity then
|
||||
diagnostics = filter_by_severity(opts.signs.severity, diagnostics)
|
||||
end
|
||||
|
||||
-- 10 is the default sign priority when none is explicitly specified
|
||||
local priority = opts.signs and opts.signs.priority or 10
|
||||
local get_priority --- @type function
|
||||
@ -1487,16 +1483,11 @@ M.handlers.underline = {
|
||||
})
|
||||
|
||||
bufnr = get_bufnr(bufnr)
|
||||
opts = opts or {}
|
||||
|
||||
if not vim.api.nvim_buf_is_loaded(bufnr) then
|
||||
return
|
||||
end
|
||||
|
||||
if opts.underline and opts.underline.severity then
|
||||
diagnostics = filter_by_severity(opts.underline.severity, diagnostics)
|
||||
end
|
||||
|
||||
local ns = M.get_namespace(namespace)
|
||||
if not ns.user_data.underline_ns then
|
||||
ns.user_data.underline_ns =
|
||||
@ -1566,7 +1557,6 @@ M.handlers.virtual_text = {
|
||||
return
|
||||
end
|
||||
|
||||
local severity --- @type vim.diagnostic.SeverityFilter?
|
||||
if opts.virtual_text then
|
||||
if opts.virtual_text.format then
|
||||
diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics)
|
||||
@ -1577,9 +1567,6 @@ M.handlers.virtual_text = {
|
||||
then
|
||||
diagnostics = prefix_source(diagnostics)
|
||||
end
|
||||
if opts.virtual_text.severity then
|
||||
severity = opts.virtual_text.severity
|
||||
end
|
||||
end
|
||||
|
||||
local ns = M.get_namespace(namespace)
|
||||
@ -1591,9 +1578,6 @@ M.handlers.virtual_text = {
|
||||
local virt_text_ns = ns.user_data.virt_text_ns
|
||||
local buffer_line_diagnostics = diagnostic_lines(diagnostics)
|
||||
for line, line_diagnostics in pairs(buffer_line_diagnostics) do
|
||||
if severity then
|
||||
line_diagnostics = filter_by_severity(severity, line_diagnostics)
|
||||
end
|
||||
local virt_texts = M._get_virt_text_chunks(line_diagnostics, opts.virtual_text)
|
||||
|
||||
if virt_texts then
|
||||
@ -1808,7 +1792,8 @@ function M.show(namespace, bufnr, diagnostics, opts)
|
||||
|
||||
for handler_name, handler in pairs(M.handlers) do
|
||||
if handler.show and opts_res[handler_name] then
|
||||
handler.show(namespace, bufnr, diagnostics, opts_res)
|
||||
local filtered = filter_by_severity(opts_res[handler_name].severity, diagnostics)
|
||||
handler.show(namespace, bufnr, filtered, opts_res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -77,12 +77,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
|
||||
|
@ -152,14 +152,14 @@ function M.open(path)
|
||||
else
|
||||
return nil, 'vim.ui.open: rundll32 not found'
|
||||
end
|
||||
elseif vim.fn.executable('wslview') == 1 then
|
||||
cmd = { 'wslview', path }
|
||||
elseif vim.fn.executable('explorer.exe') == 1 then
|
||||
cmd = { 'explorer.exe', path }
|
||||
elseif vim.fn.executable('xdg-open') == 1 then
|
||||
cmd = { 'xdg-open', path }
|
||||
opts.stdout = false
|
||||
opts.stderr = false
|
||||
elseif vim.fn.executable('wslview') == 1 then
|
||||
cmd = { 'wslview', path }
|
||||
elseif vim.fn.executable('explorer.exe') == 1 then
|
||||
cmd = { 'explorer.exe', path }
|
||||
else
|
||||
return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,36 +29,30 @@ 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.
|
||||
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.
|
||||
|
@ -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 read 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=%d pending=%d", !!events, pending_events(events));
|
||||
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 };
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,42 +1071,28 @@ 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()
|
||||
]]
|
||||
)
|
||||
)
|
||||
matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]]))
|
||||
|
||||
matches(
|
||||
'wrong number of arguments %(given 1, expected at least 3%)',
|
||||
pcall_err(
|
||||
exec_lua,
|
||||
[[
|
||||
return vim.tbl_deep_extend("keep")
|
||||
]]
|
||||
)
|
||||
pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep")]])
|
||||
)
|
||||
|
||||
matches(
|
||||
'wrong number of arguments %(given 2, expected at least 3%)',
|
||||
pcall_err(
|
||||
exec_lua,
|
||||
[[
|
||||
return vim.tbl_deep_extend("keep", {})
|
||||
]]
|
||||
)
|
||||
pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {})]])
|
||||
)
|
||||
|
||||
matches(
|
||||
'after the second argument%: expected table, got number',
|
||||
pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {}, 42)]])
|
||||
)
|
||||
end)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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(...)
|
||||
|
Loading…
Reference in New Issue
Block a user