mouse_spec.lua 26 KB

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