aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ui
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/ui')
-rw-r--r--test/functional/ui/bufhl_spec.lua19
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua893
-rw-r--r--test/functional/ui/cursor_spec.lua246
-rw-r--r--test/functional/ui/highlight_spec.lua696
-rw-r--r--test/functional/ui/inccommand_spec.lua272
-rw-r--r--test/functional/ui/input_spec.lua6
-rw-r--r--test/functional/ui/mode_spec.lua227
-rw-r--r--test/functional/ui/mouse_spec.lua84
-rw-r--r--test/functional/ui/output_spec.lua13
-rw-r--r--test/functional/ui/quickfix_spec.lua52
-rw-r--r--test/functional/ui/screen.lua171
-rw-r--r--test/functional/ui/screen_basic_spec.lua275
-rw-r--r--test/functional/ui/searchhl_spec.lua34
-rw-r--r--test/functional/ui/sign_spec.lua14
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua70
-rw-r--r--test/functional/ui/tabline_spec.lua57
-rw-r--r--test/functional/ui/wildmode_spec.lua159
17 files changed, 2626 insertions, 662 deletions
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 53fe303762..e1e11203e0 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -1,7 +1,8 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local execute, request, neq = helpers.execute, helpers.request, helpers.neq
+local command, request, neq = helpers.command, helpers.request, helpers.neq
if helpers.pending_win32(pending) then return end
@@ -11,7 +12,7 @@ describe('Buffer highlighting', function()
before_each(function()
clear()
- execute("syntax on")
+ command('syntax on')
screen = Screen.new(40, 8)
screen:attach()
screen:set_default_attr_ids({
@@ -106,7 +107,7 @@ describe('Buffer highlighting', function()
combining highlights
from different sources]])
- execute("hi ImportantWord gui=bold cterm=bold")
+ command("hi ImportantWord gui=bold cterm=bold")
id1 = add_hl(0, "ImportantWord", 0, 2, 8)
add_hl(id1, "ImportantWord", 1, 12, -1)
add_hl(id1, "ImportantWord", 2, 0, 9)
@@ -131,7 +132,7 @@ describe('Buffer highlighting', function()
{1:~ }|
{1:~ }|
{1:~ }|
- :hi ImportantWord gui=bold cterm=bold |
+ |
]])
end)
@@ -145,7 +146,7 @@ describe('Buffer highlighting', function()
{1:~ }|
{1:~ }|
{1:~ }|
- :hi ImportantWord gui=bold cterm=bold |
+ |
]])
end)
@@ -159,7 +160,7 @@ describe('Buffer highlighting', function()
{1:~ }|
{1:~ }|
{1:~ }|
- :hi ImportantWord gui=bold cterm=bold |
+ |
]])
end)
@@ -175,7 +176,7 @@ describe('Buffer highlighting', function()
{1:~ }|
{1:~ }|
{1:~ }|
- :hi ImportantWord gui=bold cterm=bold |
+ |
]])
end)
@@ -192,7 +193,7 @@ describe('Buffer highlighting', function()
|
]])
- execute(':3move 4')
+ command(':3move 4')
screen:expect([[
a {5:longer} example |
|
@@ -201,7 +202,7 @@ describe('Buffer highlighting', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ::3move 4 |
+ |
]])
end)
end)
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
new file mode 100644
index 0000000000..d87ce72599
--- /dev/null
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -0,0 +1,893 @@
+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 command = helpers.command
+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:id = ''
+ cnoremap <expr> {REDRAW} Redraw()
+ function DoPrompt(do_return) abort
+ let id = g:id
+ let Cb = g:Nvim_color_input{g:id}
+ let out = input({'prompt': ':', 'highlight': Cb})
+ let g:out{id} = out
+ return (a:do_return ? out : '')
+ endfunction
+ nnoremap <expr> {PROMPT} DoPrompt(0)
+ cnoremap <expr> {PROMPT} DoPrompt(1)
+ 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
+ function ReturningGlobal(cmdline)
+ return g:callback_return
+ endfunction
+ function ReturningGlobal2(cmdline)
+ return g:callback_return[:len(a:cmdline)-1]
+ endfunction
+ function ReturningGlobalN(n, cmdline)
+ return g:callback_return{a:n}
+ endfunction
+ let g:recording_calls = []
+ function Recording(cmdline)
+ call add(g:recording_calls, a:cmdline)
+ return []
+ 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},
+ PE={bold = true, foreground = Screen.colors.SeaGreen4}
+ })
+end)
+
+local function set_color_cb(funcname, callback_return, id)
+ meths.set_var('id', id or '')
+ if id and id ~= '' and funcs.exists('*' .. funcname .. 'N') then
+ command(('let g:Nvim_color_input%s = {cmdline -> %sN(%s, cmdline)}'):format(
+ id, funcname, id))
+ if callback_return then
+ meths.set_var('callback_return' .. id, callback_return)
+ end
+ else
+ meths.set_var('Nvim_color_input', funcname)
+ if callback_return then
+ meths.set_var('callback_return', callback_return)
+ end
+ end
+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('silences :echo', function()
+ set_color_cb('Echoing')
+ start_prompt('e')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :e^ |
+ ]])
+ eq('', meths.command_output('messages'))
+ end)
+ it('silences :echon', function()
+ set_color_cb('Echoning')
+ start_prompt('e')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :e^ |
+ ]])
+ eq('', meths.command_output('messages'))
+ end)
+ it('silences :echomsg', function()
+ set_color_cb('Echomsging')
+ start_prompt('e')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :e^ |
+ ]])
+ eq('', meths.command_output('messages'))
+ 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:~ }|
+ |
+ ]])
+ screen:sleep(500)
+ 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)
+ it('errors out when callback returns something wrong', function()
+ command('cnoremap + ++')
+ set_color_cb('ReturningGlobal', '')
+ start_prompt('#')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ : |
+ {ERR:E5400: Callback should return list} |
+ :#^ |
+ ]])
+
+ feed('<CR><CR><CR>')
+ set_color_cb('ReturningGlobal', {{0, 1, 'Normal'}, 42})
+ start_prompt('#')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ : |
+ {ERR:E5401: List item 1 is not a List} |
+ :#^ |
+ ]])
+
+ feed('<CR><CR><CR>')
+ set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {1}})
+ start_prompt('+')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :+ |
+ {ERR:E5402: List item 1 has incorrect length:}|
+ {ERR: 1 /= 3} |
+ :++^ |
+ ]])
+
+ feed('<CR><CR><CR>')
+ set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {2, 3, 'Normal'}})
+ start_prompt('+')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :+ |
+ {ERR:E5403: Chunk 1 start 2 not in range [1, }|
+ {ERR:2)} |
+ :++^ |
+ ]])
+
+ feed('<CR><CR><CR>')
+ set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {1, 3, 'Normal'}})
+ start_prompt('+')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :+ |
+ {ERR:E5404: Chunk 1 end 3 not in range (1, 2]}|
+ |
+ :++^ |
+ ]])
+ end)
+ it('does not error out when called from a errorred out cycle', function()
+ set_color_cb('ReturningGlobal', {{0, 1, 'Normal'}})
+ feed(dedent([[
+ :set regexpengine=2
+ :for pat in [' \ze*', ' \zs*']
+ : try
+ : let l = matchlist('x x', pat)
+ : $put =input({'prompt':'>','highlight':'ReturningGlobal'})
+ :
+ : $put ='E888 NOT detected for ' . pat
+ : catch
+ : $put =input({'prompt':'>','highlight':'ReturningGlobal'})
+ :
+ : $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)
+ it('allows nesting input()s', function()
+ set_color_cb('ReturningGlobal', {{0, 1, 'RBP1'}}, '')
+ start_prompt('1')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP1:1}^ |
+ ]])
+
+ set_color_cb('ReturningGlobal', {{0, 1, 'RBP2'}}, '1')
+ start_prompt('2')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP2:2}^ |
+ ]])
+
+ set_color_cb('ReturningGlobal', {{0, 1, 'RBP3'}}, '2')
+ start_prompt('3')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP3:3}^ |
+ ]])
+
+ set_color_cb('ReturningGlobal', {{0, 1, 'RBP4'}}, '3')
+ start_prompt('4')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP4:4}^ |
+ ]])
+
+ feed('<CR>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP3:3}4^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP2:2}34^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :{RBP1:1}234^ |
+ ]])
+ feed('<CR><CR><C-l>')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]])
+ eq('1234', meths.get_var('out'))
+ eq('234', meths.get_var('out1'))
+ eq('34', meths.get_var('out2'))
+ eq('4', meths.get_var('out3'))
+ eq(0, funcs.exists('g:out4'))
+ end)
+ it('runs callback with the same data only once', function()
+ local function new_recording_calls(...)
+ eq({...}, meths.get_var('recording_calls'))
+ meths.set_var('recording_calls', {})
+ end
+ set_color_cb('Recording')
+ start_prompt('')
+ -- Regression test. Disambiguation:
+ --
+ -- new_recording_calls(expected_result) -- (actual_before_fix)
+ --
+ feed('a')
+ new_recording_calls('a') -- ('a', 'a')
+ feed('b')
+ new_recording_calls('ab') -- ('a', 'ab', 'ab')
+ feed('c')
+ new_recording_calls('abc') -- ('ab', 'abc', 'abc')
+ feed('<BS>')
+ new_recording_calls('ab') -- ('abc', 'ab', 'ab')
+ feed('<BS>')
+ new_recording_calls('a') -- ('ab', 'a', 'a')
+ feed('<BS>')
+ new_recording_calls() -- ('a')
+ feed('<CR><CR>')
+ eq('', meths.get_var('out'))
+ end)
+end)
+describe('Ex commands coloring support', function()
+ it('works', function()
+ meths.set_var('Nvim_color_cmdline', 'RainBowParens')
+ feed(':echo (((1)))')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :echo {RBP1:(}{RBP2:(}{RBP3:(}1{RBP3:)}{RBP2:)}{RBP1:)}^ |
+ ]])
+ end)
+ 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)
+ it('does not crash when using `n` in debug mode', function()
+ feed(':debug execute "echo 1"\n')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Entering Debug mode. Type "cont" to con|
+ tinue. |
+ cmd: execute "echo 1" |
+ >^ |
+ ]])
+ feed('n\n')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ Entering Debug mode. Type "cont" to con|
+ tinue. |
+ cmd: execute "echo 1" |
+ >n |
+ 1 |
+ {PE:Press ENTER or type command to continue}^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]])
+ end)
+ it('does not prevent mapping error from cancelling prompt', function()
+ command("cnoremap <expr> x execute('throw 42')[-1]")
+ feed(':#x')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ :# |
+ {ERR:Error detected while processing :} |
+ {ERR:E605: Exception not caught: 42} |
+ :#^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]])
+ eq('\nError detected while processing :\nE605: Exception not caught: 42',
+ meths.command_output('messages'))
+ end)
+ it('errors out when failing to get callback', function()
+ meths.set_var('Nvim_color_cmdline', 42)
+ feed(':#')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ : |
+ {ERR:E5408: Unable to get g:Nvim_color_cmdlin}|
+ {ERR:e callback: Vim:E6000: Argument is not a}|
+ {ERR: function or function name} |
+ :#^ |
+ ]])
+ end)
+end)
+describe('Expressions coloring support', function()
+ it('works', function()
+ meths.set_var('Nvim_color_expr', 'RainBowParens')
+ feed(':echo <C-r>=(((1)))')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ ={RBP1:(}{RBP2:(}{RBP3:(}1{RBP3:)}{RBP2:)}{RBP1:)}^ |
+ ]])
+ end)
+ it('errors out when failing to get callback', function()
+ meths.set_var('Nvim_color_expr', 42)
+ feed(':<C-r>=1')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ = |
+ {ERR:E5409: Unable to get g:Nvim_color_expr c}|
+ {ERR:allback: Vim:E6000: Argument is not a fu}|
+ {ERR:nction or function name} |
+ =1^ |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
new file mode 100644
index 0000000000..b47210a777
--- /dev/null
+++ b/test/functional/ui/cursor_spec.lua
@@ -0,0 +1,246 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, meths = helpers.clear, helpers.meths
+local eq = helpers.eq
+local command = helpers.command
+
+describe('ui/cursor', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach()
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it("'guicursor' is published as a UI event", function()
+ local expected_mode_info = {
+ [1] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 0,
+ cursor_shape = 'block',
+ name = 'normal',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'n' },
+ [2] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 0,
+ cursor_shape = 'block',
+ name = 'visual',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'v' },
+ [3] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 25,
+ cursor_shape = 'vertical',
+ name = 'insert',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'i' },
+ [4] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 20,
+ cursor_shape = 'horizontal',
+ name = 'replace',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'r' },
+ [5] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 0,
+ cursor_shape = 'block',
+ name = 'cmdline_normal',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'c' },
+ [6] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 25,
+ cursor_shape = 'vertical',
+ name = 'cmdline_insert',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'ci' },
+ [7] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 20,
+ cursor_shape = 'horizontal',
+ name = 'cmdline_replace',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'cr' },
+ [8] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 20,
+ cursor_shape = 'horizontal',
+ name = 'operator',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 'o' },
+ [9] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 25,
+ cursor_shape = 'vertical',
+ name = 'visual_select',
+ hl_id = 0,
+ id_lm = 0,
+ mouse_shape = 0,
+ short_name = 've' },
+ [10] = {
+ name = 'cmdline_hover',
+ mouse_shape = 0,
+ short_name = 'e' },
+ [11] = {
+ name = 'statusline_hover',
+ mouse_shape = 0,
+ short_name = 's' },
+ [12] = {
+ name = 'statusline_drag',
+ mouse_shape = 0,
+ short_name = 'sd' },
+ [13] = {
+ name = 'vsep_hover',
+ mouse_shape = 0,
+ short_name = 'vs' },
+ [14] = {
+ name = 'vsep_drag',
+ mouse_shape = 0,
+ short_name = 'vd' },
+ [15] = {
+ name = 'more',
+ mouse_shape = 0,
+ short_name = 'm' },
+ [16] = {
+ name = 'more_lastline',
+ mouse_shape = 0,
+ short_name = 'ml' },
+ [17] = {
+ blinkoff = 0,
+ blinkon = 0,
+ blinkwait = 0,
+ cell_percentage = 0,
+ cursor_shape = 'block',
+ name = 'showmatch',
+ hl_id = 0,
+ id_lm = 0,
+ short_name = 'sm' },
+ }
+
+ screen:expect(function()
+ -- Default 'guicursor', published on startup.
+ eq(expected_mode_info, screen._mode_info)
+ eq(true, screen._cursor_style_enabled)
+ eq('normal', screen.mode)
+ end)
+
+ -- Event is published ONLY if the cursor style changed.
+ screen._mode_info = nil
+ command("echo 'test'")
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ test |
+ ]], nil, nil, function()
+ eq(nil, screen._mode_info)
+ end)
+
+ -- Change the cursor style.
+ helpers.command('set guicursor=n-v-c:block,i-ci-ve:ver25,r-cr-o:hor20'
+ ..',a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor'
+ ..',sm:block-blinkwait175-blinkoff150-blinkon175')
+
+ -- Update the expected values.
+ for _, m in ipairs(expected_mode_info) do
+ if m.name == 'showmatch' then
+ if m.blinkon then m.blinkon = 175 end
+ if m.blinkoff then m.blinkoff = 150 end
+ if m.blinkwait then m.blinkwait = 175 end
+ else
+ if m.blinkon then m.blinkon = 250 end
+ if m.blinkoff then m.blinkoff = 400 end
+ if m.blinkwait then m.blinkwait = 700 end
+ end
+ if m.hl_id then m.hl_id = 48 end
+ if m.id_lm then m.id_lm = 49 end
+ end
+
+ -- Assert the new expectation.
+ screen:expect(function()
+ eq(expected_mode_info, screen._mode_info)
+ eq(true, screen._cursor_style_enabled)
+ eq('normal', screen.mode)
+ end)
+
+ -- Another cursor style.
+ meths.set_option('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173'
+ ..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42')
+ screen:expect(function()
+ local named = {}
+ for _, m in ipairs(screen._mode_info) do
+ named[m.name] = m
+ end
+ eq('vertical', named.normal.cursor_shape)
+ eq(35, named.normal.cell_percentage)
+ eq('horizontal', named.visual_select.cursor_shape)
+ eq(35, named.visual_select.cell_percentage)
+ eq('vertical', named.operator.cursor_shape)
+ eq(50, named.operator.cell_percentage)
+ eq('block', named.insert.cursor_shape)
+ eq('vertical', named.showmatch.cursor_shape)
+ eq(90, named.cmdline_replace.cell_percentage)
+ eq(171, named.normal.blinkwait)
+ eq(172, named.normal.blinkoff)
+ eq(173, named.normal.blinkon)
+ eq(42, named.showmatch.cell_percentage)
+ end)
+ end)
+
+ it("empty 'guicursor' sets cursor_shape=block in all modes", function()
+ meths.set_option('guicursor', '')
+ screen:expect(function()
+ -- Empty 'guicursor' sets enabled=false.
+ eq(false, screen._cursor_style_enabled)
+ for _, m in ipairs(screen._mode_info) do
+ if m['cursor_shape'] ~= nil then
+ eq('block', m.cursor_shape)
+ eq(0, m.blinkon)
+ end
+ end
+ end)
+ end)
+
+end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 945b16ef92..d1357ea525 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -2,23 +2,24 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local os = require('os')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local execute, request, eq = helpers.execute, helpers.request, helpers.eq
+local command = helpers.command
+local eval, exc_exec = helpers.eval, helpers.exc_exec
+local feed_command, request, eq = helpers.feed_command, helpers.request, helpers.eq
+local curbufmeths = helpers.curbufmeths
-if helpers.pending_win32(pending) then return end
-
-describe('color scheme compatibility', function()
+describe('colorscheme compatibility', function()
before_each(function()
clear()
end)
it('t_Co is set to 256 by default', function()
- eq('256', request('vim_eval', '&t_Co'))
+ eq('256', eval('&t_Co'))
request('nvim_set_option', 't_Co', '88')
- eq('88', request('vim_eval', '&t_Co'))
+ eq('88', eval('&t_Co'))
end)
end)
-describe('manual syntax highlight', function()
+describe('highlight: `:syntax manual`', function()
-- When using manual syntax highlighting, it should be preserved even when
-- switching buffers... bug did only occur without :set hidden
-- Ref: vim patch 7.4.1236
@@ -41,18 +42,18 @@ describe('manual syntax highlight', function()
end)
it("works with buffer switch and 'hidden'", function()
- execute('e tmp1.vim')
- execute('e Xtest-functional-ui-highlight.tmp.vim')
- execute('filetype on')
- execute('syntax manual')
- execute('set ft=vim')
- execute('set syntax=ON')
+ feed_command('e tmp1.vim')
+ feed_command('e Xtest-functional-ui-highlight.tmp.vim')
+ feed_command('filetype on')
+ feed_command('syntax manual')
+ feed_command('set ft=vim')
+ feed_command('set syntax=ON')
feed('iecho 1<esc>0')
- execute('set hidden')
- execute('w')
- execute('bn')
- execute('bp')
+ feed_command('set hidden')
+ feed_command('w')
+ feed_command('bn')
+ feed_command('bp')
screen:expect([[
{1:^echo} 1 |
{0:~ }|
@@ -63,32 +64,32 @@ describe('manual syntax highlight', function()
end)
it("works with buffer switch and 'nohidden'", function()
- execute('e tmp1.vim')
- execute('e Xtest-functional-ui-highlight.tmp.vim')
- execute('filetype on')
- execute('syntax manual')
- execute('set ft=vim')
- execute('set syntax=ON')
+ command('e tmp1.vim')
+ command('e Xtest-functional-ui-highlight.tmp.vim')
+ command('filetype on')
+ command('syntax manual')
+ command('set filetype=vim fileformat=unix')
+ command('set syntax=ON')
feed('iecho 1<esc>0')
- execute('set nohidden')
- execute('w')
- execute('bn')
- execute('bp')
+ command('set nohidden')
+ command('w')
+ command('silent bn')
+ eq("tmp1.vim", eval("fnamemodify(bufname('%'), ':t')"))
+ feed_command('silent bp')
+ eq("Xtest-functional-ui-highlight.tmp.vim", eval("fnamemodify(bufname('%'), ':t')"))
screen:expect([[
{1:^echo} 1 |
{0:~ }|
{0:~ }|
{0:~ }|
- <ht.tmp.vim" 1L, 7C |
+ :silent bp |
]])
end)
end)
-describe('Default highlight groups', function()
- -- Test the default attributes for highlight groups shown by the :highlight
- -- command
+describe('highlight defaults', function()
local screen
before_each(function()
@@ -107,7 +108,7 @@ describe('Default highlight groups', function()
[1] = {reverse = true, bold = true}, -- StatusLine
[2] = {reverse = true} -- StatusLineNC
})
- execute('sp', 'vsp', 'vsp')
+ feed_command('sp', 'vsp', 'vsp')
screen:expect([[
^ {2:|} {2:|} |
{0:~ }{2:|}{0:~ }{2:|}{0:~ }|
@@ -200,58 +201,31 @@ describe('Default highlight groups', function()
it('insert mode text', function()
feed('i')
+ screen:try_resize(53, 4)
screen:expect([[
^ |
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
{1:-- INSERT --} |
]], {[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {bold = true}})
end)
it('end of file markers', function()
+ screen:try_resize(53, 4)
screen:expect([[
^ |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
|
]], {[1] = {bold = true, foreground = Screen.colors.Blue}})
end)
it('"wait return" text', function()
+ screen:try_resize(53, 4)
feed(':ls<cr>')
screen:expect([[
{0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
:ls |
1 %a "[No Name]" line 1 |
{1:Press ENTER or type command to continue}^ |
@@ -259,89 +233,84 @@ describe('Default highlight groups', function()
[1] = {bold = true, foreground = Screen.colors.SeaGreen}})
feed('<cr>') -- skip the "Press ENTER..." state or tests will hang
end)
+
it('can be cleared and linked to other highlight groups', function()
- execute('highlight clear ModeMsg')
+ screen:try_resize(53, 4)
+ feed_command('highlight clear ModeMsg')
feed('i')
screen:expect([[
^ |
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
-- INSERT -- |
]], {[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {bold=true}})
feed('<esc>')
- execute('highlight CustomHLGroup guifg=red guibg=green')
- execute('highlight link ModeMsg CustomHLGroup')
+ feed_command('highlight CustomHLGroup guifg=red guibg=green')
+ feed_command('highlight link ModeMsg CustomHLGroup')
feed('i')
screen:expect([[
^ |
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
{1:-- INSERT --} |
]], {[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {foreground = Screen.colors.Red, background = Screen.colors.Green}})
end)
+
it('can be cleared by assigning NONE', function()
- execute('syn keyword TmpKeyword neovim')
- execute('hi link TmpKeyword ErrorMsg')
+ screen:try_resize(53, 4)
+ feed_command('syn keyword TmpKeyword neovim')
+ feed_command('hi link TmpKeyword ErrorMsg')
insert('neovim')
screen:expect([[
{1:neovi^m} |
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
|
]], {
[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {foreground = Screen.colors.White, background = Screen.colors.Red}
})
- execute("hi ErrorMsg term=NONE cterm=NONE ctermfg=NONE ctermbg=NONE"
+ feed_command("hi ErrorMsg term=NONE cterm=NONE ctermfg=NONE ctermbg=NONE"
.. " gui=NONE guifg=NONE guibg=NONE guisp=NONE")
screen:expect([[
neovi^m |
{0:~ }|
{0:~ }|
+ |
+ ]], {[0] = {bold=true, foreground=Screen.colors.Blue}})
+ end)
+
+ it('Cursor after `:hi clear|syntax reset` #6508', function()
+ command('highlight clear|syntax reset')
+ eq('guifg=bg guibg=fg', eval([[matchstr(execute('hi Cursor'), '\v(gui|cterm).*$')]]))
+ end)
+
+ it('Whitespace highlight', function()
+ screen:try_resize(53, 4)
+ feed_command('highlight NonText gui=NONE guifg=#FF0000')
+ feed_command('set listchars=space:.,tab:>-,trail:*,eol:¬ list')
+ insert(' ne \t o\tv im ')
+ screen:expect([[
+ ne{0:.>----.}o{0:>-----}v{0:..}im{0:*^*¬} |
{0:~ }|
{0:~ }|
+ |
+ ]], {
+ [0] = {foreground=Screen.colors.Red},
+ [1] = {foreground=Screen.colors.Blue},
+ })
+ feed_command('highlight Whitespace gui=NONE guifg=#0000FF')
+ screen:expect([[
+ ne{1:.>----.}o{1:>-----}v{1:..}im{1:*^*}{0:¬} |
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]], {[0] = {bold=true, foreground=Screen.colors.Blue}})
+ :highlight Whitespace gui=NONE guifg=#0000FF |
+ ]], {
+ [0] = {foreground=Screen.colors.Red},
+ [1] = {foreground=Screen.colors.Blue},
+ })
end)
end)
@@ -355,19 +324,19 @@ describe('guisp (special/undercurl)', function()
end)
it('can be set and is applied like foreground or background', function()
- execute('syntax on')
- execute('syn keyword TmpKeyword neovim')
- execute('syn keyword TmpKeyword1 special')
- execute('syn keyword TmpKeyword2 specialwithbg')
- execute('syn keyword TmpKeyword3 specialwithfg')
- execute('hi! Awesome guifg=red guibg=yellow guisp=red')
- execute('hi! Awesome1 guisp=red')
- execute('hi! Awesome2 guibg=yellow guisp=red')
- execute('hi! Awesome3 guifg=red guisp=red')
- execute('hi link TmpKeyword Awesome')
- execute('hi link TmpKeyword1 Awesome1')
- execute('hi link TmpKeyword2 Awesome2')
- execute('hi link TmpKeyword3 Awesome3')
+ feed_command('syntax on')
+ feed_command('syn keyword TmpKeyword neovim')
+ feed_command('syn keyword TmpKeyword1 special')
+ feed_command('syn keyword TmpKeyword2 specialwithbg')
+ feed_command('syn keyword TmpKeyword3 specialwithfg')
+ feed_command('hi! Awesome guifg=red guibg=yellow guisp=red')
+ feed_command('hi! Awesome1 guisp=red')
+ feed_command('hi! Awesome2 guibg=yellow guisp=red')
+ feed_command('hi! Awesome3 guifg=red guisp=red')
+ feed_command('hi link TmpKeyword Awesome')
+ feed_command('hi link TmpKeyword1 Awesome1')
+ feed_command('hi link TmpKeyword2 Awesome2')
+ feed_command('hi link TmpKeyword3 Awesome3')
insert([[
neovim
awesome neovim
@@ -401,7 +370,7 @@ describe('guisp (special/undercurl)', function()
end)
end)
-describe("'cursorline' with 'listchars'", function()
+describe("'listchars' highlight", function()
local screen
before_each(function()
@@ -419,8 +388,8 @@ describe("'cursorline' with 'listchars'", function()
[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {background=Screen.colors.Grey90}
})
- execute('highlight clear ModeMsg')
- execute('set cursorline')
+ feed_command('highlight clear ModeMsg')
+ feed_command('set cursorline')
feed('i')
screen:expect([[
{1:^ }|
@@ -445,7 +414,7 @@ describe("'cursorline' with 'listchars'", function()
{0:~ }|
|
]])
- execute('set nocursorline')
+ feed_command('set nocursorline')
screen:expect([[
abcdefg |
kkasd^f |
@@ -469,8 +438,8 @@ describe("'cursorline' with 'listchars'", function()
^f |
|
]])
- execute('set cursorline')
- execute('set cursorcolumn')
+ feed_command('set cursorline')
+ feed_command('set cursorcolumn')
feed('kkiabcdefghijk<esc>hh')
screen:expect([[
kkasd {1: } |
@@ -509,11 +478,11 @@ describe("'cursorline' with 'listchars'", function()
foreground=Screen.colors.Red,
},
})
- execute('highlight clear ModeMsg')
- execute('highlight SpecialKey guifg=#FF0000')
- execute('set cursorline')
- execute('set tabstop=8')
- execute('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
+ feed_command('highlight clear ModeMsg')
+ feed_command('highlight Whitespace guifg=#FF0000')
+ feed_command('set cursorline')
+ feed_command('set tabstop=8')
+ feed_command('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
feed('i\t abcd <cr>\t abcd <cr><esc>k')
screen:expect([[
{5:>-------.}abcd{5:*}{4:¬} |
@@ -530,7 +499,7 @@ describe("'cursorline' with 'listchars'", function()
{4:~ }|
|
]])
- execute('set nocursorline')
+ feed_command('set nocursorline')
screen:expect([[
{5:^>-------.}abcd{5:*}{4:¬} |
{5:>-------.}abcd{5:*}{4:¬} |
@@ -538,7 +507,7 @@ describe("'cursorline' with 'listchars'", function()
{4:~ }|
:set nocursorline |
]])
- execute('set nowrap')
+ feed_command('set nowrap')
feed('ALorem ipsum dolor sit amet<ESC>0')
screen:expect([[
{5:^>-------.}abcd{5:.}Lorem{4:>}|
@@ -547,7 +516,7 @@ describe("'cursorline' with 'listchars'", function()
{4:~ }|
|
]])
- execute('set cursorline')
+ feed_command('set cursorline')
screen:expect([[
{2:^>-------.}{1:abcd}{2:.}{1:Lorem}{4:>}|
{5:>-------.}abcd{5:*}{4:¬} |
@@ -605,12 +574,12 @@ describe("'cursorline' with 'listchars'", function()
bold=true,
},
})
- execute('highlight clear ModeMsg')
- execute('highlight SpecialKey guifg=#FF0000')
- execute('set cursorline')
- execute('set tabstop=8')
- execute('set nowrap')
- execute('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
+ feed_command('highlight clear ModeMsg')
+ feed_command('highlight Whitespace guifg=#FF0000')
+ feed_command('set cursorline')
+ feed_command('set tabstop=8')
+ feed_command('set nowrap')
+ feed_command('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
feed('i\t abcd <cr>\t abcd Lorem ipsum dolor sit amet<cr><esc>kkk0')
screen:expect([[
{2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }|
@@ -644,4 +613,453 @@ describe("'cursorline' with 'listchars'", function()
|
]])
end)
+
+ it("'cursorline' with :match", function()
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {background=Screen.colors.Grey90},
+ [2] = {foreground=Screen.colors.Red},
+ [3] = {foreground=Screen.colors.Green1},
+ })
+ feed_command('highlight clear ModeMsg')
+ feed_command('highlight Whitespace guifg=#FF0000')
+ feed_command('highlight Error guifg=#00FF00')
+ feed_command('set nowrap')
+ feed('ia \t bc \t <esc>')
+ screen:expect([[
+ a bc ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed_command('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
+ screen:expect([[
+ a{2:.>-----.}bc{2:*>---*^*}{0:¬} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed_command('match Error /\\s\\+$/')
+ screen:expect([[
+ a{2:.>-----.}bc{3:*>---*^*}{0:¬} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+end)
+
+describe("'winhighlight' highlight", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(20,8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {background = Screen.colors.DarkBlue},
+ [2] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Blue1},
+ [3] = {bold = true, reverse = true},
+ [4] = {reverse = true},
+ [5] = {background = Screen.colors.DarkGreen},
+ [6] = {background = Screen.colors.DarkGreen, bold = true, foreground = Screen.colors.Blue1},
+ [7] = {background = Screen.colors.DarkMagenta},
+ [8] = {background = Screen.colors.DarkMagenta, bold = true, foreground = Screen.colors.Blue1},
+ [9] = {foreground = Screen.colors.Brown},
+ [10] = {foreground = Screen.colors.Brown, background = Screen.colors.DarkBlue},
+ [11] = {background = Screen.colors.DarkBlue, bold = true, reverse = true},
+ [12] = {background = Screen.colors.DarkGreen, reverse = true},
+ [13] = {background = Screen.colors.Magenta4, reverse = true},
+ [14] = {background = Screen.colors.DarkBlue, reverse = true},
+ [15] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [16] = {foreground = Screen.colors.Blue1},
+ [17] = {background = Screen.colors.LightRed},
+ [18] = {background = Screen.colors.Gray90},
+ [19] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray},
+ [20] = {background = Screen.colors.LightGrey, underline = true},
+ [21] = {bold = true},
+ [22] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [23] = {background = Screen.colors.LightMagenta},
+ [24] = {background = Screen.colors.WebGray},
+ })
+ command("hi Background1 guibg=DarkBlue")
+ command("hi Background2 guibg=DarkGreen")
+ end)
+
+ it('works for background color', function()
+ insert("aa")
+ command("split")
+ command("set winhl=Normal:Background1")
+ screen:expect([[
+ {1:a^a }|
+ {2:~ }|
+ {2:~ }|
+ {11:[No Name] [+] }|
+ aa |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+
+ command("enew")
+ screen:expect([[
+ {1:^ }|
+ {2:~ }|
+ {2:~ }|
+ {11:[No Name] }|
+ aa |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end)
+
+ it('handles invalid values', function()
+ command("set winhl=Normal:Background1")
+ screen:expect([[
+ {1:^ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+
+ eq('Vim(set):E474: Invalid argument: winhl=xxx:yyy',
+ exc_exec("set winhl=xxx:yyy"))
+ eq('Normal:Background1', eval('&winhl'))
+ screen:expect([[
+ {1:^ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+
+
+ it('works local to the buffer', function()
+ insert("aa")
+ command("split")
+ command("setlocal winhl=Normal:Background1")
+ screen:expect([[
+ {1:a^a }|
+ {2:~ }|
+ {2:~ }|
+ {11:[No Name] [+] }|
+ aa |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+
+ command("enew")
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
+ aa |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+
+ command("bnext")
+ screen:expect([[
+ {1:^aa }|
+ {2:~ }|
+ {2:~ }|
+ {11:[No Name] [+] }|
+ aa |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ <f 1 --100%-- col 1 |
+ ]])
+ end)
+
+ it('for inactive window background works', function()
+ command("set winhl=Normal:Background1,NormalNC:Background2")
+ -- tests global value is copied across split
+ command("split")
+ screen:expect([[
+ {1:^ }|
+ {2:~ }|
+ {2:~ }|
+ {11:[No Name] }|
+ {5: }|
+ {6:~ }|
+ {12:[No Name] }|
+ |
+ ]])
+
+ feed("<c-w><c-w>")
+ screen:expect([[
+ {5: }|
+ {6:~ }|
+ {6:~ }|
+ {12:[No Name] }|
+ {1:^ }|
+ {2:~ }|
+ {11:[No Name] }|
+ |
+ ]])
+
+ feed("<c-w><c-w>")
+ screen:expect([[
+ {1:^ }|
+ {2:~ }|
+ {2:~ }|
+ {11:[No Name] }|
+ {5: }|
+ {6:~ }|
+ {12:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('works with NormalNC', function()
+ command("hi NormalNC guibg=DarkMagenta")
+ -- tests global value is copied across split
+ command("split")
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
+ {7: }|
+ {8:~ }|
+ {13:[No Name] }|
+ |
+ ]])
+
+ command("wincmd w")
+ screen:expect([[
+ {7: }|
+ {8:~ }|
+ {8:~ }|
+ {13:[No Name] }|
+ ^ |
+ {0:~ }|
+ {3:[No Name] }|
+ |
+ ]])
+
+
+ -- winbg=Normal:... overrides global NormalNC
+ command("set winhl=Normal:Background1")
+ screen:expect([[
+ {7: }|
+ {8:~ }|
+ {8:~ }|
+ {13:[No Name] }|
+ {1:^ }|
+ {2:~ }|
+ {11:[No Name] }|
+ |
+ ]])
+
+ command("wincmd w")
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
+ {1: }|
+ {2:~ }|
+ {14:[No Name] }|
+ |
+ ]])
+
+ command("wincmd w")
+ command("set winhl=Normal:Background1,NormalNC:Background2")
+ screen:expect([[
+ {7: }|
+ {8:~ }|
+ {8:~ }|
+ {13:[No Name] }|
+ {1:^ }|
+ {2:~ }|
+ {11:[No Name] }|
+ |
+ ]])
+
+ command("wincmd w")
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
+ {5: }|
+ {6:~ }|
+ {12:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('background applies also to non-text', function()
+ insert('Lorem ipsum dolor sit amet ')
+ command('set shiftwidth=2')
+ feed('>>')
+ command('set number')
+ command('set breakindent')
+ command('set briopt=shift:5,min:0')
+ command('set list')
+ command('set showbreak=↪')
+ screen:expect([[
+ {9: 1 } ^Lorem ipsum do|
+ {9: } {0:↪}lor sit |
+ {9: } {0:↪}amet{0:-} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ command('set winhl=Normal:Background1')
+ screen:expect([[
+ {10: 1 }{1: ^Lorem ipsum do}|
+ {10: }{1: }{2:↪}{1:lor sit }|
+ {10: }{1: }{2:↪}{1:amet}{2:-}{1: }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+
+ command('set nowrap')
+ command('set listchars+=extends:❯,precedes:❮')
+ feed('3w')
+ screen:expect([[
+ {10: 1 }{2:❮}{1: dolor ^sit ame}{2:❯}|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+
+ it('can override NonText, Conceal and EndOfBuffer', function()
+ curbufmeths.set_lines(0,-1,true, {"raa\000"})
+ command('call matchaddpos("Conceal", [[1,2]], 0, -1, {"conceal": "#"})')
+ command('set cole=2 cocu=nvic')
+ command('split')
+ command('call matchaddpos("Conceal", [[1,2]], 0, -1, {"conceal": "#"})')
+ command('set winhl=SpecialKey:ErrorMsg,EndOfBuffer:Background1,'
+ ..'Conceal:Background2')
+
+ screen:expect([[
+ ^r{5:#}a{15:^@} |
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] [+] }|
+ r{19:#}a{16:^@} |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end)
+
+ it('can override LineNr, CursorColumn and ColorColumn', function()
+ insert('very text\nmore text')
+ command('set number')
+ command('set colorcolumn=2')
+ command('set cursorcolumn')
+
+ command('split')
+ command('set winhl=LineNr:Background1,CursorColumn:Background2,'
+ ..'ColorColumn:ErrorMsg')
+ screen:expect([[
+ {1: 1 }v{15:e}ry tex{5:t} |
+ {1: 2 }m{15:o}re tex^t |
+ {0:~ }|
+ {3:[No Name] [+] }|
+ {9: 1 }v{17:e}ry tex{18:t} |
+ {9: 2 }m{17:o}re text |
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end)
+
+ it('can override Tabline', function()
+ command('tabnew')
+ command('set winhl=TabLine:Background1,TabLineSel:ErrorMsg')
+
+ screen:expect([[
+ {20: No Name] }{15: No Name]}{20:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ command("tabnext")
+ screen:expect([[
+ {21: No Name] }{1: No Name]}{20:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('can override popupmenu', function()
+ insert('word wording wordy')
+ command('split')
+ command('set winhl=Pmenu:Background1,PmenuSel:Background2,'
+ ..'PmenuSbar:ErrorMsg,PmenuThumb:Normal')
+ screen:expect([[
+ word wording word^y |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] [+] }|
+ word wording wordy |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+
+ feed('oword<c-x><c-p>')
+ screen:expect([[
+ word wording wordy |
+ wordy^ |
+ {1:word }{0: }|
+ {1:wording }{3: }|
+ {5:wordy }rdy |
+ wordy |
+ {4:[No Name] [+] }|
+ {21:-- }{22:match 1 of 3} |
+ ]])
+
+ feed('<esc>u<c-w><c-w>oword<c-x><c-p>')
+ screen:expect([[
+ word wording wordy |
+ wordy |
+ {23:word }{0: }|
+ {23:wording }{4: }|
+ {24:wordy }rdy |
+ wordy^ |
+ {3:[No Name] [+] }|
+ {21:-- }{22:match 1 of 3} |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 35aeb6e67c..64965ccb94 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -1,10 +1,11 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
+local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq = helpers.eq
local eval = helpers.eval
-local execute = helpers.execute
+local feed_command = helpers.feed_command
local expect = helpers.expect
local feed = helpers.feed
local insert = helpers.insert
@@ -21,9 +22,9 @@ local default_text = [[
local function common_setup(screen, inccommand, text)
if screen then
- execute("syntax on")
- execute("set nohlsearch")
- execute("hi Substitute guifg=red guibg=yellow")
+ command("syntax on")
+ command("set nohlsearch")
+ command("hi Substitute guifg=red guibg=yellow")
screen:attach()
screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.Fuchsia},
@@ -42,10 +43,11 @@ local function common_setup(screen, inccommand, text)
[14] = {foreground = Screen.colors.White, background = Screen.colors.Red},
[15] = {bold=true, foreground=Screen.colors.Blue},
[16] = {background=Screen.colors.Grey90}, -- cursorline
+ vis = {background=Screen.colors.LightGrey}
})
end
- execute("set inccommand=" .. (inccommand and inccommand or ""))
+ command("set inccommand=" .. (inccommand and inccommand or ""))
if text then
insert(text)
@@ -90,8 +92,8 @@ describe(":substitute, 'inccommand' preserves", function()
local screen = Screen.new(30,10)
common_setup(screen, "split", "ABC")
- execute("%s/AB/BA/")
- execute("ls")
+ feed_command("%s/AB/BA/")
+ feed_command("ls")
screen:expect([[
{15:~ }|
@@ -110,25 +112,25 @@ describe(":substitute, 'inccommand' preserves", function()
for _, case in pairs{"", "split", "nosplit"} do
it("various delimiters (inccommand="..case..")", function()
insert(default_text)
- execute("set inccommand=" .. case)
+ feed_command("set inccommand=" .. case)
local delims = { '/', '#', ';', '%', ',', '@', '!', ''}
for _,delim in pairs(delims) do
- execute("%s"..delim.."lines"..delim.."LINES"..delim.."g")
+ feed_command("%s"..delim.."lines"..delim.."LINES"..delim.."g")
expect([[
Inc substitution on
two LINES
]])
- execute("undo")
+ feed_command("undo")
end
end)
end
for _, case in pairs{"", "split", "nosplit"} do
it("'undolevels' (inccommand="..case..")", function()
- execute("set undolevels=139")
- execute("setlocal undolevels=34")
- execute("set inccommand=" .. case)
+ feed_command("set undolevels=139")
+ feed_command("setlocal undolevels=34")
+ feed_command("set inccommand=" .. case)
insert("as")
feed(":%s/as/glork/<enter>")
eq(meths.get_option('undolevels'), 139)
@@ -138,8 +140,8 @@ describe(":substitute, 'inccommand' preserves", function()
for _, case in ipairs({"", "split", "nosplit"}) do
it("empty undotree() (inccommand="..case..")", function()
- execute("set undolevels=1000")
- execute("set inccommand=" .. case)
+ feed_command("set undolevels=1000")
+ feed_command("set inccommand=" .. case)
local expected_undotree = eval("undotree()")
-- Start typing an incomplete :substitute command.
@@ -156,8 +158,8 @@ describe(":substitute, 'inccommand' preserves", function()
for _, case in ipairs({"", "split", "nosplit"}) do
it("undotree() with branches (inccommand="..case..")", function()
- execute("set undolevels=1000")
- execute("set inccommand=" .. case)
+ feed_command("set undolevels=1000")
+ feed_command("set inccommand=" .. case)
-- Make some changes.
feed([[isome text 1<C-\><C-N>]])
feed([[osome text 2<C-\><C-N>]])
@@ -191,7 +193,7 @@ describe(":substitute, 'inccommand' preserves", function()
for _, case in pairs{"", "split", "nosplit"} do
it("b:changedtick (inccommand="..case..")", function()
- execute("set inccommand=" .. case)
+ feed_command("set inccommand=" .. case)
feed([[isome text 1<C-\><C-N>]])
feed([[osome text 2<C-\><C-N>]])
local expected_tick = eval("b:changedtick")
@@ -207,6 +209,42 @@ describe(":substitute, 'inccommand' preserves", function()
end)
end
+ for _, case in pairs{"", "split", "nosplit"} do
+ it("visual selection for non-previewable command (inccommand="..case..") #5888", function()
+ local screen = Screen.new(30,10)
+ common_setup(screen, case, default_text)
+ feed('1G2V')
+
+ feed(':s')
+ screen:expect([[
+ {vis:Inc substitution on} |
+ t{vis:wo lines} |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :'<,'>s^ |
+ ]])
+
+ feed('o')
+ screen:expect([[
+ {vis:Inc substitution on} |
+ t{vis:wo lines} |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :'<,'>so^ |
+ ]])
+ end)
+ end
+
end)
describe(":substitute, 'inccommand' preserves undo", function()
@@ -234,18 +272,18 @@ describe(":substitute, 'inccommand' preserves undo", function()
local function test_sub(substring, split, redoable)
clear()
- execute("set inccommand=" .. split)
+ feed_command("set inccommand=" .. split)
insert("1")
feed("o2<esc>")
- execute("undo")
+ feed_command("undo")
feed("o3<esc>")
if redoable then
feed("o4<esc>")
- execute("undo")
+ feed_command("undo")
end
feed(substring.. "<enter>")
- execute("undo")
+ feed_command("undo")
feed("g-")
expect([[
@@ -260,15 +298,15 @@ describe(":substitute, 'inccommand' preserves undo", function()
local function test_notsub(substring, split, redoable)
clear()
- execute("set inccommand=" .. split)
+ feed_command("set inccommand=" .. split)
insert("1")
feed("o2<esc>")
- execute("undo")
+ feed_command("undo")
feed("o3<esc>")
if redoable then
feed("o4<esc>")
- execute("undo")
+ feed_command("undo")
end
feed(substring .. "<esc>")
@@ -294,7 +332,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
local function test_threetree(substring, split)
clear()
- execute("set inccommand=" .. split)
+ feed_command("set inccommand=" .. split)
insert("1")
feed("o2<esc>")
@@ -315,6 +353,14 @@ describe(":substitute, 'inccommand' preserves undo", function()
feed("2u")
feed(substring .. "<esc>")
+ expect([[
+ 1]])
+ feed("g-")
+ expect([[
+ ]])
+ feed("g+")
+ expect([[
+ 1]])
feed("<c-r>")
expect([[
1
@@ -337,9 +383,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
2]])
end
- -- TODO(vim): This does not work, even in Vim.
- -- Waiting for fix (perhaps from upstream).
- pending("at a non-leaf of the undo tree", function()
+ it("at a non-leaf of the undo tree", function()
for _, case in pairs(cases) do
for _, str in pairs(substrings) do
for _, redoable in pairs({true}) do
@@ -381,22 +425,22 @@ describe(":substitute, 'inccommand' preserves undo", function()
for _, case in pairs(cases) do
clear()
common_setup(nil, case, default_text)
- execute("set undolevels=0")
+ feed_command("set undolevels=0")
feed("1G0")
insert("X")
feed(":%s/tw/MO/<esc>")
- execute("undo")
+ feed_command("undo")
expect(default_text)
- execute("undo")
+ feed_command("undo")
expect(default_text:gsub("Inc", "XInc"))
- execute("undo")
+ feed_command("undo")
- execute("%s/tw/MO/g")
+ feed_command("%s/tw/MO/g")
expect(default_text:gsub("tw", "MO"))
- execute("undo")
+ feed_command("undo")
expect(default_text)
- execute("undo")
+ feed_command("undo")
expect(default_text:gsub("tw", "MO"))
end
end)
@@ -407,13 +451,13 @@ describe(":substitute, 'inccommand' preserves undo", function()
for _, case in pairs(cases) do
clear()
common_setup(screen, case, default_text)
- execute("set undolevels=1")
+ feed_command("set undolevels=1")
feed("1G0")
insert("X")
feed("IY<esc>")
feed(":%s/tw/MO/<esc>")
- -- execute("undo") here would cause "Press ENTER".
+ -- feed_command("undo") here would cause "Press ENTER".
feed("u")
expect(default_text:gsub("Inc", "XInc"))
feed("u")
@@ -439,7 +483,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
else
screen:expect([[
@@ -452,7 +496,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
end
end
@@ -465,13 +509,13 @@ describe(":substitute, 'inccommand' preserves undo", function()
for _, case in pairs(cases) do
clear()
common_setup(screen, case, default_text)
- execute("set undolevels=2")
+ feed_command("set undolevels=2")
feed("2GAx<esc>")
feed("Ay<esc>")
feed("Az<esc>")
feed(":%s/tw/AR<esc>")
- -- using execute("undo") here will result in a "Press ENTER" prompt
+ -- feed_command("undo") here would cause "Press ENTER".
feed("u")
expect(default_text:gsub("lines", "linesxy"))
feed("u")
@@ -491,7 +535,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
else
screen:expect([[
@@ -504,7 +548,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
end
@@ -531,7 +575,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
else
screen:expect([[
@@ -544,7 +588,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
end
screen:detach()
@@ -558,9 +602,9 @@ describe(":substitute, 'inccommand' preserves undo", function()
clear()
common_setup(screen, case, default_text)
- execute("set undolevels=-1")
+ feed_command("set undolevels=-1")
feed(":%s/tw/MO/g<enter>")
- -- using execute("undo") here will result in a "Press ENTER" prompt
+ -- feed_command("undo") here will result in a "Press ENTER" prompt
feed("u")
if case == "split" then
screen:expect([[
@@ -573,7 +617,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
else
screen:expect([[
@@ -586,7 +630,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
end
@@ -594,7 +638,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
clear()
common_setup(screen, case, default_text)
- execute("set undolevels=-1")
+ feed_command("set undolevels=-1")
feed("1G")
feed("IL<esc>")
feed(":%s/tw/MO/g<esc>")
@@ -610,7 +654,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
{15:~ }|
{15:~ }|
{15:~ }|
- Already...st change |
+ Already ...t change |
]])
end
screen:detach()
@@ -633,7 +677,7 @@ describe(":substitute, inccommand=split", function()
end)
it("preserves 'modified' buffer flag", function()
- execute("set nomodified")
+ feed_command("set nomodified")
feed(":%s/tw")
screen:expect([[
Inc substitution on |
@@ -761,7 +805,7 @@ describe(":substitute, inccommand=split", function()
it('does not show split window for :s/', function()
feed("2gg")
feed(":s/tw")
- wait()
+ screen:sleep(1)
screen:expect([[
Inc substitution on |
two lines |
@@ -782,7 +826,7 @@ describe(":substitute, inccommand=split", function()
end)
it("'hlsearch' is active, 'cursorline' is not", function()
- execute("set hlsearch cursorline")
+ feed_command("set hlsearch cursorline")
feed("gg")
-- Assert that 'cursorline' is active.
@@ -874,7 +918,7 @@ describe(":substitute, inccommand=split", function()
feed("gg")
feed("2yy")
feed("2000p")
- execute("1,1000s/tw/BB/g")
+ feed_command("1,1000s/tw/BB/g")
feed(":%s/tw/X")
screen:expect([[
@@ -940,9 +984,9 @@ describe(":substitute, inccommand=split", function()
-- Assert that 'inccommand' is ENABLED initially.
eq("split", eval("&inccommand"))
-- Set 'redrawtime' to minimal value, to ensure timeout is triggered.
- execute("set redrawtime=1 nowrap")
+ feed_command("set redrawtime=1 nowrap")
-- Load a big file.
- execute("silent edit! test/functional/fixtures/bigfile.txt")
+ feed_command("silent edit! test/functional/fixtures/bigfile_oneline.txt")
-- Start :substitute with a slow pattern.
feed([[:%s/B.*N/x]])
wait()
@@ -952,19 +996,19 @@ describe(":substitute, inccommand=split", function()
-- Assert that preview cleared (or never manifested).
screen:expect([[
0000;<control>;Cc;0;BN;;;;;N;N|
- 0001;<control>;Cc;0;BN;;;;;N;S|
- 0002;<control>;Cc;0;BN;;;;;N;S|
- 0003;<control>;Cc;0;BN;;;;;N;E|
- 0004;<control>;Cc;0;BN;;;;;N;E|
- 0005;<control>;Cc;0;BN;;;;;N;E|
- 0006;<control>;Cc;0;BN;;;;;N;A|
- 0007;<control>;Cc;0;BN;;;;;N;B|
- 0008;<control>;Cc;0;BN;;;;;N;B|
- 0009;<control>;Cc;0;S;;;;;N;CH|
- 000A;<control>;Cc;0;B;;;;;N;LI|
- 000B;<control>;Cc;0;S;;;;;N;LI|
- 000C;<control>;Cc;0;WS;;;;;N;F|
- 000D;<control>;Cc;0;B;;;;;N;CA|
+ 2F923;CJK COMPATIBILITY IDEOGR|
+ 2F924;CJK COMPATIBILITY IDEOGR|
+ 2F925;CJK COMPATIBILITY IDEOGR|
+ 2F926;CJK COMPATIBILITY IDEOGR|
+ 2F927;CJK COMPATIBILITY IDEOGR|
+ 2F928;CJK COMPATIBILITY IDEOGR|
+ 2F929;CJK COMPATIBILITY IDEOGR|
+ 2F92A;CJK COMPATIBILITY IDEOGR|
+ 2F92B;CJK COMPATIBILITY IDEOGR|
+ 2F92C;CJK COMPATIBILITY IDEOGR|
+ 2F92D;CJK COMPATIBILITY IDEOGR|
+ 2F92E;CJK COMPATIBILITY IDEOGR|
+ 2F92F;CJK COMPATIBILITY IDEOGR|
:%s/B.*N/x^ |
]])
@@ -975,7 +1019,7 @@ describe(":substitute, inccommand=split", function()
it("clears preview if non-previewable command is edited #5585", function()
-- Put a non-previewable command in history.
- execute("echo 'foo'")
+ feed_command("echo 'foo'")
-- Start an incomplete :substitute command.
feed(":1,2s/t/X")
@@ -1036,7 +1080,7 @@ describe("inccommand=nosplit", function()
end)
it("works with :smagic, :snomagic", function()
- execute("set hlsearch")
+ feed_command("set hlsearch")
insert("Line *.3.* here")
feed(":%smagic/3.*/X") -- start :smagic command
@@ -1071,7 +1115,7 @@ describe("inccommand=nosplit", function()
end)
it('never shows preview buffer', function()
- execute("set hlsearch")
+ feed_command("set hlsearch")
feed(":%s/tw")
screen:expect([[
@@ -1132,7 +1176,7 @@ describe("inccommand=nosplit", function()
it("clears preview if non-previewable command is edited", function()
-- Put a non-previewable command in history.
- execute("echo 'foo'")
+ feed_command("echo 'foo'")
-- Start an incomplete :substitute command.
feed(":1,2s/t/X")
@@ -1181,7 +1225,7 @@ describe(":substitute, 'inccommand' with a failing expression", function()
it('in the pattern does nothing', function()
for _, case in pairs(cases) do
refresh(case)
- execute("set inccommand=" .. case)
+ feed_command("set inccommand=" .. case)
feed(":silent! %s/tw\\(/LARD/<enter>")
expect(default_text)
end
@@ -1193,14 +1237,48 @@ describe(":substitute, 'inccommand' with a failing expression", function()
local replacements = { "\\='LARD", "\\=xx_novar__xx" }
for _, repl in pairs(replacements) do
- execute("set inccommand=" .. case)
+ feed_command("set inccommand=" .. case)
feed(":silent! %s/tw/" .. repl .. "/<enter>")
expect(default_text:gsub("tw", ""))
- execute("undo")
+ feed_command("undo")
end
end
end)
+ it('in the range does not error #5912', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ feed(':100s/')
+
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :100s/^ |
+ ]])
+
+ feed('<enter>')
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ ^ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {14:E16: Invalid range} |
+ ]])
+ end
+ end)
+
end)
describe("'inccommand' and :cnoremap", function()
@@ -1214,14 +1292,14 @@ describe("'inccommand' and :cnoremap", function()
it('work with remapped characters', function()
for _, case in pairs(cases) do
refresh(case)
- local command = "%s/lines/LINES/g"
+ local cmd = "%s/lines/LINES/g"
- for i = 1, string.len(command) do
- local c = string.sub(command, i, i)
- execute("cnoremap ".. c .. " " .. c)
+ for i = 1, string.len(cmd) do
+ local c = string.sub(cmd, i, i)
+ feed_command("cnoremap ".. c .. " " .. c)
end
- execute(command)
+ feed_command(cmd)
expect([[
Inc substitution on
two LINES
@@ -1232,7 +1310,7 @@ describe("'inccommand' and :cnoremap", function()
it('work when mappings move the cursor', function()
for _, case in pairs(cases) do
refresh(case)
- execute("cnoremap ,S LINES/<left><left><left><left><left><left>")
+ feed_command("cnoremap ,S LINES/<left><left><left><left><left><left>")
feed(":%s/lines/,Sor three <enter>")
expect([[
@@ -1240,21 +1318,21 @@ describe("'inccommand' and :cnoremap", function()
two or three LINES
]])
- execute("cnoremap ;S /X/<left><left><left>")
+ feed_command("cnoremap ;S /X/<left><left><left>")
feed(":%s/;SI<enter>")
expect([[
Xnc substitution on
two or three LXNES
]])
- execute("cnoremap ,T //Y/<left><left><left>")
+ feed_command("cnoremap ,T //Y/<left><left><left>")
feed(":%s,TX<enter>")
expect([[
Ync substitution on
two or three LYNES
]])
- execute("cnoremap ;T s//Z/<left><left><left>")
+ feed_command("cnoremap ;T s//Z/<left><left><left>")
feed(":%;TY<enter>")
expect([[
Znc substitution on
@@ -1266,7 +1344,7 @@ describe("'inccommand' and :cnoremap", function()
it('does not work with a failing mapping', function()
for _, case in pairs(cases) do
refresh(case)
- execute("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
+ feed_command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
feed(":%s/tw/tox<enter>")
@@ -1279,7 +1357,7 @@ describe("'inccommand' and :cnoremap", function()
it('work when temporarily moving the cursor', function()
for _, case in pairs(cases) do
refresh(case)
- execute("cnoremap <expr> x cursor(1, 1)[-1].'x'")
+ feed_command("cnoremap <expr> x cursor(1, 1)[-1].'x'")
feed(":%s/tw/tox/g<enter>")
expect(default_text:gsub("tw", "tox"))
@@ -1289,7 +1367,7 @@ describe("'inccommand' and :cnoremap", function()
it("work when a mapping disables 'inccommand'", function()
for _, case in pairs(cases) do
refresh(case)
- execute("cnoremap <expr> x execute('set inccommand=')[-1]")
+ feed_command("cnoremap <expr> x execute('set inccommand=')[-1]")
feed(":%s/tw/toxa/g<enter>")
expect(default_text:gsub("tw", "toa"))
@@ -1363,7 +1441,7 @@ describe("'inccommand' autocommands", function()
local function register_autocmd(event)
meths.set_var(event .. "_fired", {})
- execute("autocmd " .. event .. " * call add(g:" .. event .. "_fired, expand('<abuf>'))")
+ feed_command("autocmd " .. event .. " * call add(g:" .. event .. "_fired, expand('<abuf>'))")
end
it('are not fired when splitting', function()
@@ -1416,8 +1494,8 @@ describe("'inccommand' split windows", function()
refresh()
feed("gg")
- execute("vsplit")
- execute("split")
+ feed_command("vsplit")
+ feed_command("split")
feed(":%s/tw")
screen:expect([[
Inc substitution on {10:|}Inc substitution on|
@@ -1453,9 +1531,9 @@ describe("'inccommand' split windows", function()
]])
feed("<esc>")
- execute("only")
- execute("split")
- execute("vsplit")
+ feed_command("only")
+ feed_command("split")
+ feed_command("vsplit")
feed(":%s/tw")
screen:expect([[
@@ -1504,7 +1582,7 @@ describe("'inccommand' split windows", function()
it("are not affected by various settings", function()
for _, setting in pairs(settings) do
refresh()
- execute("set " .. setting)
+ feed_command("set " .. setting)
feed(":%s/tw")
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index cec19250d2..29d974b709 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -1,5 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim
+local clear, feed_command, nvim = helpers.clear, helpers.feed_command, helpers.nvim
local feed, next_message, eq = helpers.feed, helpers.next_message, helpers.eq
local expect = helpers.expect
local Screen = require('test.functional.ui.screen')
@@ -12,7 +12,7 @@ describe('mappings', function()
local add_mapping = function(mapping, send)
local cmd = "nnoremap "..mapping.." :call rpcnotify("..cid..", 'mapped', '"
..send:gsub('<', '<lt>').."')<cr>"
- execute(cmd)
+ feed_command(cmd)
end
local check_mapping = function(mapping, expected)
@@ -57,7 +57,7 @@ describe('feeding large chunks of input with <Paste>', function()
clear()
screen = Screen.new()
screen:attach()
- execute('set ruler')
+ feed_command('set ruler')
end)
it('ok', function()
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
new file mode 100644
index 0000000000..f0cedfeeb5
--- /dev/null
+++ b/test/functional/ui/mode_spec.lua
@@ -0,0 +1,227 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command, eval = helpers.command, helpers.eval
+local eq = helpers.eq
+
+describe('ui mode_change event', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 4)
+ screen:attach({rgb= true})
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=255},
+ [1] = {bold=true, reverse=true},
+ [2] = {bold=true},
+ [3] = {reverse=true},
+ })
+ end)
+
+ it('works in normal mode', function()
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+
+ feed('d')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("operator", screen.mode)
+ end)
+
+ feed('<esc>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+
+ it('works in insert mode', function()
+ feed('i')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]],nil,nil,function ()
+ eq("insert", screen.mode)
+ end)
+
+ feed('word<esc>')
+ screen:expect([[
+ wor^d |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]], nil, nil, function ()
+ eq("normal", screen.mode)
+ end)
+
+ command("set showmatch")
+ eq(eval('&matchtime'), 5) -- tenths of seconds
+ feed('a(stuff')
+ screen:expect([[
+ word(stuff^ |
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]], nil, nil, function ()
+ eq("insert", screen.mode)
+ end)
+
+ feed(')')
+ screen:expect([[
+ word^(stuff) |
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]], nil, nil, function ()
+ eq("showmatch", screen.mode)
+ end)
+
+ screen:sleep(400)
+ screen:expect([[
+ word(stuff)^ |
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]], nil, nil, function ()
+ eq("insert", screen.mode)
+ end)
+ end)
+
+ it('works in replace mode', function()
+ feed('R')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {2:-- REPLACE --} |
+ ]], nil, nil, function ()
+ eq("replace", screen.mode)
+ end)
+
+ feed('word<esc>')
+ screen:expect([[
+ wor^d |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]], nil, nil, function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+
+ it('works in cmdline mode', function()
+ feed(':')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ :^ |
+ ]],nil,nil,function ()
+ eq("cmdline_normal", screen.mode)
+ end)
+
+ feed('x<left>')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ :^x |
+ ]],nil,nil,function ()
+ eq("cmdline_insert", screen.mode)
+ end)
+
+ feed('<insert>')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ :^x |
+ ]],nil,nil,function ()
+ eq("cmdline_replace", screen.mode)
+ end)
+
+
+ feed('<right>')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ :x^ |
+ ]],nil,nil,function ()
+ eq("cmdline_normal", screen.mode)
+ end)
+
+ feed('<esc>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+
+ it('works in visal mode', function()
+ insert("text")
+ feed('v')
+ screen:expect([[
+ tex^t |
+ {0:~ }|
+ {0:~ }|
+ {2:-- VISUAL --} |
+ ]],nil,nil,function ()
+ eq("visual", screen.mode)
+ end)
+
+ feed('<esc>')
+ screen:expect([[
+ tex^t |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+
+ command('set selection=exclusive')
+ feed('v')
+ screen:expect([[
+ tex^t |
+ {0:~ }|
+ {0:~ }|
+ {2:-- VISUAL --} |
+ ]],nil,nil,function ()
+ eq("visual_select", screen.mode)
+ end)
+
+ feed('<esc>')
+ screen:expect([[
+ tex^t |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+end)
+
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 17d949825a..3daf92eea0 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1,21 +1,18 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
-local insert, execute = helpers.insert, helpers.execute
+local insert, feed_command = helpers.insert, helpers.feed_command
local eq, funcs = helpers.eq, helpers.funcs
if helpers.pending_win32(pending) then return end
-describe('Mouse input', function()
+describe('ui/mouse/input', function()
local screen
before_each(function()
clear()
meths.set_option('mouse', 'a')
meths.set_option('listchars', 'eol:$')
- -- set mousetime to very high value to ensure that even in valgrind/travis,
- -- nvim will still pick multiple clicks
- meths.set_option('mousetime', 5000)
screen = Screen.new(25, 5)
screen:attach()
screen:set_default_attr_ids({
@@ -119,13 +116,12 @@ describe('Mouse input', function()
sel = { bold=true },
fill = { reverse=true }
})
- screen.timeout = 15000
end)
it('in tabline on filler space moves tab to the end', function()
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -160,9 +156,9 @@ describe('Mouse input', function()
return
end
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -190,9 +186,9 @@ describe('Mouse input', function()
end)
it('in tabline to the right moves tab right', function()
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -220,9 +216,9 @@ describe('Mouse input', function()
end)
it('out of tabline under filler space moves tab to the end', function()
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -265,9 +261,9 @@ describe('Mouse input', function()
return
end
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -303,9 +299,9 @@ describe('Mouse input', function()
end)
it('out of tabline to the right moves tab right', function()
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -352,9 +348,9 @@ describe('Mouse input', function()
end)
it('left click in default tabline (position 4) switches to tab', function()
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -375,9 +371,9 @@ describe('Mouse input', function()
it('left click in default tabline (position 24) closes tab', function()
meths.set_option('hidden', true)
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -398,9 +394,9 @@ describe('Mouse input', function()
it('double click in default tabline (position 4) opens new tab', function()
meths.set_option('hidden', true)
- execute('%delete')
+ feed_command('%delete')
insert('this is foo')
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
@@ -421,13 +417,13 @@ describe('Mouse input', function()
describe('%@ label', function()
before_each(function()
- execute([[
+ feed_command([[
function Test(...)
let g:reply = a:000
return copy(a:000) " Check for memory leaks: return should be freed
endfunction
]])
- execute([[
+ feed_command([[
function Test2(...)
return call('Test', a:000 + [2])
endfunction
@@ -533,9 +529,9 @@ describe('Mouse input', function()
fill = { reverse=true },
vis = { background=Screen.colors.LightGrey }
})
- execute('silent file foo | tabnew | file bar')
+ feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
- execute('tabprevious') -- go to first tab
+ feed_command('tabprevious') -- go to first tab
screen:expect([[
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
mouse |
@@ -641,7 +637,7 @@ describe('Mouse input', function()
mouse scrolling
]])
screen:try_resize(53, 14)
- execute('sp', 'vsp')
+ feed_command('sp', 'vsp')
screen:expect([[
lines {4:|}lines |
to {4:|}to |
@@ -658,7 +654,7 @@ describe('Mouse input', function()
{4:[No Name] [+] }|
:vsp |
]])
- feed('<MouseUp><0,0>')
+ feed('<ScrollWheelDown><0,0>')
screen:expect([[
mouse scrolling {4:|}lines |
^ {4:|}to |
@@ -675,7 +671,7 @@ describe('Mouse input', function()
{4:[No Name] [+] }|
|
]])
- feed('<MouseDown><27,0>')
+ feed('<ScrollWheelUp><27,0>')
screen:expect([[
mouse scrolling {4:|}text |
^ {4:|}with |
@@ -692,7 +688,7 @@ describe('Mouse input', function()
{4:[No Name] [+] }|
|
]])
- feed('<MouseDown><27,7><MouseDown>')
+ feed('<ScrollWheelUp><27,7><ScrollWheelUp>')
screen:expect([[
mouse scrolling {4:|}text |
^ {4:|}with |
@@ -754,12 +750,12 @@ describe('Mouse input', function()
})
feed('ggdG')
- execute('set concealcursor=n')
- execute('set nowrap')
- execute('syntax match NonText "\\<amet\\>" conceal')
- execute('syntax match NonText "\\cs\\|g." conceal cchar=X')
- execute('syntax match NonText "\\%(lo\\|cl\\)." conceal')
- execute('syntax match NonText "Lo" conceal cchar=Y')
+ feed_command('set concealcursor=n')
+ feed_command('set nowrap')
+ feed_command('syntax match NonText "\\<amet\\>" conceal')
+ feed_command('syntax match NonText "\\cs\\|g." conceal cchar=X')
+ feed_command('syntax match NonText "\\%(lo\\|cl\\)." conceal')
+ feed_command('syntax match NonText "Lo" conceal cchar=Y')
insert([[
Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
@@ -770,7 +766,7 @@ describe('Mouse input', function()
end)
it('(level 1) click on non-wrapped lines', function()
- execute('let &conceallevel=1', 'echo')
+ feed_command('let &conceallevel=1', 'echo')
feed('<esc><LeftMouse><0,0>')
screen:expect([[
@@ -818,7 +814,7 @@ describe('Mouse input', function()
end) -- level 1 - non wrapped
it('(level 1) click on wrapped lines', function()
- execute('let &conceallevel=1', 'let &wrap=1', 'echo')
+ feed_command('let &conceallevel=1', 'let &wrap=1', 'echo')
feed('<esc><LeftMouse><0,0>')
screen:expect([[
@@ -867,7 +863,7 @@ describe('Mouse input', function()
it('(level 2) click on non-wrapped lines', function()
- execute('let &conceallevel=2', 'echo')
+ feed_command('let &conceallevel=2', 'echo')
feed('<esc><LeftMouse><0,0>')
screen:expect([[
@@ -915,7 +911,7 @@ describe('Mouse input', function()
end) -- level 2 - non wrapped
it('(level 2) click on wrapped lines', function()
- execute('let &conceallevel=2', 'let &wrap=1', 'echo')
+ feed_command('let &conceallevel=2', 'let &wrap=1', 'echo')
feed('<esc><LeftMouse><0,0>')
screen:expect([[
@@ -964,7 +960,7 @@ describe('Mouse input', function()
it('(level 3) click on non-wrapped lines', function()
- execute('let &conceallevel=3', 'echo')
+ feed_command('let &conceallevel=3', 'echo')
feed('<esc><LeftMouse><0,0>')
screen:expect([[
@@ -1012,7 +1008,7 @@ describe('Mouse input', function()
end) -- level 3 - non wrapped
it('(level 3) click on wrapped lines', function()
- execute('let &conceallevel=3', 'let &wrap=1', 'echo')
+ feed_command('let &conceallevel=3', 'let &wrap=1', 'echo')
feed('<esc><LeftMouse><0,0>')
screen:expect([[
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index d6d8f1c4e5..c6d564e8dc 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -8,13 +8,13 @@ describe("shell command :!", function()
before_each(function()
session.clear()
screen = child_session.screen_setup(0, '["'..session.nvim_prog..
- '", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]')
+ '", "-u", "NONE", "-i", "NONE", "--cmd", "'..session.nvim_set..'"]')
screen:expect([[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
- {5:[No Name] }|
+ {4:~ }|
|
{3:-- TERMINAL --} |
]])
@@ -25,14 +25,14 @@ describe("shell command :!", function()
screen:detach()
end)
- it("displays output even without LF/EOF. #4646 #4569 #3772", function()
+ it("displays output without LF/EOF. #4646 #4569 #3772", function()
-- NOTE: We use a child nvim (within a :term buffer)
-- to avoid triggering a UI flush.
child_session.feed_data(":!printf foo; sleep 200\n")
screen:expect([[
{4:~ }|
{4:~ }|
- {5:[No Name] }|
+ {4:~ }|
:!printf foo; sleep 200 |
|
foo |
@@ -41,6 +41,11 @@ describe("shell command :!", function()
end)
it("throttles shell-command output greater than ~10KB", function()
+ if os.getenv("TRAVIS") and session.os_name() == "osx" then
+ pending("[Unreliable on Travis macOS.]", function() end)
+ return
+ end
+
screen.timeout = 20000 -- Avoid false failure on slow systems.
child_session.feed_data(
":!for i in $(seq 2 3000); do echo XXXXXXXXXX $i; done\n")
diff --git a/test/functional/ui/quickfix_spec.lua b/test/functional/ui/quickfix_spec.lua
index 29b28fe9f0..b0d89ee3b6 100644
--- a/test/functional/ui/quickfix_spec.lua
+++ b/test/functional/ui/quickfix_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
-local insert, execute = helpers.insert, helpers.execute
+local insert, command = helpers.insert, helpers.command
describe('quickfix selection highlight', function()
@@ -28,8 +28,8 @@ describe('quickfix selection highlight', function()
})
meths.set_option('errorformat', '%m %l')
- execute('syntax on')
- execute('highlight Search guibg=Green')
+ command('syntax on')
+ command('highlight Search guibg=Green')
insert([[
Line 1
@@ -39,7 +39,7 @@ describe('quickfix selection highlight', function()
Line 5
]])
- execute('cad')
+ command('cad')
feed('gg')
screen:expect([[
@@ -52,12 +52,12 @@ describe('quickfix selection highlight', function()
{1:~ }|
{1:~ }|
{1:~ }|
- :cad |
+ |
]])
end)
it('using default Search highlight group', function()
- execute('copen')
+ command('copen')
screen:expect([[
Line 1 |
@@ -69,10 +69,10 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :copen |
+ |
]])
- execute('cnext')
+ command('cnext')
screen:expect([[
Line 1 |
@@ -84,14 +84,14 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :cnext |
+ |
]])
end)
it('using QuickFixLine highlight group', function()
- execute('highlight QuickFixLine guibg=Red')
+ command('highlight QuickFixLine guibg=Red')
- execute('copen')
+ command('copen')
screen:expect([[
Line 1 |
@@ -103,10 +103,10 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :copen |
+ |
]])
- execute('cnext')
+ command('cnext')
screen:expect([[
Line 1 |
@@ -118,16 +118,16 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :cnext |
+ |
]])
end)
it('combines with CursorLine', function()
- execute('set cursorline')
- execute('highlight QuickFixLine guifg=Red')
- execute('highlight CursorLine guibg=Fuchsia')
+ command('set cursorline')
+ command('highlight QuickFixLine guifg=Red')
+ command('highlight CursorLine guibg=Fuchsia')
- execute('copen')
+ command('copen')
screen:expect([[
{9:Line 1 }|
@@ -139,7 +139,7 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :copen |
+ |
]])
feed('j')
@@ -154,16 +154,16 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :copen |
+ |
]])
end)
it('QuickFixLine background takes precedence over CursorLine', function()
- execute('set cursorline')
- execute('highlight QuickFixLine guibg=Red')
- execute('highlight CursorLine guibg=Fuchsia')
+ command('set cursorline')
+ command('highlight QuickFixLine guibg=Red')
+ command('highlight CursorLine guibg=Fuchsia')
- execute('copen')
+ command('copen')
screen:expect([[
{9:Line 1 }|
@@ -175,7 +175,7 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :copen |
+ |
]])
feed('j')
@@ -190,7 +190,7 @@ describe('quickfix selection highlight', function()
|{3:5}| Line |
|| |
{4:[Quickfix List] }|
- :copen |
+ |
]])
end)
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 2581b36711..a6b7fb2997 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -1,31 +1,17 @@
--- This module contains the Screen class, a complete Nvim screen implementation
--- designed for functional testing. The goal is to provide a simple and
--- intuitive API for verifying screen state after a set of actions.
+-- This module contains the Screen class, a complete Nvim UI implementation
+-- designed for functional testing (verifying screen state, in particular).
--
--- The screen class exposes a single assertion method, "Screen:expect". This
--- method takes a string representing the expected screen state and an optional
--- set of attribute identifiers for checking highlighted characters(more on
--- this later).
---
--- The string passed to "expect" will be processed according to these rules:
---
--- - Each line of the string represents and is matched individually against
--- a screen row.
--- - The entire string is stripped of common indentation
--- - Expected screen rows are stripped of the last character. The last
--- character should be used to write pipes(|) that make clear where the
--- screen ends
--- - The last line is stripped, so the string must have (row count + 1)
--- lines.
+-- Screen:expect() takes a string representing the expected screen state and an
+-- optional set of attribute identifiers for checking highlighted characters.
--
-- Example usage:
--
-- local screen = Screen.new(25, 10)
--- -- attach the screen to the current Nvim instance
+-- -- Attach the screen to the current Nvim instance.
-- screen:attach()
--- --enter insert mode and type some text
+-- -- Enter insert-mode and type some text.
-- feed('ihello screen')
--- -- declare an expectation for the eventual screen state
+-- -- Assert the expected screen state.
-- screen:expect([[
-- hello screen |
-- ~ |
@@ -39,31 +25,19 @@
-- -- INSERT -- |
-- ]]) -- <- Last line is stripped
--
--- Since screen updates are received asynchronously, "expect" is actually
--- specifying the eventual screen state. This is how "expect" works: It will
--- start the event loop with a timeout of 5 seconds. Each time it receives an
--- update the expected state will be checked against the updated state.
---
--- If the expected state matches the current state, the event loop will be
--- stopped and "expect" will return. If the timeout expires, the last match
--- error will be reported and the test will fail.
+-- Since screen updates are received asynchronously, expect() actually specifies
+-- the _eventual_ screen state.
--
--- If the second argument is passed to "expect", the screen rows will be
--- transformed before being matched against the string lines. The
--- transformation rule is simple: Each substring "S" composed with characters
--- having the exact same set of attributes will be substituted by "{K:S}",
--- where K is a key associated the attribute set via the second argument of
--- "expect".
--- If a transformation table is present, unexpected attribute sets in the final
--- state is considered an error. To make testing simpler, a list of attribute
--- sets that should be ignored can be passed as a third argument. Alternatively,
--- this third argument can be "true" to indicate that all unexpected attribute
--- sets should be ignored.
+-- This is how expect() works:
+-- * It starts the event loop with a timeout.
+-- * Each time it receives an update it checks that against the expected state.
+-- * If the expected state matches the current state, the event loop will be
+-- stopped and expect() will return.
+-- * If the timeout expires, the last match error will be reported and the
+-- test will fail.
--
--- To illustrate how this works, let's say that in the above example we wanted
--- to assert that the "-- INSERT --" string is highlighted with the bold
--- attribute(which normally is), here's how the call to "expect" should look
--- like:
+-- Continuing the above example, say we want to assert that "-- INSERT --" is
+-- highlighted with the bold attribute. The expect() call should look like this:
--
-- NonText = Screen.colors.Blue
-- screen:expect([[
@@ -81,29 +55,21 @@
--
-- In this case "b" is a string associated with the set composed of one
-- attribute: bold. Note that since the {b:} markup is not a real part of the
--- screen, the delimiter(|) had to be moved right. Also, the highlighting of the
--- NonText markers (~) is ignored in this test.
+-- screen, the delimiter "|" moved to the right. Also, the highlighting of the
+-- NonText markers "~" is ignored in this test.
+--
+-- Tests will often share a group of attribute sets to expect(). Those can be
+-- defined at the beginning of a test:
--
--- Multiple expect:s will likely share a group of attribute sets to test.
--- Therefore these could be specified at the beginning of a test like this:
-- NonText = Screen.colors.Blue
-- screen:set_default_attr_ids( {
-- [1] = {reverse = true, bold = true},
-- [2] = {reverse = true}
-- })
-- screen:set_default_attr_ignore( {{}, {bold=true, foreground=NonText}} )
--- These can be overridden for a specific expect expression, by passing
--- different sets as parameters.
--
--- To help writing screen tests, there is a utility function
--- "screen:snapshot_util()", that can be placed in a test file at any point an
--- "expect(...)" should be. It will wait a short amount of time and then dump
--- the current state of the screen, in the form of an "expect(..)" expression
--- that would match it exactly. "snapshot_util" optionally also take the
--- transformation and ignore set as parameters, like expect, or uses the default
--- set. It will generate a larger attribute transformation set, if needed.
--- To generate a text-only test without highlight checks,
--- use `screen:snapshot_util({},true)`
+-- To help write screen tests, see Screen:snapshot_util().
+-- To debug screen tests, see Screen:redraw_debug().
local helpers = require('test.functional.helpers')(nil)
local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
@@ -205,24 +171,45 @@ end
function Screen:try_resize(columns, rows)
uimeths.try_resize(columns, rows)
+ -- Give ourselves a chance to _handle_resize, which requires using
+ -- self.sleep() (for the resize notification) rather than run()
+ self:sleep(0.1)
end
-- Asserts that `expected` eventually matches the screen state.
--
--- expected: Expected screen state (string).
--- attr_ids: Text attribute definitions.
--- attr_ignore: Ignored text attributes.
+-- expected: Expected screen state (string). Each line represents a screen
+-- row. Last character of each row (typically "|") is stripped.
+-- Common indentation is stripped.
+-- Used as `condition` if NOT a string; must be the ONLY arg then.
+-- attr_ids: Expected text attributes. Screen rows are transformed according
+-- to this table, as follows: each substring S composed of
+-- characters having the same attributes will be substituted by
+-- "{K:S}", where K is a key in `attr_ids`. Any unexpected
+-- attributes in the final state are an error.
+-- attr_ignore: Ignored text attributes, or `true` to ignore all.
-- condition: Function asserting some arbitrary condition.
-- any: true: Succeed if `expected` matches ANY screen line(s).
-- false (default): `expected` must match screen exactly.
function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
- -- remove the last line and dedent
- expected = dedent(expected:gsub('\n[ ]+$', ''))
local expected_rows = {}
- for row in expected:gmatch('[^\n]+') do
- -- the last character should be the screen delimiter
- row = row:sub(1, #row - 1)
- table.insert(expected_rows, row)
+ if type(expected) ~= "string" then
+ assert(not (attr_ids or attr_ignore or condition or any))
+ condition = expected
+ expected = nil
+ else
+ -- Remove the last line and dedent. Note that gsub returns more then one
+ -- value.
+ expected = dedent(expected:gsub('\n[ ]+$', ''), 0)
+ for row in expected:gmatch('[^\n]+') do
+ row = row:sub(1, #row - 1) -- Last char must be the screen delimiter.
+ table.insert(expected_rows, row)
+ end
+ if not any then
+ assert(self._height == #expected_rows,
+ "Expected screen state's row count(" .. #expected_rows
+ .. ') differs from configured height(' .. self._height .. ') of Screen.')
+ end
end
local ids = attr_ids or self._default_attr_ids
local ignore = attr_ignore or self._default_attr_ignore
@@ -238,7 +225,9 @@ function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
actual_rows[i] = self:_row_repr(self._rows[i], ids, ignore)
end
- if any then
+ if expected == nil then
+ return
+ elseif any then
-- Search for `expected` anywhere in the screen lines.
local actual_screen_str = table.concat(actual_rows, '\n')
if nil == string.find(actual_screen_str, expected) then
@@ -262,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
@@ -296,18 +285,13 @@ function Screen:wait(check, timeout)
if failure_after_success then
print([[
-Warning: Screen changes have been received after the expected state was seen.
-This is probably due to an indeterminism in the test. Try adding
-`wait()` (or even a separate `screen:expect(...)`) at a point of possible
-indeterminism, typically in between a `feed()` or `execute()` which is non-
-synchronous, and a synchronous api call.
-
-Note that sometimes a `wait` can trigger redraws and consequently generate more
-indeterminism. If adding `wait` calls seems to increase the frequency of these
-messages, try removing every `wait` call in the test.
-
-If everything else fails, use Screen:redraw_debug to help investigate what is
- causing the problem.
+
+Warning: Screen changes were received after the expected state. This indicates
+indeterminism in the test. Try adding wait() (or screen:expect(...)) between
+asynchronous (feed(), nvim_input()) and synchronous API calls.
+ - Use Screen:redraw_debug() to investigate the problem.
+ - wait() can trigger redraws and consequently generate more indeterminism.
+ In that case try removing every wait().
]])
local tb = debug.traceback()
local index = string.find(tb, '\n%s*%[C]')
@@ -329,10 +313,13 @@ function Screen:_redraw(updates)
-- print(require('inspect')(update))
local method = update[1]
for i = 2, #update do
- local handler = self['_handle_'..method]
+ local handler_name = '_handle_'..method
+ local handler = self[handler_name]
if handler ~= nil then
handler(self, unpack(update[i]))
else
+ assert(self._on_event,
+ "Add Screen:"..handler_name.." or call Screen:set_on_event_handler")
self._on_event(method, update[i])
end
end
@@ -363,6 +350,11 @@ function Screen:_handle_resize(width, height)
}
end
+function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
+ self._cursor_style_enabled = cursor_style_enabled
+ self._mode_info = mode_info
+end
+
function Screen:_handle_clear()
self:_clear_block(self._scroll_region.top, self._scroll_region.bot,
self._scroll_region.left, self._scroll_region.right)
@@ -394,9 +386,8 @@ function Screen:_handle_mouse_off()
self._mouse_enabled = false
end
-function Screen:_handle_mode_change(mode)
- assert(mode == 'insert' or mode == 'replace'
- or mode == 'normal' or mode == 'cmdline')
+function Screen:_handle_mode_change(mode, idx)
+ assert(mode == self._mode_info[idx+1].name)
self.mode = mode
end
@@ -541,8 +532,12 @@ function Screen:_current_screen()
return table.concat(rv, '\n')
end
+-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
+-- dumps the current screen state in the form of Screen:expect().
+-- Use snapshot_util({},true) to generate a text-only (no attributes) test.
+--
+-- @see Screen:redraw_debug()
function Screen:snapshot_util(attrs, ignore)
- -- util to generate screen test
self:sleep(250)
self:print_snapshot(attrs, ignore)
end
@@ -629,7 +624,7 @@ function Screen:_pprint_attrs(attrs)
return table.concat(items, ", ")
end
-function backward_find_meaningful(tbl, from) -- luacheck: ignore
+local function backward_find_meaningful(tbl, from) -- luacheck: no unused
for i = from or #tbl, 1, -1 do
if tbl[i] ~= ' ' then
return i + 1
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index d03f98c26f..bfcdc7f652 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -1,16 +1,15 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.clear
-local feed, execute = helpers.feed, helpers.execute
+local feed, command = helpers.feed, helpers.command
local insert = helpers.insert
local eq = helpers.eq
+local eval = helpers.eval
-if helpers.pending_win32(pending) then return end
-
-describe('Initial screen', function()
+describe('screen', function()
local screen
local nvim_argv = {helpers.nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N',
- '--cmd', 'set shortmess+=I background=light noswapfile',
+ '--cmd', 'set shortmess+=I background=light noswapfile belloff= noshowcmd noruler',
'--embed'}
before_each(function()
@@ -28,7 +27,7 @@ describe('Initial screen', function()
screen:detach()
end)
- it('is the default initial screen', function()
+ it('default initial screen', function()
screen:expect([[
^ |
{0:~ }|
@@ -74,33 +73,29 @@ describe('Screen', function()
describe(':suspend', function()
it('is forwarded to the UI', function()
local function check()
- if not screen.suspended then
- return 'Screen was not suspended'
- end
+ eq(true, screen.suspended)
end
- execute('suspend')
- screen:wait(check)
+ command('suspend')
+ screen:expect(check)
screen.suspended = false
feed('<c-z>')
- screen:wait(check)
+ screen:expect(check)
end)
end)
describe('bell/visual bell', function()
it('is forwarded to the UI', function()
feed('<left>')
- screen:wait(function()
- if not screen.bell or screen.visual_bell then
- return 'Bell was not sent'
- end
+ screen:expect(function()
+ eq(true, screen.bell)
+ eq(false, screen.visual_bell)
end)
screen.bell = false
- execute('set visualbell')
+ command('set visualbell')
feed('<left>')
- screen:wait(function()
- if not screen.visual_bell or screen.bell then
- return 'Visual bell was not sent'
- end
+ screen:expect(function()
+ eq(true, screen.visual_bell)
+ eq(false, screen.bell)
end)
end)
end)
@@ -108,36 +103,27 @@ describe('Screen', function()
describe(':set title', function()
it('is forwarded to the UI', function()
local expected = 'test-title'
- execute('set titlestring='..expected)
- execute('set title')
- screen:wait(function()
- local actual = screen.title
- if actual ~= expected then
- return 'Expected title to be "'..expected..'" but was "'..actual..'"'
- end
+ command('set titlestring='..expected)
+ command('set title')
+ screen:expect(function()
+ eq(expected, screen.title)
end)
end)
it('has correct default title with unnamed file', function()
local expected = '[No Name] - NVIM'
- execute('set title')
- screen:wait(function()
- local actual = screen.title
- if actual ~= expected then
- return 'Expected title to be "'..expected..'" but was "'..actual..'"'
- end
+ command('set title')
+ screen:expect(function()
+ eq(expected, screen.title)
end)
end)
it('has correct default title with named file', function()
local expected = 'myfile (/mydir) - NVIM'
- execute('set title')
- execute('file /mydir/myfile')
- screen:wait(function()
- local actual = screen.title
- if actual ~= expected then
- return 'Expected title to be "'..expected..'" but was "'..actual..'"'
- end
+ command('set title')
+ command('file /mydir/myfile')
+ screen:expect(function()
+ eq(expected, screen.title)
end)
end)
end)
@@ -145,13 +131,10 @@ describe('Screen', function()
describe(':set icon', function()
it('is forwarded to the UI', function()
local expected = 'test-icon'
- execute('set iconstring='..expected)
- execute('set icon')
- screen:wait(function()
- local actual = screen.icon
- if actual ~= expected then
- return 'Expected title to be "'..expected..'" but was "'..actual..'"'
- end
+ command('set iconstring='..expected)
+ command('set icon')
+ screen:expect(function()
+ eq(expected, screen.icon)
end)
end)
end)
@@ -159,7 +142,7 @@ describe('Screen', function()
describe('window', function()
describe('split', function()
it('horizontal', function()
- execute('sp')
+ command('sp')
screen:expect([[
^ |
{0:~ }|
@@ -174,13 +157,13 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{3:[No Name] }|
- :sp |
+ |
]])
end)
it('horizontal and resize', function()
- execute('sp')
- execute('resize 8')
+ command('sp')
+ command('resize 8')
screen:expect([[
^ |
{0:~ }|
@@ -195,12 +178,14 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{3:[No Name] }|
- :resize 8 |
+ |
]])
end)
it('horizontal and vertical', function()
- execute('sp', 'vsp', 'vsp')
+ command('sp')
+ command('vsp')
+ command('vsp')
screen:expect([[
^ {3:|} {3:|} |
{0:~ }{3:|}{0:~ }{3:|}{0:~ }|
@@ -240,7 +225,9 @@ describe('Screen', function()
describe('tabnew', function()
it('creates a new buffer', function()
- execute('sp', 'vsp', 'vsp')
+ command('sp')
+ command('vsp')
+ command('vsp')
insert('hello')
screen:expect([[
hell^o {3:|}hello {3:|}hello |
@@ -258,7 +245,7 @@ describe('Screen', function()
{3:[No Name] [+] }|
|
]])
- execute('tabnew')
+ command('tabnew')
insert('hello2')
feed('h')
screen:expect([[
@@ -277,7 +264,7 @@ describe('Screen', function()
{0:~ }|
|
]])
- execute('tabprevious')
+ command('tabprevious')
screen:expect([[
{2: }{6:4}{2:+ [No Name] }{4: + [No Name] }{3: }{4:X}|
hell^o {3:|}hello {3:|}hello |
@@ -322,9 +309,9 @@ describe('Screen', function()
describe('normal mode', function()
-- https://code.google.com/p/vim/issues/detail?id=339
it("setting 'ruler' doesn't reset the preferred column", function()
- execute('set virtualedit=')
+ command('set virtualedit=')
feed('i0123456<cr>789<esc>kllj')
- execute('set ruler')
+ command('set ruler')
feed('k')
screen:expect([[
0123^456 |
@@ -340,7 +327,7 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :set ruler 1,5 All |
+ 1,5 All |
]])
end)
end)
@@ -405,7 +392,9 @@ describe('Screen', function()
split
windows
]])
- execute('sp', 'vsp', 'vsp')
+ command('sp')
+ command('vsp')
+ command('vsp')
screen:expect([[
and {3:|}and {3:|}and |
clearing {3:|}clearing {3:|}clearing |
@@ -563,11 +552,10 @@ describe('Screen', function()
]])
end)
- -- FIXME this has some race conditions that cause it to fail periodically
- pending('has minimum width/height values', function()
+ it('has minimum width/height values', function()
screen:try_resize(1, 1)
screen:expect([[
- -- INS^ERT --|
+ {2:-- INS^ERT --}|
|
]])
feed('<esc>:ls')
@@ -578,116 +566,61 @@ describe('Screen', function()
end)
end)
- describe('mode change', function()
- before_each(function()
- screen:try_resize(25, 5)
- end)
-
- it('works in normal mode', function()
+ describe('press enter', function()
+ it('does not crash on <F1> at “Press ENTER”', function()
+ command('nnoremap <F1> :echo "TEST"<CR>')
+ feed(':ls<CR>')
screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
- end)
-
- it('works in insert mode', function()
- feed('i')
- screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {2:-- INSERT --} |
- ]],nil,nil,function ()
- eq("insert", screen.mode)
- end)
-
- feed('word<esc>')
- screen:expect([[
- wor^d |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]], nil, nil, function ()
- eq("normal", screen.mode)
- end)
- end)
-
- it('works in replace mode', function()
- feed('R')
- screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {2:-- REPLACE --} |
- ]], nil, nil, function ()
- eq("replace", screen.mode)
- end)
-
- feed('word<esc>')
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<F1>')
screen:expect([[
- wor^d |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]], nil, nil, function ()
- eq("normal", screen.mode)
- end)
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ TEST |
+ ]])
end)
+ end)
+end)
- it('works in cmdline mode', function()
- feed(':')
- screen:expect([[
- |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- :^ |
- ]],nil,nil,function ()
- eq("cmdline", screen.mode)
- end)
-
- feed('<esc>/')
- screen:expect([[
- |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- /^ |
- ]],nil,nil,function ()
- eq("cmdline", screen.mode)
- end)
-
-
- feed('<esc>?')
- screen:expect([[
- |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- ?^ |
- ]],nil,nil,function ()
- eq("cmdline", screen.mode)
- end)
-
- feed('<esc>')
- screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
- end)
+describe('nvim_ui_attach()', function()
+ before_each(function()
+ clear()
+ end)
+ it('handles very large width/height #2180', function()
+ local screen = Screen.new(999, 999)
+ screen:attach()
+ eq(999, eval('&lines'))
+ eq(999, eval('&columns'))
+ end)
+ it('invalid option returns error', function()
+ local screen = Screen.new()
+ local status, rv = pcall(function() screen:attach({foo={'foo'}}) end)
+ eq(false, status)
+ eq('No such ui option', rv:match("No such .*"))
end)
end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 3914648e8f..11b18d015f 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local execute = helpers.execute
+local feed_command = helpers.feed_command
if helpers.pending_win32(pending) then return end
@@ -22,7 +22,7 @@ describe('search highlighting', function()
end)
it('is disabled by ":set nohlsearch"', function()
- execute('set nohlsearch')
+ feed_command('set nohlsearch')
insert("some text\nmore text")
feed("gg/text<cr>")
screen:expect([[
@@ -79,7 +79,7 @@ describe('search highlighting', function()
/\<text\> |
]])
- execute("nohlsearch")
+ feed_command("nohlsearch")
screen:expect([[
some text |
more textstuff |
@@ -92,8 +92,8 @@ describe('search highlighting', function()
end)
it('works with incsearch', function()
- execute('set hlsearch')
- execute('set incsearch')
+ feed_command('set hlsearch')
+ feed_command('set incsearch')
insert([[
the first line
in a little file
@@ -156,8 +156,8 @@ describe('search highlighting', function()
end)
it('works with incsearch and offset', function()
- execute('set hlsearch')
- execute('set incsearch')
+ feed_command('set hlsearch')
+ feed_command('set incsearch')
insert([[
not the match you're looking for
the match is here]])
@@ -198,7 +198,7 @@ describe('search highlighting', function()
end)
it('works with multiline regexps', function()
- execute('set hlsearch')
+ feed_command('set hlsearch')
feed('4oa repeated line<esc>')
feed('/line\\na<cr>')
screen:expect([[
@@ -234,19 +234,19 @@ describe('search highlighting', function()
[6] = {italic = true, background = colors.Magenta},
[7] = {bold = true, background = colors.Yellow},
} )
- execute('set hlsearch')
+ feed_command('set hlsearch')
insert([[
very special text
]])
- execute("syntax on")
- execute("highlight MyGroup guibg=Green gui=bold")
- execute("highlight MyGroup2 guibg=Magenta gui=italic")
- execute("call matchadd('MyGroup', 'special')")
- execute("call matchadd('MyGroup2', 'text', 0)")
+ feed_command("syntax on")
+ feed_command("highlight MyGroup guibg=Green gui=bold")
+ feed_command("highlight MyGroup2 guibg=Magenta gui=italic")
+ feed_command("call matchadd('MyGroup', 'special')")
+ feed_command("call matchadd('MyGroup2', 'text', 0)")
-- searchhl and matchadd matches are exclusive, only the higest priority
-- is used (and matches with lower priorities are not combined)
- execute("/ial te")
+ feed_command("/ial te")
screen:expect([[
very {5:spec^ial}{2: te}{6:xt} |
|
@@ -257,7 +257,7 @@ describe('search highlighting', function()
{4:search hit BOTTOM, continuing at TOP} |
]])
- execute("call clearmatches()")
+ feed_command("call clearmatches()")
screen:expect([[
very spec{2:^ial te}xt |
|
@@ -270,7 +270,7 @@ describe('search highlighting', function()
-- searchhl has priority over syntax, but in this case
-- nonconflicting attributes are combined
- execute("syntax keyword MyGroup special")
+ feed_command("syntax keyword MyGroup special")
screen:expect([[
very {5:spec}{7:^ial}{2: te}xt |
|
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index d02fc83809..e5c96f2ec0 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+local clear, feed, command = helpers.clear, helpers.feed, helpers.command
if helpers.pending_win32(pending) then return end
@@ -25,11 +25,11 @@ describe('Signs', function()
describe(':sign place', function()
it('shadows previously placed signs', function()
feed('ia<cr>b<cr>c<cr><esc>')
- execute('sign define piet text=>> texthl=Search')
- execute('sign define pietx text=>! texthl=Search')
- execute('sign place 1 line=1 name=piet buffer=1')
- execute('sign place 2 line=3 name=piet buffer=1')
- execute('sign place 3 line=1 name=pietx buffer=1')
+ command('sign define piet text=>> texthl=Search')
+ command('sign define pietx text=>! texthl=Search')
+ command('sign place 1 line=1 name=piet buffer=1')
+ command('sign place 2 line=3 name=piet buffer=1')
+ command('sign place 3 line=1 name=pietx buffer=1')
screen:expect([[
{1:>!}a |
{2: }b |
@@ -44,7 +44,7 @@ describe('Signs', function()
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
- :sign place 3 line=1 name=pietx buffer=1 |
+ |
]])
end)
end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index ee3e4fa32a..28a104360d 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+local clear, feed, command = helpers.clear, helpers.feed, helpers.command
local insert = helpers.insert
if helpers.pending_win32(pending) then return end
@@ -25,7 +25,7 @@ describe('Screen', function()
describe("match and conceal", function()
before_each(function()
- execute("let &conceallevel=1")
+ command("let &conceallevel=1")
end)
describe("multiple", function()
@@ -38,7 +38,7 @@ describe('Screen', function()
&&
&&
]])
- execute("syn match dAmpersand '[&][&]' conceal cchar=∧")
+ command("syn match dAmpersand '[&][&]' conceal cchar=∧")
end)
it("double characters.", function()
@@ -52,7 +52,7 @@ describe('Screen', function()
^ |
{0:~ }|
{0:~ }|
- :syn match dAmpersand '[&][&]' conceal cchar=∧ |
+ |
]])
end)
@@ -68,7 +68,7 @@ describe('Screen', function()
|
{0:~ }|
{0:~ }|
- :syn match dAmpersand '[&][&]' conceal cchar=∧ |
+ |
]])
end)
@@ -84,7 +84,7 @@ describe('Screen', function()
|
{0:~ }|
{0:~ }|
- :syn match dAmpersand '[&][&]' conceal cchar=∧ |
+ |
]])
end)
@@ -100,7 +100,7 @@ describe('Screen', function()
|
{0:~ }|
{0:~ }|
- :syn match dAmpersand '[&][&]' conceal cchar=∧ |
+ |
]])
end)
@@ -116,15 +116,15 @@ describe('Screen', function()
^ |
{0:~ }|
{0:~ }|
- :syn match dAmpersand '[&][&]' conceal cchar=∧ |
+ |
]])
end)
end) -- multiple
it("keyword instances in initially in the document.", function()
feed("2ilambda<cr><ESC>")
- execute("let &conceallevel=1")
- execute("syn keyword kLambda lambda conceal cchar=λ")
+ command("let &conceallevel=1")
+ command("syn keyword kLambda lambda conceal cchar=λ")
screen:expect([[
{1:λ} |
{1:λ} |
@@ -135,7 +135,7 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :syn keyword kLambda lambda conceal cchar=λ |
+ |
]])
end) -- Keyword
@@ -144,11 +144,11 @@ describe('Screen', function()
before_each(function()
feed("2")
insert("<r> a region of text </r>\n")
- execute("let &conceallevel=1")
+ command("let &conceallevel=1")
end)
it('initially and conceal it.', function()
- execute("syn region rText start='<r>' end='</r>' conceal cchar=R")
+ command("syn region rText start='<r>' end='</r>' conceal cchar=R")
screen:expect([[
{1:R} |
{1:R} |
@@ -166,7 +166,7 @@ describe('Screen', function()
it('initially and conceal its start tag and end tag.', function()
-- concealends has a known bug (todo.txt) where the first match won't
-- be replaced with cchar.
- execute("syn region rText matchgroup=rMatch start='<r>' end='</r>' concealends cchar=-")
+ command("syn region rText matchgroup=rMatch start='<r>' end='</r>' concealends cchar=-")
screen:expect([[
{1: } a region of text {1:-} |
{1: } a region of text {1:-} |
@@ -182,7 +182,7 @@ describe('Screen', function()
end)
it('that are nested and conceal the nested region\'s start and end tags.', function()
- execute("syn region rText contains=rText matchgroup=rMatch start='<r>' end='</r>' concealends cchar=-")
+ command("syn region rText contains=rText matchgroup=rMatch start='<r>' end='</r>' concealends cchar=-")
insert("<r> A region with <r> a nested <r> nested region.</r> </r> </r>\n")
screen:expect([[
{1: } a region of text {1:-} |
@@ -201,10 +201,10 @@ describe('Screen', function()
describe("a region of text", function()
before_each(function()
- execute("syntax conceal on")
+ command("syntax conceal on")
feed("2")
insert("<r> a region of text </r>\n")
- execute("syn region rText start='<r>' end='</r>' cchar=-")
+ command("syn region rText start='<r>' end='</r>' cchar=-")
end)
it("and turn on implicit concealing", function()
@@ -218,15 +218,15 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :syn region rText start='<r>' end='</r>' cchar=- |
+ |
]])
end)
it("and then turn on, then off, and then back on implicit concealing.", function()
- execute("syntax conceal off")
+ command("syntax conceal off")
feed("2")
insert("<i> italian text </i>\n")
- execute("syn region iText start='<i>' end='</i>' cchar=*")
+ command("syn region iText start='<i>' end='</i>' cchar=*")
screen:expect([[
{1:-} |
{1:-} |
@@ -237,10 +237,10 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :syn region iText start='<i>' end='</i>' cchar=* |
+ |
]])
- execute("syntax conceal on")
- execute("syn region iText start='<i>' end='</i>' cchar=*")
+ command("syntax conceal on")
+ command("syn region iText start='<i>' end='</i>' cchar=*")
screen:expect([[
{1:-} |
{1:-} |
@@ -251,7 +251,7 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :syn region iText start='<i>' end='</i>' cchar=* |
+ |
]])
end)
end) -- a region of text (implicit concealing)
@@ -262,13 +262,13 @@ describe('Screen', function()
insert("// No Conceal\n")
insert('"Conceal without a cchar"\n')
insert("+ With cchar\n\n")
- execute("syn match noConceal '^//.*$'")
- execute("syn match concealNoCchar '\".\\{-}\"$' conceal")
- execute("syn match concealWCchar '^+.\\{-}$' conceal cchar=C")
+ command("syn match noConceal '^//.*$'")
+ command("syn match concealNoCchar '\".\\{-}\"$' conceal")
+ command("syn match concealWCchar '^+.\\{-}$' conceal cchar=C")
end)
it("0. No concealing.", function()
- execute("let &conceallevel=0")
+ command("let &conceallevel=0")
screen:expect([[
// No Conceal |
"Conceal without a cchar" |
@@ -279,12 +279,12 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :let &conceallevel=0 |
+ |
]])
end)
it("1. Conceal using cchar or reference listchars.", function()
- execute("let &conceallevel=1")
+ command("let &conceallevel=1")
screen:expect([[
// No Conceal |
{1: } |
@@ -295,12 +295,12 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :let &conceallevel=1 |
+ |
]])
end)
it("2. Hidden unless cchar is set.", function()
- execute("let &conceallevel=2")
+ command("let &conceallevel=2")
screen:expect([[
// No Conceal |
|
@@ -311,12 +311,12 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :let &conceallevel=2 |
+ |
]])
end)
it("3. Hide all concealed text.", function()
- execute("let &conceallevel=3")
+ command("let &conceallevel=3")
screen:expect([[
// No Conceal |
|
@@ -327,7 +327,7 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- :let &conceallevel=3 |
+ |
]])
end)
end) -- conceallevel
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
new file mode 100644
index 0000000000..56331a33b5
--- /dev/null
+++ b/test/functional/ui/tabline_spec.lua
@@ -0,0 +1,57 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, command, eq = helpers.clear, helpers.command, helpers.eq
+
+describe('ui/tabline', function()
+ local screen
+ local event_tabs, event_curtab
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach({rgb=true, ext_tabline=true})
+ screen:set_on_event_handler(function(name, data)
+ if name == "tabline_update" then
+ event_curtab, event_tabs = unpack(data)
+ end
+ end)
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ describe('externalized', function()
+ it('publishes UI events', function()
+ command("tabedit another-tab")
+
+ local expected_tabs = {
+ {tab = { id = 1 }, name = '[No Name]'},
+ {tab = { id = 2 }, name = 'another-tab'},
+ }
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], nil, nil, function()
+ eq({ id = 2 }, event_curtab)
+ eq(expected_tabs, event_tabs)
+ end)
+
+ command("tabNext")
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], nil, nil, function()
+ eq({ id = 1 }, event_curtab)
+ eq(expected_tabs, event_tabs)
+ end)
+
+ end)
+ end)
+end)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 6a6dc99c3d..41a751c284 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -1,36 +1,151 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+local clear, feed, command = helpers.clear, helpers.feed, helpers.command
+local iswin = helpers.iswin
local funcs = helpers.funcs
+local eq = helpers.eq
+local eval = helpers.eval
+local retry = helpers.retry
-if helpers.pending_win32(pending) then return end
-
-describe("'wildmode'", function()
+describe("'wildmenu'", function()
local screen
-
before_each(function()
clear()
screen = Screen.new(25, 5)
screen:attach()
end)
-
after_each(function()
screen:detach()
end)
- describe("'wildmenu'", function()
- it(':sign <tab> shows wildmenu completions', function()
- execute('set wildmode=full')
- execute('set wildmenu')
- feed(':sign <tab>')
- screen:expect([[
- |
- ~ |
- ~ |
- define jump list > |
- :sign define^ |
- ]])
+ it(':sign <tab> shows wildmenu completions', function()
+ command('set wildmode=full')
+ command('set wildmenu')
+ feed(':sign <tab>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ define jump list > |
+ :sign define^ |
+ ]])
+ end)
+
+ it('does not crash after cycling back to original text', function()
+ command('set wildmode=full')
+ feed(':j<Tab><Tab><Tab>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ join jumps |
+ :j^ |
+ ]])
+ -- This would cause nvim to crash before #6650
+ feed('<BS><Tab>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ! # & < = > @ > |
+ :!^ |
+ ]])
+ end)
+
+ it('is preserved during :terminal activity', function()
+ -- Because this test verifies a _lack_ of activity after screen:sleep(), we
+ -- must wait the full timeout. So make it reasonable.
+ screen.timeout = 1000
+
+ command('set wildmenu wildmode=full')
+ command('set scrollback=4')
+ if iswin() then
+ if helpers.pending_win32(pending) then return end
+ -- feed([[:terminal 1,2,3,4,5 | foreach-object -process {echo $_; sleep 0.1}]])
+ else
+ feed([[:terminal for i in $(seq 1 5000); do printf 'foo\nfoo\nfoo\n'; sleep 0.1; done<cr>]])
+ end
+
+ feed([[<C-\><C-N>gg]])
+ feed([[:sign <Tab>]]) -- Invoke wildmenu.
+ screen:sleep(50) -- Allow some terminal output.
+ screen:expect([[
+ foo |
+ foo |
+ foo |
+ define jump list > |
+ :sign define^ |
+ ]])
+
+ -- cmdline CTRL-D display should also be preserved.
+ feed([[<C-\><C-N>]])
+ feed([[:sign <C-D>]]) -- Invoke cmdline CTRL-D.
+ screen:sleep(50) -- Allow some terminal output.
+ screen:expect([[
+ :sign |
+ define place |
+ jump undefine |
+ list unplace |
+ :sign ^ |
+ ]])
+
+ -- Exiting cmdline should show the buffer.
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ ^foo |
+ foo |
+ foo |
+ foo |
+ |
+ ]])
+ end)
+
+ it('ignores :redrawstatus called from a timer #7108', function()
+ -- Because this test verifies a _lack_ of activity after screen:sleep(), we
+ -- must wait the full timeout. So make it reasonable.
+ screen.timeout = 1000
+
+ command('set wildmenu wildmode=full')
+ command([[call timer_start(10, {->execute('redrawstatus')}, {'repeat':-1})]])
+ feed([[<C-\><C-N>]])
+ feed([[:sign <Tab>]]) -- Invoke wildmenu.
+ screen:sleep(30) -- Allow some timer activity.
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ define jump list > |
+ :sign define^ |
+ ]])
+ end)
+
+ it('with laststatus=0, :vsplit, :term #2255', function()
+ -- Because this test verifies a _lack_ of activity after screen:sleep(), we
+ -- must wait the full timeout. So make it reasonable.
+ screen.timeout = 1000
+
+ if not iswin() then
+ command('set shell=sh') -- Need a predictable "$" prompt.
+ end
+ command('set laststatus=0')
+ command('vsplit')
+ command('term')
+
+ -- Check for a shell prompt to verify that the terminal loaded.
+ retry(nil, nil, function()
+ if iswin() then
+ eq('Microsoft', eval("matchstr(join(getline(1, '$')), 'Microsoft')"))
+ else
+ eq('$', eval([[matchstr(getline(1), '\$')]]))
+ end
end)
+
+ feed([[<C-\><C-N>]])
+ feed([[:<Tab>]]) -- Invoke wildmenu.
+ screen:sleep(10) -- Flush
+ -- Check only the last 2 lines, because the shell output is
+ -- system-dependent.
+ screen:expect('! # & < = > @ > \n:!^', nil, nil, nil, true)
end)
end)
@@ -50,10 +165,10 @@ describe('command line completion', function()
it('lists directories with empty PATH', function()
local tmp = funcs.tempname()
- execute('e '.. tmp)
- execute('cd %:h')
- execute("call mkdir('Xtest-functional-viml-compl-dir')")
- execute('let $PATH=""')
+ command('e '.. tmp)
+ command('cd %:h')
+ command("call mkdir('Xtest-functional-viml-compl-dir')")
+ command('let $PATH=""')
feed(':!<tab><bs>')
screen:expect([[
|