local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') local tt = require('test.functional.testterm') local feed_data = tt.feed_data local feed_csi = tt.feed_csi local feed, clear = n.feed, n.clear local poke_eventloop = n.poke_eventloop local exec_lua = n.exec_lua local command = n.command local retry = t.retry local eq = t.eq local eval = n.eval local skip = t.skip local is_os = t.is_os describe(':terminal window', function() before_each(clear) it('sets local values of window options #29325', function() command('setglobal wrap list') command('terminal') eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]')) command('enew') eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]')) command('buffer #') eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]')) command('new') eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]')) end) end) describe(':terminal window', function() local screen before_each(function() clear() screen = tt.setup_screen() end) it('sets topline correctly #8556', function() skip(is_os('win')) -- Test has hardcoded assumptions of dimensions. eq(7, eval('&lines')) feed_data('\n\n\n') -- Add blank lines. -- Terminal/shell contents must exceed the height of this window. command('topleft 1split') eq('terminal', eval('&buftype')) feed([[i]]) -- Check topline _while_ in terminal-mode. retry(nil, nil, function() eq(6, eval('winsaveview()["topline"]')) end) end) describe("with 'number'", function() it('wraps text', function() feed([[]]) feed([[:set numberwidth=1 numberi]]) screen:expect([[ {121:1 }tty ready | {121:2 }rows: 6, cols: 48 | {121:3 }^ | {121:4 } | {121:5 } | {121:6 } | {5:-- TERMINAL --} | ]]) feed_data('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') screen:expect([[ {121:1 }tty ready | {121:2 }rows: 6, cols: 48 | {121:3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV| {121:4 }WXYZ^ | {121:5 } | {121:6 } | {5:-- TERMINAL --} | ]]) -- numberwidth=9 feed([[]]) feed([[:set numberwidth=9 numberi]]) screen:expect([[ {121: 1 }tty ready | {121: 2 }rows: 6, cols: 48 | {121: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| {121: 4 }PQRSTUVWXYZrows: 6, cols: 41 | {121: 5 }^ | {121: 6 } | {5:-- TERMINAL --} | ]]) feed_data(' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') screen:expect([[ {121: 1 }tty ready | {121: 2 }rows: 6, cols: 48 | {121: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| {121: 4 }PQRSTUVWXYZrows: 6, cols: 41 | {121: 5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN| {121: 6 }OPQRSTUVWXYZ^ | {5:-- TERMINAL --} | ]]) end) end) describe("with 'statuscolumn'", function() it('wraps text', function() command([[set number statuscolumn=++%l\ \ ]]) screen:expect([[ {121:++1 }tty ready | {121:++2 }rows: 6, cols: 45 | {121:++3 }^ | {121:++4 } | {121:++5 } | {121:++6 } | {5:-- TERMINAL --} | ]]) feed_data('\n\n\n\n\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') screen:expect([[ {121:++4 } | {121:++5 } | {121:++6 } | {121:++7 } | {121:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS| {121:++9 }TUVWXYZ^ | {5:-- TERMINAL --} | ]]) feed_data('\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') screen:expect([[ {121:++ 7 } | {121:++ 8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| {121:++ 9 }STUVWXYZ | {121:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| {121:++11 }STUVWXYZrows: 6, cols: 44 | {121:++12 }^ | {5:-- TERMINAL --} | ]]) end) end) describe("with 'colorcolumn'", function() before_each(function() feed([[]]) screen:expect([[ tty ready | ^ | |*5 ]]) feed(':set colorcolumn=20i') end) it('wont show the color column', function() screen:expect([[ tty ready | ^ | |*4 {5:-- TERMINAL --} | ]]) end) end) describe('with fold set', function() before_each(function() feed([[:set foldenable foldmethod=manuali]]) feed_data({ 'line1', 'line2', 'line3', 'line4', '' }) screen:expect([[ tty ready | line1 | line2 | line3 | line4 | ^ | {5:-- TERMINAL --} | ]]) end) it('wont show any folds', function() feed([[ggvGzf]]) poke_eventloop() screen:expect([[ ^tty ready | line1 | line2 | line3 | line4 | | | ]]) end) end) it('redrawn when restoring cursorline/column', function() screen:set_default_attr_ids({ [1] = { bold = true }, [2] = { foreground = 130 }, [3] = { foreground = 130, underline = true }, [12] = { underline = true }, [19] = { background = 7 }, }) feed([[]]) command('setlocal cursorline') screen:expect([[ tty ready | {12:^ }| |*5 ]]) feed('i') screen:expect([[ tty ready | ^ | |*4 {1:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ tty ready | {12:^ }| |*5 ]]) command('setlocal number') screen:expect([[ {2: 1 }tty ready | {3: 2 }{12:^rows: 6, cols: 46 }| {2: 3 } | {2: 4 } | {2: 5 } | {2: 6 } | | ]]) feed('i') screen:expect([[ {2: 1 }tty ready | {2: 2 }rows: 6, cols: 46 | {3: 3 }^ | {2: 4 } | {2: 5 } | {2: 6 } | {1:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ {2: 1 }tty ready | {2: 2 }rows: 6, cols: 46 | {3: 3 }{12:^ }| {2: 4 } | {2: 5 } | {2: 6 } | | ]]) command('setlocal nonumber nocursorline cursorcolumn') screen:expect([[ {19:t}ty ready | {19:r}ows: 6, cols: 46 | ^rows: 6, cols: 50 | {19: } |*3 | ]]) feed('i') screen:expect([[ tty ready | rows: 6, cols: 46 | rows: 6, cols: 50 | ^ | |*2 {1:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ {19:t}ty ready | {19:r}ows: 6, cols: 46 | {19:r}ows: 6, cols: 50 | ^ | {19: } |*2 | ]]) end) it('redraws cursor info in terminal mode', function() skip(is_os('win'), '#31587') command('file AMOGUS | set laststatus=2 ruler') screen:expect([[ tty ready | rows: 5, cols: 50 | ^ | |*2 {120:AMOGUS [-] 3,0-1 All}| {5:-- TERMINAL --} | ]]) feed_data('you are the imposter') screen:expect([[ tty ready | rows: 5, cols: 50 | you are the imposter^ | |*2 {120:AMOGUS [-] 3,21 All}| {5:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ tty ready | rows: 5, cols: 50 | you are the imposte^r | |*2 {120:AMOGUS [-] 3,20 All}| | ]]) end) it('redraws stale statuslines and mode when not updating screen', function() command('file foo | set ruler | vsplit') screen:expect([[ tty ready │tty ready | rows: 5, cols: 25 │rows: 5, cols: 25 | ^ │ | │ |*2 {120:]]) command([[ file foo setlocal cursorline vsplit setlocal nocursorline cursorcolumn ]]) screen:expect([[ {19:t}ty ready │tty ready | ^rows: 5, cols: 25 │{12:rows: 5, cols: 25 }| {19: } │ |*3 {17:foo [-] }{18:foo [-] }| | ]]) feed('i') screen:expect([[ tty ready │tty ready | rows: 5, cols: 25 │{12:rows: 5, cols: 25 }| ^ │ | │ |*2 {17:foo [-] }{18:foo [-] }| {1:-- TERMINAL --} | ]]) command('wincmd p') screen:expect([[ {19:t}ty ready │tty ready | {19:r}ows: 5, cols: 25 │rows: 5, cols: 25 | │^ | {19: } │ |*2 {18:foo [-] }{17:foo [-] }| {1:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ {19:t}ty ready │tty ready | {19:r}ows: 5, cols: 25 │rows: 5, cols: 25 | │{12:^ }| {19: } │ |*2 {18:foo [-] }{17:foo [-] }| | ]]) -- Ensure things work when switching tabpages. command('tab split | setlocal cursorline cursorcolumn') screen:expect([[ {2: }{3:2}{2: foo }{1: foo }{4: }{2:X}| {19:t}ty ready | {19:r}ows: 5, cols: 25 | {12:^rows: 5, cols: 50 }| {19: } |*2 | ]]) feed('i') screen:expect([[ {2: }{3:2}{2: foo }{1: foo }{4: }{2:X}| tty ready | rows: 5, cols: 25 | rows: 5, cols: 50 | ^ | | {1:-- TERMINAL --} | ]]) command('tabprevious') screen:expect([[ {1: }{5:2}{1: foo }{2: foo }{4: }{2:X}| {19:r}ows: 5, cols: 25 │rows: 5, cols: 25 | rows: 5, cols: 50 │rows: 5, cols: 50 | {19: } │^ | {19: } │ | {18:foo [-] }{17:foo [-] }| {1:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ {1: }{5:2}{1: foo }{2: foo }{4: }{2:X}| {19:r}ows: 5, cols: 25 │rows: 5, cols: 25 | rows: 5, cols: 50 │rows: 5, cols: 50 | {19: } │{12:^ }| {19: } │ | {18:foo [-] }{17:foo [-] }| | ]]) command('tabnext') screen:expect([[ {2: }{3:2}{2: foo }{1: foo }{4: }{2:X}| {19:t}ty ready | {19:r}ows: 5, cols: 25 | {19:r}ows: 5, cols: 50 | {12:^ }| {19: } | | ]]) -- Closing windows shouldn't break things. command('tabprevious') feed('i') screen:expect([[ {1: }{5:2}{1: foo }{2: foo }{4: }{2:X}| {19:r}ows: 5, cols: 25 │rows: 5, cols: 25 | rows: 5, cols: 50 │rows: 5, cols: 50 | {19: } │^ | {19: } │ | {18:foo [-] }{17:foo [-] }| {1:-- TERMINAL --} | ]]) command('quit') screen:expect([[ {1: foo }{2: foo }{4: }{2:X}| tty ready | rows: 5, cols: 25 | rows: 5, cols: 50 | ^ | | {1:-- TERMINAL --} | ]]) feed([[]]) screen:expect([[ {1: foo }{2: foo }{4: }{2:X}| {19:t}ty ready | {19:r}ows: 5, cols: 25 | {19:r}ows: 5, cols: 50 | ^ | {19: } | | ]]) -- Switching to a non-terminal. command('vnew') feed([[pi]]) screen:expect([[ {1: }{5:2}{1: foo }{2: foo }{4: }{2:X}| │rows: 5, cols: 25 | {6:~ }│rows: 5, cols: 50 | {6:~ }│^ | {6:~ }│ | {4:[No Name] }{17:foo [-] }| {1:-- TERMINAL --} | ]]) command('wincmd p') screen:expect([[ {1: }{5:2}{1: [No Name] }{2: foo }{4: }{2:X}| ^ │{19:r}ows: 5, cols: 25 | {6:~ }│{19:r}ows: 5, cols: 50 | {6:~ }│ | {6:~ }│{19: } | {7:[No Name] }{18:foo [-] }| | ]]) end) it('not unnecessarily redrawn by events', function() eq('t', eval('mode()')) exec_lua(function() _G.redraws = {} local ns = vim.api.nvim_create_namespace('test') vim.api.nvim_set_decoration_provider(ns, { on_start = function() table.insert(_G.redraws, 'start') end, on_win = function(_, win) table.insert(_G.redraws, 'win ' .. win) end, on_end = function() table.insert(_G.redraws, 'end') end, }) -- Setting a decoration provider typically causes an initial redraw. vim.cmd.redraw() _G.redraws = {} end) -- The event we sent above to set up the test shouldn't have caused a redraw. -- For good measure, also poke the event loop. poke_eventloop() eq({}, exec_lua('return _G.redraws')) -- Redraws if we do something useful, of course. feed_data('foo') screen:expect { any = 'foo' } eq({ 'start', 'win 1000', 'end' }, exec_lua('return _G.redraws')) end) end) describe(':terminal with multigrid', function() local screen before_each(function() clear() screen = tt.setup_screen(0, nil, 50, nil, { ext_multigrid = true }) end) it('resizes to requested size', function() screen:expect([[ ## grid 1 [2:--------------------------------------------------]|*6 [3:--------------------------------------------------]| ## grid 2 tty ready | ^ | |*4 ## grid 3 {5:-- TERMINAL --} | ]]) screen:try_resize_grid(2, 20, 10) if is_os('win') then screen:expect { any = 'rows: 10, cols: 20' } else screen:expect([[ ## grid 1 [2:--------------------------------------------------]|*6 [3:--------------------------------------------------]| ## grid 2 tty ready | rows: 10, cols: 20 | ^ | |*7 ## grid 3 {5:-- TERMINAL --} | ]]) end screen:try_resize_grid(2, 70, 3) if is_os('win') then screen:expect { any = 'rows: 3, cols: 70' } else screen:expect([[ ## grid 1 [2:--------------------------------------------------]|*6 [3:--------------------------------------------------]| ## grid 2 rows: 10, cols: 20 | rows: 3, cols: 70 | ^ | ## grid 3 {5:-- TERMINAL --} | ]]) end screen:try_resize_grid(2, 0, 0) if is_os('win') then screen:expect { any = 'rows: 6, cols: 50' } else screen:expect([[ ## grid 1 [2:--------------------------------------------------]|*6 [3:--------------------------------------------------]| ## grid 2 tty ready | rows: 10, cols: 20 | rows: 3, cols: 70 | rows: 6, cols: 50 | ^ | | ## grid 3 {5:-- TERMINAL --} | ]]) end end) end)