buffer_updates_spec.lua 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. -- Test suite for testing interactions with API bindings
  2. local t = require('test.testutil')
  3. local n = require('test.functional.testnvim')()
  4. local Screen = require('test.functional.ui.screen')
  5. local command = n.command
  6. local api = n.api
  7. local fn = n.fn
  8. local clear = n.clear
  9. local eq = t.eq
  10. local fail = t.fail
  11. local exec_lua = n.exec_lua
  12. local feed = n.feed
  13. local expect_events = t.expect_events
  14. local write_file = t.write_file
  15. local dedent = t.dedent
  16. local origlines = {
  17. 'original line 1',
  18. 'original line 2',
  19. 'original line 3',
  20. 'original line 4',
  21. 'original line 5',
  22. 'original line 6',
  23. ' indented line',
  24. }
  25. before_each(function()
  26. clear()
  27. exec_lua(function()
  28. local events = {}
  29. function _G.test_register(bufnr, evname, id, changedtick, utf_sizes, preview)
  30. local function callback(...)
  31. table.insert(events, { id, ... })
  32. if _G.test_unreg == id then
  33. return true
  34. end
  35. end
  36. local opts = {
  37. [evname] = callback,
  38. on_detach = callback,
  39. on_reload = callback,
  40. utf_sizes = utf_sizes,
  41. preview = preview,
  42. }
  43. if changedtick then
  44. opts.on_changedtick = callback
  45. end
  46. vim.api.nvim_buf_attach(bufnr, false, opts)
  47. end
  48. function _G.get_events()
  49. local ret_events = events
  50. events = {}
  51. return ret_events
  52. end
  53. end)
  54. end)
  55. describe('lua buffer event callbacks: on_lines', function()
  56. local function setup_eventcheck(verify, utf_sizes, lines)
  57. local lastsize
  58. api.nvim_buf_set_lines(0, 0, -1, true, lines)
  59. if verify then
  60. lastsize = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0))
  61. end
  62. exec_lua('return test_register(...)', 0, 'on_lines', 'test1', false, utf_sizes)
  63. local verify_name = 'test1'
  64. local function check_events(expected)
  65. local events = exec_lua('return get_events(...)')
  66. if utf_sizes then
  67. -- this test case uses ASCII only, so sizes should be the same.
  68. -- Unicode is tested below.
  69. for _, event in ipairs(expected) do
  70. event[9] = event[9] or event[8]
  71. event[10] = event[10] or event[9]
  72. end
  73. end
  74. expect_events(expected, events, 'line updates')
  75. if verify then
  76. for _, event in ipairs(events) do
  77. if event[1] == verify_name and event[2] == 'lines' then
  78. local startline, endline = event[5], event[7]
  79. local newrange = api.nvim_buf_get_offset(0, endline)
  80. - api.nvim_buf_get_offset(0, startline)
  81. local newsize = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0))
  82. local oldrange = newrange + lastsize - newsize
  83. eq(oldrange, event[8])
  84. lastsize = newsize
  85. end
  86. end
  87. end
  88. end
  89. return check_events, function(new)
  90. verify_name = new
  91. end
  92. end
  93. -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
  94. -- assert the wrong thing), but masks errors with unflushed lines (as
  95. -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
  96. -- test both ways.
  97. local function check(verify, utf_sizes)
  98. local check_events, verify_name = setup_eventcheck(verify, utf_sizes, origlines)
  99. local tick = api.nvim_buf_get_changedtick(0)
  100. command('set autoindent')
  101. command('normal! GyyggP')
  102. tick = tick + 1
  103. check_events { { 'test1', 'lines', 1, tick, 0, 0, 1, 0 } }
  104. api.nvim_buf_set_lines(0, 3, 5, true, { 'changed line' })
  105. tick = tick + 1
  106. check_events { { 'test1', 'lines', 1, tick, 3, 5, 4, 32 } }
  107. exec_lua('return test_register(...)', 0, 'on_lines', 'test2', true, utf_sizes)
  108. tick = tick + 1
  109. command('undo')
  110. -- plugins can opt in to receive changedtick events, or choose
  111. -- to only receive actual changes.
  112. check_events {
  113. { 'test1', 'lines', 1, tick, 3, 4, 5, 13 },
  114. { 'test2', 'lines', 1, tick, 3, 4, 5, 13 },
  115. { 'test2', 'changedtick', 1, tick + 1 },
  116. }
  117. tick = tick + 1
  118. tick = tick + 1
  119. command('redo')
  120. check_events {
  121. { 'test1', 'lines', 1, tick, 3, 5, 4, 32 },
  122. { 'test2', 'lines', 1, tick, 3, 5, 4, 32 },
  123. { 'test2', 'changedtick', 1, tick + 1 },
  124. }
  125. tick = tick + 1
  126. tick = tick + 1
  127. command('undo!')
  128. check_events {
  129. { 'test1', 'lines', 1, tick, 3, 4, 5, 13 },
  130. { 'test2', 'lines', 1, tick, 3, 4, 5, 13 },
  131. { 'test2', 'changedtick', 1, tick + 1 },
  132. }
  133. tick = tick + 1
  134. -- simulate next callback returning true
  135. exec_lua("test_unreg = 'test1'")
  136. api.nvim_buf_set_lines(0, 6, 7, true, { 'x1', 'x2', 'x3' })
  137. tick = tick + 1
  138. -- plugins can opt in to receive changedtick events, or choose
  139. -- to only receive actual changes.
  140. check_events {
  141. { 'test1', 'lines', 1, tick, 6, 7, 9, 16 },
  142. { 'test2', 'lines', 1, tick, 6, 7, 9, 16 },
  143. }
  144. verify_name 'test2'
  145. api.nvim_buf_set_lines(0, 1, 1, true, { 'added' })
  146. tick = tick + 1
  147. check_events { { 'test2', 'lines', 1, tick, 1, 1, 2, 0 } }
  148. feed('wix')
  149. tick = tick + 1
  150. check_events { { 'test2', 'lines', 1, tick, 4, 5, 5, 16 } }
  151. -- check hot path for multiple insert
  152. feed('yz')
  153. tick = tick + 1
  154. check_events { { 'test2', 'lines', 1, tick, 4, 5, 5, 17 } }
  155. feed('<bs>')
  156. tick = tick + 1
  157. check_events { { 'test2', 'lines', 1, tick, 4, 5, 5, 19 } }
  158. feed('<esc>Go')
  159. tick = tick + 1
  160. check_events { { 'test2', 'lines', 1, tick, 11, 11, 12, 0 } }
  161. feed('x')
  162. tick = tick + 1
  163. check_events { { 'test2', 'lines', 1, tick, 11, 12, 12, 5 } }
  164. command('bwipe!')
  165. check_events { { 'test2', 'detach', 1 } }
  166. end
  167. it('works', function()
  168. check(false)
  169. end)
  170. it('works with verify', function()
  171. check(true)
  172. end)
  173. it('works with utf_sizes and ASCII text', function()
  174. check(false, true)
  175. end)
  176. local function check_unicode(verify)
  177. local unicode_text = {
  178. 'ascii text',
  179. 'latin text åäö',
  180. 'BMP text ɧ αλφά',
  181. 'BMP text 汉语 ↥↧',
  182. 'SMP 🤦 🦄🦃',
  183. 'combining å بِيَّة',
  184. }
  185. local check_events, verify_name = setup_eventcheck(verify, true, unicode_text)
  186. local tick = api.nvim_buf_get_changedtick(0)
  187. feed('ggdd')
  188. tick = tick + 1
  189. check_events { { 'test1', 'lines', 1, tick, 0, 1, 0, 11, 11, 11 } }
  190. feed('A<bs>')
  191. tick = tick + 1
  192. check_events { { 'test1', 'lines', 1, tick, 0, 1, 1, 18, 15, 15 } }
  193. feed('<esc>jylp')
  194. tick = tick + 1
  195. check_events { { 'test1', 'lines', 1, tick, 1, 2, 2, 21, 16, 16 } }
  196. feed('+eea<cr>')
  197. tick = tick + 1
  198. check_events { { 'test1', 'lines', 1, tick, 2, 3, 4, 23, 15, 15 } }
  199. feed('<esc>jdw')
  200. tick = tick + 1
  201. -- non-BMP chars count as 2 UTF-2 codeunits
  202. check_events { { 'test1', 'lines', 1, tick, 4, 5, 5, 18, 9, 12 } }
  203. feed('+rx')
  204. tick = tick + 1
  205. -- count the individual codepoints of a composed character.
  206. check_events { { 'test1', 'lines', 1, tick, 5, 6, 6, 27, 20, 20 } }
  207. feed('kJ')
  208. tick = tick + 1
  209. -- verification fails with multiple line updates, sorry about that
  210. verify_name ''
  211. -- NB: this is inefficient (but not really wrong).
  212. check_events {
  213. { 'test1', 'lines', 1, tick, 4, 5, 5, 14, 5, 8 },
  214. { 'test1', 'lines', 1, tick + 1, 5, 6, 5, 27, 20, 20 },
  215. }
  216. end
  217. it('works with utf_sizes and unicode text', function()
  218. check_unicode(false)
  219. end)
  220. it('works with utf_sizes and unicode text with verify', function()
  221. check_unicode(true)
  222. end)
  223. it('has valid cursor position while shifting', function()
  224. api.nvim_buf_set_lines(0, 0, -1, true, { 'line1' })
  225. exec_lua(function()
  226. vim.api.nvim_buf_attach(0, false, {
  227. on_lines = function()
  228. vim.api.nvim_set_var('listener_cursor_line', vim.api.nvim_win_get_cursor(0)[1])
  229. end,
  230. })
  231. end)
  232. feed('>>')
  233. eq(1, api.nvim_get_var('listener_cursor_line'))
  234. end)
  235. it('has valid cursor position while deleting lines', function()
  236. api.nvim_buf_set_lines(0, 0, -1, true, { 'line_1', 'line_2', 'line_3', 'line_4' })
  237. api.nvim_win_set_cursor(0, { 2, 0 })
  238. eq(2, api.nvim_win_get_cursor(0)[1])
  239. api.nvim_buf_set_lines(0, 0, -1, true, { 'line_1', 'line_2', 'line_3' })
  240. eq(2, api.nvim_win_get_cursor(0)[1])
  241. end)
  242. it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function()
  243. local code = function()
  244. local buf = vim.api.nvim_create_buf(false, false)
  245. vim.cmd 'split'
  246. vim.api.nvim_win_set_buf(0, buf)
  247. vim.api.nvim_buf_attach(buf, false, {
  248. on_detach = function(_, buf0)
  249. vim.fn.tabpagebuflist()
  250. vim.fn.win_findbuf(buf0)
  251. end,
  252. })
  253. end
  254. exec_lua(code)
  255. command('q!')
  256. n.assert_alive()
  257. exec_lua(code)
  258. command('bd!')
  259. n.assert_alive()
  260. end)
  261. it('#12718 lnume', function()
  262. api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' })
  263. exec_lua(function()
  264. vim.api.nvim_buf_attach(0, false, {
  265. on_lines = function(...)
  266. vim.api.nvim_set_var('linesev', { ... })
  267. end,
  268. })
  269. end)
  270. feed('1G0')
  271. feed('y<C-v>2j')
  272. feed('G0')
  273. feed('p')
  274. -- Is the last arg old_byte_size correct? Doesn't matter for this PR
  275. eq({ 'lines', 1, 4, 2, 3, 5, 4 }, api.nvim_get_var('linesev'))
  276. feed('2G0')
  277. feed('p')
  278. eq({ 'lines', 1, 5, 1, 4, 4, 8 }, api.nvim_get_var('linesev'))
  279. feed('1G0')
  280. feed('P')
  281. eq({ 'lines', 1, 6, 0, 3, 3, 9 }, api.nvim_get_var('linesev'))
  282. end)
  283. it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function()
  284. exec_lua(function()
  285. vim.api.nvim_buf_attach(0, false, {
  286. on_lines = function()
  287. vim.api.nvim_buf_call(0, function() end)
  288. end,
  289. })
  290. end)
  291. feed('itest123<Esc><C-A>')
  292. eq('test124', api.nvim_get_current_line())
  293. end)
  294. it('setting extmark in on_lines callback works', function()
  295. local screen = Screen.new(40, 6)
  296. api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' })
  297. exec_lua(function()
  298. local ns = vim.api.nvim_create_namespace('')
  299. vim.api.nvim_buf_attach(0, false, {
  300. on_lines = function(_, _, _, row, _, end_row)
  301. vim.api.nvim_buf_clear_namespace(0, ns, row, end_row)
  302. for i = row, end_row - 1 do
  303. vim.api.nvim_buf_set_extmark(0, ns, i, 0, {
  304. virt_text = { { 'NEW' .. tostring(i), 'WarningMsg' } },
  305. })
  306. end
  307. end,
  308. })
  309. end)
  310. feed('o')
  311. screen:expect({
  312. grid = [[
  313. aaa |
  314. ^ {19:NEW1} |
  315. bbb |
  316. ccc |
  317. {1:~ }|
  318. {5:-- INSERT --} |
  319. ]],
  320. })
  321. feed('<CR>')
  322. screen:expect({
  323. grid = [[
  324. aaa |
  325. {19:NEW1} |
  326. ^ {19:NEW2} |
  327. bbb |
  328. ccc |
  329. {5:-- INSERT --} |
  330. ]],
  331. })
  332. end)
  333. it('line lengths are correct when pressing TAB with folding #29119', function()
  334. api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' })
  335. exec_lua(function()
  336. _G.res = {}
  337. vim.o.foldmethod = 'indent'
  338. vim.o.softtabstop = -1
  339. vim.api.nvim_buf_attach(0, false, {
  340. on_lines = function(_, bufnr, _, row, _, end_row)
  341. local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true)
  342. table.insert(_G.res, lines)
  343. end,
  344. })
  345. end)
  346. feed('i<Tab>')
  347. eq({ '\ta' }, exec_lua('return _G.res[#_G.res]'))
  348. end)
  349. end)
  350. describe('lua: nvim_buf_attach on_bytes', function()
  351. -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
  352. -- assert the wrong thing), but masks errors with unflushed lines (as
  353. -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
  354. -- test both ways.
  355. local function setup_eventcheck(verify, start_txt)
  356. if start_txt then
  357. api.nvim_buf_set_lines(0, 0, -1, true, start_txt)
  358. else
  359. start_txt = api.nvim_buf_get_lines(0, 0, -1, true)
  360. end
  361. local shadowbytes = table.concat(start_txt, '\n') .. '\n'
  362. -- TODO: while we are brewing the real strong coffee,
  363. -- verify should check buf_get_offset after every check_events
  364. if verify then
  365. local len = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0))
  366. eq(len == -1 and 1 or len, string.len(shadowbytes))
  367. end
  368. exec_lua('return test_register(...)', 0, 'on_bytes', 'test1', false, false, true)
  369. api.nvim_buf_get_changedtick(0)
  370. local verify_name = 'test1'
  371. local function check_events(expected)
  372. local events = exec_lua('return get_events(...)')
  373. expect_events(expected, events, 'byte updates')
  374. if not verify then
  375. return
  376. end
  377. for _, event in ipairs(events) do
  378. for _, elem in ipairs(event) do
  379. if type(elem) == 'number' and elem < 0 then
  380. fail(string.format('Received event has negative values'))
  381. end
  382. end
  383. if event[1] == verify_name and event[2] == 'bytes' then
  384. local _, _, _, _, _, _, start_byte, _, _, old_byte, _, _, new_byte = unpack(event)
  385. local before = string.sub(shadowbytes, 1, start_byte)
  386. -- no text in the tests will contain 0xff bytes (invalid UTF-8)
  387. -- so we can use it as marker for unknown bytes
  388. local unknown = string.rep('\255', new_byte)
  389. local after = string.sub(shadowbytes, start_byte + old_byte + 1)
  390. shadowbytes = before .. unknown .. after
  391. elseif event[1] == verify_name and event[2] == 'reload' then
  392. shadowbytes = table.concat(api.nvim_buf_get_lines(0, 0, -1, true), '\n') .. '\n'
  393. end
  394. end
  395. local text = api.nvim_buf_get_lines(0, 0, -1, true)
  396. local bytes = table.concat(text, '\n') .. '\n'
  397. eq(
  398. string.len(bytes),
  399. string.len(shadowbytes),
  400. '\non_bytes: total bytecount of buffer is wrong'
  401. )
  402. for i = 1, string.len(shadowbytes) do
  403. local shadowbyte = string.sub(shadowbytes, i, i)
  404. if shadowbyte ~= '\255' then
  405. eq(string.sub(bytes, i, i), shadowbyte, i)
  406. end
  407. end
  408. end
  409. return check_events
  410. end
  411. -- Yes, we can do both
  412. local function do_both(verify)
  413. it('single and multiple join', function()
  414. local check_events = setup_eventcheck(verify, origlines)
  415. feed 'ggJ'
  416. check_events {
  417. { 'test1', 'bytes', 1, 3, 0, 15, 15, 1, 0, 1, 0, 1, 1 },
  418. }
  419. feed '3J'
  420. check_events {
  421. { 'test1', 'bytes', 1, 5, 0, 31, 31, 1, 0, 1, 0, 1, 1 },
  422. { 'test1', 'bytes', 1, 5, 0, 47, 47, 1, 0, 1, 0, 1, 1 },
  423. }
  424. end)
  425. it('opening lines', function()
  426. local check_events = setup_eventcheck(verify, origlines)
  427. api.nvim_set_option_value('autoindent', false, {})
  428. feed 'Go'
  429. check_events {
  430. { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
  431. }
  432. feed '<cr>'
  433. check_events {
  434. { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
  435. }
  436. end)
  437. it('opening lines with autoindent', function()
  438. local check_events = setup_eventcheck(verify, origlines)
  439. api.nvim_set_option_value('autoindent', true, {})
  440. feed 'Go'
  441. check_events {
  442. { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 5 },
  443. }
  444. feed '<cr>'
  445. check_events {
  446. { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 },
  447. { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 4, 5 },
  448. }
  449. end)
  450. it('setline(num, line)', function()
  451. local check_events = setup_eventcheck(verify, origlines)
  452. fn.setline(2, 'babla')
  453. check_events {
  454. { 'test1', 'bytes', 1, 3, 1, 0, 16, 0, 15, 15, 0, 5, 5 },
  455. }
  456. fn.setline(2, { 'foo', 'bar' })
  457. check_events {
  458. { 'test1', 'bytes', 1, 4, 1, 0, 16, 0, 5, 5, 0, 3, 3 },
  459. { 'test1', 'bytes', 1, 5, 2, 0, 20, 0, 15, 15, 0, 3, 3 },
  460. }
  461. local buf_len = api.nvim_buf_line_count(0)
  462. fn.setline(buf_len + 1, 'baz')
  463. check_events {
  464. { 'test1', 'bytes', 1, 6, 7, 0, 90, 0, 0, 0, 1, 0, 4 },
  465. }
  466. end)
  467. it('continuing comments with fo=or', function()
  468. local check_events = setup_eventcheck(verify, { '// Comment' })
  469. api.nvim_set_option_value('formatoptions', 'ro', {})
  470. api.nvim_set_option_value('filetype', 'c', {})
  471. feed 'A<CR>'
  472. check_events {
  473. { 'test1', 'bytes', 1, 3, 0, 10, 10, 0, 0, 0, 1, 3, 4 },
  474. }
  475. feed '<ESC>'
  476. check_events {
  477. { 'test1', 'bytes', 1, 4, 1, 2, 13, 0, 1, 1, 0, 0, 0 },
  478. }
  479. feed 'ggo' -- goto first line to continue testing
  480. check_events {
  481. { 'test1', 'bytes', 1, 5, 1, 0, 11, 0, 0, 0, 1, 0, 4 },
  482. }
  483. feed '<CR>'
  484. check_events {
  485. { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 },
  486. { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 0, 0, 1, 3, 4 },
  487. }
  488. end)
  489. it('editing empty buffers', function()
  490. local check_events = setup_eventcheck(verify, {})
  491. feed 'ia'
  492. check_events {
  493. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  494. }
  495. end)
  496. it('deleting lines', function()
  497. local check_events = setup_eventcheck(verify, origlines)
  498. feed('dd')
  499. check_events {
  500. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 },
  501. }
  502. feed('d2j')
  503. check_events {
  504. { 'test1', 'bytes', 1, 4, 0, 0, 0, 3, 0, 48, 0, 0, 0 },
  505. }
  506. feed('ld<c-v>2j')
  507. check_events {
  508. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
  509. { 'test1', 'bytes', 1, 5, 1, 1, 16, 0, 1, 1, 0, 0, 0 },
  510. { 'test1', 'bytes', 1, 5, 2, 1, 31, 0, 1, 1, 0, 0, 0 },
  511. }
  512. feed('vjwd')
  513. check_events {
  514. { 'test1', 'bytes', 1, 10, 0, 1, 1, 1, 9, 23, 0, 0, 0 },
  515. }
  516. end)
  517. it('changing lines', function()
  518. local check_events = setup_eventcheck(verify, origlines)
  519. feed 'cc'
  520. check_events {
  521. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 15, 15, 0, 0, 0 },
  522. }
  523. feed '<ESC>'
  524. check_events {}
  525. feed 'c3j'
  526. check_events {
  527. { 'test1', 'bytes', 1, 4, 1, 0, 1, 3, 0, 48, 0, 0, 0 },
  528. }
  529. end)
  530. it('visual charwise paste', function()
  531. local check_events = setup_eventcheck(verify, { '1234567890' })
  532. fn.setreg('a', '___')
  533. feed '1G1|vll'
  534. check_events {}
  535. feed '"ap'
  536. check_events {
  537. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0 },
  538. { 'test1', 'bytes', 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 3 },
  539. }
  540. end)
  541. it('blockwise paste', function()
  542. local check_events = setup_eventcheck(verify, { '1', '2', '3' })
  543. feed('1G0')
  544. feed('y<C-v>2j')
  545. feed('G0')
  546. feed('p')
  547. check_events {
  548. { 'test1', 'bytes', 1, 3, 2, 1, 5, 0, 0, 0, 0, 1, 1 },
  549. { 'test1', 'bytes', 1, 3, 3, 0, 7, 0, 0, 0, 0, 3, 3 },
  550. { 'test1', 'bytes', 1, 3, 4, 0, 10, 0, 0, 0, 0, 3, 3 },
  551. }
  552. feed('2G0')
  553. feed('p')
  554. check_events {
  555. { 'test1', 'bytes', 1, 4, 1, 1, 3, 0, 0, 0, 0, 1, 1 },
  556. { 'test1', 'bytes', 1, 4, 2, 1, 6, 0, 0, 0, 0, 1, 1 },
  557. { 'test1', 'bytes', 1, 4, 3, 1, 10, 0, 0, 0, 0, 1, 1 },
  558. }
  559. feed('1G0')
  560. feed('P')
  561. check_events {
  562. { 'test1', 'bytes', 1, 5, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  563. { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 1, 1 },
  564. { 'test1', 'bytes', 1, 5, 2, 0, 7, 0, 0, 0, 0, 1, 1 },
  565. }
  566. end)
  567. it('linewise paste', function()
  568. local check_events = setup_eventcheck(verify, origlines)
  569. feed 'yyp'
  570. check_events {
  571. { 'test1', 'bytes', 1, 3, 1, 0, 16, 0, 0, 0, 1, 0, 16 },
  572. }
  573. feed 'Gyyp'
  574. check_events {
  575. { 'test1', 'bytes', 1, 4, 8, 0, 130, 0, 0, 0, 1, 0, 18 },
  576. }
  577. end)
  578. it('inccomand=nosplit and substitute', function()
  579. local check_events = setup_eventcheck(verify, { 'abcde', '12345' })
  580. api.nvim_set_option_value('inccommand', 'nosplit', {})
  581. -- linewise substitute
  582. feed(':%s/bcd/')
  583. check_events {
  584. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 },
  585. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 },
  586. }
  587. feed('a')
  588. check_events {
  589. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 },
  590. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 },
  591. }
  592. feed('<esc>')
  593. -- splitting lines
  594. feed([[:%s/abc/\r]])
  595. check_events {
  596. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 1, 0, 1 },
  597. { 'test1', 'bytes', 1, 6, 0, 0, 0, 1, 0, 1, 0, 3, 3 },
  598. }
  599. feed('<esc>')
  600. -- multi-line regex
  601. feed([[:%s/de\n123/a]])
  602. check_events {
  603. { 'test1', 'bytes', 1, 3, 0, 3, 3, 1, 3, 6, 0, 1, 1 },
  604. { 'test1', 'bytes', 1, 6, 0, 3, 3, 0, 1, 1, 1, 3, 6 },
  605. }
  606. feed('<esc>')
  607. -- replacing with unicode
  608. feed(':%s/b/→')
  609. check_events {
  610. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 3, 3 },
  611. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 3, 3, 0, 1, 1 },
  612. }
  613. feed('<esc>')
  614. -- replacing with expression register
  615. feed([[:%s/b/\=5+5]])
  616. check_events {
  617. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 },
  618. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 },
  619. }
  620. feed('<esc>')
  621. -- replacing with backslash
  622. feed([[:%s/b/\\]])
  623. check_events {
  624. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  625. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  626. }
  627. feed('<esc>')
  628. -- replacing with backslash from expression register
  629. feed([[:%s/b/\='\']])
  630. check_events {
  631. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  632. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  633. }
  634. feed('<esc>')
  635. -- replacing with backslash followed by another character
  636. feed([[:%s/b/\\!]])
  637. check_events {
  638. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 },
  639. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 },
  640. }
  641. feed('<esc>')
  642. -- replacing with backslash followed by another character from expression register
  643. feed([[:%s/b/\='\!']])
  644. check_events {
  645. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 },
  646. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 },
  647. }
  648. end)
  649. it('nvim_buf_set_text insert', function()
  650. local check_events = setup_eventcheck(verify, { 'bastext' })
  651. api.nvim_buf_set_text(0, 0, 3, 0, 3, { 'fiol', 'kontra' })
  652. check_events {
  653. { 'test1', 'bytes', 1, 3, 0, 3, 3, 0, 0, 0, 1, 6, 11 },
  654. }
  655. api.nvim_buf_set_text(0, 1, 6, 1, 6, { 'punkt', 'syntgitarr', 'övnings' })
  656. check_events {
  657. { 'test1', 'bytes', 1, 4, 1, 6, 14, 0, 0, 0, 2, 8, 25 },
  658. }
  659. eq(
  660. { 'basfiol', 'kontrapunkt', 'syntgitarr', 'övningstext' },
  661. api.nvim_buf_get_lines(0, 0, -1, true)
  662. )
  663. end)
  664. it('nvim_buf_set_text replace', function()
  665. local check_events = setup_eventcheck(verify, origlines)
  666. api.nvim_buf_set_text(0, 2, 3, 2, 8, { 'very text' })
  667. check_events {
  668. { 'test1', 'bytes', 1, 3, 2, 3, 35, 0, 5, 5, 0, 9, 9 },
  669. }
  670. api.nvim_buf_set_text(0, 3, 5, 3, 7, { ' splitty', 'line ' })
  671. check_events {
  672. { 'test1', 'bytes', 1, 4, 3, 5, 57, 0, 2, 2, 1, 5, 14 },
  673. }
  674. api.nvim_buf_set_text(0, 0, 8, 1, 2, { 'JOINY' })
  675. check_events {
  676. { 'test1', 'bytes', 1, 5, 0, 8, 8, 1, 2, 10, 0, 5, 5 },
  677. }
  678. api.nvim_buf_set_text(0, 4, 0, 6, 0, { 'was 5,6', '' })
  679. check_events {
  680. { 'test1', 'bytes', 1, 6, 4, 0, 75, 2, 0, 32, 1, 0, 8 },
  681. }
  682. eq({
  683. 'originalJOINYiginal line 2',
  684. 'orivery text line 3',
  685. 'origi splitty',
  686. 'line l line 4',
  687. 'was 5,6',
  688. ' indented line',
  689. }, api.nvim_buf_get_lines(0, 0, -1, true))
  690. end)
  691. it('nvim_buf_set_text delete', function()
  692. local check_events = setup_eventcheck(verify, origlines)
  693. -- really {""} but accepts {} as a shorthand
  694. api.nvim_buf_set_text(0, 0, 0, 1, 0, {})
  695. check_events {
  696. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 },
  697. }
  698. -- TODO(bfredl): this works but is not as convenient as set_lines
  699. api.nvim_buf_set_text(0, 4, 15, 5, 17, { '' })
  700. check_events {
  701. { 'test1', 'bytes', 1, 4, 4, 15, 79, 1, 17, 18, 0, 0, 0 },
  702. }
  703. eq({
  704. 'original line 2',
  705. 'original line 3',
  706. 'original line 4',
  707. 'original line 5',
  708. 'original line 6',
  709. }, api.nvim_buf_get_lines(0, 0, -1, true))
  710. end)
  711. it('checktime autoread', function()
  712. write_file(
  713. 'Xtest-reload',
  714. dedent [[
  715. old line 1
  716. old line 2]]
  717. )
  718. local atime = os.time() - 10
  719. vim.uv.fs_utime('Xtest-reload', atime, atime)
  720. command 'e Xtest-reload'
  721. command 'set autoread'
  722. local check_events = setup_eventcheck(verify, nil)
  723. write_file(
  724. 'Xtest-reload',
  725. dedent [[
  726. new line 1
  727. new line 2
  728. new line 3]]
  729. )
  730. command 'checktime'
  731. check_events {
  732. { 'test1', 'reload', 1 },
  733. }
  734. feed 'ggJ'
  735. check_events {
  736. { 'test1', 'bytes', 1, 5, 0, 10, 10, 1, 0, 1, 0, 1, 1 },
  737. }
  738. eq({ 'new line 1 new line 2', 'new line 3' }, api.nvim_buf_get_lines(0, 0, -1, true))
  739. -- check we can undo and redo a reload event.
  740. feed 'u'
  741. check_events {
  742. { 'test1', 'bytes', 1, 8, 0, 10, 10, 0, 1, 1, 1, 0, 1 },
  743. }
  744. feed 'u'
  745. check_events {
  746. { 'test1', 'reload', 1 },
  747. }
  748. feed '<c-r>'
  749. check_events {
  750. { 'test1', 'reload', 1 },
  751. }
  752. feed '<c-r>'
  753. check_events {
  754. { 'test1', 'bytes', 1, 14, 0, 10, 10, 1, 0, 1, 0, 1, 1 },
  755. }
  756. end)
  757. it('tab with noexpandtab and softtabstop', function()
  758. command('set noet')
  759. command('set ts=4')
  760. command('set sw=2')
  761. command('set sts=4')
  762. local check_events = setup_eventcheck(verify, { 'asdfasdf' })
  763. feed('gg0i<tab>')
  764. check_events {
  765. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  766. { 'test1', 'bytes', 1, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  767. }
  768. feed('<tab>')
  769. -- when spaces are merged into a tabstop
  770. check_events {
  771. { 'test1', 'bytes', 1, 5, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
  772. { 'test1', 'bytes', 1, 6, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  773. { 'test1', 'bytes', 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
  774. }
  775. feed('<esc>u')
  776. check_events {
  777. { 'test1', 'bytes', 1, 9, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
  778. { 'test1', 'bytes', 1, 9, 0, 0, 0, 0, 4, 4, 0, 0, 0 },
  779. }
  780. -- in REPLACE mode
  781. feed('R<tab><tab>')
  782. check_events {
  783. { 'test1', 'bytes', 1, 10, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
  784. { 'test1', 'bytes', 1, 11, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  785. { 'test1', 'bytes', 1, 12, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
  786. { 'test1', 'bytes', 1, 13, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  787. { 'test1', 'bytes', 1, 14, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
  788. }
  789. feed('<esc>u')
  790. check_events {
  791. { 'test1', 'bytes', 1, 16, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
  792. { 'test1', 'bytes', 1, 16, 0, 2, 2, 0, 2, 2, 0, 1, 1 },
  793. { 'test1', 'bytes', 1, 16, 0, 0, 0, 0, 2, 2, 0, 1, 1 },
  794. }
  795. -- in VISUALREPLACE mode
  796. feed('gR<tab><tab>')
  797. check_events {
  798. { 'test1', 'bytes', 1, 17, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
  799. { 'test1', 'bytes', 1, 18, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  800. { 'test1', 'bytes', 1, 19, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
  801. { 'test1', 'bytes', 1, 20, 0, 3, 3, 0, 1, 1, 0, 1, 1 },
  802. { 'test1', 'bytes', 1, 21, 0, 3, 3, 0, 1, 1, 0, 0, 0 },
  803. { 'test1', 'bytes', 1, 22, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  804. { 'test1', 'bytes', 1, 24, 0, 2, 2, 0, 1, 1, 0, 0, 0 },
  805. { 'test1', 'bytes', 1, 25, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
  806. { 'test1', 'bytes', 1, 27, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
  807. { 'test1', 'bytes', 1, 28, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  808. { 'test1', 'bytes', 1, 30, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
  809. { 'test1', 'bytes', 1, 31, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  810. { 'test1', 'bytes', 1, 33, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
  811. }
  812. -- inserting tab after other tabs
  813. command('set sw=4')
  814. feed('<esc>0a<tab>')
  815. check_events {
  816. { 'test1', 'bytes', 1, 34, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  817. { 'test1', 'bytes', 1, 35, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
  818. { 'test1', 'bytes', 1, 36, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  819. { 'test1', 'bytes', 1, 37, 0, 4, 4, 0, 0, 0, 0, 1, 1 },
  820. { 'test1', 'bytes', 1, 38, 0, 1, 1, 0, 4, 4, 0, 1, 1 },
  821. }
  822. end)
  823. it('retab', function()
  824. command('set noet')
  825. command('set ts=4')
  826. local check_events = setup_eventcheck(verify, { ' asdf' })
  827. command('retab 8')
  828. check_events {
  829. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 7, 7, 0, 9, 9 },
  830. }
  831. end)
  832. it('sends events when undoing with undofile', function()
  833. write_file(
  834. 'Xtest-undofile',
  835. dedent([[
  836. 12345
  837. hello world
  838. ]])
  839. )
  840. command('e! Xtest-undofile')
  841. command('set undodir=. | set undofile')
  842. local ns = n.request('nvim_create_namespace', 'ns1')
  843. api.nvim_buf_set_extmark(0, ns, 0, 0, {})
  844. eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  845. -- splice
  846. feed('gg0d2l')
  847. eq({ '345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  848. -- move
  849. command('.m+1')
  850. eq({ 'hello world', '345' }, api.nvim_buf_get_lines(0, 0, -1, true))
  851. -- reload undofile and undo changes
  852. command('w')
  853. command('set noundofile')
  854. command('bw!')
  855. command('e! Xtest-undofile')
  856. command('set undofile')
  857. local check_events = setup_eventcheck(verify, nil)
  858. feed('u')
  859. eq({ '345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  860. check_events {
  861. { 'test1', 'bytes', 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 },
  862. { 'test1', 'bytes', 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 },
  863. }
  864. feed('u')
  865. eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  866. check_events {
  867. { 'test1', 'bytes', 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
  868. }
  869. command('bw!')
  870. end)
  871. it('blockwise paste with uneven line lengths', function()
  872. local check_events = setup_eventcheck(verify, { 'aaaa', 'aaa', 'aaa' })
  873. -- eq({}, api.nvim_buf_get_lines(0, 0, -1, true))
  874. feed('gg0<c-v>jj$d')
  875. check_events {
  876. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0 },
  877. { 'test1', 'bytes', 1, 3, 1, 0, 1, 0, 3, 3, 0, 0, 0 },
  878. { 'test1', 'bytes', 1, 3, 2, 0, 2, 0, 3, 3, 0, 0, 0 },
  879. }
  880. feed('p')
  881. check_events {
  882. { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4 },
  883. { 'test1', 'bytes', 1, 4, 1, 0, 5, 0, 0, 0, 0, 3, 3 },
  884. { 'test1', 'bytes', 1, 4, 2, 0, 9, 0, 0, 0, 0, 3, 3 },
  885. }
  886. end)
  887. it(':luado', function()
  888. local check_events = setup_eventcheck(verify, { 'abc', '12345' })
  889. command(".luado return 'a'")
  890. check_events {
  891. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 1, 1 },
  892. }
  893. command('luado return 10')
  894. check_events {
  895. { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 1, 1, 0, 2, 2 },
  896. { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 5, 5, 0, 2, 2 },
  897. }
  898. end)
  899. it('flushes deleted bytes on move', function()
  900. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC', 'DDD' })
  901. feed(':.move+1<cr>')
  902. check_events {
  903. { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 4, 0, 0, 0 },
  904. { 'test1', 'bytes', 1, 5, 1, 0, 4, 0, 0, 0, 1, 0, 4 },
  905. }
  906. feed('jd2j')
  907. check_events {
  908. { 'test1', 'bytes', 1, 6, 2, 0, 8, 2, 0, 8, 0, 0, 0 },
  909. }
  910. end)
  911. it('virtual edit', function()
  912. local check_events = setup_eventcheck(verify, { '', ' ' })
  913. api.nvim_set_option_value('virtualedit', 'all', {})
  914. feed [[<Right><Right>iab<ESC>]]
  915. check_events {
  916. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
  917. { 'test1', 'bytes', 1, 4, 0, 2, 2, 0, 0, 0, 0, 2, 2 },
  918. }
  919. feed [[j<Right><Right>iab<ESC>]]
  920. check_events {
  921. { 'test1', 'bytes', 1, 5, 1, 0, 5, 0, 1, 1, 0, 8, 8 },
  922. { 'test1', 'bytes', 1, 6, 1, 5, 10, 0, 0, 0, 0, 2, 2 },
  923. }
  924. end)
  925. it('block visual paste', function()
  926. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })
  927. fn.setreg('a', '___')
  928. feed([[gg0l<c-v>3jl"ap]])
  929. check_events {
  930. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 2, 2, 0, 0, 0 },
  931. { 'test1', 'bytes', 1, 3, 1, 1, 3, 0, 2, 2, 0, 0, 0 },
  932. { 'test1', 'bytes', 1, 3, 2, 1, 5, 0, 2, 2, 0, 0, 0 },
  933. { 'test1', 'bytes', 1, 3, 3, 1, 7, 0, 2, 2, 0, 0, 0 },
  934. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 },
  935. { 'test1', 'bytes', 1, 6, 1, 1, 6, 0, 0, 0, 0, 3, 3 },
  936. { 'test1', 'bytes', 1, 7, 2, 1, 11, 0, 0, 0, 0, 3, 3 },
  937. { 'test1', 'bytes', 1, 8, 3, 1, 16, 0, 0, 0, 0, 3, 3 },
  938. }
  939. end)
  940. it('visual paste', function()
  941. local check_events = setup_eventcheck(verify, { 'aaa {', 'b', '}' })
  942. -- Setting up
  943. feed [[jdd]]
  944. check_events {
  945. { 'test1', 'bytes', 1, 3, 1, 0, 6, 1, 0, 2, 0, 0, 0 },
  946. }
  947. -- Actually testing
  948. feed [[v%p]]
  949. check_events {
  950. { 'test1', 'bytes', 1, 8, 0, 4, 4, 1, 1, 3, 0, 0, 0 },
  951. { 'test1', 'bytes', 1, 8, 0, 4, 4, 0, 0, 0, 2, 0, 3 },
  952. }
  953. end)
  954. it('visual paste 2: splitting an empty line', function()
  955. local check_events = setup_eventcheck(verify, { 'abc', '{', 'def', '}' })
  956. feed('ggyyjjvi{p')
  957. check_events {
  958. { 'test1', 'bytes', 1, 6, 2, 0, 6, 1, 0, 4, 0, 0, 0 },
  959. { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 2, 0, 5 },
  960. }
  961. end)
  962. it('nvim_buf_set_lines', function()
  963. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB' })
  964. -- delete
  965. api.nvim_buf_set_lines(0, 0, 1, true, {})
  966. check_events {
  967. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 },
  968. }
  969. -- add
  970. api.nvim_buf_set_lines(0, 0, 0, true, { 'asdf' })
  971. check_events {
  972. { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 },
  973. }
  974. -- replace
  975. api.nvim_buf_set_lines(0, 0, 1, true, { 'asdf', 'fdsa' })
  976. check_events {
  977. { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 },
  978. }
  979. end)
  980. it('flushes delbytes on substitute', function()
  981. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  982. feed('gg0')
  983. command('s/AAA/GGG/')
  984. check_events {
  985. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 3, 3 },
  986. }
  987. -- check that byte updates for :delete (which uses curbuf->deleted_bytes2)
  988. -- are correct
  989. command('delete')
  990. check_events {
  991. { 'test1', 'bytes', 1, 4, 0, 0, 0, 1, 0, 4, 0, 0, 0 },
  992. }
  993. end)
  994. it('flushes delbytes on join', function()
  995. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  996. feed('gg0J')
  997. check_events {
  998. { 'test1', 'bytes', 1, 3, 0, 3, 3, 1, 0, 1, 0, 1, 1 },
  999. }
  1000. command('delete')
  1001. check_events {
  1002. { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 8, 0, 0, 0 },
  1003. }
  1004. end)
  1005. it('sends updates on U', function()
  1006. feed('ggiAAA<cr>BBB')
  1007. feed('<esc>gg$a CCC')
  1008. local check_events = setup_eventcheck(verify, nil)
  1009. feed('ggU')
  1010. check_events {
  1011. { 'test1', 'bytes', 1, 6, 0, 7, 7, 0, 0, 0, 0, 3, 3 },
  1012. }
  1013. end)
  1014. it('delete in completely empty buffer', function()
  1015. local check_events = setup_eventcheck(verify, nil)
  1016. command 'delete'
  1017. check_events {}
  1018. end)
  1019. it('delete the only line of a buffer', function()
  1020. local check_events = setup_eventcheck(verify, { 'AAA' })
  1021. command 'delete'
  1022. check_events {
  1023. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 4, 1, 0, 1 },
  1024. }
  1025. end)
  1026. it('delete the last line of a buffer with two lines', function()
  1027. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB' })
  1028. command '2delete'
  1029. check_events {
  1030. { 'test1', 'bytes', 1, 3, 1, 0, 4, 1, 0, 4, 0, 0, 0 },
  1031. }
  1032. end)
  1033. it(':sort lines', function()
  1034. local check_events = setup_eventcheck(verify, { 'CCC', 'BBB', 'AAA' })
  1035. command '%sort'
  1036. check_events {
  1037. { 'test1', 'bytes', 1, 3, 0, 0, 0, 3, 0, 12, 3, 0, 12 },
  1038. }
  1039. end)
  1040. it('handles already sorted lines', function()
  1041. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  1042. command '%sort'
  1043. check_events {}
  1044. end)
  1045. it('works with accepting spell suggestions', function()
  1046. local check_events = setup_eventcheck(verify, { 'hallo world', 'hallo world' })
  1047. feed('gg0z=4<cr><cr>') -- accepts 'Hello'
  1048. check_events {
  1049. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 2, 2, 0, 2, 2 },
  1050. }
  1051. command('spellrepall') -- replaces whole words
  1052. check_events {
  1053. { 'test1', 'bytes', 1, 4, 1, 0, 12, 0, 5, 5, 0, 5, 5 },
  1054. }
  1055. end)
  1056. it('works with :diffput and :diffget', function()
  1057. local check_events = setup_eventcheck(verify, { 'AAA' })
  1058. command('diffthis')
  1059. command('new')
  1060. command('diffthis')
  1061. api.nvim_buf_set_lines(0, 0, -1, true, { 'AAA', 'BBB' })
  1062. feed('G')
  1063. command('diffput')
  1064. check_events {
  1065. { 'test1', 'bytes', 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 4 },
  1066. }
  1067. api.nvim_buf_set_lines(0, 0, -1, true, { 'AAA', 'CCC' })
  1068. feed('<C-w>pG')
  1069. command('diffget')
  1070. check_events {
  1071. { 'test1', 'bytes', 1, 4, 1, 0, 4, 1, 0, 4, 1, 0, 4 },
  1072. }
  1073. end)
  1074. it('prompt buffer', function()
  1075. local check_events = setup_eventcheck(verify, {})
  1076. api.nvim_set_option_value('buftype', 'prompt', {})
  1077. feed('i')
  1078. check_events {
  1079. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
  1080. }
  1081. feed('<CR>')
  1082. check_events {
  1083. { 'test1', 'bytes', 1, 4, 1, 0, 3, 0, 0, 0, 1, 0, 1 },
  1084. { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 2, 2 },
  1085. }
  1086. feed('<CR>')
  1087. check_events {
  1088. { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 1, 0, 1 },
  1089. { 'test1', 'bytes', 1, 7, 2, 0, 6, 0, 0, 0, 0, 2, 2 },
  1090. }
  1091. end)
  1092. local function test_lockmarks(mode)
  1093. local description = (mode ~= '') and mode or '(baseline)'
  1094. it('test_lockmarks ' .. description .. ' %delete _', function()
  1095. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  1096. command(mode .. ' %delete _')
  1097. check_events {
  1098. { 'test1', 'bytes', 1, 3, 0, 0, 0, 3, 0, 12, 1, 0, 1 },
  1099. }
  1100. end)
  1101. it('test_lockmarks ' .. description .. ' append()', function()
  1102. local check_events = setup_eventcheck(verify)
  1103. command(mode .. " call append(0, 'CCC')")
  1104. check_events {
  1105. { 'test1', 'bytes', 1, 2, 0, 0, 0, 0, 0, 0, 1, 0, 4 },
  1106. }
  1107. command(mode .. " call append(1, 'BBBB')")
  1108. check_events {
  1109. { 'test1', 'bytes', 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 5 },
  1110. }
  1111. command(mode .. " call append(2, '')")
  1112. check_events {
  1113. { 'test1', 'bytes', 1, 4, 2, 0, 9, 0, 0, 0, 1, 0, 1 },
  1114. }
  1115. command(mode .. ' $delete _')
  1116. check_events {
  1117. { 'test1', 'bytes', 1, 5, 3, 0, 10, 1, 0, 1, 0, 0, 0 },
  1118. }
  1119. eq('CCC|BBBB|', table.concat(api.nvim_buf_get_lines(0, 0, -1, true), '|'))
  1120. end)
  1121. end
  1122. -- check that behavior is identical with and without "lockmarks"
  1123. test_lockmarks ''
  1124. test_lockmarks 'lockmarks'
  1125. teardown(function()
  1126. os.remove 'Xtest-reload'
  1127. os.remove 'Xtest-undofile'
  1128. os.remove '.Xtest-undofile.un~'
  1129. end)
  1130. end
  1131. describe('(with verify) handles', function()
  1132. do_both(true)
  1133. end)
  1134. describe('(without verify) handles', function()
  1135. do_both(false)
  1136. end)
  1137. end)