hl_spec.lua (13476B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local exec_lua = n.exec_lua 6 local eq = t.eq 7 local eval = n.eval 8 local command = n.command 9 local clear = n.clear 10 local api = n.api 11 12 describe('vim.hl.range', function() 13 local screen 14 15 before_each(function() 16 clear() 17 screen = Screen.new(60, 6) 18 screen:add_extra_attr_ids({ 19 [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, 20 }) 21 api.nvim_set_option_value('list', true, {}) 22 api.nvim_set_option_value('listchars', 'eol:$', {}) 23 api.nvim_buf_set_lines(0, 0, -1, true, { 24 'asdfghjkl', 25 '«口=口»', 26 'qwertyuiop', 27 '口口=口口', 28 'zxcvbnm', 29 }) 30 screen:expect([[ 31 ^asdfghjkl{1:$} | 32 «口=口»{1:$} | 33 qwertyuiop{1:$} | 34 口口=口口{1:$} | 35 zxcvbnm{1:$} | 36 | 37 ]]) 38 end) 39 40 it('works with charwise selection', function() 41 exec_lua(function() 42 local ns = vim.api.nvim_create_namespace('') 43 vim.hl.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) 44 end) 45 screen:expect([[ 46 ^asdfghjkl{1:$} | 47 «口{10:=口»}{100:$} | 48 {10:qwertyuiop}{100:$} | 49 {10:口口=口}口{1:$} | 50 zxcvbnm{1:$} | 51 | 52 ]]) 53 end) 54 55 it('works with linewise selection', function() 56 exec_lua(function() 57 local ns = vim.api.nvim_create_namespace('') 58 vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) 59 end) 60 screen:expect([[ 61 {10:^asdfghjkl}{100:$} | 62 {10:«口=口»}{100:$} | 63 {10:qwertyuiop}{100:$} | 64 {10:口口=口口}{100:$} | 65 {10:zxcvbnm}{100:$} | 66 | 67 ]]) 68 end) 69 70 it('works with blockwise selection', function() 71 exec_lua(function() 72 local ns = vim.api.nvim_create_namespace('') 73 vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) 74 end) 75 screen:expect([[ 76 {10:^asdf}ghjkl{1:$} | 77 {10:«口=}口»{1:$} | 78 {10:qwer}tyuiop{1:$} | 79 {10:口口}=口口{1:$} | 80 {10:zxcv}bnm{1:$} | 81 | 82 ]]) 83 end) 84 85 it('works with blockwise selection with width', function() 86 exec_lua(function() 87 local ns = vim.api.nvim_create_namespace('') 88 vim.hl.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) 89 end) 90 screen:expect([[ 91 ^asdf{10:ghjkl}{1:$} | 92 «口={10:口»}{1:$} | 93 qwer{10:tyuiop}{1:$} | 94 口口{10:=口口}{1:$} | 95 zxcv{10:bnm}{1:$} | 96 | 97 ]]) 98 end) 99 100 it('can use -1 or v:maxcol to indicate end of line', function() 101 exec_lua(function() 102 local ns = vim.api.nvim_create_namespace('') 103 vim.hl.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) 104 vim.hl.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) 105 end) 106 screen:expect([[ 107 ^asdf{10:ghjkl}{100:$} | 108 {10:«口=口»}{100:$} | 109 qwerty{10:uiop}{100:$} | 110 {10:口口=口口}{1:$} | 111 zxcvbnm{1:$} | 112 | 113 ]]) 114 end) 115 116 it('removes highlight after given `timeout`', function() 117 local timeout = 300 118 exec_lua(function() 119 local ns = vim.api.nvim_create_namespace('') 120 vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { timeout = timeout }) 121 end) 122 screen:expect({ 123 grid = [[ 124 {10:^asdfghjkl}{100:$} | 125 {10:«口=口»}{100:$} | 126 {10:qwertyuiop}{100:$} | 127 {10:口口=口口}{1:$} | 128 zxcvbnm{1:$} | 129 | 130 ]], 131 timeout = timeout / 3, 132 }) 133 screen:expect([[ 134 ^asdfghjkl{1:$} | 135 «口=口»{1:$} | 136 qwertyuiop{1:$} | 137 口口=口口{1:$} | 138 zxcvbnm{1:$} | 139 | 140 ]]) 141 end) 142 143 it('shows multiple highlights with different timeouts simultaneously', function() 144 local timeout1 = 300 145 local timeout2 = 600 146 exec_lua(function() 147 local ns = vim.api.nvim_create_namespace('') 148 vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { timeout = timeout1 }) 149 vim.hl.range(0, ns, 'Search', { 2, 6 }, { 3, 5 }, { timeout = timeout2 }) 150 end) 151 screen:expect({ 152 grid = [[ 153 {10:^asdfghjkl}{100:$} | 154 {10:«口=口»}{100:$} | 155 {10:qwertyuiop}{100:$} | 156 {10:口口=口口}{1:$} | 157 zxcvbnm{1:$} | 158 | 159 ]], 160 timeout = timeout1 / 3, 161 }) 162 screen:expect({ 163 grid = [[ 164 ^asdfghjkl{1:$} | 165 «口=口»{1:$} | 166 qwerty{10:uiop}{100:$} | 167 {10:口口}=口口{1:$} | 168 zxcvbnm{1:$} | 169 | 170 ]], 171 timeout = timeout1 + ((timeout2 - timeout1) / 3), 172 }) 173 screen:expect([[ 174 ^asdfghjkl{1:$} | 175 «口=口»{1:$} | 176 qwertyuiop{1:$} | 177 口口=口口{1:$} | 178 zxcvbnm{1:$} | 179 | 180 ]]) 181 end) 182 183 it('allows cancelling a highlight that has not timed out', function() 184 exec_lua(function() 185 local timeout = 3000 186 local range_timer 187 local range_hl_clear 188 local ns = vim.api.nvim_create_namespace('') 189 range_timer, range_hl_clear = vim.hl.range( 190 0, 191 ns, 192 'Search', 193 { 0, 0 }, 194 { 4, 0 }, 195 { timeout = timeout } 196 ) 197 if range_timer and not range_timer:is_closing() then 198 range_timer:close() 199 assert(range_hl_clear) 200 range_hl_clear() 201 range_hl_clear() -- Exercise redundant call 202 end 203 end) 204 screen:expect({ 205 grid = [[ 206 ^asdfghjkl{1:$} | 207 «口=口»{1:$} | 208 qwertyuiop{1:$} | 209 口口=口口{1:$} | 210 zxcvbnm{1:$} | 211 | 212 ]], 213 unchanged = true, 214 }) 215 end) 216 end) 217 218 describe('vim.hl.on_yank', function() 219 before_each(function() 220 clear() 221 end) 222 223 it('does not show errors even if buffer is wiped before timeout', function() 224 command('new') 225 n.feed('ifoo<esc>') -- set '[, '] 226 exec_lua(function() 227 vim.hl.on_yank({ 228 timeout = 10, 229 on_macro = true, 230 event = { operator = 'y', regtype = 'v' }, 231 }) 232 vim.cmd('bwipeout!') 233 end) 234 vim.uv.sleep(10) 235 n.feed('<cr>') -- avoid hang if error message exists 236 eq('', eval('v:errmsg')) 237 end) 238 239 it('does not close timer twice', function() 240 exec_lua(function() 241 vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) 242 vim.uv.sleep(10) 243 vim.schedule(function() 244 vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) 245 end) 246 end) 247 eq('', eval('v:errmsg')) 248 end) 249 250 it('does not show in another window', function() 251 command('vsplit') 252 exec_lua(function() 253 vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) 254 vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) 255 vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) 256 end) 257 local ns = api.nvim_create_namespace('nvim.hlyank') 258 local win = api.nvim_get_current_win() 259 eq({ win }, api.nvim__ns_get(ns).wins) 260 command('wincmd w') 261 eq({ win }, api.nvim__ns_get(ns).wins) 262 -- Use a new vim.hl.on_yank() call to cancel the previous timer 263 exec_lua(function() 264 vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) 265 end) 266 end) 267 268 it('removes old highlight if new one is created before old one times out', function() 269 command('vnew') 270 exec_lua(function() 271 vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) 272 vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) 273 vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) 274 end) 275 local ns = api.nvim_create_namespace('nvim.hlyank') 276 eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) 277 command('wincmd w') 278 exec_lua(function() 279 vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) 280 vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) 281 vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) 282 end) 283 local win = api.nvim_get_current_win() 284 eq({ win }, api.nvim__ns_get(ns).wins) 285 command('wincmd w') 286 eq({ win }, api.nvim__ns_get(ns).wins) 287 -- Use a new vim.hl.on_yank() call to cancel the previous timer 288 exec_lua(function() 289 vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) 290 end) 291 end) 292 293 it('highlights last character with exclusive motion', function() 294 local screen = Screen.new(60, 4) 295 screen:add_extra_attr_ids({ 296 [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, 297 }) 298 command('autocmd TextYankPost * lua vim.hl.on_yank{timeout=100000}') 299 api.nvim_buf_set_lines(0, 0, -1, true, { 300 [[foo(bar) 'baz']], 301 [[foo(bar) 'baz']], 302 }) 303 n.feed('yw') 304 screen:expect([[ 305 {2:^foo}(bar) 'baz' | 306 foo(bar) 'baz' | 307 {1:~ }| 308 | 309 ]]) 310 n.feed("yi'") 311 screen:expect([[ 312 foo(bar) '{2:^baz}' | 313 foo(bar) 'baz' | 314 {1:~ }| 315 | 316 ]]) 317 n.feed('yvj') 318 screen:expect([[ 319 foo(bar) '{2:^baz'} | 320 {2:foo(bar) '}baz' | 321 {1:~ }| 322 | 323 ]]) 324 -- Use a new vim.hl.on_yank() call to cancel the previous timer 325 exec_lua(function() 326 vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) 327 end) 328 end) 329 end)