Merge #15677 release-0.5: backports

This commit is contained in:
Justin M. Keyes 2021-09-16 12:00:13 -07:00 committed by GitHub
commit 7d67bd5865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 427 additions and 41 deletions

View File

@ -85,7 +85,11 @@ function highlight.on_yank(opts)
highlight.range(bufnr, yank_ns, higroup, pos1, pos2, event.regtype, event.inclusive)
vim.defer_fn(
function() api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) end,
function()
if api.nvim_buf_is_valid(bufnr) then
api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1)
end
end,
timeout
)
end

View File

@ -1150,7 +1150,7 @@ end
---@param bufnr (number) Buffer handle, or 0 for current
---@param client_id (number) the client id
function lsp.buf_is_attached(bufnr, client_id)
return (all_buffer_active_clients[bufnr] or {})[client_id] == true
return (all_buffer_active_clients[resolve_bufnr(bufnr)] or {})[client_id] == true
end
--- Gets a client by id, or nil if the id is invalid.

View File

@ -1042,16 +1042,17 @@ function M.on_publish_diagnostics(_, _, params, client_id, _, config)
end
-- restores the extmarks set by M.display
--- @param last number last line that was changed
-- @private
local function restore_extmarks(bufnr)
local lcount = api.nvim_buf_line_count(bufnr)
local function restore_extmarks(bufnr, last)
for client_id, extmarks in pairs(diagnostic_cache_extmarks[bufnr]) do
local ns = M._get_diagnostic_namespace(client_id)
local extmarks_current = api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {details = true})
local found = {}
for _, extmark in ipairs(extmarks_current) do
-- HACK: the missing extmarks seem to still exist, but at the line after the last
if extmark[2] < lcount then
-- nvim_buf_set_lines will move any extmark to the line after the last
-- nvim_buf_set_text will move any extmark to the last line
if extmark[2] ~= last + 1 then
found[extmark[1]] = true
end
end
@ -1076,8 +1077,8 @@ local function save_extmarks(bufnr, client_id)
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
if not diagnostic_attached_buffers[bufnr] then
api.nvim_buf_attach(bufnr, false, {
on_lines = function()
restore_extmarks(bufnr)
on_lines = function(_, _, _, _, _, last)
restore_extmarks(bufnr, last - 1)
end,
on_detach = function()
diagnostic_cache_extmarks[bufnr] = nil

View File

@ -18,10 +18,8 @@ local function err_message(...)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
M['workspace/executeCommand'] = function(err, _)
if err then
error("Could not execute code action: "..err.message)
end
M['workspace/executeCommand'] = function()
-- Error handling is done implicitly by wrapping all handlers; see end of this file
end
-- @msg of type ProgressParams
@ -158,13 +156,12 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration
M['workspace/configuration'] = function(err, _, params, client_id)
M['workspace/configuration'] = function(_, _, params, client_id)
local client = vim.lsp.get_client_by_id(client_id)
if not client then
err_message("LSP[id=", client_id, "] client has shut down after sending the message")
return
end
if err then error(vim.inspect(err)) end
if not params.items then
return {}
end
@ -191,30 +188,33 @@ M['textDocument/codeLens'] = function(...)
return require('vim.lsp.codelens').on_codelens(...)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
M['textDocument/references'] = function(_, _, result)
if not result then return end
util.set_qflist(util.locations_to_items(result))
api.nvim_command("copen")
end
--@private
--- Prints given list of symbols to the quickfix list.
--@param _ (not used)
--@param _ (not used)
--@param result (list of Symbols) LSP method name
--@param result (table) result of LSP method; a location or a list of locations.
---(`textDocument/definition` can return `Location` or `Location[]`
local symbol_handler = function(_, _, result, _, bufnr)
if not result or vim.tbl_isempty(result) then return end
util.set_qflist(util.symbols_to_items(result, bufnr))
api.nvim_command("copen")
--- Return a function that converts LSP responses to quickfix items and opens the qflist
--
--@param map_result function `((resp, bufnr) -> list)` to convert the response
--@param entity name of the resource used in a `not found` error message
local function response_to_qflist(map_result, entity)
return function(_, _, result, _, bufnr)
if not result or vim.tbl_isempty(result) then
vim.notify('No ' .. entity .. ' found')
else
util.set_qflist(map_result(result, bufnr))
api.nvim_command("copen")
end
end
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
M['textDocument/references'] = response_to_qflist(util.locations_to_items, 'references')
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
M['textDocument/documentSymbol'] = symbol_handler
M['textDocument/documentSymbol'] = response_to_qflist(util.symbols_to_items, 'document symbols')
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
M['workspace/symbol'] = symbol_handler
M['workspace/symbol'] = response_to_qflist(util.symbols_to_items, 'symbols')
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
M['textDocument/rename'] = function(_, _, result)
@ -436,7 +436,12 @@ for k, fn in pairs(M) do
})
if err then
return err_message(tostring(err))
-- LSP spec:
-- interface ResponseError:
-- code: integer;
-- message: string;
-- data?: string | number | boolean | array | object | null;
return err_message(tostring(err.code) .. ': ' .. err.message)
end
return fn(err, method, params, client_id, bufnr, config)

View File

@ -17,7 +17,7 @@ local current_log_level = log.levels.WARN
local log_date_format = "%FT%H:%M:%S%z"
do
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
local path_sep = vim.loop.os_uname().version:match("Windows") and "\\" or "/"
--@private
local function path_join(...)
return table.concat(vim.tbl_flatten{...}, path_sep)

View File

@ -1724,7 +1724,7 @@ BYPASS_AU:
void block_autocmds(void)
{
// Remember the value of v:termresponse.
if (is_autocmd_blocked()) {
if (!is_autocmd_blocked()) {
old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
}
autocmd_blocked++;
@ -1737,7 +1737,7 @@ void unblock_autocmds(void)
// When v:termresponse was set while autocommands were blocked, trigger
// the autocommands now. Esp. useful when executing a shell command
// during startup (nvim -d).
if (is_autocmd_blocked()
if (!is_autocmd_blocked()
&& get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) {
apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, false, curbuf);
}

View File

@ -268,7 +268,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
}
ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns;
map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id);
map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark.id);
map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, start_id);
marktree_del_itr(buf->b_marktree, itr, false);
} else {
marktree_itr_next(buf->b_marktree, itr);

View File

@ -676,7 +676,7 @@ void win_set_minimal_style(win_T *wp)
}
// signcolumn: use 'auto'
if (wp->w_p_scl[0] != 'a') {
if (wp->w_p_scl[0] != 'a' || STRLEN(wp->w_p_scl) >= 8) {
xfree(wp->w_p_scl);
wp->w_p_scl = (char_u *)xstrdup("auto");
}
@ -737,6 +737,37 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
redraw_later(wp, NOT_VALID);
}
// compute initial position
if (wp->w_float_config.relative == kFloatRelativeWindow) {
int row = wp->w_float_config.row;
int col = wp->w_float_config.col;
Error dummy = ERROR_INIT;
win_T *parent = find_window_by_handle(wp->w_float_config.window, &dummy);
if (parent) {
row += parent->w_winrow;
col += parent->w_wincol;
ScreenGrid *grid = &parent->w_grid;
int row_off = 0, col_off = 0;
screen_adjust_grid(&grid, &row_off, &col_off);
row += row_off;
col += col_off;
}
api_clear_error(&dummy);
if (wp->w_float_config.bufpos.lnum >= 0) {
pos_T pos = { wp->w_float_config.bufpos.lnum + 1,
wp->w_float_config.bufpos.col, 0 };
int trow, tcol, tcolc, tcole;
textpos2screenpos(wp, &pos, &trow, &tcol, &tcolc, &tcole, true);
row += trow - 1;
col += tcol - 1;
}
wp->w_winrow = row;
wp->w_wincol = col;
} else {
wp->w_winrow = fconfig.row;
wp->w_wincol = fconfig.col;
}
// changing border style while keeping border only requires redrawing border
if (fconfig.border) {
wp->w_redr_border = true;
@ -770,7 +801,6 @@ int win_fdccol_count(win_T *wp)
}
}
void ui_ext_win_position(win_T *wp)
{
if (!wp->w_floating) {
@ -817,6 +847,8 @@ void ui_ext_win_position(win_T *wp)
int comp_row = (int)row - (south ? wp->w_height : 0);
int comp_col = (int)col - (east ? wp->w_width : 0);
comp_row += grid->comp_row;
comp_col += grid->comp_col;
comp_row = MAX(MIN(comp_row, Rows-wp->w_height_outer-1), 0);
comp_col = MAX(MIN(comp_col, Columns-wp->w_width_outer), 0);
wp->w_winrow = comp_row;
@ -2702,7 +2734,11 @@ static win_T *win_free_mem(
// When deleting the current window of another tab page select a new
// current window.
if (tp != NULL && win == tp->tp_curwin) {
tp->tp_curwin = wp;
if (win_valid(tp->tp_prevwin) && tp->tp_prevwin != win) {
tp->tp_curwin = tp->tp_prevwin;
} else {
tp->tp_curwin = tp->tp_firstwin;
}
}
return wp;

View File

@ -346,6 +346,21 @@ describe('API/win', function()
eq(2, #meths.list_wins())
eq('', funcs.getcmdwintype())
end)
it('closing current (float) window of another tabpage #15313', function()
command('tabedit')
eq(2, eval('tabpagenr()'))
local win = meths.open_win(0, true, {
relative='editor', row=10, col=10, width=50, height=10
})
local tabpage = eval('tabpagenr()')
command('tabprevious')
eq(1, eval('tabpagenr()'))
meths.win_close(win, false)
eq(1001, meths.tabpage_get_win(tabpage).id)
helpers.assert_alive()
end)
end)
describe('hide', function()

View File

@ -0,0 +1,25 @@
local helpers = require('test.functional.helpers')(after_each)
local exec_lua = helpers.exec_lua
local eq = helpers.eq
local eval = helpers.eval
local command = helpers.command
local clear = helpers.clear
describe('vim.highlight.on_yank', function()
before_each(function()
clear()
end)
it('does not show errors even if buffer is wiped before timeout', function()
command('new')
exec_lua[[
vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}})
vim.cmd('bwipeout!')
]]
helpers.sleep(10)
helpers.feed('<cr>') -- avoid hang if error message exists
eq('', eval('v:errmsg'))
end)
end)

View File

@ -697,4 +697,50 @@ end]]
|
]]}
end)
it('does not crash when deleting a cleared buffer #15212', function()
exec_lua [[
ns = vim.api.nvim_create_namespace("myplugin")
vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0})
]]
screen:expect{grid=[[
^ a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
exec_lua [[
vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
vim.cmd("bdelete")
]]
screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
helpers.assert_alive()
end)
end)

View File

@ -152,6 +152,132 @@ describe('float window', function()
eq(10, width)
end)
it('opened with correct position', function()
local pos = exec_lua([[
local bufnr = vim.api.nvim_create_buf(false, true)
local opts = {
width = 10,
height = 10,
col = 7,
row = 9,
relative = 'editor',
style = 'minimal'
}
local win_id = vim.api.nvim_open_win(bufnr, false, opts)
return vim.api.nvim_win_get_position(win_id)
]])
eq(9, pos[1])
eq(7, pos[2])
end)
it('opened with correct position relative to the cursor', function()
local pos = exec_lua([[
local bufnr = vim.api.nvim_create_buf(false, true)
local opts = {
width = 10,
height = 10,
col = 7,
row = 9,
relative = 'cursor',
style = 'minimal'
}
local win_id = vim.api.nvim_open_win(bufnr, false, opts)
return vim.api.nvim_win_get_position(win_id)
]])
eq(9, pos[1])
eq(7, pos[2])
end)
it('opened with correct position relative to another window', function()
local pos = exec_lua([[
local bufnr = vim.api.nvim_create_buf(false, true)
local par_opts = {
width = 50,
height = 50,
col = 7,
row = 9,
relative = 'editor',
style = 'minimal'
}
local par_win_id = vim.api.nvim_open_win(bufnr, false, par_opts)
local opts = {
width = 10,
height = 10,
col = 7,
row = 9,
relative = 'win',
style = 'minimal',
win = par_win_id
}
local win_id = vim.api.nvim_open_win(bufnr, false, opts)
return vim.api.nvim_win_get_position(win_id)
]])
eq(18, pos[1])
eq(14, pos[2])
end)
it('opened with correct position relative to another relative window', function()
local pos = exec_lua([[
local bufnr = vim.api.nvim_create_buf(false, true)
local root_opts = {
width = 50,
height = 50,
col = 7,
row = 9,
relative = 'editor',
style = 'minimal'
}
local root_win_id = vim.api.nvim_open_win(bufnr, false, root_opts)
local par_opts = {
width = 20,
height = 20,
col = 2,
row = 3,
relative = 'win',
win = root_win_id,
style = 'minimal'
}
local par_win_id = vim.api.nvim_open_win(bufnr, false, par_opts)
local opts = {
width = 10,
height = 10,
col = 3,
row = 2,
relative = 'win',
win = par_win_id,
style = 'minimal'
}
local win_id = vim.api.nvim_open_win(bufnr, false, opts)
return vim.api.nvim_win_get_position(win_id)
]])
eq(14, pos[1])
eq(12, pos[2])
end)
local function with_ext_multigrid(multigrid)
local screen
before_each(function()
@ -620,6 +746,134 @@ describe('float window', function()
end
end)
it("would not break 'minimal' style with signcolumn=auto:[min]-[max]", function()
command('set number')
command('set signcolumn=auto:1-3')
command('set colorcolumn=1')
command('set cursorline')
command('set foldcolumn=1')
command('hi NormalFloat guibg=#333333')
feed('ix<cr>y<cr><esc>gg')
local win = meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'})
if multigrid then
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[3:----------------------------------------]|
## grid 2
{19: }{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } |
{0:~ }|
{0:~ }|
{0:~ }|
## grid 3
|
## grid 4
{15:x }|
{15:y }|
{15: }|
{15: }|
]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect{grid=[[
{19: }{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } {15:x } |
{0:~ }{15:y }{0: }|
{0:~ }{15: }{0: }|
{0:~ }{15: }{0: }|
|
]]}
end
command('sign define piet1 text=𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄ texthl=Search')
command('sign place 1 line=1 name=piet1 buffer=1')
-- signcolumn=auto:1-3 still works if there actually are signs
if multigrid then
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[3:----------------------------------------]|
## grid 2
{19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } |
{0:~ }|
{0:~ }|
{0:~ }|
## grid 3
|
## grid 4
{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
{19: }{15:y }|
{19: }{15: }|
{15: }|
]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect([[
{19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } |
{0:~ }{19: }{15:y }{0: }|
{0:~ }{19: }{15: }{0: }|
{0:~ }{15: }{0: }|
|
]])
end
command('sign unplace 1 buffer=1')
local buf = meths.create_buf(false, true)
meths.win_set_buf(win, buf)
if multigrid then
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
[3:----------------------------------------]|
## grid 2
{19: }{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } |
{0:~ }|
{0:~ }|
{0:~ }|
## grid 3
|
## grid 4
{15: }|
{15: }|
{15: }|
{15: }|
]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect([[
{19: }{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } {15: } |
{0:~ }{15: }{0: }|
{0:~ }{15: }{0: }|
{0:~ }{15: }{0: }|
|
]])
end
end)
it('can have border', function()
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',