aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ui
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/ui')
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua460
-rw-r--r--test/functional/ui/screen.lua2
2 files changed, 461 insertions, 1 deletions
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
new file mode 100644
index 0000000000..62c0694c8c
--- /dev/null
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -0,0 +1,460 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local eq = helpers.eq
+local feed = helpers.feed
+local clear = helpers.clear
+local meths = helpers.meths
+local funcs = helpers.funcs
+local source = helpers.source
+local dedent = helpers.dedent
+local curbufmeths = helpers.curbufmeths
+
+local screen
+
+-- Bug in input() handling: {REDRAW} will erase the whole prompt up until
+-- user types something. It exists in Vim as well, so using `h<BS>` as
+-- a workaround.
+local function redraw_input()
+ feed('{REDRAW}h<BS>')
+end
+
+before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:attach()
+ source([[
+ highlight RBP1 guibg=Red
+ highlight RBP2 guibg=Yellow
+ highlight RBP3 guibg=Green
+ highlight RBP4 guibg=Blue
+ let g:NUM_LVLS = 4
+ function Redraw()
+ redraw!
+ return ''
+ endfunction
+ let g:EMPTY = ''
+ cnoremap <expr> {REDRAW} Redraw()
+ nnoremap <expr> {PROMPT} extend(g:, {"out": input({"prompt": ":", "highlight": g:Nvim_color_input})}).EMPTY
+ function RainBowParens(cmdline)
+ let ret = []
+ let i = 0
+ let lvl = 0
+ while i < len(a:cmdline)
+ if a:cmdline[i] is# '('
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
+ let lvl += 1
+ elseif a:cmdline[i] is# ')'
+ let lvl -= 1
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
+ endif
+ let i += 1
+ endwhile
+ return ret
+ endfunction
+ function SplittedMultibyteStart(cmdline)
+ let ret = []
+ let i = 0
+ while i < len(a:cmdline)
+ let char = nr2char(char2nr(a:cmdline[i:]))
+ if a:cmdline[i:i + len(char) - 1] is# char
+ if len(char) > 1
+ call add(ret, [i + 1, i + len(char), 'RBP2'])
+ endif
+ let i += len(char)
+ else
+ let i += 1
+ endif
+ endwhile
+ return ret
+ endfunction
+ function SplittedMultibyteEnd(cmdline)
+ let ret = []
+ let i = 0
+ while i < len(a:cmdline)
+ let char = nr2char(char2nr(a:cmdline[i:]))
+ if a:cmdline[i:i + len(char) - 1] is# char
+ if len(char) > 1
+ call add(ret, [i, i + 1, 'RBP1'])
+ endif
+ let i += len(char)
+ else
+ let i += 1
+ endif
+ endwhile
+ return ret
+ endfunction
+ function Echoing(cmdline)
+ echo 'HERE'
+ return v:_null_list
+ endfunction
+ function Echoning(cmdline)
+ echon 'HERE'
+ return v:_null_list
+ endfunction
+ function Echomsging(cmdline)
+ echomsg 'HERE'
+ return v:_null_list
+ endfunction
+ function Echoerring(cmdline)
+ echoerr 'HERE'
+ return v:_null_list
+ endfunction
+ function Redrawing(cmdline)
+ redraw!
+ return v:_null_list
+ endfunction
+ function Throwing(cmdline)
+ throw "ABC"
+ return v:_null_list
+ endfunction
+ function Halting(cmdline)
+ while 1
+ endwhile
+ endfunction
+ ]])
+ screen:set_default_attr_ids({
+ RBP1={background = Screen.colors.Red},
+ RBP2={background = Screen.colors.Yellow},
+ RBP3={background = Screen.colors.Green},
+ RBP4={background = Screen.colors.Blue},
+ EOB={bold = true, foreground = Screen.colors.Blue1},
+ ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ SK={foreground = Screen.colors.Blue},
+ })
+end)
+
+local function set_color_cb(funcname)
+ meths.set_var('Nvim_color_input', funcname)
+end
+local function start_prompt(text)
+ feed('{PROMPT}' .. (text or ''))
+end
+
+describe('Command-line coloring', function()
+ it('works', function()
+ set_color_cb('RainBowParens')
+ meths.set_option('more', false)
+ start_prompt()
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :^ |
+ ]])
+ feed('e')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :e^ |
+ ]])
+ feed('cho ')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo ^ |
+ ]])
+ feed('(')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}^ |
+ ]])
+ feed('(')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}{RBP2:(}^ |
+ ]])
+ feed('42')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}{RBP2:(}42^ |
+ ]])
+ feed('))')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}{RBP2:(}42{RBP2:)}{RBP1:)}^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
+ ]])
+ redraw_input()
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
+ ]])
+ end)
+ for _, func_part in ipairs({'', 'n', 'msg'}) do
+ it('disables :echo' .. func_part .. ' messages', function()
+ set_color_cb('Echo' .. func_part .. 'ing')
+ start_prompt('echo')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo^ |
+ ]])
+ end)
+ end
+ it('does the right thing when hl start appears to split multibyte char',
+ function()
+ set_color_cb('SplittedMultibyteStart')
+ start_prompt('echo "«')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo " |
+ {ERR:E5405: Chunk 0 start 7 splits multibyte }|
+ {ERR:character} |
+ :echo "«^ |
+ ]])
+ feed('»')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo " |
+ {ERR:E5405: Chunk 0 start 7 splits multibyte }|
+ {ERR:character} |
+ :echo "«»^ |
+ ]])
+ end)
+ it('does the right thing when hl end appears to split multibyte char',
+ function()
+ set_color_cb('SplittedMultibyteEnd')
+ start_prompt('echo "«')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo " |
+ {ERR:E5406: Chunk 0 end 7 splits multibyte ch}|
+ {ERR:aracter} |
+ :echo "«^ |
+ ]])
+ end)
+ it('does the right thing when errorring', function()
+ set_color_cb('Echoerring')
+ start_prompt('e')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ : |
+ {ERR:E5407: Callback has thrown an exception:}|
+ {ERR: Vim(echoerr):HERE} |
+ :e^ |
+ ]])
+ end)
+ it('does the right thing when throwing', function()
+ set_color_cb('Throwing')
+ start_prompt('e')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ : |
+ {ERR:E5407: Callback has thrown an exception:}|
+ {ERR: ABC} |
+ :e^ |
+ ]])
+ end)
+ it('stops executing callback after a number of errors', function()
+ set_color_cb('SplittedMultibyteStart')
+ start_prompt('let x = "«»«»«»«»«»"\n')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :let x = " |
+ {ERR:E5405: Chunk 0 start 10 splits multibyte}|
+ {ERR: character} |
+ ^:let x = "«»«»«»«»«»" |
+ ]])
+ feed('\n')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]])
+ eq('let x = "«»«»«»«»«»"', meths.get_var('out'))
+ local msg = '\nE5405: Chunk 0 start 10 splits multibyte character'
+ eq(msg:rep(1), funcs.execute('messages'))
+ end)
+ it('allows interrupting callback with <C-c>', function()
+ set_color_cb('Halting')
+ start_prompt('echo 42')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]])
+ feed('<C-c>')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ : |
+ {ERR:E5407: Callback has thrown an exception:}|
+ {ERR: Keyboard interrupt} |
+ :echo 42^ |
+ ]])
+ redraw_input()
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo 42^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ ^:echo 42 |
+ ]])
+ feed('\n')
+ eq('echo 42', meths.get_var('out'))
+ feed('<C-c>')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Type :quit<Enter> to exit Nvim |
+ ]])
+ end)
+ it('works fine with NUL, NL, CR', function()
+ set_color_cb('RainBowParens')
+ start_prompt('echo ("<C-v><CR><C-v><Nul><C-v><NL>")')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}"{SK:^M^@^@}"{RBP1:)}^ |
+ ]])
+ end)
+ -- TODO Check for all other errors
+ -- TODO Check for colored input() called in a cycle which previously errorred
+ -- out
+end)
+describe('Ex commands coloring support', function()
+ it('still executes command-line even if errored out', function()
+ meths.set_var('Nvim_color_cmdline', 'SplittedMultibyteStart')
+ feed(':let x = "«"\n')
+ eq('«', meths.get_var('x'))
+ local msg = 'E5405: Chunk 0 start 10 splits multibyte character'
+ eq('\n'..msg, funcs.execute('messages'))
+ end)
+ it('does not error out when called from a errorred out cycle', function()
+ -- Apparently when there is a cycle in which one of the commands errors out
+ -- this error may be caught by color_cmdline before it is presented to the
+ -- user.
+ feed(dedent([[
+ :set regexpengine=2
+ :for pat in [' \ze*', ' \zs*']
+ : try
+ : let l = matchlist('x x', pat)
+ : $put ='E888 NOT detected for ' . pat
+ : catch
+ : $put ='E888 detected for ' . pat
+ : endtry
+ :endfor
+ ]]))
+ eq({'', 'E888 detected for \\ze*', 'E888 detected for \\zs*'},
+ curbufmeths.get_lines(0, -1, false))
+ eq('', funcs.execute('messages'))
+ end)
+end)
+
+-- TODO Specifically test for coloring in cmdline and expr modes
+-- TODO Check for errors from tv_dict_get_callback()
+-- TODO Check using highlighted input() from inside highlighted input()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 5408e1e195..a6b7fb2997 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -251,7 +251,7 @@ function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
..'Expected:\n |'..table.concat(msg_expected_rows, '|\n |')..'|\n'
..'Actual:\n |'..table.concat(actual_rows, '|\n |')..'|\n\n'..[[
To print the expect() call that would assert the current screen state, use
-screen:snaphot_util(). In case of non-deterministic failures, use
+screen:snapshot_util(). In case of non-deterministic failures, use
screen:redraw_debug() to show all intermediate screen states. ]])
end
end