aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/api/vim_spec.lua5
-rw-r--r--test/functional/ui/messages_spec.lua632
-rw-r--r--test/functional/ui/options_spec.lua1
-rw-r--r--test/functional/ui/screen.lua55
4 files changed, 688 insertions, 5 deletions
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 5c0fb8f88d..7d99f9725c 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1277,8 +1277,9 @@ describe('API', function()
ext_wildmenu = false,
ext_linegrid = screen._options.ext_linegrid or false,
ext_multigrid = false,
- ext_hlstate=false,
- ext_termcolors=false,
+ ext_hlstate = false,
+ ext_termcolors = false,
+ ext_messages = false,
height = 4,
rgb = true,
width = 20,
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
new file mode 100644
index 0000000000..388c6b3e95
--- /dev/null
+++ b/test/functional/ui/messages_spec.lua
@@ -0,0 +1,632 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, feed = helpers.clear, helpers.feed
+local eval = helpers.eval
+local eq = helpers.eq
+local command = helpers.command
+
+
+describe('ui/ext_messages', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach({rgb=true, ext_messages=true, ext_popupmenu=true})
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [3] = {bold = true},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {foreground = Screen.colors.Blue1},
+ [6] = {bold = true, reverse = true},
+ })
+ end)
+
+ it('supports :echoerr', function()
+ feed(':echoerr "raa"<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{"raa", 2}},
+ kind = "echoerr",
+ }}}
+
+ -- cmdline in a later input cycle clears error message
+ feed(':')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], cmdline={{
+ firstc = ":",
+ content = {{ "" }},
+ pos = 0,
+ }}}
+
+
+ feed('echoerr "bork" | echoerr "fail"<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "bork", 2 }},
+ kind = "echoerr"
+ }, {
+ content = {{ "fail", 2 }},
+ kind = "echoerr"
+ }, {
+ content = {{ "Press ENTER or type command to continue", 4 }},
+ kind = "return_prompt"
+ }}}
+
+ feed(':echoerr "extrafail"<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = { { "bork", 2 } },
+ kind = "echoerr"
+ }, {
+ content = { { "fail", 2 } },
+ kind = "echoerr"
+ }, {
+ content = { { "extrafail", 2 } },
+ kind = "echoerr"
+ }, {
+ content = { { "Press ENTER or type command to continue", 4 } },
+ kind = "return_prompt"
+ }}}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+
+ -- cmdline without interleaving wait/display keeps the error message
+ feed(':echoerr "problem" | let x = input("foo> ")<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "problem", 2 }},
+ kind = "echoerr"
+ }}, cmdline={{
+ prompt = "foo> ",
+ content = {{ "" }},
+ pos = 0,
+ }}}
+
+ feed('solution<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+ eq('solution', eval('x'))
+
+ feed(":messages<cr>")
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {kind="echoerr", content={{"raa", 2}}},
+ {kind="echoerr", content={{"bork", 2}}},
+ {kind="echoerr", content={{"fail", 2}}},
+ {kind="echoerr", content={{"extrafail", 2}}},
+ {kind="echoerr", content={{"problem", 2}}}
+ }}
+ end)
+
+ it('supports showmode', function()
+ command('imap <f2> <cmd>echomsg "stuff"<cr>')
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={{"-- INSERT --", 3}}}
+
+ feed('alphpabet<cr>alphanum<cr>')
+ screen:expect{grid=[[
+ alphpabet |
+ alphanum |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "-- INSERT --", 3 } }}
+
+ feed('<c-x>')
+ screen:expect{grid=[[
+ alphpabet |
+ alphanum |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)", 3 } }}
+
+ feed('<c-p>')
+ screen:expect{grid=[[
+ alphpabet |
+ alphanum |
+ alphanum^ |
+ {1:~ }|
+ {1:~ }|
+ ]], popupmenu={
+ anchor = { 2, 0 },
+ items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } },
+ pos = 1
+ }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 1 of 2", 4 } }}
+
+ -- echomsg and showmode don't overwrite each other, this is the same
+ -- as the TUI behavior with cmdheight=2 or larger.
+ feed('<f2>')
+ screen:expect{grid=[[
+ alphpabet |
+ alphanum |
+ alphanum^ |
+ {1:~ }|
+ {1:~ }|
+ ]], popupmenu={
+ anchor = { 2, 0 },
+ items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } },
+ pos = 1
+ }, messages={ {
+ content = { { "stuff" } },
+ kind = "echomsg"
+ } }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 1 of 2", 4 } }}
+
+ feed('<c-p>')
+ screen:expect{grid=[[
+ alphpabet |
+ alphanum |
+ alphpabet^ |
+ {1:~ }|
+ {1:~ }|
+ ]], popupmenu={
+ anchor = { 2, 0 },
+ items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } },
+ pos = 0
+ }, messages={ {
+ content = { { "stuff" } },
+ kind = "echomsg"
+ } }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 2 of 2", 4 } }}
+
+ feed("<esc>:messages<cr>")
+ screen:expect{grid=[[
+ alphpabet |
+ alphanum |
+ alphpabe^t |
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {kind="echomsg", content={{"stuff"}}},
+ }}
+ end)
+
+ it('supports showmode with recording message', function()
+ feed('qq')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "recording @q", 3 } }}
+
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "-- INSERT --recording @q", 3 } }}
+
+ feed('<esc>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "recording @q", 3 } }}
+
+ feed('q')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ end)
+
+ it('shows recording message with noshowmode', function()
+ command("set noshowmode")
+ feed('qq')
+ -- also check mode to avoid immediate success
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "recording @q", 3 } }, mode="normal"}
+
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "recording @q", 3 } }, mode="insert"}
+
+ feed('<esc>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "recording @q", 3 } }, mode="normal"}
+
+ feed('q')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], mode="normal"}
+ end)
+
+ it('supports showcmd and ruler', function()
+ command('set showcmd ruler')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], ruler={ { "0,0-1 All" } }}
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showmode={ { "-- INSERT --", 3 } }, ruler={ { "0,1 All" } }}
+ feed('abcde<cr>12345<esc>')
+ screen:expect{grid=[[
+ abcde |
+ 1234^5 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], ruler={ { "2,5 All" } }}
+ feed('d')
+ screen:expect{grid=[[
+ abcde |
+ 1234^5 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showcmd={ { "d" } }, ruler={ { "2,5 All" } }}
+ feed('<esc>^')
+ screen:expect{grid=[[
+ abcde |
+ ^12345 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], ruler={ { "2,1 All" } }}
+ feed('d')
+ screen:expect{grid=[[
+ abcde |
+ ^12345 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showcmd={ { "d" } }, ruler={ { "2,1 All" } }}
+ feed('i')
+ screen:expect{grid=[[
+ abcde |
+ ^12345 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], showcmd={ { "di" } }, ruler={ { "2,1 All" } }}
+ feed('w')
+ screen:expect{grid=[[
+ abcde |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], ruler={ { "2,0-1 All" } }}
+
+ -- when ruler is part of statusline it is not externalized.
+ -- this will be added as part of future ext_statusline support
+ command("set laststatus=2")
+ screen:expect([[
+ abcde |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {6:<o Name] [+] 2,0-1 All}|
+ ]])
+ end)
+
+ it('keeps history of message of different kinds', function()
+ feed(':echomsg "howdy"<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "howdy" }}, kind = "echomsg"}
+ }}
+
+ -- always test a message without kind. If this one gets promoted to a
+ -- category, add a new message without kind.
+ feed('<c-c>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "Type :qa! and press <Enter> to abandon all changes and exit Nvim" }},
+ kind = ""}
+ }}
+
+ feed(':echoerr "bork"<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "bork", 2 }}, kind = "echoerr"}
+ }}
+
+ feed(':echo "xyz"<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "xyz" }}, kind = "echo"}
+ }}
+
+ feed(':call nosuchfunction()<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{ "E117: Unknown function: nosuchfunction", 2 }},
+ kind = "emsg"}
+ }}
+
+ feed(':messages<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {kind="echomsg", content={{"howdy"}}},
+ {kind="", content={{"Type :qa! and press <Enter> to abandon all changes and exit Nvim"}}},
+ {kind="echoerr", content={{"bork", 2}}},
+ {kind="emsg", content={{"E117: Unknown function: nosuchfunction", 2}}}
+ }}
+ end)
+
+ it('implies ext_cmdline and ignores cmdheight', function()
+ eq(0, eval('&cmdheight'))
+ feed(':set cmdheight=1')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], cmdline={{
+ content = { { "set cmdheight=1" } },
+ firstc = ":",
+ pos = 15 }
+ }}
+
+ feed('<cr>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ eq(0, eval('&cmdheight'))
+
+ -- normally this would be an error
+ feed(':set cmdheight=0')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], cmdline={{
+ content = { { "set cmdheight=0" } },
+ firstc = ":",
+ pos = 15 }
+ }}
+ feed('<cr>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ eq(0, eval('&cmdheight'))
+ end)
+
+ it('supports multiline messages', function()
+ feed(':lua error("such\\nmultiline\\nerror")<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={{
+ content = {{'E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: such\nmultiline\nerror', 2}},
+ kind = "emsg"
+ }}}
+ end)
+end)
+
+describe('ui/ext_messages', function()
+ local screen
+
+ before_each(function()
+ clear{headless=false, args={"--cmd", "set shortmess-=I"}}
+ screen = Screen.new(80, 24)
+ screen:attach({rgb=true, ext_messages=true, ext_popupmenu=true})
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [3] = {bold = true},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {foreground = Screen.colors.Blue1},
+ })
+ end)
+
+ it('supports intro screen', function()
+ -- intro message is not externalized. But check that it still works.
+ -- Note parts of it depends on version or is indeterministic. We ignore those parts.
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {IGNORE}|
+ {1:~ }|
+ {1:~ }Nvim is open source and freely distributable{1: }|
+ {1:~ }https://neovim.io/#chat{1: }|
+ {1:~ }|
+ {1:~ }type :help nvim{5:<Enter>} if you are new! {1: }|
+ {1:~ }type :checkhealth{5:<Enter>} to optimize Nvim{1: }|
+ {1:~ }type :q{5:<Enter>} to exit {1: }|
+ {1:~ }type :help{5:<Enter>} for help {1: }|
+ {1:~ }|
+ {IGNORE}|
+ {IGNORE}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ feed("<c-l>")
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ feed(":intro<cr>")
+ screen:expect{grid=[[
+ |
+ |
+ |
+ |
+ |
+ |
+ {IGNORE}|
+ |
+ Nvim is open source and freely distributable |
+ https://neovim.io/#chat |
+ |
+ type :help nvim{5:<Enter>} if you are new! |
+ type :checkhealth{5:<Enter>} to optimize Nvim |
+ type :q{5:<Enter>} to exit |
+ type :help{5:<Enter>} for help |
+ |
+ {IGNORE}|
+ {IGNORE}|
+ |
+ |
+ |
+ |
+ |
+ |
+ ]], messages={
+ {content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" }
+ }}
+ end)
+end)
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 966669fa95..ed630259be 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -28,6 +28,7 @@ describe('ui receives option updates', function()
ext_linegrid=false,
ext_hlstate=false,
ext_multigrid=false,
+ ext_messages=false,
ext_termcolors=false,
}
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 038bf48839..2eae549ebd 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -159,6 +159,11 @@ function Screen.new(width, height)
wildmenu_selected = nil,
win_position = {},
_session = nil,
+ messages = {},
+ msg_history = {},
+ showmode = {},
+ showcmd = {},
+ ruler = {},
_default_attr_ids = nil,
_default_attr_ignore = nil,
_mouse_enabled = true,
@@ -250,7 +255,8 @@ end
-- canonical order of ext keys, used to generate asserts
local ext_keys = {
- 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos'
+ 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos',
+ 'messages', 'showmode', 'showcmd', 'ruler',
}
-- Asserts that the screen state eventually matches an expected state
@@ -392,7 +398,7 @@ function Screen:expect(expected, attr_ids, attr_ignore)
.. ') differs from configured height(' .. #actual_rows .. ') of Screen.'
end
for i = 1, #actual_rows do
- if expected_rows[i] ~= actual_rows[i] then
+ if expected_rows[i] ~= actual_rows[i] and expected_rows[i] ~= "{IGNORE}|" then
local msg_expected_rows = {}
for j = 1, #expected_rows do
msg_expected_rows[j] = expected_rows[j]
@@ -917,7 +923,7 @@ function Screen:_handle_option_set(name, value)
end
function Screen:_handle_popupmenu_show(items, selected, row, col)
- self.popupmenu = {items=items,pos=selected, anchor={row, col}}
+ self.popupmenu = {items=items, pos=selected, anchor={row, col}}
end
function Screen:_handle_popupmenu_select(selected)
@@ -973,6 +979,34 @@ function Screen:_handle_wildmenu_hide()
self.wildmenu_items, self.wildmenu_pos = nil, nil
end
+function Screen:_handle_msg_show(kind, chunks, replace_last)
+ local pos = #self.messages
+ if not replace_last or pos == 0 then
+ pos = pos + 1
+ end
+ self.messages[pos] = {kind=kind, content=chunks}
+end
+
+function Screen:_handle_msg_clear()
+ self.messages = {}
+end
+
+function Screen:_handle_msg_showcmd(msg)
+ self.showcmd = msg
+end
+
+function Screen:_handle_msg_showmode(msg)
+ self.showmode = msg
+end
+
+function Screen:_handle_msg_ruler(msg)
+ self.ruler = msg
+end
+
+function Screen:_handle_msg_history_show(entries)
+ self.msg_history = entries
+end
+
function Screen:_clear_block(grid, top, bot, left, right)
for i = top, bot do
self:_clear_row_section(grid, i, left, right)
@@ -1057,12 +1091,27 @@ function Screen:_extstate_repr(attr_state)
cmdline_block[i] = self:_chunks_repr(entry, attr_state)
end
+ local messages = {}
+ for i, entry in ipairs(self.messages) do
+ messages[i] = {kind=entry.kind, content=self:_chunks_repr(entry.content, attr_state)}
+ end
+
+ local msg_history = {}
+ for i, entry in ipairs(self.msg_history) do
+ messages[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
+ end
+
return {
popupmenu=self.popupmenu,
cmdline=cmdline,
cmdline_block=cmdline_block,
wildmenu_items=self.wildmenu_items,
wildmenu_pos=self.wildmenu_pos,
+ messages=messages,
+ showmode=self:_chunks_repr(self.showmode, attr_state),
+ showcmd=self:_chunks_repr(self.showcmd, attr_state),
+ ruler=self:_chunks_repr(self.ruler, attr_state),
+ msg_history=msg_history,
}
end