cursor_spec.lua 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local tt = require('test.functional.testterm')
  4. local feed, clear = n.feed, n.clear
  5. local testprg, command = n.testprg, n.command
  6. local eq, eval = t.eq, n.eval
  7. local matches = t.matches
  8. local call = n.call
  9. local hide_cursor = tt.hide_cursor
  10. local show_cursor = tt.show_cursor
  11. local is_os = t.is_os
  12. local skip = t.skip
  13. describe(':terminal cursor', function()
  14. local screen
  15. local terminal_mode_idx ---@type number
  16. before_each(function()
  17. clear()
  18. screen = tt.setup_screen()
  19. if terminal_mode_idx == nil then
  20. for i, v in ipairs(screen._mode_info) do
  21. if v.name == 'terminal' then
  22. terminal_mode_idx = i
  23. end
  24. end
  25. assert(terminal_mode_idx)
  26. end
  27. end)
  28. it('moves the screen cursor when focused', function()
  29. tt.feed_data('testing cursor')
  30. screen:expect([[
  31. tty ready |
  32. testing cursor^ |
  33. |*4
  34. {3:-- TERMINAL --} |
  35. ]])
  36. end)
  37. it('is highlighted when not focused', function()
  38. feed('<c-\\><c-n>')
  39. screen:expect([[
  40. tty ready |
  41. ^ |
  42. |*5
  43. ]])
  44. end)
  45. describe('with number column', function()
  46. before_each(function()
  47. feed('<c-\\><c-n>:set number<cr>')
  48. end)
  49. it('is positioned correctly when unfocused', function()
  50. screen:expect([[
  51. {7: 1 }tty ready |
  52. {7: 2 }^rows: 6, cols: 46 |
  53. {7: 3 } |
  54. {7: 4 } |
  55. {7: 5 } |
  56. {7: 6 } |
  57. :set number |
  58. ]])
  59. end)
  60. it('is positioned correctly when focused', function()
  61. screen:expect([[
  62. {7: 1 }tty ready |
  63. {7: 2 }^rows: 6, cols: 46 |
  64. {7: 3 } |
  65. {7: 4 } |
  66. {7: 5 } |
  67. {7: 6 } |
  68. :set number |
  69. ]])
  70. feed('i')
  71. n.poke_eventloop()
  72. screen:expect([[
  73. {7: 1 }tty ready |
  74. {7: 2 }rows: 6, cols: 46 |
  75. {7: 3 }^ |
  76. {7: 4 } |
  77. {7: 5 } |
  78. {7: 6 } |
  79. {3:-- TERMINAL --} |
  80. ]])
  81. end)
  82. end)
  83. describe('when invisible', function()
  84. it('is not highlighted', function()
  85. skip(is_os('win'), '#31587')
  86. hide_cursor()
  87. screen:expect([[
  88. tty ready |
  89. |*5
  90. {3:-- TERMINAL --} |
  91. ]])
  92. show_cursor()
  93. screen:expect([[
  94. tty ready |
  95. ^ |
  96. |*4
  97. {3:-- TERMINAL --} |
  98. ]])
  99. -- same for when the terminal is unfocused
  100. feed('<c-\\><c-n>')
  101. hide_cursor()
  102. screen:expect({
  103. grid = [[
  104. tty ready |
  105. ^ |
  106. |*5
  107. ]],
  108. unchanged = true,
  109. })
  110. show_cursor()
  111. screen:expect({
  112. grid = [[
  113. tty ready |
  114. ^ |
  115. |*5
  116. ]],
  117. unchanged = true,
  118. })
  119. end)
  120. it('becomes visible when exiting Terminal mode', function()
  121. skip(is_os('win'), '#31587')
  122. hide_cursor()
  123. screen:expect([[
  124. tty ready |
  125. |*5
  126. {3:-- TERMINAL --} |
  127. ]])
  128. feed('<c-\\><c-n>')
  129. screen:expect([[
  130. tty ready |
  131. ^ |
  132. |*5
  133. ]])
  134. feed('i')
  135. screen:expect([[
  136. tty ready |
  137. |*5
  138. {3:-- TERMINAL --} |
  139. ]])
  140. end)
  141. end)
  142. it('can be modified by application #3681 #31685', function()
  143. skip(is_os('win'), '#31587')
  144. local states = {
  145. [1] = { blink = true, shape = 'block' },
  146. [2] = { blink = false, shape = 'block' },
  147. [3] = { blink = true, shape = 'horizontal' },
  148. [4] = { blink = false, shape = 'horizontal' },
  149. [5] = { blink = true, shape = 'vertical' },
  150. [6] = { blink = false, shape = 'vertical' },
  151. }
  152. for k, v in pairs(states) do
  153. tt.feed_csi(('%d q'):format(k))
  154. screen:expect({
  155. grid = [[
  156. tty ready |
  157. ^ |
  158. |*4
  159. {3:-- TERMINAL --} |
  160. ]],
  161. condition = function()
  162. if v.blink then
  163. eq(500, screen._mode_info[terminal_mode_idx].blinkon)
  164. eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
  165. else
  166. eq(0, screen._mode_info[terminal_mode_idx].blinkon)
  167. eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
  168. end
  169. eq(v.shape, screen._mode_info[terminal_mode_idx].cursor_shape)
  170. -- Cell percentages are hard coded for each shape in terminal.c
  171. if v.shape == 'horizontal' then
  172. eq(20, screen._mode_info[terminal_mode_idx].cell_percentage)
  173. elseif v.shape == 'vertical' then
  174. eq(25, screen._mode_info[terminal_mode_idx].cell_percentage)
  175. end
  176. end,
  177. })
  178. end
  179. feed([[<C-\><C-N>]])
  180. screen:expect([[
  181. tty ready |
  182. ^ |
  183. |*5
  184. ]])
  185. -- Cursor returns to default on TermLeave
  186. eq(500, screen._mode_info[terminal_mode_idx].blinkon)
  187. eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
  188. eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
  189. end)
  190. it('can be modified per terminal', function()
  191. skip(is_os('win'), '#31587')
  192. -- Set cursor to vertical bar with blink
  193. tt.feed_csi('5 q')
  194. screen:expect({
  195. grid = [[
  196. tty ready |
  197. ^ |
  198. |*4
  199. {3:-- TERMINAL --} |
  200. ]],
  201. condition = function()
  202. eq(500, screen._mode_info[terminal_mode_idx].blinkon)
  203. eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
  204. eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
  205. end,
  206. })
  207. tt.hide_cursor()
  208. screen:expect({
  209. grid = [[
  210. tty ready |
  211. |
  212. |*4
  213. {3:-- TERMINAL --} |
  214. ]],
  215. condition = function()
  216. eq(500, screen._mode_info[terminal_mode_idx].blinkon)
  217. eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
  218. eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
  219. end,
  220. })
  221. -- Exit terminal mode to reset terminal cursor settings to default and
  222. -- create a new terminal window
  223. feed([[<C-\><C-N>]])
  224. command('set statusline=~~~')
  225. command('new')
  226. call('jobstart', { testprg('tty-test') }, { term = true })
  227. feed('i')
  228. screen:expect({
  229. grid = [[
  230. tty ready |
  231. ^ |
  232. {17:~~~ }|
  233. rows: 2, cols: 50 |
  234. |
  235. {18:~~~ }|
  236. {3:-- TERMINAL --} |
  237. ]],
  238. condition = function()
  239. -- New terminal, cursor resets to defaults
  240. eq(500, screen._mode_info[terminal_mode_idx].blinkon)
  241. eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
  242. eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
  243. end,
  244. })
  245. -- Set cursor to underline, no blink
  246. tt.feed_csi('4 q')
  247. screen:expect({
  248. grid = [[
  249. tty ready |
  250. ^ |
  251. {17:~~~ }|
  252. rows: 2, cols: 50 |
  253. |
  254. {18:~~~ }|
  255. {3:-- TERMINAL --} |
  256. ]],
  257. condition = function()
  258. eq(0, screen._mode_info[terminal_mode_idx].blinkon)
  259. eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
  260. eq('horizontal', screen._mode_info[terminal_mode_idx].cursor_shape)
  261. end,
  262. })
  263. -- Switch back to first terminal, cursor should still be hidden
  264. command('wincmd p')
  265. screen:expect({
  266. grid = [[
  267. tty ready |
  268. |
  269. {18:~~~ }|
  270. rows: 2, cols: 50 |
  271. |
  272. {17:~~~ }|
  273. {3:-- TERMINAL --} |
  274. ]],
  275. condition = function()
  276. eq(500, screen._mode_info[terminal_mode_idx].blinkon)
  277. eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
  278. eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
  279. end,
  280. })
  281. end)
  282. it('can be positioned arbitrarily', function()
  283. clear()
  284. screen = tt.setup_child_nvim({
  285. '-u',
  286. 'NONE',
  287. '-i',
  288. 'NONE',
  289. '--cmd',
  290. n.nvim_set .. ' noshowmode',
  291. })
  292. screen:expect([[
  293. ^ |
  294. ~ |*4
  295. |
  296. {3:-- TERMINAL --} |
  297. ]])
  298. feed('i<Tab>')
  299. screen:expect([[
  300. ^ |
  301. ~ |*4
  302. |
  303. {3:-- TERMINAL --} |
  304. ]])
  305. end)
  306. it('preserves guicursor value on TermLeave #31612', function()
  307. eq(3, screen._mode_info[terminal_mode_idx].hl_id)
  308. -- Change 'guicursor' while terminal mode is active
  309. command('set guicursor+=t:Error')
  310. local error_hl_id = call('hlID', 'Error')
  311. screen:expect({
  312. condition = function()
  313. eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
  314. end,
  315. })
  316. -- Exit terminal mode
  317. feed([[<C-\><C-N>]])
  318. screen:expect([[
  319. tty ready |
  320. ^ |
  321. |*5
  322. ]])
  323. eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
  324. end)
  325. end)
  326. describe('buffer cursor position is correct in terminal without number column', function()
  327. local screen
  328. local function setup_ex_register(str)
  329. screen = tt.setup_child_nvim({
  330. '-u',
  331. 'NONE',
  332. '-i',
  333. 'NONE',
  334. '-E',
  335. '--cmd',
  336. string.format('let @r = "%s"', str),
  337. -- <Left> and <Right> don't always work
  338. '--cmd',
  339. 'cnoremap <C-X> <Left>',
  340. '--cmd',
  341. 'cnoremap <C-O> <Right>',
  342. '--cmd',
  343. 'set notermguicolors',
  344. }, {
  345. cols = 70,
  346. })
  347. -- Also check for real cursor position, as it is used for stuff like input methods
  348. screen._handle_busy_start = function() end
  349. screen._handle_busy_stop = function() end
  350. screen:expect([[
  351. |*4
  352. Entering Ex mode. Type "visual" to go to Normal mode. |
  353. :^ |
  354. {3:-- TERMINAL --} |
  355. ]])
  356. end
  357. before_each(clear)
  358. describe('in a line with no multibyte chars or trailing spaces,', function()
  359. before_each(function()
  360. setup_ex_register('aaaaaaaa')
  361. end)
  362. it('at the end', function()
  363. feed('<C-R>r')
  364. screen:expect([[
  365. |*4
  366. Entering Ex mode. Type "visual" to go to Normal mode. |
  367. :aaaaaaaa^ |
  368. {3:-- TERMINAL --} |
  369. ]])
  370. eq({ 6, 9 }, eval('nvim_win_get_cursor(0)'))
  371. feed([[<C-\><C-N>]])
  372. screen:expect([[
  373. |*4
  374. Entering Ex mode. Type "visual" to go to Normal mode. |
  375. :aaaaaaa^a |
  376. |
  377. ]])
  378. eq({ 6, 8 }, eval('nvim_win_get_cursor(0)'))
  379. end)
  380. it('near the end', function()
  381. feed('<C-R>r<C-X><C-X>')
  382. screen:expect([[
  383. |*4
  384. Entering Ex mode. Type "visual" to go to Normal mode. |
  385. :aaaaaa^aa |
  386. {3:-- TERMINAL --} |
  387. ]])
  388. eq({ 6, 7 }, eval('nvim_win_get_cursor(0)'))
  389. feed([[<C-\><C-N>]])
  390. screen:expect([[
  391. |*4
  392. Entering Ex mode. Type "visual" to go to Normal mode. |
  393. :aaaaa^aaa |
  394. |
  395. ]])
  396. eq({ 6, 6 }, eval('nvim_win_get_cursor(0)'))
  397. end)
  398. it('near the start', function()
  399. feed('<C-R>r<C-B><C-O>')
  400. screen:expect([[
  401. |*4
  402. Entering Ex mode. Type "visual" to go to Normal mode. |
  403. :a^aaaaaaa |
  404. {3:-- TERMINAL --} |
  405. ]])
  406. eq({ 6, 2 }, eval('nvim_win_get_cursor(0)'))
  407. feed([[<C-\><C-N>]])
  408. screen:expect([[
  409. |*4
  410. Entering Ex mode. Type "visual" to go to Normal mode. |
  411. :^aaaaaaaa |
  412. |
  413. ]])
  414. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  415. end)
  416. end)
  417. describe('in a line with single-cell multibyte chars and no trailing spaces,', function()
  418. before_each(function()
  419. setup_ex_register('µµµµµµµµ')
  420. end)
  421. it('at the end', function()
  422. feed('<C-R>r')
  423. screen:expect([[
  424. |*4
  425. Entering Ex mode. Type "visual" to go to Normal mode. |
  426. :µµµµµµµµ^ |
  427. {3:-- TERMINAL --} |
  428. ]])
  429. eq({ 6, 17 }, eval('nvim_win_get_cursor(0)'))
  430. feed([[<C-\><C-N>]])
  431. screen:expect([[
  432. |*4
  433. Entering Ex mode. Type "visual" to go to Normal mode. |
  434. :µµµµµµµ^µ |
  435. |
  436. ]])
  437. eq({ 6, 15 }, eval('nvim_win_get_cursor(0)'))
  438. end)
  439. it('near the end', function()
  440. feed('<C-R>r<C-X><C-X>')
  441. screen:expect([[
  442. |*4
  443. Entering Ex mode. Type "visual" to go to Normal mode. |
  444. :µµµµµµ^µµ |
  445. {3:-- TERMINAL --} |
  446. ]])
  447. eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
  448. feed([[<C-\><C-N>]])
  449. screen:expect([[
  450. |*4
  451. Entering Ex mode. Type "visual" to go to Normal mode. |
  452. :µµµµµ^µµµ |
  453. |
  454. ]])
  455. eq({ 6, 11 }, eval('nvim_win_get_cursor(0)'))
  456. end)
  457. it('near the start', function()
  458. feed('<C-R>r<C-B><C-O>')
  459. screen:expect([[
  460. |*4
  461. Entering Ex mode. Type "visual" to go to Normal mode. |
  462. :µ^µµµµµµµ |
  463. {3:-- TERMINAL --} |
  464. ]])
  465. eq({ 6, 3 }, eval('nvim_win_get_cursor(0)'))
  466. feed([[<C-\><C-N>]])
  467. screen:expect([[
  468. |*4
  469. Entering Ex mode. Type "visual" to go to Normal mode. |
  470. :^µµµµµµµµ |
  471. |
  472. ]])
  473. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  474. end)
  475. end)
  476. describe('in a line with single-cell composed multibyte chars and no trailing spaces,', function()
  477. before_each(function()
  478. setup_ex_register('µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳')
  479. end)
  480. it('at the end', function()
  481. feed('<C-R>r')
  482. screen:expect([[
  483. |*4
  484. Entering Ex mode. Type "visual" to go to Normal mode. |
  485. :µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳^ |
  486. {3:-- TERMINAL --} |
  487. ]])
  488. eq({ 6, 33 }, eval('nvim_win_get_cursor(0)'))
  489. feed([[<C-\><C-N>]])
  490. screen:expect([[
  491. |*4
  492. Entering Ex mode. Type "visual" to go to Normal mode. |
  493. :µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳ |
  494. |
  495. ]])
  496. eq({ 6, 29 }, eval('nvim_win_get_cursor(0)'))
  497. end)
  498. it('near the end', function()
  499. skip(is_os('win'))
  500. feed('<C-R>r<C-X><C-X>')
  501. screen:expect([[
  502. |*4
  503. Entering Ex mode. Type "visual" to go to Normal mode. |
  504. :µ̳µ̳µ̳µ̳µ̳µ̳^µ̳µ̳ |
  505. {3:-- TERMINAL --} |
  506. ]])
  507. eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
  508. feed([[<C-\><C-N>]])
  509. screen:expect([[
  510. |*4
  511. Entering Ex mode. Type "visual" to go to Normal mode. |
  512. :µ̳µ̳µ̳µ̳µ̳^µ̳µ̳µ̳ |
  513. |
  514. ]])
  515. eq({ 6, 21 }, eval('nvim_win_get_cursor(0)'))
  516. end)
  517. it('near the start', function()
  518. skip(is_os('win'))
  519. feed('<C-R>r<C-B><C-O>')
  520. screen:expect([[
  521. |*4
  522. Entering Ex mode. Type "visual" to go to Normal mode. |
  523. :µ̳^µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
  524. {3:-- TERMINAL --} |
  525. ]])
  526. eq({ 6, 5 }, eval('nvim_win_get_cursor(0)'))
  527. feed([[<C-\><C-N>]])
  528. screen:expect([[
  529. |*4
  530. Entering Ex mode. Type "visual" to go to Normal mode. |
  531. :^µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
  532. |
  533. ]])
  534. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  535. end)
  536. end)
  537. describe('in a line with double-cell multibyte chars and no trailing spaces,', function()
  538. before_each(function()
  539. setup_ex_register('哦哦哦哦哦哦哦哦')
  540. end)
  541. it('at the end', function()
  542. feed('<C-R>r')
  543. screen:expect([[
  544. |*4
  545. Entering Ex mode. Type "visual" to go to Normal mode. |
  546. :哦哦哦哦哦哦哦哦^ |
  547. {3:-- TERMINAL --} |
  548. ]])
  549. eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
  550. feed([[<C-\><C-N>]])
  551. screen:expect([[
  552. |*4
  553. Entering Ex mode. Type "visual" to go to Normal mode. |
  554. :哦哦哦哦哦哦哦^哦 |
  555. |
  556. ]])
  557. eq({ 6, 22 }, eval('nvim_win_get_cursor(0)'))
  558. end)
  559. it('near the end', function()
  560. feed('<C-R>r<C-X><C-X>')
  561. screen:expect([[
  562. |*4
  563. Entering Ex mode. Type "visual" to go to Normal mode. |
  564. :哦哦哦哦哦哦^哦哦 |
  565. {3:-- TERMINAL --} |
  566. ]])
  567. eq({ 6, 19 }, eval('nvim_win_get_cursor(0)'))
  568. feed([[<C-\><C-N>]])
  569. screen:expect([[
  570. |*4
  571. Entering Ex mode. Type "visual" to go to Normal mode. |
  572. :哦哦哦哦哦^哦哦哦 |
  573. |
  574. ]])
  575. eq({ 6, 16 }, eval('nvim_win_get_cursor(0)'))
  576. end)
  577. it('near the start', function()
  578. feed('<C-R>r<C-B><C-O>')
  579. screen:expect([[
  580. |*4
  581. Entering Ex mode. Type "visual" to go to Normal mode. |
  582. :哦^哦哦哦哦哦哦哦 |
  583. {3:-- TERMINAL --} |
  584. ]])
  585. eq({ 6, 4 }, eval('nvim_win_get_cursor(0)'))
  586. feed([[<C-\><C-N>]])
  587. screen:expect([[
  588. |*4
  589. Entering Ex mode. Type "visual" to go to Normal mode. |
  590. :^哦哦哦哦哦哦哦哦 |
  591. |
  592. ]])
  593. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  594. end)
  595. end)
  596. it('at the end of a line with trailing spaces #16234', function()
  597. setup_ex_register('aaaaaaaa ')
  598. feed('<C-R>r')
  599. screen:expect([[
  600. |*4
  601. Entering Ex mode. Type "visual" to go to Normal mode. |
  602. :aaaaaaaa ^ |
  603. {3:-- TERMINAL --} |
  604. ]])
  605. matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
  606. eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
  607. feed([[<C-\><C-N>]])
  608. screen:expect([[
  609. |*4
  610. Entering Ex mode. Type "visual" to go to Normal mode. |
  611. :aaaaaaaa ^ |
  612. |
  613. ]])
  614. eq({ 6, 12 }, eval('nvim_win_get_cursor(0)'))
  615. end)
  616. end)
  617. describe('buffer cursor position is correct in terminal with number column', function()
  618. local screen
  619. local function setup_ex_register(str)
  620. screen = tt.setup_child_nvim({
  621. '-u',
  622. 'NONE',
  623. '-i',
  624. 'NONE',
  625. '-E',
  626. '--cmd',
  627. string.format('let @r = "%s"', str),
  628. -- <Left> and <Right> don't always work
  629. '--cmd',
  630. 'cnoremap <C-X> <Left>',
  631. '--cmd',
  632. 'cnoremap <C-O> <Right>',
  633. '--cmd',
  634. 'set notermguicolors',
  635. }, {
  636. cols = 70,
  637. })
  638. -- Also check for real cursor position, as it is used for stuff like input methods
  639. screen._handle_busy_start = function() end
  640. screen._handle_busy_stop = function() end
  641. screen:expect([[
  642. {7: 1 } |
  643. {7: 2 } |
  644. {7: 3 } |
  645. {7: 4 } |
  646. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  647. {7: 6 }:^ |
  648. {3:-- TERMINAL --} |
  649. ]])
  650. end
  651. before_each(function()
  652. clear()
  653. command('au TermOpen * set number')
  654. end)
  655. describe('in a line with no multibyte chars or trailing spaces,', function()
  656. before_each(function()
  657. setup_ex_register('aaaaaaaa')
  658. end)
  659. it('at the end', function()
  660. feed('<C-R>r')
  661. screen:expect([[
  662. {7: 1 } |
  663. {7: 2 } |
  664. {7: 3 } |
  665. {7: 4 } |
  666. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  667. {7: 6 }:aaaaaaaa^ |
  668. {3:-- TERMINAL --} |
  669. ]])
  670. eq({ 6, 9 }, eval('nvim_win_get_cursor(0)'))
  671. feed([[<C-\><C-N>]])
  672. screen:expect([[
  673. {7: 1 } |
  674. {7: 2 } |
  675. {7: 3 } |
  676. {7: 4 } |
  677. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  678. {7: 6 }:aaaaaaa^a |
  679. |
  680. ]])
  681. eq({ 6, 8 }, eval('nvim_win_get_cursor(0)'))
  682. end)
  683. it('near the end', function()
  684. feed('<C-R>r<C-X><C-X>')
  685. screen:expect([[
  686. {7: 1 } |
  687. {7: 2 } |
  688. {7: 3 } |
  689. {7: 4 } |
  690. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  691. {7: 6 }:aaaaaa^aa |
  692. {3:-- TERMINAL --} |
  693. ]])
  694. eq({ 6, 7 }, eval('nvim_win_get_cursor(0)'))
  695. feed([[<C-\><C-N>]])
  696. screen:expect([[
  697. {7: 1 } |
  698. {7: 2 } |
  699. {7: 3 } |
  700. {7: 4 } |
  701. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  702. {7: 6 }:aaaaa^aaa |
  703. |
  704. ]])
  705. eq({ 6, 6 }, eval('nvim_win_get_cursor(0)'))
  706. end)
  707. it('near the start', function()
  708. feed('<C-R>r<C-B><C-O>')
  709. screen:expect([[
  710. {7: 1 } |
  711. {7: 2 } |
  712. {7: 3 } |
  713. {7: 4 } |
  714. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  715. {7: 6 }:a^aaaaaaa |
  716. {3:-- TERMINAL --} |
  717. ]])
  718. eq({ 6, 2 }, eval('nvim_win_get_cursor(0)'))
  719. feed([[<C-\><C-N>]])
  720. screen:expect([[
  721. {7: 1 } |
  722. {7: 2 } |
  723. {7: 3 } |
  724. {7: 4 } |
  725. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  726. {7: 6 }:^aaaaaaaa |
  727. |
  728. ]])
  729. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  730. end)
  731. end)
  732. describe('in a line with single-cell multibyte chars and no trailing spaces,', function()
  733. before_each(function()
  734. setup_ex_register('µµµµµµµµ')
  735. end)
  736. it('at the end', function()
  737. feed('<C-R>r')
  738. screen:expect([[
  739. {7: 1 } |
  740. {7: 2 } |
  741. {7: 3 } |
  742. {7: 4 } |
  743. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  744. {7: 6 }:µµµµµµµµ^ |
  745. {3:-- TERMINAL --} |
  746. ]])
  747. eq({ 6, 17 }, eval('nvim_win_get_cursor(0)'))
  748. feed([[<C-\><C-N>]])
  749. screen:expect([[
  750. {7: 1 } |
  751. {7: 2 } |
  752. {7: 3 } |
  753. {7: 4 } |
  754. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  755. {7: 6 }:µµµµµµµ^µ |
  756. |
  757. ]])
  758. eq({ 6, 15 }, eval('nvim_win_get_cursor(0)'))
  759. end)
  760. it('near the end', function()
  761. feed('<C-R>r<C-X><C-X>')
  762. screen:expect([[
  763. {7: 1 } |
  764. {7: 2 } |
  765. {7: 3 } |
  766. {7: 4 } |
  767. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  768. {7: 6 }:µµµµµµ^µµ |
  769. {3:-- TERMINAL --} |
  770. ]])
  771. eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
  772. feed([[<C-\><C-N>]])
  773. screen:expect([[
  774. {7: 1 } |
  775. {7: 2 } |
  776. {7: 3 } |
  777. {7: 4 } |
  778. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  779. {7: 6 }:µµµµµ^µµµ |
  780. |
  781. ]])
  782. eq({ 6, 11 }, eval('nvim_win_get_cursor(0)'))
  783. end)
  784. it('near the start', function()
  785. feed('<C-R>r<C-B><C-O>')
  786. screen:expect([[
  787. {7: 1 } |
  788. {7: 2 } |
  789. {7: 3 } |
  790. {7: 4 } |
  791. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  792. {7: 6 }:µ^µµµµµµµ |
  793. {3:-- TERMINAL --} |
  794. ]])
  795. eq({ 6, 3 }, eval('nvim_win_get_cursor(0)'))
  796. feed([[<C-\><C-N>]])
  797. screen:expect([[
  798. {7: 1 } |
  799. {7: 2 } |
  800. {7: 3 } |
  801. {7: 4 } |
  802. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  803. {7: 6 }:^µµµµµµµµ |
  804. |
  805. ]])
  806. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  807. end)
  808. end)
  809. describe('in a line with single-cell composed multibyte chars and no trailing spaces,', function()
  810. before_each(function()
  811. setup_ex_register('µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳')
  812. end)
  813. it('at the end', function()
  814. feed('<C-R>r')
  815. screen:expect([[
  816. {7: 1 } |
  817. {7: 2 } |
  818. {7: 3 } |
  819. {7: 4 } |
  820. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  821. {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳^ |
  822. {3:-- TERMINAL --} |
  823. ]])
  824. eq({ 6, 33 }, eval('nvim_win_get_cursor(0)'))
  825. feed([[<C-\><C-N>]])
  826. screen:expect([[
  827. {7: 1 } |
  828. {7: 2 } |
  829. {7: 3 } |
  830. {7: 4 } |
  831. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  832. {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳ |
  833. |
  834. ]])
  835. eq({ 6, 29 }, eval('nvim_win_get_cursor(0)'))
  836. end)
  837. it('near the end', function()
  838. skip(is_os('win'))
  839. feed('<C-R>r<C-X><C-X>')
  840. screen:expect([[
  841. {7: 1 } |
  842. {7: 2 } |
  843. {7: 3 } |
  844. {7: 4 } |
  845. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  846. {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳^µ̳µ̳ |
  847. {3:-- TERMINAL --} |
  848. ]])
  849. eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
  850. feed([[<C-\><C-N>]])
  851. screen:expect([[
  852. {7: 1 } |
  853. {7: 2 } |
  854. {7: 3 } |
  855. {7: 4 } |
  856. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  857. {7: 6 }:µ̳µ̳µ̳µ̳µ̳^µ̳µ̳µ̳ |
  858. |
  859. ]])
  860. eq({ 6, 21 }, eval('nvim_win_get_cursor(0)'))
  861. end)
  862. it('near the start', function()
  863. skip(is_os('win'))
  864. feed('<C-R>r<C-B><C-O>')
  865. screen:expect([[
  866. {7: 1 } |
  867. {7: 2 } |
  868. {7: 3 } |
  869. {7: 4 } |
  870. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  871. {7: 6 }:µ̳^µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
  872. {3:-- TERMINAL --} |
  873. ]])
  874. eq({ 6, 5 }, eval('nvim_win_get_cursor(0)'))
  875. feed([[<C-\><C-N>]])
  876. screen:expect([[
  877. {7: 1 } |
  878. {7: 2 } |
  879. {7: 3 } |
  880. {7: 4 } |
  881. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  882. {7: 6 }:^µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
  883. |
  884. ]])
  885. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  886. end)
  887. end)
  888. describe('in a line with double-cell multibyte chars and no trailing spaces,', function()
  889. before_each(function()
  890. setup_ex_register('哦哦哦哦哦哦哦哦')
  891. end)
  892. it('at the end', function()
  893. feed('<C-R>r')
  894. screen:expect([[
  895. {7: 1 } |
  896. {7: 2 } |
  897. {7: 3 } |
  898. {7: 4 } |
  899. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  900. {7: 6 }:哦哦哦哦哦哦哦哦^ |
  901. {3:-- TERMINAL --} |
  902. ]])
  903. eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
  904. feed([[<C-\><C-N>]])
  905. screen:expect([[
  906. {7: 1 } |
  907. {7: 2 } |
  908. {7: 3 } |
  909. {7: 4 } |
  910. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  911. {7: 6 }:哦哦哦哦哦哦哦^哦 |
  912. |
  913. ]])
  914. eq({ 6, 22 }, eval('nvim_win_get_cursor(0)'))
  915. end)
  916. it('near the end', function()
  917. feed('<C-R>r<C-X><C-X>')
  918. screen:expect([[
  919. {7: 1 } |
  920. {7: 2 } |
  921. {7: 3 } |
  922. {7: 4 } |
  923. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  924. {7: 6 }:哦哦哦哦哦哦^哦哦 |
  925. {3:-- TERMINAL --} |
  926. ]])
  927. eq({ 6, 19 }, eval('nvim_win_get_cursor(0)'))
  928. feed([[<C-\><C-N>]])
  929. screen:expect([[
  930. {7: 1 } |
  931. {7: 2 } |
  932. {7: 3 } |
  933. {7: 4 } |
  934. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  935. {7: 6 }:哦哦哦哦哦^哦哦哦 |
  936. |
  937. ]])
  938. eq({ 6, 16 }, eval('nvim_win_get_cursor(0)'))
  939. end)
  940. it('near the start', function()
  941. feed('<C-R>r<C-B><C-O>')
  942. screen:expect([[
  943. {7: 1 } |
  944. {7: 2 } |
  945. {7: 3 } |
  946. {7: 4 } |
  947. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  948. {7: 6 }:哦^哦哦哦哦哦哦哦 |
  949. {3:-- TERMINAL --} |
  950. ]])
  951. eq({ 6, 4 }, eval('nvim_win_get_cursor(0)'))
  952. feed([[<C-\><C-N>]])
  953. screen:expect([[
  954. {7: 1 } |
  955. {7: 2 } |
  956. {7: 3 } |
  957. {7: 4 } |
  958. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  959. {7: 6 }:^哦哦哦哦哦哦哦哦 |
  960. |
  961. ]])
  962. eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
  963. end)
  964. end)
  965. it('at the end of a line with trailing spaces #16234', function()
  966. setup_ex_register('aaaaaaaa ')
  967. feed('<C-R>r')
  968. screen:expect([[
  969. {7: 1 } |
  970. {7: 2 } |
  971. {7: 3 } |
  972. {7: 4 } |
  973. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  974. {7: 6 }:aaaaaaaa ^ |
  975. {3:-- TERMINAL --} |
  976. ]])
  977. matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
  978. eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
  979. feed([[<C-\><C-N>]])
  980. screen:expect([[
  981. {7: 1 } |
  982. {7: 2 } |
  983. {7: 3 } |
  984. {7: 4 } |
  985. {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
  986. {7: 6 }:aaaaaaaa ^ |
  987. |
  988. ]])
  989. eq({ 6, 12 }, eval('nvim_win_get_cursor(0)'))
  990. end)
  991. end)