buffer_updates_spec.lua 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416
  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('no invalid lnum error for closed memline in on_detach #31251', function()
  262. eq(vim.NIL, exec_lua('return _G.did_detach'))
  263. exec_lua([[
  264. vim.api.nvim_buf_set_lines(0, 0, -1, false, { '' })
  265. local bufname = 'buf2'
  266. local buf = vim.api.nvim_create_buf(false, true)
  267. vim.api.nvim_buf_set_name(buf, bufname)
  268. vim.bo[buf].bufhidden = 'wipe'
  269. vim.cmd('vertical diffsplit '..bufname)
  270. vim.api.nvim_buf_attach(0, false, { on_detach = function()
  271. vim.cmd("redraw")
  272. _G.did_detach = true
  273. end})
  274. vim.cmd.bdelete()
  275. ]])
  276. eq(true, exec_lua('return _G.did_detach'))
  277. end)
  278. it('#12718 lnume', function()
  279. api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' })
  280. exec_lua(function()
  281. vim.api.nvim_buf_attach(0, false, {
  282. on_lines = function(...)
  283. vim.api.nvim_set_var('linesev', { ... })
  284. end,
  285. })
  286. end)
  287. feed('1G0')
  288. feed('y<C-v>2j')
  289. feed('G0')
  290. feed('p')
  291. -- Is the last arg old_byte_size correct? Doesn't matter for this PR
  292. eq({ 'lines', 1, 4, 2, 3, 5, 4 }, api.nvim_get_var('linesev'))
  293. feed('2G0')
  294. feed('p')
  295. eq({ 'lines', 1, 5, 1, 4, 4, 8 }, api.nvim_get_var('linesev'))
  296. feed('1G0')
  297. feed('P')
  298. eq({ 'lines', 1, 6, 0, 3, 3, 9 }, api.nvim_get_var('linesev'))
  299. end)
  300. it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function()
  301. exec_lua(function()
  302. vim.api.nvim_buf_attach(0, false, {
  303. on_lines = function()
  304. vim.api.nvim_buf_call(0, function() end)
  305. end,
  306. })
  307. end)
  308. feed('itest123<Esc><C-A>')
  309. eq('test124', api.nvim_get_current_line())
  310. end)
  311. it('setting extmark in on_lines callback works', function()
  312. local screen = Screen.new(40, 6)
  313. api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' })
  314. exec_lua(function()
  315. local ns = vim.api.nvim_create_namespace('')
  316. vim.api.nvim_buf_attach(0, false, {
  317. on_lines = function(_, _, _, row, _, end_row)
  318. vim.api.nvim_buf_clear_namespace(0, ns, row, end_row)
  319. for i = row, end_row - 1 do
  320. vim.api.nvim_buf_set_extmark(0, ns, i, 0, {
  321. virt_text = { { 'NEW' .. tostring(i), 'WarningMsg' } },
  322. })
  323. end
  324. end,
  325. })
  326. end)
  327. feed('o')
  328. screen:expect({
  329. grid = [[
  330. aaa |
  331. ^ {19:NEW1} |
  332. bbb |
  333. ccc |
  334. {1:~ }|
  335. {5:-- INSERT --} |
  336. ]],
  337. })
  338. feed('<CR>')
  339. screen:expect({
  340. grid = [[
  341. aaa |
  342. {19:NEW1} |
  343. ^ {19:NEW2} |
  344. bbb |
  345. ccc |
  346. {5:-- INSERT --} |
  347. ]],
  348. })
  349. end)
  350. it('line lengths are correct when pressing TAB with folding #29119', function()
  351. api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' })
  352. exec_lua(function()
  353. _G.res = {}
  354. vim.o.foldmethod = 'indent'
  355. vim.o.softtabstop = -1
  356. vim.api.nvim_buf_attach(0, false, {
  357. on_lines = function(_, bufnr, _, row, _, end_row)
  358. local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true)
  359. table.insert(_G.res, lines)
  360. end,
  361. })
  362. end)
  363. feed('i<Tab>')
  364. eq({ '\ta' }, exec_lua('return _G.res[#_G.res]'))
  365. end)
  366. it('quickfix buffer send change', function()
  367. command('copen')
  368. exec_lua(function()
  369. vim.api.nvim_buf_attach(vim.api.nvim_get_current_buf(), false, {
  370. on_lines = function(...)
  371. vim.g.qf_on_lines = { ... }
  372. end,
  373. on_bytes = function(...)
  374. vim.g.qf_on_bytes = { ... }
  375. end,
  376. })
  377. end)
  378. command('caddexpr "foo"')
  379. eq({ 'bytes', 2, 2, 0, 0, 0, 0, 0, 0, 0, 6, 6 }, api.nvim_get_var('qf_on_bytes'))
  380. eq({ 'lines', 2, 3, 0, 1, 1, 1 }, api.nvim_get_var('qf_on_lines'))
  381. command('caddexpr "bar"')
  382. eq({ 'bytes', 2, 3, 0, 6, 6, 0, 0, 0, 1, 6, 6 }, api.nvim_get_var('qf_on_bytes'))
  383. eq({ 'lines', 2, 4, 1, 1, 2, 0 }, api.nvim_get_var('qf_on_lines'))
  384. command('caddexpr ["line1", "line2", "line3"]')
  385. eq({ 'bytes', 2, 4, 1, 6, 13, 0, 0, 0, 3, 8, 26 }, api.nvim_get_var('qf_on_bytes'))
  386. eq({ 'lines', 2, 5, 2, 2, 5, 0 }, api.nvim_get_var('qf_on_lines'))
  387. command('cexpr "replace"')
  388. eq({ 'bytes', 2, 5, 0, 0, 0, 4, 0, 40, 0, 10, 10 }, api.nvim_get_var('qf_on_bytes'))
  389. eq({ 'lines', 2, 6, 0, 5, 1, 42 }, api.nvim_get_var('qf_on_lines'))
  390. end)
  391. end)
  392. describe('lua: nvim_buf_attach on_bytes', function()
  393. -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
  394. -- assert the wrong thing), but masks errors with unflushed lines (as
  395. -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
  396. -- test both ways.
  397. local function setup_eventcheck(verify, start_txt)
  398. if start_txt then
  399. api.nvim_buf_set_lines(0, 0, -1, true, start_txt)
  400. else
  401. start_txt = api.nvim_buf_get_lines(0, 0, -1, true)
  402. end
  403. local shadowbytes = table.concat(start_txt, '\n') .. '\n'
  404. -- TODO: while we are brewing the real strong coffee,
  405. -- verify should check buf_get_offset after every check_events
  406. if verify then
  407. local len = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0))
  408. eq(len == -1 and 1 or len, string.len(shadowbytes))
  409. end
  410. exec_lua('return test_register(...)', 0, 'on_bytes', 'test1', false, false, true)
  411. api.nvim_buf_get_changedtick(0)
  412. local verify_name = 'test1'
  413. local function check_events(expected)
  414. local events = exec_lua('return get_events(...)')
  415. expect_events(expected, events, 'byte updates')
  416. if not verify then
  417. return
  418. end
  419. for _, event in ipairs(events) do
  420. for _, elem in ipairs(event) do
  421. if type(elem) == 'number' and elem < 0 then
  422. fail(string.format('Received event has negative values'))
  423. end
  424. end
  425. if event[1] == verify_name and event[2] == 'bytes' then
  426. local _, _, _, _, _, _, start_byte, _, _, old_byte, _, _, new_byte = unpack(event)
  427. local before = string.sub(shadowbytes, 1, start_byte)
  428. -- no text in the tests will contain 0xff bytes (invalid UTF-8)
  429. -- so we can use it as marker for unknown bytes
  430. local unknown = string.rep('\255', new_byte)
  431. local after = string.sub(shadowbytes, start_byte + old_byte + 1)
  432. shadowbytes = before .. unknown .. after
  433. elseif event[1] == verify_name and event[2] == 'reload' then
  434. shadowbytes = table.concat(api.nvim_buf_get_lines(0, 0, -1, true), '\n') .. '\n'
  435. end
  436. end
  437. local text = api.nvim_buf_get_lines(0, 0, -1, true)
  438. local bytes = table.concat(text, '\n') .. '\n'
  439. eq(
  440. string.len(bytes),
  441. string.len(shadowbytes),
  442. '\non_bytes: total bytecount of buffer is wrong'
  443. )
  444. for i = 1, string.len(shadowbytes) do
  445. local shadowbyte = string.sub(shadowbytes, i, i)
  446. if shadowbyte ~= '\255' then
  447. eq(string.sub(bytes, i, i), shadowbyte, i)
  448. end
  449. end
  450. end
  451. return check_events
  452. end
  453. -- Yes, we can do both
  454. local function do_both(verify)
  455. it('single and multiple join', function()
  456. local check_events = setup_eventcheck(verify, origlines)
  457. feed 'ggJ'
  458. check_events {
  459. { 'test1', 'bytes', 1, 3, 0, 15, 15, 1, 0, 1, 0, 1, 1 },
  460. }
  461. feed '3J'
  462. check_events {
  463. { 'test1', 'bytes', 1, 5, 0, 31, 31, 1, 0, 1, 0, 1, 1 },
  464. { 'test1', 'bytes', 1, 5, 0, 47, 47, 1, 0, 1, 0, 1, 1 },
  465. }
  466. end)
  467. it('opening lines', function()
  468. local check_events = setup_eventcheck(verify, origlines)
  469. api.nvim_set_option_value('autoindent', false, {})
  470. feed 'Go'
  471. check_events {
  472. { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
  473. }
  474. feed '<cr>'
  475. check_events {
  476. { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
  477. }
  478. end)
  479. it('opening lines with autoindent', function()
  480. local check_events = setup_eventcheck(verify, origlines)
  481. api.nvim_set_option_value('autoindent', true, {})
  482. feed 'Go'
  483. check_events {
  484. { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 5 },
  485. }
  486. feed '<cr>'
  487. check_events {
  488. { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 },
  489. { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 4, 5 },
  490. }
  491. end)
  492. it('setline(num, line)', function()
  493. local check_events = setup_eventcheck(verify, origlines)
  494. fn.setline(2, 'babla')
  495. check_events {
  496. { 'test1', 'bytes', 1, 3, 1, 0, 16, 0, 15, 15, 0, 5, 5 },
  497. }
  498. fn.setline(2, { 'foo', 'bar' })
  499. check_events {
  500. { 'test1', 'bytes', 1, 4, 1, 0, 16, 0, 5, 5, 0, 3, 3 },
  501. { 'test1', 'bytes', 1, 5, 2, 0, 20, 0, 15, 15, 0, 3, 3 },
  502. }
  503. local buf_len = api.nvim_buf_line_count(0)
  504. fn.setline(buf_len + 1, 'baz')
  505. check_events {
  506. { 'test1', 'bytes', 1, 6, 7, 0, 90, 0, 0, 0, 1, 0, 4 },
  507. }
  508. end)
  509. it('continuing comments with fo=or', function()
  510. local check_events = setup_eventcheck(verify, { '// Comment' })
  511. api.nvim_set_option_value('formatoptions', 'ro', {})
  512. api.nvim_set_option_value('filetype', 'c', {})
  513. feed 'A<CR>'
  514. check_events {
  515. { 'test1', 'bytes', 1, 3, 0, 10, 10, 0, 0, 0, 1, 3, 4 },
  516. }
  517. feed '<ESC>'
  518. check_events {
  519. { 'test1', 'bytes', 1, 4, 1, 2, 13, 0, 1, 1, 0, 0, 0 },
  520. }
  521. feed 'ggo' -- goto first line to continue testing
  522. check_events {
  523. { 'test1', 'bytes', 1, 5, 1, 0, 11, 0, 0, 0, 1, 0, 4 },
  524. }
  525. feed '<CR>'
  526. check_events {
  527. { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 },
  528. { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 0, 0, 1, 3, 4 },
  529. }
  530. end)
  531. it('editing empty buffers', function()
  532. local check_events = setup_eventcheck(verify, {})
  533. feed 'ia'
  534. check_events {
  535. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  536. }
  537. end)
  538. it('deleting lines', function()
  539. local check_events = setup_eventcheck(verify, origlines)
  540. feed('dd')
  541. check_events {
  542. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 },
  543. }
  544. feed('d2j')
  545. check_events {
  546. { 'test1', 'bytes', 1, 4, 0, 0, 0, 3, 0, 48, 0, 0, 0 },
  547. }
  548. feed('ld<c-v>2j')
  549. check_events {
  550. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
  551. { 'test1', 'bytes', 1, 5, 1, 1, 16, 0, 1, 1, 0, 0, 0 },
  552. { 'test1', 'bytes', 1, 5, 2, 1, 31, 0, 1, 1, 0, 0, 0 },
  553. }
  554. feed('vjwd')
  555. check_events {
  556. { 'test1', 'bytes', 1, 10, 0, 1, 1, 1, 9, 23, 0, 0, 0 },
  557. }
  558. end)
  559. it('changing lines', function()
  560. local check_events = setup_eventcheck(verify, origlines)
  561. feed 'cc'
  562. check_events {
  563. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 15, 15, 0, 0, 0 },
  564. }
  565. feed '<ESC>'
  566. check_events {}
  567. feed 'c3j'
  568. check_events {
  569. { 'test1', 'bytes', 1, 4, 1, 0, 1, 3, 0, 48, 0, 0, 0 },
  570. }
  571. end)
  572. it('visual charwise paste', function()
  573. local check_events = setup_eventcheck(verify, { '1234567890' })
  574. fn.setreg('a', '___')
  575. feed '1G1|vll'
  576. check_events {}
  577. feed '"ap'
  578. check_events {
  579. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0 },
  580. { 'test1', 'bytes', 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 3 },
  581. }
  582. end)
  583. it('blockwise paste', function()
  584. local check_events = setup_eventcheck(verify, { '1', '2', '3' })
  585. feed('1G0')
  586. feed('y<C-v>2j')
  587. feed('G0')
  588. feed('p')
  589. check_events {
  590. { 'test1', 'bytes', 1, 3, 2, 1, 5, 0, 0, 0, 0, 1, 1 },
  591. { 'test1', 'bytes', 1, 3, 3, 0, 7, 0, 0, 0, 0, 3, 3 },
  592. { 'test1', 'bytes', 1, 3, 4, 0, 10, 0, 0, 0, 0, 3, 3 },
  593. }
  594. feed('2G0')
  595. feed('p')
  596. check_events {
  597. { 'test1', 'bytes', 1, 4, 1, 1, 3, 0, 0, 0, 0, 1, 1 },
  598. { 'test1', 'bytes', 1, 4, 2, 1, 6, 0, 0, 0, 0, 1, 1 },
  599. { 'test1', 'bytes', 1, 4, 3, 1, 10, 0, 0, 0, 0, 1, 1 },
  600. }
  601. feed('1G0')
  602. feed('P')
  603. check_events {
  604. { 'test1', 'bytes', 1, 5, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  605. { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 1, 1 },
  606. { 'test1', 'bytes', 1, 5, 2, 0, 7, 0, 0, 0, 0, 1, 1 },
  607. }
  608. end)
  609. it('linewise paste', function()
  610. local check_events = setup_eventcheck(verify, origlines)
  611. feed 'yyp'
  612. check_events {
  613. { 'test1', 'bytes', 1, 3, 1, 0, 16, 0, 0, 0, 1, 0, 16 },
  614. }
  615. feed 'Gyyp'
  616. check_events {
  617. { 'test1', 'bytes', 1, 4, 8, 0, 130, 0, 0, 0, 1, 0, 18 },
  618. }
  619. end)
  620. it('inccomand=nosplit and substitute', function()
  621. local check_events = setup_eventcheck(verify, { 'abcde', '12345' })
  622. api.nvim_set_option_value('inccommand', 'nosplit', {})
  623. -- linewise substitute
  624. feed(':%s/bcd/')
  625. check_events {
  626. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 },
  627. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 },
  628. }
  629. feed('a')
  630. check_events {
  631. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 },
  632. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 },
  633. }
  634. feed('<esc>')
  635. -- splitting lines
  636. feed([[:%s/abc/\r]])
  637. check_events {
  638. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 1, 0, 1 },
  639. { 'test1', 'bytes', 1, 6, 0, 0, 0, 1, 0, 1, 0, 3, 3 },
  640. }
  641. feed('<esc>')
  642. -- multi-line regex
  643. feed([[:%s/de\n123/a]])
  644. check_events {
  645. { 'test1', 'bytes', 1, 3, 0, 3, 3, 1, 3, 6, 0, 1, 1 },
  646. { 'test1', 'bytes', 1, 6, 0, 3, 3, 0, 1, 1, 1, 3, 6 },
  647. }
  648. feed('<esc>')
  649. -- replacing with unicode
  650. feed(':%s/b/→')
  651. check_events {
  652. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 3, 3 },
  653. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 3, 3, 0, 1, 1 },
  654. }
  655. feed('<esc>')
  656. -- replacing with expression register
  657. feed([[:%s/b/\=5+5]])
  658. check_events {
  659. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 },
  660. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 },
  661. }
  662. feed('<esc>')
  663. -- replacing with backslash
  664. feed([[:%s/b/\\]])
  665. check_events {
  666. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  667. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  668. }
  669. feed('<esc>')
  670. -- replacing with backslash from expression register
  671. feed([[:%s/b/\='\']])
  672. check_events {
  673. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  674. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  675. }
  676. feed('<esc>')
  677. -- replacing with backslash followed by another character
  678. feed([[:%s/b/\\!]])
  679. check_events {
  680. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 },
  681. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 },
  682. }
  683. feed('<esc>')
  684. -- replacing with backslash followed by another character from expression register
  685. feed([[:%s/b/\='\!']])
  686. check_events {
  687. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 },
  688. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 },
  689. }
  690. end)
  691. it('nvim_buf_set_text insert', function()
  692. local check_events = setup_eventcheck(verify, { 'bastext' })
  693. api.nvim_buf_set_text(0, 0, 3, 0, 3, { 'fiol', 'kontra' })
  694. check_events {
  695. { 'test1', 'bytes', 1, 3, 0, 3, 3, 0, 0, 0, 1, 6, 11 },
  696. }
  697. api.nvim_buf_set_text(0, 1, 6, 1, 6, { 'punkt', 'syntgitarr', 'övnings' })
  698. check_events {
  699. { 'test1', 'bytes', 1, 4, 1, 6, 14, 0, 0, 0, 2, 8, 25 },
  700. }
  701. eq(
  702. { 'basfiol', 'kontrapunkt', 'syntgitarr', 'övningstext' },
  703. api.nvim_buf_get_lines(0, 0, -1, true)
  704. )
  705. end)
  706. it('nvim_buf_set_text replace', function()
  707. local check_events = setup_eventcheck(verify, origlines)
  708. api.nvim_buf_set_text(0, 2, 3, 2, 8, { 'very text' })
  709. check_events {
  710. { 'test1', 'bytes', 1, 3, 2, 3, 35, 0, 5, 5, 0, 9, 9 },
  711. }
  712. api.nvim_buf_set_text(0, 3, 5, 3, 7, { ' splitty', 'line ' })
  713. check_events {
  714. { 'test1', 'bytes', 1, 4, 3, 5, 57, 0, 2, 2, 1, 5, 14 },
  715. }
  716. api.nvim_buf_set_text(0, 0, 8, 1, 2, { 'JOINY' })
  717. check_events {
  718. { 'test1', 'bytes', 1, 5, 0, 8, 8, 1, 2, 10, 0, 5, 5 },
  719. }
  720. api.nvim_buf_set_text(0, 4, 0, 6, 0, { 'was 5,6', '' })
  721. check_events {
  722. { 'test1', 'bytes', 1, 6, 4, 0, 75, 2, 0, 32, 1, 0, 8 },
  723. }
  724. eq({
  725. 'originalJOINYiginal line 2',
  726. 'orivery text line 3',
  727. 'origi splitty',
  728. 'line l line 4',
  729. 'was 5,6',
  730. ' indented line',
  731. }, api.nvim_buf_get_lines(0, 0, -1, true))
  732. end)
  733. it('nvim_buf_set_text delete', function()
  734. local check_events = setup_eventcheck(verify, origlines)
  735. -- really {""} but accepts {} as a shorthand
  736. api.nvim_buf_set_text(0, 0, 0, 1, 0, {})
  737. check_events {
  738. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 },
  739. }
  740. -- TODO(bfredl): this works but is not as convenient as set_lines
  741. api.nvim_buf_set_text(0, 4, 15, 5, 17, { '' })
  742. check_events {
  743. { 'test1', 'bytes', 1, 4, 4, 15, 79, 1, 17, 18, 0, 0, 0 },
  744. }
  745. eq({
  746. 'original line 2',
  747. 'original line 3',
  748. 'original line 4',
  749. 'original line 5',
  750. 'original line 6',
  751. }, api.nvim_buf_get_lines(0, 0, -1, true))
  752. end)
  753. it('checktime autoread', function()
  754. write_file(
  755. 'Xtest-reload',
  756. dedent [[
  757. old line 1
  758. old line 2]]
  759. )
  760. local atime = os.time() - 10
  761. vim.uv.fs_utime('Xtest-reload', atime, atime)
  762. command 'e Xtest-reload'
  763. command 'set autoread'
  764. local check_events = setup_eventcheck(verify, nil)
  765. write_file(
  766. 'Xtest-reload',
  767. dedent [[
  768. new line 1
  769. new line 2
  770. new line 3]]
  771. )
  772. command 'checktime'
  773. check_events {
  774. { 'test1', 'reload', 1 },
  775. }
  776. feed 'ggJ'
  777. check_events {
  778. { 'test1', 'bytes', 1, 5, 0, 10, 10, 1, 0, 1, 0, 1, 1 },
  779. }
  780. eq({ 'new line 1 new line 2', 'new line 3' }, api.nvim_buf_get_lines(0, 0, -1, true))
  781. -- check we can undo and redo a reload event.
  782. feed 'u'
  783. check_events {
  784. { 'test1', 'bytes', 1, 8, 0, 10, 10, 0, 1, 1, 1, 0, 1 },
  785. }
  786. feed 'u'
  787. check_events {
  788. { 'test1', 'reload', 1 },
  789. }
  790. feed '<c-r>'
  791. check_events {
  792. { 'test1', 'reload', 1 },
  793. }
  794. feed '<c-r>'
  795. check_events {
  796. { 'test1', 'bytes', 1, 14, 0, 10, 10, 1, 0, 1, 0, 1, 1 },
  797. }
  798. end)
  799. it('tab with noexpandtab and softtabstop', function()
  800. command('set noet')
  801. command('set ts=4')
  802. command('set sw=2')
  803. command('set sts=4')
  804. local check_events = setup_eventcheck(verify, { 'asdfasdf' })
  805. feed('gg0i<tab>')
  806. check_events {
  807. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  808. { 'test1', 'bytes', 1, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  809. }
  810. feed('<tab>')
  811. -- when spaces are merged into a tabstop
  812. check_events {
  813. { 'test1', 'bytes', 1, 5, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
  814. { 'test1', 'bytes', 1, 6, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  815. { 'test1', 'bytes', 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
  816. }
  817. feed('<esc>u')
  818. check_events {
  819. { 'test1', 'bytes', 1, 9, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
  820. { 'test1', 'bytes', 1, 9, 0, 0, 0, 0, 4, 4, 0, 0, 0 },
  821. }
  822. -- in REPLACE mode
  823. feed('R<tab><tab>')
  824. check_events {
  825. { 'test1', 'bytes', 1, 10, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
  826. { 'test1', 'bytes', 1, 11, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  827. { 'test1', 'bytes', 1, 12, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
  828. { 'test1', 'bytes', 1, 13, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  829. { 'test1', 'bytes', 1, 14, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
  830. }
  831. feed('<esc>u')
  832. check_events {
  833. { 'test1', 'bytes', 1, 16, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
  834. { 'test1', 'bytes', 1, 16, 0, 2, 2, 0, 2, 2, 0, 1, 1 },
  835. { 'test1', 'bytes', 1, 16, 0, 0, 0, 0, 2, 2, 0, 1, 1 },
  836. }
  837. -- in VISUALREPLACE mode
  838. feed('gR<tab><tab>')
  839. check_events {
  840. { 'test1', 'bytes', 1, 17, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
  841. { 'test1', 'bytes', 1, 18, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
  842. { 'test1', 'bytes', 1, 19, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
  843. { 'test1', 'bytes', 1, 20, 0, 3, 3, 0, 1, 1, 0, 1, 1 },
  844. { 'test1', 'bytes', 1, 21, 0, 3, 3, 0, 1, 1, 0, 0, 0 },
  845. { 'test1', 'bytes', 1, 22, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  846. { 'test1', 'bytes', 1, 24, 0, 2, 2, 0, 1, 1, 0, 0, 0 },
  847. { 'test1', 'bytes', 1, 25, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
  848. { 'test1', 'bytes', 1, 27, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
  849. { 'test1', 'bytes', 1, 28, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  850. { 'test1', 'bytes', 1, 30, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
  851. { 'test1', 'bytes', 1, 31, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
  852. { 'test1', 'bytes', 1, 33, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
  853. }
  854. -- inserting tab after other tabs
  855. command('set sw=4')
  856. feed('<esc>0a<tab>')
  857. check_events {
  858. { 'test1', 'bytes', 1, 34, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
  859. { 'test1', 'bytes', 1, 35, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
  860. { 'test1', 'bytes', 1, 36, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
  861. { 'test1', 'bytes', 1, 37, 0, 4, 4, 0, 0, 0, 0, 1, 1 },
  862. { 'test1', 'bytes', 1, 38, 0, 1, 1, 0, 4, 4, 0, 1, 1 },
  863. }
  864. end)
  865. it('retab', function()
  866. command('set noet')
  867. command('set ts=4')
  868. local check_events = setup_eventcheck(verify, { ' asdf' })
  869. command('retab 8')
  870. check_events {
  871. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 7, 7, 0, 9, 9 },
  872. }
  873. end)
  874. it('sends events when undoing with undofile', function()
  875. write_file(
  876. 'Xtest-undofile',
  877. dedent([[
  878. 12345
  879. hello world
  880. ]])
  881. )
  882. command('e! Xtest-undofile')
  883. command('set undodir=. | set undofile')
  884. local ns = n.request('nvim_create_namespace', 'ns1')
  885. api.nvim_buf_set_extmark(0, ns, 0, 0, {})
  886. eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  887. -- splice
  888. feed('gg0d2l')
  889. eq({ '345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  890. -- move
  891. command('.m+1')
  892. eq({ 'hello world', '345' }, api.nvim_buf_get_lines(0, 0, -1, true))
  893. -- reload undofile and undo changes
  894. command('w')
  895. command('set noundofile')
  896. command('bw!')
  897. command('e! Xtest-undofile')
  898. command('set undofile')
  899. local check_events = setup_eventcheck(verify, nil)
  900. feed('u')
  901. eq({ '345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  902. check_events {
  903. { 'test1', 'bytes', 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 },
  904. { 'test1', 'bytes', 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 },
  905. }
  906. feed('u')
  907. eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
  908. check_events {
  909. { 'test1', 'bytes', 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
  910. }
  911. command('bw!')
  912. end)
  913. it('blockwise paste with uneven line lengths', function()
  914. local check_events = setup_eventcheck(verify, { 'aaaa', 'aaa', 'aaa' })
  915. -- eq({}, api.nvim_buf_get_lines(0, 0, -1, true))
  916. feed('gg0<c-v>jj$d')
  917. check_events {
  918. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0 },
  919. { 'test1', 'bytes', 1, 3, 1, 0, 1, 0, 3, 3, 0, 0, 0 },
  920. { 'test1', 'bytes', 1, 3, 2, 0, 2, 0, 3, 3, 0, 0, 0 },
  921. }
  922. feed('p')
  923. check_events {
  924. { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4 },
  925. { 'test1', 'bytes', 1, 4, 1, 0, 5, 0, 0, 0, 0, 3, 3 },
  926. { 'test1', 'bytes', 1, 4, 2, 0, 9, 0, 0, 0, 0, 3, 3 },
  927. }
  928. end)
  929. it(':luado', function()
  930. local check_events = setup_eventcheck(verify, { 'abc', '12345' })
  931. command(".luado return 'a'")
  932. check_events {
  933. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 1, 1 },
  934. }
  935. command('luado return 10')
  936. check_events {
  937. { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 1, 1, 0, 2, 2 },
  938. { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 5, 5, 0, 2, 2 },
  939. }
  940. end)
  941. it('flushes deleted bytes on move', function()
  942. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC', 'DDD' })
  943. feed(':.move+1<cr>')
  944. check_events {
  945. { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 4, 0, 0, 0 },
  946. { 'test1', 'bytes', 1, 5, 1, 0, 4, 0, 0, 0, 1, 0, 4 },
  947. }
  948. feed('jd2j')
  949. check_events {
  950. { 'test1', 'bytes', 1, 6, 2, 0, 8, 2, 0, 8, 0, 0, 0 },
  951. }
  952. end)
  953. it('virtual edit', function()
  954. local check_events = setup_eventcheck(verify, { '', ' ' })
  955. api.nvim_set_option_value('virtualedit', 'all', {})
  956. feed [[<Right><Right>iab<ESC>]]
  957. check_events {
  958. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
  959. { 'test1', 'bytes', 1, 4, 0, 2, 2, 0, 0, 0, 0, 2, 2 },
  960. }
  961. feed [[j<Right><Right>iab<ESC>]]
  962. check_events {
  963. { 'test1', 'bytes', 1, 5, 1, 0, 5, 0, 1, 1, 0, 8, 8 },
  964. { 'test1', 'bytes', 1, 6, 1, 5, 10, 0, 0, 0, 0, 2, 2 },
  965. }
  966. end)
  967. it('block visual paste', function()
  968. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })
  969. fn.setreg('a', '___')
  970. feed([[gg0l<c-v>3jl"ap]])
  971. check_events {
  972. { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 2, 2, 0, 0, 0 },
  973. { 'test1', 'bytes', 1, 3, 1, 1, 3, 0, 2, 2, 0, 0, 0 },
  974. { 'test1', 'bytes', 1, 3, 2, 1, 5, 0, 2, 2, 0, 0, 0 },
  975. { 'test1', 'bytes', 1, 3, 3, 1, 7, 0, 2, 2, 0, 0, 0 },
  976. { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 },
  977. { 'test1', 'bytes', 1, 6, 1, 1, 6, 0, 0, 0, 0, 3, 3 },
  978. { 'test1', 'bytes', 1, 7, 2, 1, 11, 0, 0, 0, 0, 3, 3 },
  979. { 'test1', 'bytes', 1, 8, 3, 1, 16, 0, 0, 0, 0, 3, 3 },
  980. }
  981. end)
  982. it('visual paste', function()
  983. local check_events = setup_eventcheck(verify, { 'aaa {', 'b', '}' })
  984. -- Setting up
  985. feed [[jdd]]
  986. check_events {
  987. { 'test1', 'bytes', 1, 3, 1, 0, 6, 1, 0, 2, 0, 0, 0 },
  988. }
  989. -- Actually testing
  990. feed [[v%p]]
  991. check_events {
  992. { 'test1', 'bytes', 1, 8, 0, 4, 4, 1, 1, 3, 0, 0, 0 },
  993. { 'test1', 'bytes', 1, 8, 0, 4, 4, 0, 0, 0, 2, 0, 3 },
  994. }
  995. end)
  996. it('visual paste 2: splitting an empty line', function()
  997. local check_events = setup_eventcheck(verify, { 'abc', '{', 'def', '}' })
  998. feed('ggyyjjvi{p')
  999. check_events {
  1000. { 'test1', 'bytes', 1, 6, 2, 0, 6, 1, 0, 4, 0, 0, 0 },
  1001. { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 2, 0, 5 },
  1002. }
  1003. end)
  1004. it('nvim_buf_set_lines', function()
  1005. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB' })
  1006. -- delete
  1007. api.nvim_buf_set_lines(0, 0, 1, true, {})
  1008. check_events {
  1009. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 },
  1010. }
  1011. -- add
  1012. api.nvim_buf_set_lines(0, 0, 0, true, { 'asdf' })
  1013. check_events {
  1014. { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 },
  1015. }
  1016. -- replace
  1017. api.nvim_buf_set_lines(0, 0, 1, true, { 'asdf', 'fdsa' })
  1018. check_events {
  1019. { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 },
  1020. }
  1021. end)
  1022. it('flushes delbytes on substitute', function()
  1023. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  1024. feed('gg0')
  1025. command('s/AAA/GGG/')
  1026. check_events {
  1027. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 3, 3 },
  1028. }
  1029. -- check that byte updates for :delete (which uses curbuf->deleted_bytes2)
  1030. -- are correct
  1031. command('delete')
  1032. check_events {
  1033. { 'test1', 'bytes', 1, 4, 0, 0, 0, 1, 0, 4, 0, 0, 0 },
  1034. }
  1035. end)
  1036. it('flushes delbytes on join', function()
  1037. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  1038. feed('gg0J')
  1039. check_events {
  1040. { 'test1', 'bytes', 1, 3, 0, 3, 3, 1, 0, 1, 0, 1, 1 },
  1041. }
  1042. command('delete')
  1043. check_events {
  1044. { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 8, 0, 0, 0 },
  1045. }
  1046. end)
  1047. it('sends updates on U', function()
  1048. feed('ggiAAA<cr>BBB')
  1049. feed('<esc>gg$a CCC')
  1050. local check_events = setup_eventcheck(verify, nil)
  1051. feed('ggU')
  1052. check_events {
  1053. { 'test1', 'bytes', 1, 6, 0, 7, 7, 0, 0, 0, 0, 3, 3 },
  1054. }
  1055. end)
  1056. it('delete in completely empty buffer', function()
  1057. local check_events = setup_eventcheck(verify, nil)
  1058. command 'delete'
  1059. check_events {}
  1060. end)
  1061. it('delete the only line of a buffer', function()
  1062. local check_events = setup_eventcheck(verify, { 'AAA' })
  1063. command 'delete'
  1064. check_events {
  1065. { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 4, 1, 0, 1 },
  1066. }
  1067. end)
  1068. it('delete the last line of a buffer with two lines', function()
  1069. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB' })
  1070. command '2delete'
  1071. check_events {
  1072. { 'test1', 'bytes', 1, 3, 1, 0, 4, 1, 0, 4, 0, 0, 0 },
  1073. }
  1074. end)
  1075. it(':sort lines', function()
  1076. local check_events = setup_eventcheck(verify, { 'CCC', 'BBB', 'AAA' })
  1077. command '%sort'
  1078. check_events {
  1079. { 'test1', 'bytes', 1, 3, 0, 0, 0, 3, 0, 12, 3, 0, 12 },
  1080. }
  1081. end)
  1082. it('handles already sorted lines', function()
  1083. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  1084. command '%sort'
  1085. check_events {}
  1086. end)
  1087. it('works with accepting spell suggestions', function()
  1088. local check_events = setup_eventcheck(verify, { 'hallo world', 'hallo world' })
  1089. feed('gg0z=4<cr><cr>') -- accepts 'Hello'
  1090. check_events {
  1091. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 2, 2, 0, 2, 2 },
  1092. }
  1093. command('spellrepall') -- replaces whole words
  1094. check_events {
  1095. { 'test1', 'bytes', 1, 4, 1, 0, 12, 0, 5, 5, 0, 5, 5 },
  1096. }
  1097. end)
  1098. it('works with :diffput and :diffget', function()
  1099. local check_events = setup_eventcheck(verify, { 'AAA' })
  1100. command('diffthis')
  1101. command('new')
  1102. command('diffthis')
  1103. api.nvim_buf_set_lines(0, 0, -1, true, { 'AAA', 'BBB' })
  1104. feed('G')
  1105. command('diffput')
  1106. check_events {
  1107. { 'test1', 'bytes', 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 4 },
  1108. }
  1109. api.nvim_buf_set_lines(0, 0, -1, true, { 'AAA', 'CCC' })
  1110. feed('<C-w>pG')
  1111. command('diffget')
  1112. check_events {
  1113. { 'test1', 'bytes', 1, 4, 1, 0, 4, 1, 0, 4, 1, 0, 4 },
  1114. }
  1115. end)
  1116. it('prompt buffer', function()
  1117. local check_events = setup_eventcheck(verify, {})
  1118. api.nvim_set_option_value('buftype', 'prompt', {})
  1119. feed('i')
  1120. check_events {
  1121. { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
  1122. }
  1123. feed('<CR>')
  1124. check_events {
  1125. { 'test1', 'bytes', 1, 4, 1, 0, 3, 0, 0, 0, 1, 0, 1 },
  1126. { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 2, 2 },
  1127. }
  1128. feed('<CR>')
  1129. check_events {
  1130. { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 1, 0, 1 },
  1131. { 'test1', 'bytes', 1, 7, 2, 0, 6, 0, 0, 0, 0, 2, 2 },
  1132. }
  1133. end)
  1134. local function test_lockmarks(mode)
  1135. local description = (mode ~= '') and mode or '(baseline)'
  1136. it('test_lockmarks ' .. description .. ' %delete _', function()
  1137. local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' })
  1138. command(mode .. ' %delete _')
  1139. check_events {
  1140. { 'test1', 'bytes', 1, 3, 0, 0, 0, 3, 0, 12, 1, 0, 1 },
  1141. }
  1142. end)
  1143. it('test_lockmarks ' .. description .. ' append()', function()
  1144. local check_events = setup_eventcheck(verify)
  1145. command(mode .. " call append(0, 'CCC')")
  1146. check_events {
  1147. { 'test1', 'bytes', 1, 2, 0, 0, 0, 0, 0, 0, 1, 0, 4 },
  1148. }
  1149. command(mode .. " call append(1, 'BBBB')")
  1150. check_events {
  1151. { 'test1', 'bytes', 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 5 },
  1152. }
  1153. command(mode .. " call append(2, '')")
  1154. check_events {
  1155. { 'test1', 'bytes', 1, 4, 2, 0, 9, 0, 0, 0, 1, 0, 1 },
  1156. }
  1157. command(mode .. ' $delete _')
  1158. check_events {
  1159. { 'test1', 'bytes', 1, 5, 3, 0, 10, 1, 0, 1, 0, 0, 0 },
  1160. }
  1161. eq('CCC|BBBB|', table.concat(api.nvim_buf_get_lines(0, 0, -1, true), '|'))
  1162. end)
  1163. end
  1164. -- check that behavior is identical with and without "lockmarks"
  1165. test_lockmarks ''
  1166. test_lockmarks 'lockmarks'
  1167. teardown(function()
  1168. os.remove 'Xtest-reload'
  1169. os.remove 'Xtest-undofile'
  1170. os.remove '.Xtest-undofile.un~'
  1171. end)
  1172. end
  1173. describe('(with verify) handles', function()
  1174. do_both(true)
  1175. end)
  1176. describe('(without verify) handles', function()
  1177. do_both(false)
  1178. end)
  1179. end)