mouse_spec.lua (30335B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 4 local tt = require('test.functional.testterm') 5 local clear, eq, eval = n.clear, t.eq, n.eval 6 local feed, api, command = n.feed, n.api, n.command 7 local feed_data = tt.feed_data 8 local is_os = t.is_os 9 local skip = t.skip 10 11 describe(':terminal mouse', function() 12 local screen 13 14 before_each(function() 15 clear() 16 api.nvim_set_option_value('statusline', '==========', {}) 17 screen = tt.setup_screen() 18 command('highlight StatusLine NONE') 19 command('highlight StatusLineNC NONE') 20 command('highlight StatusLineTerm NONE') 21 command('highlight StatusLineTermNC NONE') 22 command('highlight VertSplit NONE') 23 local lines = {} 24 for i = 1, 30 do 25 table.insert(lines, 'line' .. tostring(i)) 26 end 27 table.insert(lines, '') 28 feed_data(lines) 29 screen:expect([[ 30 line26 | 31 line27 | 32 line28 | 33 line29 | 34 line30 | 35 ^ | 36 {5:-- TERMINAL --} | 37 ]]) 38 end) 39 40 describe('when the terminal has focus', function() 41 it('will exit focus on mouse-scroll', function() 42 eq('t', eval('mode(1)')) 43 feed('<ScrollWheelUp><0,0>') 44 eq('nt', eval('mode(1)')) 45 end) 46 47 it('will exit focus and trigger Normal mode mapping on mouse click', function() 48 feed([[<C-\><C-N>qri]]) 49 command('let g:got_leftmouse = 0') 50 command('nnoremap <LeftMouse> <Cmd>let g:got_leftmouse = 1<CR>') 51 eq('t', eval('mode(1)')) 52 eq(0, eval('g:got_leftmouse')) 53 feed('<LeftMouse>') 54 eq('nt', eval('mode(1)')) 55 eq(1, eval('g:got_leftmouse')) 56 feed('q') 57 eq('i<LeftMouse>', eval('keytrans(@r)')) 58 end) 59 60 it('will exit focus and trigger Normal mode mapping on mouse click with modifier', function() 61 feed([[<C-\><C-N>qri]]) 62 command('let g:got_ctrl_leftmouse = 0') 63 command('nnoremap <C-LeftMouse> <Cmd>let g:got_ctrl_leftmouse = 1<CR>') 64 eq('t', eval('mode(1)')) 65 eq(0, eval('g:got_ctrl_leftmouse')) 66 feed('<C-LeftMouse>') 67 eq('nt', eval('mode(1)')) 68 eq(1, eval('g:got_ctrl_leftmouse')) 69 feed('q') 70 eq('i<C-LeftMouse>', eval('keytrans(@r)')) 71 end) 72 73 it('will exit focus on <C-\\> + mouse-scroll', function() 74 eq('t', eval('mode(1)')) 75 feed('<C-\\>') 76 feed('<ScrollWheelUp><0,0>') 77 eq('nt', eval('mode(1)')) 78 end) 79 80 it('will not exit focus on left-release', function() 81 eq('t', eval('mode(1)')) 82 feed('<LeftRelease><0,0>') 83 eq('t', eval('mode(1)')) 84 command('setlocal number') 85 eq('t', eval('mode(1)')) 86 feed('<LeftRelease><0,0>') 87 eq('t', eval('mode(1)')) 88 end) 89 90 it('will not exit focus on mouse movement', function() 91 eq('t', eval('mode(1)')) 92 feed('<MouseMove><0,0>') 93 eq('t', eval('mode(1)')) 94 command('setlocal number') 95 eq('t', eval('mode(1)')) 96 feed('<MouseMove><0,0>') 97 eq('t', eval('mode(1)')) 98 end) 99 100 describe('with mouse events enabled by the program', function() 101 before_each(function() 102 tt.enable_mouse() -- FIXME: this doesn't work on Windows? 103 tt.feed_data('mouse enabled\n') 104 screen:expect([[ 105 line27 | 106 line28 | 107 line29 | 108 line30 | 109 mouse enabled | 110 ^ | 111 {5:-- TERMINAL --} | 112 ]]) 113 end) 114 115 it('will forward mouse press, drag and release to the program', function() 116 skip(is_os('win')) 117 feed('<LeftMouse><1,2>') 118 screen:expect([[ 119 line27 | 120 line28 | 121 line29 | 122 line30 | 123 mouse enabled | 124 "#^ | 125 {5:-- TERMINAL --} | 126 ]]) 127 feed('<LeftDrag><2,2>') 128 screen:expect([[ 129 line27 | 130 line28 | 131 line29 | 132 line30 | 133 mouse enabled | 134 @##^ | 135 {5:-- TERMINAL --} | 136 ]]) 137 feed('<LeftDrag><3,2>') 138 screen:expect([[ 139 line27 | 140 line28 | 141 line29 | 142 line30 | 143 mouse enabled | 144 @$#^ | 145 {5:-- TERMINAL --} | 146 ]]) 147 feed('<LeftRelease><3,2>') 148 screen:expect([[ 149 line27 | 150 line28 | 151 line29 | 152 line30 | 153 mouse enabled | 154 #$#^ | 155 {5:-- TERMINAL --} | 156 ]]) 157 end) 158 159 it('will forward mouse scroll to the program', function() 160 skip(is_os('win')) 161 feed('<ScrollWheelUp><0,0>') 162 screen:expect([[ 163 line27 | 164 line28 | 165 line29 | 166 line30 | 167 mouse enabled | 168 `!!^ | 169 {5:-- TERMINAL --} | 170 ]]) 171 end) 172 173 it('dragging and scrolling do not interfere with each other', function() 174 skip(is_os('win')) 175 feed('<LeftMouse><1,2>') 176 screen:expect([[ 177 line27 | 178 line28 | 179 line29 | 180 line30 | 181 mouse enabled | 182 "#^ | 183 {5:-- TERMINAL --} | 184 ]]) 185 feed('<ScrollWheelUp><1,2>') 186 screen:expect([[ 187 line27 | 188 line28 | 189 line29 | 190 line30 | 191 mouse enabled | 192 `"#^ | 193 {5:-- TERMINAL --} | 194 ]]) 195 feed('<LeftDrag><2,2>') 196 screen:expect([[ 197 line27 | 198 line28 | 199 line29 | 200 line30 | 201 mouse enabled | 202 @##^ | 203 {5:-- TERMINAL --} | 204 ]]) 205 feed('<ScrollWheelUp><2,2>') 206 screen:expect([[ 207 line27 | 208 line28 | 209 line29 | 210 line30 | 211 mouse enabled | 212 `##^ | 213 {5:-- TERMINAL --} | 214 ]]) 215 feed('<LeftRelease><2,2>') 216 screen:expect([[ 217 line27 | 218 line28 | 219 line29 | 220 line30 | 221 mouse enabled | 222 ###^ | 223 {5:-- TERMINAL --} | 224 ]]) 225 end) 226 227 it('will forward mouse clicks to the program with the correct even if set nu', function() 228 skip(is_os('win')) 229 command('set number') 230 screen:expect([[ 231 {121: 11 }line28 | 232 {121: 12 }line29 | 233 {121: 13 }line30 | 234 {121: 14 }mouse enabled | 235 {121: 15 }rows: 6, cols: 46 | 236 {121: 16 }^ | 237 {5:-- TERMINAL --} | 238 ]]) 239 -- When the display area such as a number is clicked, it returns to the 240 -- normal mode. 241 feed('<LeftMouse><3,0>') 242 eq('nt', eval('mode(1)')) 243 screen:expect([[ 244 {121: 11 }^line28 | 245 {121: 12 }line29 | 246 {121: 13 }line30 | 247 {121: 14 }mouse enabled | 248 {121: 15 }rows: 6, cols: 46 | 249 {121: 16 } | 250 | 251 ]]) 252 -- If click on the coordinate (0,1) of the region of the terminal 253 -- (i.e. the coordinate (4,1) of vim), 'CSI !"' is sent to the terminal. 254 feed('i<LeftMouse><4,1>') 255 screen:expect([[ 256 {121: 11 }line28 | 257 {121: 12 }line29 | 258 {121: 13 }line30 | 259 {121: 14 }mouse enabled | 260 {121: 15 }rows: 6, cols: 46 | 261 {121: 16 } !"^ | 262 {5:-- TERMINAL --} | 263 ]]) 264 end) 265 266 it('will lose focus if statusline is clicked', function() 267 command('set laststatus=2') 268 screen:expect([[ 269 line29 | 270 line30 | 271 mouse enabled | 272 rows: 5, cols: 50 | 273 ^ | 274 ========== | 275 {5:-- TERMINAL --} | 276 ]]) 277 feed('<LeftMouse><0,5>') 278 screen:expect([[ 279 line29 | 280 line30 | 281 mouse enabled | 282 rows: 5, cols: 50 | 283 ^ | 284 ========== | 285 | 286 ]]) 287 feed('<LeftDrag><0,4>') 288 screen:expect([[ 289 mouse enabled | 290 rows: 5, cols: 50 | 291 rows: 4, cols: 50 | 292 ^ | 293 ========== | 294 |*2 295 ]]) 296 end) 297 298 it('will lose focus if right separator is clicked', function() 299 command('rightbelow vnew | wincmd p | startinsert') 300 screen:expect([[ 301 line29 │ | 302 line30 │{100:~ }| 303 mouse enabled │{100:~ }| 304 rows: 5, cols: 24 │{100:~ }| 305 ^ │{100:~ }| 306 ========== ========== | 307 {5:-- TERMINAL --} | 308 ]]) 309 feed('<LeftMouse><24,0>') 310 screen:expect([[ 311 line29 │ | 312 line30 │{100:~ }| 313 mouse enabled │{100:~ }| 314 rows: 5, cols: 24 │{100:~ }| 315 ^ │{100:~ }| 316 ========== ========== | 317 | 318 ]]) 319 feed('<LeftDrag><23,0>') 320 screen:expect([[ 321 line30 │ | 322 mouse enabled │{100:~ }| 323 rows: 5, cols: 24 │{100:~ }| 324 rows: 5, cols: 23 │{100:~ }| 325 ^ │{100:~ }| 326 ========== ========== | 327 | 328 ]]) 329 end) 330 331 it('will lose focus if winbar/tabline is clicked', function() 332 command('setlocal winbar=WINBAR') 333 screen:expect([[ 334 {5:WINBAR }| 335 line29 | 336 line30 | 337 mouse enabled | 338 rows: 5, cols: 50 | 339 ^ | 340 {5:-- TERMINAL --} | 341 ]]) 342 feed('<LeftMouse><0,0>') 343 screen:expect([[ 344 {5:WINBAR }| 345 line29 | 346 line30 | 347 mouse enabled | 348 rows: 5, cols: 50 | 349 ^ | 350 | 351 ]]) 352 command('set showtabline=2 tabline=TABLINE | startinsert') 353 screen:expect([[ 354 {2:TABLINE }| 355 {5:WINBAR }| 356 mouse enabled | 357 rows: 5, cols: 50 | 358 rows: 4, cols: 50 | 359 ^ | 360 {5:-- TERMINAL --} | 361 ]]) 362 feed('<LeftMouse><0,0>') 363 screen:expect([[ 364 {2:TABLINE }| 365 {5:WINBAR }| 366 mouse enabled | 367 rows: 5, cols: 50 | 368 rows: 4, cols: 50 | 369 ^ | 370 | 371 ]]) 372 command('setlocal winbar= | startinsert') 373 screen:expect([[ 374 {2:TABLINE }| 375 mouse enabled | 376 rows: 5, cols: 50 | 377 rows: 4, cols: 50 | 378 rows: 5, cols: 50 | 379 ^ | 380 {5:-- TERMINAL --} | 381 ]]) 382 feed('<LeftMouse><0,0>') 383 screen:expect([[ 384 {2:TABLINE }| 385 mouse enabled | 386 rows: 5, cols: 50 | 387 rows: 4, cols: 50 | 388 rows: 5, cols: 50 | 389 ^ | 390 | 391 ]]) 392 end) 393 394 it('mouse forwarding works with resized grid', function() 395 screen:detach() 396 local Screen = require('test.functional.ui.screen') 397 screen = Screen.new(50, 7, { ext_multigrid = true }) 398 screen:expect([[ 399 ## grid 1 400 [2:--------------------------------------------------]|*6 401 [3:--------------------------------------------------]| 402 ## grid 2 403 line27 | 404 line28 | 405 line29 | 406 line30 | 407 mouse enabled | 408 ^ | 409 ## grid 3 410 {5:-- TERMINAL --} | 411 ]]) 412 413 screen:try_resize_grid(2, 58, 11) 414 screen:expect({ any = vim.pesc('rows: 11, cols: 58') }) 415 416 api.nvim_input_mouse('right', 'press', '', 2, 0, 0) 417 screen:expect({ any = vim.pesc('"!!^') }) 418 api.nvim_input_mouse('right', 'release', '', 2, 0, 0) 419 screen:expect({ any = vim.pesc('#!!^') }) 420 421 api.nvim_input_mouse('right', 'press', '', 2, 10, 0) 422 screen:expect({ any = vim.pesc('"!+^') }) 423 api.nvim_input_mouse('right', 'release', '', 2, 10, 0) 424 screen:expect({ any = vim.pesc('#!+^') }) 425 426 api.nvim_input_mouse('right', 'press', '', 2, 0, 57) 427 screen:expect({ any = vim.pesc('"Z!^') }) 428 api.nvim_input_mouse('right', 'release', '', 2, 0, 57) 429 screen:expect({ any = vim.pesc('#Z!^') }) 430 431 api.nvim_input_mouse('right', 'press', '', 2, 10, 57) 432 screen:expect({ any = vim.pesc('"Z+^') }) 433 api.nvim_input_mouse('right', 'release', '', 2, 10, 57) 434 screen:expect({ any = vim.pesc('#Z+^') }) 435 436 command('setlocal winbar=WINBAR') 437 screen:expect({ any = vim.pesc(('{5:WINBAR%s}'):format((' '):rep(52))) }) 438 eq('t', api.nvim_get_mode().mode) 439 440 api.nvim_input_mouse('right', 'press', '', 2, 0, 0) 441 eq('nt', api.nvim_get_mode().mode) 442 api.nvim_input_mouse('right', 'release', '', 2, 0, 0) 443 feed('i') 444 eq('t', api.nvim_get_mode().mode) 445 446 api.nvim_input_mouse('right', 'press', '', 2, 0, 57) 447 eq('nt', api.nvim_get_mode().mode) 448 api.nvim_input_mouse('right', 'release', '', 2, 0, 57) 449 feed('i') 450 eq('t', api.nvim_get_mode().mode) 451 452 api.nvim_input_mouse('right', 'press', '', 2, 1, 0) 453 screen:expect({ any = vim.pesc('"!!^') }) 454 api.nvim_input_mouse('right', 'release', '', 2, 1, 0) 455 screen:expect({ any = vim.pesc('#!!^') }) 456 457 api.nvim_input_mouse('right', 'press', '', 2, 10, 0) 458 screen:expect({ any = vim.pesc('"!*^') }) 459 api.nvim_input_mouse('right', 'release', '', 2, 10, 0) 460 screen:expect({ any = vim.pesc('#!*^') }) 461 462 api.nvim_input_mouse('right', 'press', '', 2, 1, 57) 463 screen:expect({ any = vim.pesc('"Z!^') }) 464 api.nvim_input_mouse('right', 'release', '', 2, 1, 57) 465 screen:expect({ any = vim.pesc('#Z!^') }) 466 467 api.nvim_input_mouse('right', 'press', '', 2, 10, 57) 468 screen:expect({ any = vim.pesc('"Z*^') }) 469 api.nvim_input_mouse('right', 'release', '', 2, 10, 57) 470 screen:expect({ any = vim.pesc('#Z*^') }) 471 end) 472 end) 473 474 describe('with a split window and other buffer', function() 475 before_each(function() 476 feed('<c-\\><c-n>:vsp<cr>') 477 screen:expect([[ 478 line28 │line28 | 479 line29 │line29 | 480 line30 │line30 | 481 rows: 5, cols: 25 │rows: 5, cols: 25 | 482 ^ │ | 483 ========== ========== | 484 :vsp | 485 ]]) 486 feed(':enew | set number<cr>') 487 screen:expect([[ 488 {121: 1 }^ │line29 | 489 {100:~ }│line30 | 490 {100:~ }│rows: 5, cols: 25 | 491 {100:~ }│rows: 5, cols: 24 | 492 {100:~ }│ | 493 ========== ========== | 494 :enew | set number | 495 ]]) 496 feed('30iline\n<esc>') 497 screen:expect([[ 498 {121: 27 }line │line29 | 499 {121: 28 }line │line30 | 500 {121: 29 }line │rows: 5, cols: 25 | 501 {121: 30 }line │rows: 5, cols: 24 | 502 {121: 31 }^ │ | 503 ========== ========== | 504 | 505 ]]) 506 feed('<c-w>li') 507 screen:expect([[ 508 {121: 27 }line │line29 | 509 {121: 28 }line │line30 | 510 {121: 29 }line │rows: 5, cols: 25 | 511 {121: 30 }line │rows: 5, cols: 24 | 512 {121: 31 } │^ | 513 ========== ========== | 514 {5:-- TERMINAL --} | 515 ]]) 516 517 -- enabling mouse won't affect interaction with other windows 518 tt.enable_mouse() 519 tt.feed_data('mouse enabled\n') 520 screen:expect([[ 521 {121: 27 }line │line30 | 522 {121: 28 }line │rows: 5, cols: 25 | 523 {121: 29 }line │rows: 5, cols: 24 | 524 {121: 30 }line │mouse enabled | 525 {121: 31 } │^ | 526 ========== ========== | 527 {5:-- TERMINAL --} | 528 ]]) 529 end) 530 531 it("scrolling another window keeps focus and respects 'mousescroll'", function() 532 feed('<ScrollWheelUp><4,0><ScrollWheelUp><4,0>') 533 screen:expect([[ 534 {121: 21 }line │line30 | 535 {121: 22 }line │rows: 5, cols: 25 | 536 {121: 23 }line │rows: 5, cols: 24 | 537 {121: 24 }line │mouse enabled | 538 {121: 25 }line │^ | 539 ========== ========== | 540 {5:-- TERMINAL --} | 541 ]]) 542 feed('<S-ScrollWheelDown><4,0>') 543 screen:expect([[ 544 {121: 26 }line │line30 | 545 {121: 27 }line │rows: 5, cols: 25 | 546 {121: 28 }line │rows: 5, cols: 24 | 547 {121: 29 }line │mouse enabled | 548 {121: 30 }line │^ | 549 ========== ========== | 550 {5:-- TERMINAL --} | 551 ]]) 552 command('set mousescroll=ver:10') 553 feed('<ScrollWheelUp><0,0>') 554 screen:expect([[ 555 {121: 16 }line │line30 | 556 {121: 17 }line │rows: 5, cols: 25 | 557 {121: 18 }line │rows: 5, cols: 24 | 558 {121: 19 }line │mouse enabled | 559 {121: 20 }line │^ | 560 ========== ========== | 561 {5:-- TERMINAL --} | 562 ]]) 563 command('set mousescroll=ver:0') 564 feed('<ScrollWheelUp><0,0>') 565 screen:expect_unchanged() 566 feed([[<C-\><C-N><C-W>w]]) 567 command('setlocal nowrap') 568 feed('0<C-V>gg3ly$4p<C-W>wi') 569 screen:expect([[ 570 {121: 1 }linelinelinelineline │line30 | 571 {121: 2 }linelinelinelineline │rows: 5, cols: 25 | 572 {121: 3 }linelinelinelineline │rows: 5, cols: 24 | 573 {121: 4 }linelinelinelineline │mouse enabled | 574 {121: 5 }linelinelinelineline │^ | 575 ========== ========== | 576 {5:-- TERMINAL --} | 577 ]]) 578 feed('<ScrollWheelRight><4,0>') 579 screen:expect([[ 580 {121: 1 }nelinelineline │line30 | 581 {121: 2 }nelinelineline │rows: 5, cols: 25 | 582 {121: 3 }nelinelineline │rows: 5, cols: 24 | 583 {121: 4 }nelinelineline │mouse enabled | 584 {121: 5 }nelinelineline │^ | 585 ========== ========== | 586 {5:-- TERMINAL --} | 587 ]]) 588 command('set mousescroll=hor:4') 589 feed('<ScrollWheelLeft><4,0>') 590 screen:expect([[ 591 {121: 1 }nelinelinelineline │line30 | 592 {121: 2 }nelinelinelineline │rows: 5, cols: 25 | 593 {121: 3 }nelinelinelineline │rows: 5, cols: 24 | 594 {121: 4 }nelinelinelineline │mouse enabled | 595 {121: 5 }nelinelinelineline │^ | 596 ========== ========== | 597 {5:-- TERMINAL --} | 598 ]]) 599 end) 600 601 it('will lose focus if another window is clicked', function() 602 feed('<LeftMouse><5,1>') 603 screen:expect([[ 604 {121: 27 }line │line30 | 605 {121: 28 }l^ine │rows: 5, cols: 25 | 606 {121: 29 }line │rows: 5, cols: 24 | 607 {121: 30 }line │mouse enabled | 608 {121: 31 } │ | 609 ========== ========== | 610 | 611 ]]) 612 end) 613 614 it('handles terminal size when switching buffers', function() 615 api.nvim_set_option_value('hidden', true, {}) 616 feed('<c-\\><c-n><c-w><c-w>') 617 screen:expect([[ 618 {121: 27 }line │line30 | 619 {121: 28 }line │rows: 5, cols: 25 | 620 {121: 29 }line │rows: 5, cols: 24 | 621 {121: 30 }line │mouse enabled | 622 {121: 31 }^ │ | 623 ========== ========== | 624 | 625 ]]) 626 feed(':bn<cr>') 627 screen:expect([[ 628 rows: 5, cols: 25 │rows: 5, cols: 25 | 629 rows: 5, cols: 24 │rows: 5, cols: 24 | 630 mouse enabled │mouse enabled | 631 rows: 5, cols: 25 │rows: 5, cols: 25 | 632 ^ │ | 633 ========== ========== | 634 :bn | 635 ]]) 636 feed(':bn<cr>') 637 screen:expect([[ 638 {121: 27 }line │rows: 5, cols: 24 | 639 {121: 28 }line │mouse enabled | 640 {121: 29 }line │rows: 5, cols: 25 | 641 {121: 30 }line │rows: 5, cols: 24 | 642 {121: 31 }^ │ | 643 ========== ========== | 644 :bn | 645 ]]) 646 end) 647 end) 648 end) 649 end)