mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 12:52:13 +00:00
fix(ui): only internal messages are unsafe #37462
Problem: Fast context for msg_show event inhibits vim.ui_attach from
displaying a stream of messages from a single command.
Solution: Remove fast context from msg_show events emitted as a result
of explicit API/command calls. The fast context was originally
introduced to prevent issues with internal messages.
This commit is contained in:
@@ -801,8 +801,9 @@ vim.ui_attach({ns}, {opts}, {callback}) *vim.ui_attach()*
|
||||
|ui-popupmenu| and the sections below for event format for respective
|
||||
events.
|
||||
|
||||
Callbacks for `msg_show` events are executed in |api-fast| context;
|
||||
showing the message should be scheduled.
|
||||
Callbacks for `msg_show` events originating from internal messages (as
|
||||
opposed to events from commands or API calls) are executed in |api-fast|
|
||||
context; showing the message needs to be scheduled.
|
||||
|
||||
Excessive errors inside the callback will result in forced detachment.
|
||||
|
||||
|
||||
@@ -38,17 +38,19 @@ ext.msg = require('vim._extui.messages')
|
||||
ext.cmd = require('vim._extui.cmdline')
|
||||
local M = {}
|
||||
|
||||
local function ui_callback(event, ...)
|
||||
local function ui_callback(redraw_msg, event, ...)
|
||||
local handler = ext.msg[event] or ext.cmd[event]
|
||||
ext.check_targets()
|
||||
handler(...)
|
||||
-- Cmdline mode and non-empty showcmd requires an immediate redraw.
|
||||
if ext.cmd[event] or event == 'msg_showcmd' and select(1, ...)[1] then
|
||||
-- Cmdline mode, non-fast message and non-empty showcmd require an immediate redraw.
|
||||
if ext.cmd[event] or redraw_msg or (event == 'msg_showcmd' and select(1, ...)[1]) then
|
||||
ext.redrawing = true
|
||||
api.nvim__redraw({
|
||||
flush = handler ~= ext.cmd.cmdline_hide or nil,
|
||||
cursor = handler == ext.cmd[event] and true or nil,
|
||||
win = handler == ext.cmd[event] and ext.wins.cmd or nil,
|
||||
})
|
||||
ext.redrawing = false
|
||||
end
|
||||
end
|
||||
local scheduled_ui_callback = vim.schedule_wrap(ui_callback)
|
||||
@@ -86,10 +88,11 @@ function M.enable(opts)
|
||||
if not (ext.msg[event] or ext.cmd[event]) then
|
||||
return
|
||||
end
|
||||
if vim.in_fast_event() then
|
||||
scheduled_ui_callback(event, ...)
|
||||
-- Ensure cmdline is placed after a scheduled message in block mode.
|
||||
if vim.in_fast_event() or (event == 'cmdline_show' and ext.cmd.srow > 0) then
|
||||
scheduled_ui_callback(false, event, ...)
|
||||
else
|
||||
ui_callback(event, ...)
|
||||
ui_callback(event == 'msg_show', event, ...)
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
@@ -37,6 +37,13 @@ local M = {
|
||||
on_dialog_key = 0, -- vim.on_key namespace for paging in the dialog window.
|
||||
}
|
||||
|
||||
-- An external redraw indicates the start of a new batch of messages in the cmdline.
|
||||
api.nvim_set_decoration_provider(ext.ns, {
|
||||
on_start = function()
|
||||
M.cmd.count = ext.redrawing and M.cmd.count or 0
|
||||
end,
|
||||
})
|
||||
|
||||
function M.msg:close()
|
||||
self.width, M.virt.msg[M.virt.idx.dupe][1] = 1, nil
|
||||
M.prev_msg = ext.cfg.msg.target == 'msg' and '' or M.prev_msg
|
||||
@@ -182,53 +189,46 @@ end
|
||||
|
||||
-- We need to keep track of the current message column to be able to
|
||||
-- append or overwrite messages for :echon or carriage returns.
|
||||
local col, will_full, hlopts = 0, false, { undo_restore = false, invalidate = true, priority = 1 }
|
||||
local col, hlopts = 0, { undo_restore = false, invalidate = true, priority = 1 }
|
||||
|
||||
--- Move messages to cmdline or pager to show in full.
|
||||
local function msg_to_full(src)
|
||||
if will_full then
|
||||
return
|
||||
end
|
||||
will_full, M.prev_msg = true, ''
|
||||
|
||||
vim.schedule(function()
|
||||
-- Copy and clear message from src to enlarged cmdline that is dismissed by any
|
||||
-- key press, or append to pager in case that is already open (not hidden).
|
||||
local hidden = api.nvim_win_get_config(ext.wins.pager).hide
|
||||
local tar = hidden and 'cmd' or 'pager'
|
||||
if tar ~= src then
|
||||
local srow = hidden and 0 or api.nvim_buf_line_count(ext.bufs.pager)
|
||||
local marks = api.nvim_buf_get_extmarks(ext.bufs[src], -1, 0, -1, { details = true })
|
||||
local lines = api.nvim_buf_get_lines(ext.bufs[src], 0, -1, false)
|
||||
api.nvim_buf_set_lines(ext.bufs[src], 0, -1, false, {})
|
||||
api.nvim_buf_set_lines(ext.bufs[tar], srow, -1, false, lines)
|
||||
for _, mark in ipairs(marks) do
|
||||
hlopts.end_col, hlopts.hl_group = mark[4].end_col, mark[4].hl_group
|
||||
api.nvim_buf_set_extmark(ext.bufs[tar], ext.ns, srow + mark[2], mark[3], hlopts)
|
||||
end
|
||||
if tar == 'cmd' and ext.cmd.highlighter then
|
||||
ext.cmd.highlighter.active[ext.bufs.cmd] = nil
|
||||
elseif tar == 'pager' then
|
||||
api.nvim_command('norm! G')
|
||||
end
|
||||
M.virt.msg[M.virt.idx.spill][1] = nil
|
||||
else
|
||||
for _, id in pairs(M.virt.ids) do
|
||||
api.nvim_buf_del_extmark(ext.bufs.cmd, ext.ns, id)
|
||||
end
|
||||
-- Copy and clear message from src to enlarged cmdline that is dismissed by any
|
||||
-- key press, or append to pager in case that is already open (not hidden).
|
||||
local hidden = api.nvim_win_get_config(ext.wins.pager).hide
|
||||
local tar = hidden and 'cmd' or 'pager'
|
||||
if tar ~= src then
|
||||
local srow = hidden and 0 or api.nvim_buf_line_count(ext.bufs.pager)
|
||||
local marks = api.nvim_buf_get_extmarks(ext.bufs[src], -1, 0, -1, { details = true })
|
||||
local lines = api.nvim_buf_get_lines(ext.bufs[src], 0, -1, false)
|
||||
api.nvim_buf_set_lines(ext.bufs[src], 0, -1, false, {})
|
||||
api.nvim_buf_set_lines(ext.bufs[tar], srow, -1, false, lines)
|
||||
for _, mark in ipairs(marks) do
|
||||
hlopts.end_col, hlopts.hl_group = mark[4].end_col, mark[4].hl_group
|
||||
api.nvim_buf_set_extmark(ext.bufs[tar], ext.ns, srow + mark[2], mark[3], hlopts)
|
||||
end
|
||||
M.msg:close()
|
||||
M.set_pos(tar)
|
||||
M[src].count, col, will_full = 0, 0, false
|
||||
end)
|
||||
if tar == 'cmd' and ext.cmd.highlighter then
|
||||
ext.cmd.highlighter.active[ext.bufs.cmd] = nil
|
||||
elseif tar == 'pager' then
|
||||
api.nvim_command('norm! G')
|
||||
end
|
||||
M[src].count = 0
|
||||
M.virt.msg[M.virt.idx.spill][1] = nil
|
||||
else
|
||||
for _, id in pairs(M.virt.ids) do
|
||||
api.nvim_buf_del_extmark(ext.bufs.cmd, ext.ns, id)
|
||||
end
|
||||
end
|
||||
M.set_pos(tar)
|
||||
end
|
||||
|
||||
local reset_timer ---@type uv.uv_timer_t?
|
||||
---@param tar 'cmd'|'dialog'|'msg'|'pager'
|
||||
---@param content MsgContent
|
||||
---@param replace_last boolean
|
||||
---@param append boolean
|
||||
function M.show_msg(tar, content, replace_last, append)
|
||||
local msg, restart, cr, dupe, count = '', false, false, 0, 0
|
||||
append = append and col > 0
|
||||
|
||||
if M[tar] then -- tar == 'cmd'|'msg'
|
||||
if tar == ext.cfg.msg.target then
|
||||
@@ -244,7 +244,7 @@ function M.show_msg(tar, content, replace_last, append)
|
||||
count = M[tar].count + ((restart or msg == '\n') and 0 or 1)
|
||||
|
||||
-- Ensure cmdline is clear when writing the first message.
|
||||
if tar == 'cmd' and not will_full and dupe == 0 and M.cmd.count == 0 and ext.cmd.srow == 0 then
|
||||
if tar == 'cmd' and dupe == 0 and M.cmd.count == 0 and ext.cmd.srow == 0 then
|
||||
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
||||
end
|
||||
end
|
||||
@@ -257,7 +257,7 @@ function M.show_msg(tar, content, replace_last, append)
|
||||
local line_count = api.nvim_buf_line_count(ext.bufs[tar])
|
||||
---@type integer Start row after last line in the target buffer, unless
|
||||
---this is the first message, or in case of a repeated or replaced message.
|
||||
local row = M[tar] and count <= 1 and not will_full and (tar == 'cmd' and ext.cmd.erow or 0)
|
||||
local row = M[tar] and count <= 1 and ext.cmd.srow == 0 and 0
|
||||
or line_count - ((replace_last or restart or cr or append) and 1 or 0)
|
||||
local curline = (cr or append) and api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1]
|
||||
local start_row, width = row, M.msg.width
|
||||
@@ -298,7 +298,6 @@ function M.show_msg(tar, content, replace_last, append)
|
||||
local texth = api.nvim_win_text_height(ext.wins.msg, { start_row = start_row })
|
||||
if texth.all > math.ceil(o.lines * 0.5) then
|
||||
msg_to_full(tar)
|
||||
return
|
||||
end
|
||||
|
||||
M.set_pos('msg')
|
||||
@@ -314,10 +313,8 @@ function M.show_msg(tar, content, replace_last, append)
|
||||
fn.clearmatches(ext.wins.cmd) -- Clear matchparen highlights.
|
||||
if ext.cmd.srow > 0 then
|
||||
-- In block mode the cmdheight is already dynamic, so just print the full message
|
||||
-- regardless of height. Spoof cmdline_show to put cmdline below message.
|
||||
ext.cmd.srow = ext.cmd.srow + 1 + row - start_row
|
||||
ext.cmd.cmdline_show({}, 0, ':', '', ext.cmd.indent, 0, 0)
|
||||
api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd })
|
||||
-- regardless of height. Put cmdline below message.
|
||||
ext.cmd.srow = row + 1
|
||||
else
|
||||
api.nvim_win_set_cursor(ext.wins.cmd, { 1, 0 }) -- ensure first line is visible
|
||||
if ext.cmd.highlighter then
|
||||
@@ -331,7 +328,6 @@ function M.show_msg(tar, content, replace_last, append)
|
||||
|
||||
if texth.all > ext.cmdheight then
|
||||
msg_to_full(tar)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -345,10 +341,10 @@ function M.show_msg(tar, content, replace_last, append)
|
||||
end
|
||||
|
||||
-- Reset message state the next event loop iteration.
|
||||
if start_row == 0 or ext.cmd.srow > 0 then
|
||||
vim.schedule(function()
|
||||
col, M.cmd.count = 0, 0
|
||||
end)
|
||||
if not reset_timer and (col > 0 or M.cmd.count > 0) then
|
||||
reset_timer = vim.defer_fn(function()
|
||||
reset_timer, col, M.cmd.count = nil, 0, 0
|
||||
end, 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -452,9 +448,14 @@ function M.msg_history_show(entries, prev_cmd)
|
||||
return
|
||||
end
|
||||
|
||||
if prev_cmd then
|
||||
M.msg_clear() -- Showing output of previous command, clear in case still visible.
|
||||
if cmd_on_key then
|
||||
-- Dismiss a still open full message cmd window.
|
||||
api.nvim_feedkeys(vim.keycode('<CR>'), 'n', false)
|
||||
elseif prev_cmd then
|
||||
-- Showing output of previous command, clear in case still visible.
|
||||
M.msg_clear()
|
||||
end
|
||||
|
||||
api.nvim_buf_set_lines(ext.bufs.pager, 0, -1, false, {})
|
||||
for i, entry in ipairs(entries) do
|
||||
M.show_msg('pager', entry[2], i == 1, entry[3])
|
||||
@@ -483,7 +484,7 @@ function M.set_pos(type)
|
||||
}
|
||||
api.nvim_win_set_config(win, config)
|
||||
|
||||
if type == 'cmd' then
|
||||
if type == 'cmd' and not cmd_on_key then
|
||||
-- Temporarily showing a full message in the cmdline, until next key press.
|
||||
local save_spill = M.virt.msg[M.virt.idx.spill][1]
|
||||
local spill = texth.all > height and (' [+%d]'):format(texth.all - height)
|
||||
|
||||
@@ -5,6 +5,7 @@ local M = {
|
||||
ns = api.nvim_create_namespace('nvim._ext_ui'),
|
||||
augroup = api.nvim_create_augroup('nvim._ext_ui', {}),
|
||||
cmdheight = vim.o.cmdheight, -- 'cmdheight' option value set by user.
|
||||
redrawing = false, -- True when redrawing to display UI event.
|
||||
wins = { cmd = -1, dialog = -1, msg = -1, pager = -1 },
|
||||
bufs = { cmd = -1, dialog = -1, msg = -1, pager = -1 },
|
||||
cfg = {
|
||||
|
||||
@@ -227,8 +227,9 @@ function vim.wait(time, callback, interval, fast_only) end
|
||||
--- {callback} receives event name plus additional parameters. See |ui-popupmenu|
|
||||
--- and the sections below for event format for respective events.
|
||||
---
|
||||
--- Callbacks for `msg_show` events are executed in |api-fast| context; showing
|
||||
--- the message should be scheduled.
|
||||
--- Callbacks for `msg_show` events originating from internal messages (as
|
||||
--- opposed to events from commands or API calls) are executed in |api-fast|
|
||||
--- context; showing the message needs to be scheduled.
|
||||
---
|
||||
--- Excessive errors inside the callback will result in forced detachment.
|
||||
---
|
||||
|
||||
@@ -383,10 +383,6 @@ local function progress_report(len)
|
||||
-- percent=0 omits the reporting of percentage, so use 1% instead
|
||||
-- progress.percent = progress.percent == 0 and 1 or progress.percent
|
||||
progress.id = vim.api.nvim_echo({ { fmt:format(...) } }, false, progress)
|
||||
-- extui/ui2 shows all messages at once after the healthchecks are finished.
|
||||
-- This 1ms wait ensures the messages are shown separately
|
||||
vim.wait(1)
|
||||
vim.cmd.redraw()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ for i = 1, #events do
|
||||
call_output:write(' }\n')
|
||||
call_output:write(' entered = true;\n')
|
||||
write_arglist(call_output, ev)
|
||||
call_output:write((' ui_call_event("%s", %s, %s)'):format(ev.name, tostring(ev.fast), args))
|
||||
call_output:write((' ui_call_event("%s", %s)'):format(ev.name, args))
|
||||
call_output:write(';\n entered = false;\n')
|
||||
elseif ev.compositor_impl then
|
||||
call_output:write(' ui_comp_' .. ev.name)
|
||||
|
||||
@@ -166,7 +166,7 @@ void wildmenu_hide(void)
|
||||
|
||||
void msg_show(String kind, Array content, Boolean replace_last, Boolean history, Boolean append,
|
||||
Object id)
|
||||
FUNC_API_SINCE(6) FUNC_API_FAST FUNC_API_REMOTE_ONLY;
|
||||
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
|
||||
void msg_clear(void)
|
||||
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
|
||||
void msg_showcmd(Array content)
|
||||
|
||||
@@ -741,8 +741,26 @@ static void ui_attach_error(uint32_t ns_id, const char *name, const char *msg)
|
||||
msg_schedule_semsg_multiline("Error in \"%s\" UI event handler (ns=%s):\n%s", name, ns, msg);
|
||||
}
|
||||
|
||||
void ui_call_event(char *name, bool fast, Array args)
|
||||
void ui_call_event(char *name, Array args)
|
||||
{
|
||||
// Internal messages are considered unsafe and are executed in fast context.
|
||||
bool fast = strcmp(name, "msg_show") == 0;
|
||||
const char *not_fast[] = {
|
||||
"empty",
|
||||
"echo",
|
||||
"echomsg",
|
||||
"echoerr",
|
||||
"list_cmd",
|
||||
"lua_error",
|
||||
"lua_print",
|
||||
"progress",
|
||||
NULL,
|
||||
};
|
||||
|
||||
for (int i = 0; fast && not_fast[i]; i++) {
|
||||
fast = !strequal(not_fast[i], args.items[0].data.string.data);
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
UIEventCallback *event_cb;
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ describe('vim.ui_attach', function()
|
||||
exec_lua([[
|
||||
vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function(ev)
|
||||
if ev == 'msg_show' then
|
||||
vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] })
|
||||
error('foo')
|
||||
end
|
||||
end)
|
||||
]])
|
||||
@@ -437,10 +437,13 @@ describe('vim.ui_attach', function()
|
||||
screen:expect({
|
||||
grid = [[
|
||||
|
|
||||
{1:~ }|*5
|
||||
{1:~ }|*2
|
||||
{3: }|
|
||||
{9:Error in "msg_show" UI event handler (ns=(UNKNOWN PLUGIN)):} |
|
||||
{9:fast context failure} |
|
||||
{9:Lua callback:} |
|
||||
{9:[string "<nvim>"]:3: foo} |
|
||||
{9:stack traceback:} |
|
||||
{9: [C]: in function 'error'} |
|
||||
{9: [string "<nvim>"]:3: in function <[string "<nvim>"]:1>} |
|
||||
{100:Press ENTER or type command to continue}^ |
|
||||
]],
|
||||
condition = function()
|
||||
@@ -448,17 +451,12 @@ describe('vim.ui_attach', function()
|
||||
end,
|
||||
})
|
||||
feed('<Esc>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*8
|
||||
|
|
||||
]])
|
||||
|
||||
-- Also when scheduled
|
||||
exec_lua([[
|
||||
vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function(ev)
|
||||
if ev == 'msg_show' then
|
||||
vim.schedule(function() vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] }) end)
|
||||
vim.schedule(function() error('foo') end)
|
||||
end
|
||||
end)
|
||||
]])
|
||||
|
||||
@@ -64,7 +64,14 @@ describe('cmdline2', function()
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} ^ |
|
||||
]])
|
||||
feed('echo "foo"<CR>')
|
||||
feed('echo "foo"')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*11
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} {15:echo} {26:"foo"}^ |
|
||||
]])
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
@@ -73,13 +80,52 @@ describe('cmdline2', function()
|
||||
{15:foo} |
|
||||
{16::} ^ |
|
||||
]])
|
||||
feed('endif')
|
||||
feed([[echo input("foo\nbar:")<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
{1:~ }|*7
|
||||
:if 1 |
|
||||
: echo "foo" |
|
||||
foo |
|
||||
: echo input("foo\nbar:") |
|
||||
foo |
|
||||
bar:^ |
|
||||
]])
|
||||
feed('baz')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*7
|
||||
:if 1 |
|
||||
: echo "foo" |
|
||||
foo |
|
||||
: echo input("foo\nbar:") |
|
||||
foo |
|
||||
bar:baz^ |
|
||||
]])
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*5
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} {15:echo} {26:"foo"} |
|
||||
{15:foo} |
|
||||
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||
{15:foo} |
|
||||
{15:bar}:baz |
|
||||
{15:baz} |
|
||||
{16::} ^ |
|
||||
]])
|
||||
feed('endif')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*5
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} {15:echo} {26:"foo"} |
|
||||
{15:foo} |
|
||||
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||
{15:foo} |
|
||||
{15:bar}:baz |
|
||||
{15:baz} |
|
||||
{16::} {15:endif}^ |
|
||||
]])
|
||||
feed('<CR>')
|
||||
|
||||
@@ -148,6 +148,19 @@ describe('messages2', function()
|
||||
{1:~ }|*12
|
||||
|
|
||||
]])
|
||||
-- A redraw indicates the start of messages in the cmdline, which empty should clear.
|
||||
command('echo "foo" | redraw | echo "bar"')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*12
|
||||
bar |
|
||||
]])
|
||||
command('echo "foo" | redraw | echo ""')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*12
|
||||
|
|
||||
]])
|
||||
command('set cmdheight=0')
|
||||
command('echo "foo"')
|
||||
screen:expect([[
|
||||
@@ -365,61 +378,6 @@ describe('messages2', function()
|
||||
screen:expect(top)
|
||||
end)
|
||||
|
||||
it('in cmdline_block mode', function()
|
||||
feed(':if 1<CR>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*11
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} ^ |
|
||||
]])
|
||||
feed([[echo input("foo\nbar:")<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
:if 1 |
|
||||
: echo input("foo\nbar:") |
|
||||
foo |
|
||||
bar:^ |
|
||||
]])
|
||||
feed('baz<CR>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||
{15:baz} |
|
||||
{16::} ^ |
|
||||
]])
|
||||
feed([[echo input("foo\nbar:")<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*7
|
||||
:if 1 |
|
||||
: echo input("foo\nbar:") |
|
||||
baz |
|
||||
: echo input("foo\nbar:") |
|
||||
foo |
|
||||
bar:^ |
|
||||
]])
|
||||
feed('<Esc>:endif')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*8
|
||||
{16::}{15:if} {26:1} |
|
||||
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||
{15:baz} |
|
||||
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||
{16::} {16::}{15:endif}^ |
|
||||
]])
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*12
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('FileType is fired after default options are set', function()
|
||||
n.exec([[
|
||||
let g:set = {}
|
||||
@@ -430,13 +388,12 @@ describe('messages2', function()
|
||||
]])
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
{1:~ }|*10
|
||||
{3: }|
|
||||
^foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo|
|
||||
{1: }|
|
||||
foofoofoofoofoofoofoofoofo^o |
|
||||
|
|
||||
]])
|
||||
t.eq({ filetype = 4 }, n.eval('g:set')) -- still fires for 'filetype'
|
||||
t.eq({ filetype = 5 }, n.eval('g:set')) -- still fires for 'filetype'
|
||||
end)
|
||||
|
||||
it('Search highlights only apply to pager', function()
|
||||
@@ -467,4 +424,57 @@ describe('messages2', function()
|
||||
{101:fo^o}{100: }|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('shows message from still running command', function()
|
||||
exec_lua(function()
|
||||
vim.schedule(function()
|
||||
print('foo')
|
||||
vim.uv.sleep(100)
|
||||
print('bar')
|
||||
end)
|
||||
end)
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*12
|
||||
foo |
|
||||
]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*10
|
||||
{3: }|
|
||||
foo |
|
||||
bar |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('properly formatted carriage return messages', function()
|
||||
screen:try_resize(screen._width, 20)
|
||||
command([[echon "\r" | echon "Hello" | echon " " | echon "World"]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*18
|
||||
Hello World |
|
||||
]])
|
||||
exec_lua(function()
|
||||
vim.api.nvim_echo({ { 'fooo\nbarbaz\n\nlol', 'statement' }, { '\rbar' } }, true, {})
|
||||
vim.api.nvim_echo({ { 'foooooooo', 'statement' }, { 'baz\rb', 'error' } }, true, {})
|
||||
vim.api.nvim_echo({ { 'fooobar', 'statement' }, { '\rbaz\n' } }, true, {})
|
||||
vim.api.nvim_echo({ { 'fooobar', 'statement' }, { '\rbaz\rb', 'error' } }, true, {})
|
||||
vim.api.nvim_echo({ { 'fooo\rbar', 'statement' }, { 'baz', 'error' } }, true, {})
|
||||
end)
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*9
|
||||
{3: }|
|
||||
{15:fooo} |
|
||||
{15:barbaz} |
|
||||
|
|
||||
bar |
|
||||
{9:b}{15:oooooooo}{9:baz} |
|
||||
baz{15:obar} |
|
||||
|
|
||||
{9:baz}{15:obar} |
|
||||
{15:bar}{9:baz} |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user