diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2017-10-31 16:46:02 +0100 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2019-02-10 13:36:46 +0100 |
commit | 51fc54325c55eb3cefafec627d73cc19c220d7ed (patch) | |
tree | 476f20c32019ad9d4f4059031f405f90266c08c2 /test | |
parent | 3ff1228f785705a46a0bd24fb5dc2bf76b6dad68 (diff) | |
download | rneovim-51fc54325c55eb3cefafec627d73cc19c220d7ed.tar.gz rneovim-51fc54325c55eb3cefafec627d73cc19c220d7ed.tar.bz2 rneovim-51fc54325c55eb3cefafec627d73cc19c220d7ed.zip |
ui: implement ext_messages
Co-Author: Dongdong Zhou <dzhou121@gmail.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/api/vim_spec.lua | 5 | ||||
-rw-r--r-- | test/functional/ui/messages_spec.lua | 632 | ||||
-rw-r--r-- | test/functional/ui/options_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 55 |
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 |