buffer_updates_spec.lua 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local clear = helpers.clear
  3. local eq, ok = helpers.eq, helpers.ok
  4. local buffer, command, eval, nvim, next_msg = helpers.buffer,
  5. helpers.command, helpers.eval, helpers.nvim, helpers.next_msg
  6. local expect_err = helpers.expect_err
  7. local nvim_prog = helpers.nvim_prog
  8. local sleep = helpers.sleep
  9. local write_file = helpers.write_file
  10. local origlines = {"original line 1",
  11. "original line 2",
  12. "original line 3",
  13. "original line 4",
  14. "original line 5",
  15. "original line 6"}
  16. local function expectn(name, args)
  17. -- expect the next message to be the specified notification event
  18. eq({'notification', name, args}, next_msg())
  19. end
  20. local function sendkeys(keys)
  21. nvim('input', keys)
  22. -- give nvim some time to process msgpack requests before possibly sending
  23. -- more key presses - otherwise they all pile up in the queue and get
  24. -- processed at once
  25. local ntime = os.clock() + 0.1
  26. repeat until os.clock() > ntime
  27. end
  28. local function open(activate, lines)
  29. local filename = helpers.tmpname()
  30. write_file(filename, table.concat(lines, "\n").."\n", true)
  31. command('edit ' .. filename)
  32. local b = nvim('get_current_buf')
  33. -- what is the value of b:changedtick?
  34. local tick = eval('b:changedtick')
  35. -- Enable buffer events, ensure that the nvim_buf_lines_event messages
  36. -- arrive as expected
  37. if activate then
  38. local firstline = 0
  39. ok(buffer('attach', b, true, {}))
  40. expectn('nvim_buf_lines_event', {b, tick, firstline, -1, lines, false})
  41. end
  42. return b, tick, filename
  43. end
  44. local function editoriginal(activate, lines)
  45. if not lines then
  46. lines = origlines
  47. end
  48. -- load up the file with the correct contents
  49. clear()
  50. return open(activate, lines)
  51. end
  52. local function reopen(buf, expectedlines)
  53. ok(buffer('detach', buf))
  54. expectn('nvim_buf_detach_event', {buf})
  55. -- for some reason the :edit! increments tick by 2
  56. command('edit!')
  57. local tick = eval('b:changedtick')
  58. ok(buffer('attach', buf, true, {}))
  59. local firstline = 0
  60. expectn('nvim_buf_lines_event', {buf, tick, firstline, -1, expectedlines, false})
  61. command('normal! gg')
  62. return tick
  63. end
  64. local function reopenwithfolds(b)
  65. -- discard any changes to the buffer
  66. local tick = reopen(b, origlines)
  67. -- use markers for folds, make all folds open by default
  68. command('setlocal foldmethod=marker foldlevel=20')
  69. -- add a fold
  70. command('2,4fold')
  71. tick = tick + 1
  72. expectn('nvim_buf_lines_event', {b, tick, 1, 4, {'original line 2/*{{{*/',
  73. 'original line 3',
  74. 'original line 4/*}}}*/'}, false})
  75. -- make a new fold that wraps lines 1-6
  76. command('1,6fold')
  77. tick = tick + 1
  78. expectn('nvim_buf_lines_event', {b, tick, 0, 6, {'original line 1/*{{{*/',
  79. 'original line 2/*{{{*/',
  80. 'original line 3',
  81. 'original line 4/*}}}*/',
  82. 'original line 5',
  83. 'original line 6/*}}}*/'}, false})
  84. return tick
  85. end
  86. describe('API: buffer events:', function()
  87. it('when lines are added', function()
  88. local b, tick = editoriginal(true)
  89. -- add a new line at the start of the buffer
  90. command('normal! GyyggP')
  91. tick = tick + 1
  92. expectn('nvim_buf_lines_event', {b, tick, 0, 0, {'original line 6'}, false})
  93. -- add multiple lines at the start of the file
  94. command('normal! GkkyGggP')
  95. tick = tick + 1
  96. expectn('nvim_buf_lines_event', {b, tick, 0, 0, {'original line 4',
  97. 'original line 5',
  98. 'original line 6'}, false})
  99. -- add one line to the middle of the file, several times
  100. command('normal! ggYjjp')
  101. tick = tick + 1
  102. expectn('nvim_buf_lines_event', {b, tick, 3, 3, {'original line 4'}, false})
  103. command('normal! p')
  104. tick = tick + 1
  105. expectn('nvim_buf_lines_event', {b, tick, 4, 4, {'original line 4'}, false})
  106. command('normal! p')
  107. tick = tick + 1
  108. expectn('nvim_buf_lines_event', {b, tick, 5, 5, {'original line 4'}, false})
  109. -- add multiple lines to the middle of the file
  110. command('normal! gg4Yjjp')
  111. tick = tick + 1
  112. expectn('nvim_buf_lines_event', {b, tick, 3, 3, {'original line 4',
  113. 'original line 5',
  114. 'original line 6',
  115. 'original line 4'}, false})
  116. -- add one line to the end of the file
  117. command('normal! ggYGp')
  118. tick = tick + 1
  119. expectn('nvim_buf_lines_event', {b, tick, 17, 17, {'original line 4'}, false})
  120. -- add one line to the end of the file, several times
  121. command('normal! ggYGppp')
  122. tick = tick + 1
  123. expectn('nvim_buf_lines_event', {b, tick, 18, 18, {'original line 4'}, false})
  124. tick = tick + 1
  125. expectn('nvim_buf_lines_event', {b, tick, 19, 19, {'original line 4'}, false})
  126. tick = tick + 1
  127. expectn('nvim_buf_lines_event', {b, tick, 20, 20, {'original line 4'}, false})
  128. -- add several lines to the end of the file, several times
  129. command('normal! gg4YGp')
  130. command('normal! Gp')
  131. command('normal! Gp')
  132. local firstfour = {'original line 4',
  133. 'original line 5',
  134. 'original line 6',
  135. 'original line 4'}
  136. tick = tick + 1
  137. expectn('nvim_buf_lines_event', {b, tick, 21, 21, firstfour, false})
  138. tick = tick + 1
  139. expectn('nvim_buf_lines_event', {b, tick, 25, 25, firstfour, false})
  140. tick = tick + 1
  141. expectn('nvim_buf_lines_event', {b, tick, 29, 29, firstfour, false})
  142. -- create a new empty buffer and wipe out the old one ... this will
  143. -- turn off buffer events
  144. command('enew!')
  145. expectn('nvim_buf_detach_event', {b})
  146. -- add a line at the start of an empty file
  147. command('enew')
  148. tick = eval('b:changedtick')
  149. local b2 = nvim('get_current_buf')
  150. ok(buffer('attach', b2, true, {}))
  151. expectn('nvim_buf_lines_event', {b2, tick, 0, -1, {""}, false})
  152. eval('append(0, ["new line 1"])')
  153. tick = tick + 1
  154. expectn('nvim_buf_lines_event', {b2, tick, 0, 0, {'new line 1'}, false})
  155. -- turn off buffer events manually
  156. buffer('detach', b2)
  157. expectn('nvim_buf_detach_event', {b2})
  158. -- add multiple lines to a blank file
  159. command('enew!')
  160. local b3 = nvim('get_current_buf')
  161. ok(buffer('attach', b3, true, {}))
  162. tick = eval('b:changedtick')
  163. expectn('nvim_buf_lines_event', {b3, tick, 0, -1, {""}, false})
  164. eval('append(0, ["new line 1", "new line 2", "new line 3"])')
  165. tick = tick + 1
  166. expectn('nvim_buf_lines_event', {b3, tick, 0, 0, {'new line 1',
  167. 'new line 2',
  168. 'new line 3'}, false})
  169. -- use the API itself to add a line to the start of the buffer
  170. buffer('set_lines', b3, 0, 0, true, {'New First Line'})
  171. tick = tick + 1
  172. expectn('nvim_buf_lines_event', {b3, tick, 0, 0, {"New First Line"}, false})
  173. end)
  174. it('when lines are removed', function()
  175. local b, tick = editoriginal(true)
  176. -- remove one line from start of file
  177. command('normal! dd')
  178. tick = tick + 1
  179. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {}, false})
  180. -- remove multiple lines from the start of the file
  181. command('normal! 4dd')
  182. tick = tick + 1
  183. expectn('nvim_buf_lines_event', {b, tick, 0, 4, {}, false})
  184. -- remove multiple lines from middle of file
  185. tick = reopen(b, origlines)
  186. command('normal! jj3dd')
  187. tick = tick + 1
  188. expectn('nvim_buf_lines_event', {b, tick, 2, 5, {}, false})
  189. -- remove one line from the end of the file
  190. tick = reopen(b, origlines)
  191. command('normal! Gdd')
  192. tick = tick + 1
  193. expectn('nvim_buf_lines_event', {b, tick, 5, 6, {}, false})
  194. -- remove multiple lines from the end of the file
  195. tick = reopen(b, origlines)
  196. command('normal! 4G3dd')
  197. tick = tick + 1
  198. expectn('nvim_buf_lines_event', {b, tick, 3, 6, {}, false})
  199. -- pretend to remove heaps lines from the end of the file but really
  200. -- just remove two
  201. tick = reopen(b, origlines)
  202. command('normal! Gk5dd')
  203. tick = tick + 1
  204. expectn('nvim_buf_lines_event', {b, tick, 4, 6, {}, false})
  205. end)
  206. it('when text is changed', function()
  207. local b, tick = editoriginal(true)
  208. -- some normal text editing
  209. command('normal! A555')
  210. tick = tick + 1
  211. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'original line 1555'}, false})
  212. command('normal! jj8X')
  213. tick = tick + 1
  214. expectn('nvim_buf_lines_event', {b, tick, 2, 3, {'origin3'}, false})
  215. -- modify multiple lines at once using visual block mode
  216. tick = reopen(b, origlines)
  217. command('normal! jjw')
  218. sendkeys('<C-v>jjllx')
  219. tick = tick + 1
  220. expectn('nvim_buf_lines_event',
  221. {b, tick, 2, 5, {'original e 3', 'original e 4', 'original e 5'}, false})
  222. -- replace part of a line line using :s
  223. tick = reopen(b, origlines)
  224. command('3s/line 3/foo/')
  225. tick = tick + 1
  226. expectn('nvim_buf_lines_event', {b, tick, 2, 3, {'original foo'}, false})
  227. -- replace parts of several lines line using :s
  228. tick = reopen(b, origlines)
  229. command('%s/line [35]/foo/')
  230. tick = tick + 1
  231. expectn('nvim_buf_lines_event', {b, tick, 2, 5, {'original foo',
  232. 'original line 4',
  233. 'original foo'}, false})
  234. -- type text into the first line of a blank file, one character at a time
  235. command('enew!')
  236. tick = 2
  237. expectn('nvim_buf_detach_event', {b})
  238. local bnew = nvim('get_current_buf')
  239. ok(buffer('attach', bnew, true, {}))
  240. expectn('nvim_buf_lines_event', {bnew, tick, 0, -1, {''}, false})
  241. sendkeys('i')
  242. sendkeys('h')
  243. sendkeys('e')
  244. sendkeys('l')
  245. sendkeys('l')
  246. sendkeys('o\nworld')
  247. expectn('nvim_buf_lines_event', {bnew, tick + 1, 0, 1, {'h'}, false})
  248. expectn('nvim_buf_lines_event', {bnew, tick + 2, 0, 1, {'he'}, false})
  249. expectn('nvim_buf_lines_event', {bnew, tick + 3, 0, 1, {'hel'}, false})
  250. expectn('nvim_buf_lines_event', {bnew, tick + 4, 0, 1, {'hell'}, false})
  251. expectn('nvim_buf_lines_event', {bnew, tick + 5, 0, 1, {'hello'}, false})
  252. expectn('nvim_buf_lines_event', {bnew, tick + 6, 0, 1, {'hello', ''}, false})
  253. expectn('nvim_buf_lines_event', {bnew, tick + 7, 1, 2, {'world'}, false})
  254. end)
  255. it('when lines are replaced', function()
  256. local b, tick = editoriginal(true)
  257. -- blast away parts of some lines with visual mode
  258. command('normal! jjwvjjllx')
  259. tick = tick + 1
  260. expectn('nvim_buf_lines_event', {b, tick, 2, 3, {'original '}, false})
  261. tick = tick + 1
  262. expectn('nvim_buf_lines_event', {b, tick, 3, 4, {}, false})
  263. tick = tick + 1
  264. expectn('nvim_buf_lines_event', {b, tick, 3, 4, {'e 5'}, false})
  265. tick = tick + 1
  266. expectn('nvim_buf_lines_event', {b, tick, 2, 3, {'original e 5'}, false})
  267. tick = tick + 1
  268. expectn('nvim_buf_lines_event', {b, tick, 3, 4, {}, false})
  269. -- blast away a few lines using :g
  270. tick = reopen(b, origlines)
  271. command('global/line [35]/delete')
  272. tick = tick + 1
  273. expectn('nvim_buf_lines_event', {b, tick, 2, 3, {}, false})
  274. tick = tick + 1
  275. expectn('nvim_buf_lines_event', {b, tick, 3, 4, {}, false})
  276. end)
  277. it('when lines are filtered', function()
  278. -- Test filtering lines with !cat
  279. local b, tick = editoriginal(true, {"A", "C", "E", "B", "D", "F"})
  280. command('silent 2,5!cat')
  281. -- the change comes through as two changes:
  282. -- 1) addition of the new lines after the filtered lines
  283. -- 2) removal of the original lines
  284. tick = tick + 1
  285. expectn('nvim_buf_lines_event', {b, tick, 5, 5, {"C", "E", "B", "D"}, false})
  286. tick = tick + 1
  287. expectn('nvim_buf_lines_event', {b, tick, 1, 5, {}, false})
  288. end)
  289. it('when you use "o"', function()
  290. local b, tick = editoriginal(true, {'AAA', 'BBB'})
  291. command('set noautoindent nosmartindent')
  292. -- use 'o' to start a new line from a line with no indent
  293. command('normal! o')
  294. tick = tick + 1
  295. expectn('nvim_buf_lines_event', {b, tick, 1, 1, {""}, false})
  296. -- undo the change, indent line 1 a bit, and try again
  297. command('undo')
  298. tick = tick + 1
  299. expectn('nvim_buf_lines_event', {b, tick, 1, 2, {}, false})
  300. tick = tick + 1
  301. expectn('nvim_buf_changedtick_event', {b, tick})
  302. command('set autoindent')
  303. command('normal! >>')
  304. tick = tick + 1
  305. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {"\tAAA"}, false})
  306. command('normal! ommm')
  307. tick = tick + 1
  308. expectn('nvim_buf_lines_event', {b, tick, 1, 1, {"\t"}, false})
  309. tick = tick + 1
  310. expectn('nvim_buf_lines_event', {b, tick, 1, 2, {"\tmmm"}, false})
  311. -- undo the change, and try again with 'O'
  312. command('undo')
  313. tick = tick + 1
  314. expectn('nvim_buf_lines_event', {b, tick, 1, 2, {'\t'}, false})
  315. tick = tick + 1
  316. expectn('nvim_buf_lines_event', {b, tick, 1, 2, {}, false})
  317. tick = tick + 1
  318. expectn('nvim_buf_changedtick_event', {b, tick})
  319. command('normal! ggOmmm')
  320. tick = tick + 1
  321. expectn('nvim_buf_lines_event', {b, tick, 0, 0, {"\t"}, false})
  322. tick = tick + 1
  323. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {"\tmmm"}, false})
  324. end)
  325. it('deactivates if the buffer is changed externally', function()
  326. -- Test changing file from outside vim and reloading using :edit
  327. local lines = {"Line 1", "Line 2"};
  328. local b, tick, filename = editoriginal(true, lines)
  329. command('normal! x')
  330. tick = tick + 1
  331. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'ine 1'}, false})
  332. command('undo')
  333. tick = tick + 1
  334. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'Line 1'}, false})
  335. tick = tick + 1
  336. expectn('nvim_buf_changedtick_event', {b, tick})
  337. -- change the file directly
  338. write_file(filename, "another line\n", true, true)
  339. -- reopen the file and watch buffer events shut down
  340. command('edit')
  341. expectn('nvim_buf_detach_event', {b})
  342. end)
  343. it('channel can watch many buffers at once', function()
  344. -- edit 3 buffers, make sure they all have windows visible so that when we
  345. -- move between buffers, none of them are unloaded
  346. local b1, tick1 = editoriginal(true, {'A1', 'A2'})
  347. local b1nr = eval('bufnr("")')
  348. command('split')
  349. local b2, tick2 = open(true, {'B1', 'B2'})
  350. local b2nr = eval('bufnr("")')
  351. command('split')
  352. local b3, tick3 = open(true, {'C1', 'C2'})
  353. local b3nr = eval('bufnr("")')
  354. -- make a new window for moving between buffers
  355. command('split')
  356. command('b'..b1nr)
  357. command('normal! x')
  358. tick1 = tick1 + 1
  359. expectn('nvim_buf_lines_event', {b1, tick1, 0, 1, {'1'}, false})
  360. command('undo')
  361. tick1 = tick1 + 1
  362. expectn('nvim_buf_lines_event', {b1, tick1, 0, 1, {'A1'}, false})
  363. tick1 = tick1 + 1
  364. expectn('nvim_buf_changedtick_event', {b1, tick1})
  365. command('b'..b2nr)
  366. command('normal! x')
  367. tick2 = tick2 + 1
  368. expectn('nvim_buf_lines_event', {b2, tick2, 0, 1, {'1'}, false})
  369. command('undo')
  370. tick2 = tick2 + 1
  371. expectn('nvim_buf_lines_event', {b2, tick2, 0, 1, {'B1'}, false})
  372. tick2 = tick2 + 1
  373. expectn('nvim_buf_changedtick_event', {b2, tick2})
  374. command('b'..b3nr)
  375. command('normal! x')
  376. tick3 = tick3 + 1
  377. expectn('nvim_buf_lines_event', {b3, tick3, 0, 1, {'1'}, false})
  378. command('undo')
  379. tick3 = tick3 + 1
  380. expectn('nvim_buf_lines_event', {b3, tick3, 0, 1, {'C1'}, false})
  381. tick3 = tick3 + 1
  382. expectn('nvim_buf_changedtick_event', {b3, tick3})
  383. end)
  384. it('does not get confused if enabled/disabled many times', function()
  385. local channel = nvim('get_api_info')[1]
  386. local b, tick = editoriginal(false)
  387. -- Enable buffer events many times.
  388. ok(buffer('attach', b, true, {}))
  389. ok(buffer('attach', b, true, {}))
  390. ok(buffer('attach', b, true, {}))
  391. ok(buffer('attach', b, true, {}))
  392. ok(buffer('attach', b, true, {}))
  393. expectn('nvim_buf_lines_event', {b, tick, 0, -1, origlines, false})
  394. eval('rpcnotify('..channel..', "Hello There")')
  395. expectn('Hello There', {})
  396. -- Disable buffer events many times.
  397. ok(buffer('detach', b))
  398. ok(buffer('detach', b))
  399. ok(buffer('detach', b))
  400. ok(buffer('detach', b))
  401. ok(buffer('detach', b))
  402. expectn('nvim_buf_detach_event', {b})
  403. eval('rpcnotify('..channel..', "Hello Again")')
  404. expectn('Hello Again', {})
  405. end)
  406. it('can notify several channels at once', function()
  407. clear()
  408. -- create several new sessions, in addition to our main API
  409. local sessions = {}
  410. local pipe = helpers.new_pipename()
  411. eval("serverstart('"..pipe.."')")
  412. sessions[1] = helpers.connect(pipe)
  413. sessions[2] = helpers.connect(pipe)
  414. sessions[3] = helpers.connect(pipe)
  415. local function request(sessionnr, method, ...)
  416. local status, rv = sessions[sessionnr]:request(method, ...)
  417. if not status then
  418. error(rv[2])
  419. end
  420. return rv
  421. end
  422. local function wantn(sessionid, name, args)
  423. local session = sessions[sessionid]
  424. eq({'notification', name, args}, session:next_message(10000))
  425. end
  426. -- Edit a new file, but don't enable buffer events.
  427. local lines = {'AAA', 'BBB'}
  428. local b, tick = open(false, lines)
  429. -- Enable buffer events for sessions 1, 2 and 3.
  430. ok(request(1, 'nvim_buf_attach', b, true, {}))
  431. ok(request(2, 'nvim_buf_attach', b, true, {}))
  432. ok(request(3, 'nvim_buf_attach', b, true, {}))
  433. wantn(1, 'nvim_buf_lines_event', {b, tick, 0, -1, lines, false})
  434. wantn(2, 'nvim_buf_lines_event', {b, tick, 0, -1, lines, false})
  435. wantn(3, 'nvim_buf_lines_event', {b, tick, 0, -1, lines, false})
  436. -- Change the buffer.
  437. command('normal! x')
  438. tick = tick + 1
  439. wantn(1, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false})
  440. wantn(2, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false})
  441. wantn(3, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false})
  442. -- Stop watching on channel 1.
  443. ok(request(1, 'nvim_buf_detach', b))
  444. wantn(1, 'nvim_buf_detach_event', {b})
  445. -- Undo the change to buffer 1.
  446. command('undo')
  447. tick = tick + 1
  448. wantn(2, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AAA'}, false})
  449. wantn(3, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AAA'}, false})
  450. tick = tick + 1
  451. wantn(2, 'nvim_buf_changedtick_event', {b, tick})
  452. wantn(3, 'nvim_buf_changedtick_event', {b, tick})
  453. -- make sure there are no other pending nvim_buf_lines_event messages going to
  454. -- channel 1
  455. local channel1 = request(1, 'nvim_get_api_info')[1]
  456. eval('rpcnotify('..channel1..', "Hello")')
  457. wantn(1, 'Hello', {})
  458. -- close the buffer and channels 2 and 3 should get a nvim_buf_detach_event
  459. -- notification
  460. command('edit')
  461. wantn(2, 'nvim_buf_detach_event', {b})
  462. wantn(3, 'nvim_buf_detach_event', {b})
  463. -- make sure there are no other pending nvim_buf_lines_event messages going to
  464. -- channel 1
  465. channel1 = request(1, 'nvim_get_api_info')[1]
  466. eval('rpcnotify('..channel1..', "Hello Again")')
  467. wantn(1, 'Hello Again', {})
  468. end)
  469. it('works with :diffput and :diffget', function()
  470. local b1, tick1 = editoriginal(true, {"AAA", "BBB"})
  471. local channel = nvim('get_api_info')[1]
  472. command('diffthis')
  473. command('rightbelow vsplit')
  474. local b2, tick2 = open(true, {"BBB", "CCC"})
  475. command('diffthis')
  476. -- go back to first buffer, and push the 'AAA' line to the second buffer
  477. command('1wincmd w')
  478. command('normal! gg')
  479. command('diffput')
  480. tick2 = tick2 + 1
  481. expectn('nvim_buf_lines_event', {b2, tick2, 0, 0, {"AAA"}, false})
  482. -- use :diffget to grab the other change from buffer 2
  483. command('normal! G')
  484. command('diffget')
  485. tick1 = tick1 + 1
  486. expectn('nvim_buf_lines_event', {b1, tick1, 2, 2, {"CCC"}, false})
  487. eval('rpcnotify('..channel..', "Goodbye")')
  488. expectn('Goodbye', {})
  489. end)
  490. it('works with :sort', function()
  491. -- test for :sort
  492. local b, tick = editoriginal(true, {"B", "D", "C", "A", "E"})
  493. command('%sort')
  494. tick = tick + 1
  495. expectn('nvim_buf_lines_event', {b, tick, 0, 5, {"A", "B", "C", "D", "E"}, false})
  496. end)
  497. it('works with :left', function()
  498. local b, tick = editoriginal(true, {" A", " B", "B", "\tB", "\t\tC"})
  499. command('2,4left')
  500. tick = tick + 1
  501. expectn('nvim_buf_lines_event', {b, tick, 1, 4, {"B", "B", "B"}, false})
  502. end)
  503. it('works with :right', function()
  504. local b, tick = editoriginal(true, {" A",
  505. "\t B",
  506. "\t \tBB",
  507. " \tB",
  508. "\t\tC"})
  509. command('set ts=2 et')
  510. command('2,4retab')
  511. tick = tick + 1
  512. expectn('nvim_buf_lines_event', {b, tick, 1, 4, {" B", " BB", " B"}, false})
  513. end)
  514. it('works with :move', function()
  515. local b, tick = editoriginal(true, origlines)
  516. -- move text down towards the end of the file
  517. command('2,3move 4')
  518. tick = tick + 2
  519. expectn('nvim_buf_lines_event', {b, tick, 4, 4, {"original line 2",
  520. "original line 3"}, false})
  521. tick = tick + 1
  522. expectn('nvim_buf_lines_event', {b, tick, 1, 3, {}, false})
  523. -- move text up towards the start of the file
  524. tick = reopen(b, origlines)
  525. command('4,5move 2')
  526. tick = tick + 2
  527. expectn('nvim_buf_lines_event', {b, tick, 2, 2, {"original line 4",
  528. "original line 5"}, false})
  529. tick = tick + 1
  530. expectn('nvim_buf_lines_event', {b, tick, 5, 7, {}, false})
  531. end)
  532. it('when you manually add/remove folds', function()
  533. local b = editoriginal(true)
  534. local tick = reopenwithfolds(b)
  535. -- delete the inner fold
  536. command('normal! zR3Gzd')
  537. tick = tick + 1
  538. expectn('nvim_buf_lines_event', {b, tick, 1, 4, {'original line 2',
  539. 'original line 3',
  540. 'original line 4'}, false})
  541. -- delete the outer fold
  542. command('normal! zd')
  543. tick = tick + 1
  544. expectn('nvim_buf_lines_event', {b, tick, 0, 6, origlines, false})
  545. -- discard changes and put the folds back
  546. tick = reopenwithfolds(b)
  547. -- remove both folds at once
  548. command('normal! ggzczD')
  549. tick = tick + 1
  550. expectn('nvim_buf_lines_event', {b, tick, 0, 6, origlines, false})
  551. -- discard changes and put the folds back
  552. tick = reopenwithfolds(b)
  553. -- now delete all folds at once
  554. command('normal! zE')
  555. tick = tick + 1
  556. expectn('nvim_buf_lines_event', {b, tick, 0, 6, origlines, false})
  557. -- create a fold from line 4 to the end of the file
  558. command('normal! 4GA/*{{{*/')
  559. tick = tick + 1
  560. expectn('nvim_buf_lines_event', {b, tick, 3, 4, {'original line 4/*{{{*/'}, false})
  561. -- delete the fold which only has one marker
  562. command('normal! Gzd')
  563. tick = tick + 1
  564. expectn('nvim_buf_lines_event', {b, tick, 3, 6, {'original line 4',
  565. 'original line 5',
  566. 'original line 6'}, false})
  567. end)
  568. it('detaches if the buffer is closed', function()
  569. local b, tick = editoriginal(true, {'AAA'})
  570. local channel = nvim('get_api_info')[1]
  571. -- Test that buffer events are working.
  572. command('normal! x')
  573. tick = tick + 1
  574. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false})
  575. command('undo')
  576. tick = tick + 1
  577. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AAA'}, false})
  578. tick = tick + 1
  579. expectn('nvim_buf_changedtick_event', {b, tick})
  580. -- close our buffer by creating a new one
  581. command('enew')
  582. expectn('nvim_buf_detach_event', {b})
  583. -- Reopen the original buffer, make sure there are no buffer events sent.
  584. command('b1')
  585. command('normal! x')
  586. eval('rpcnotify('..channel..', "Hello There")')
  587. expectn('Hello There', {})
  588. end)
  589. it('stays attached if the buffer is hidden', function()
  590. local b, tick = editoriginal(true, {'AAA'})
  591. local channel = nvim('get_api_info')[1]
  592. -- Test that buffer events are working.
  593. command('normal! x')
  594. tick = tick + 1
  595. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false})
  596. command('undo')
  597. tick = tick + 1
  598. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AAA'}, false})
  599. tick = tick + 1
  600. expectn('nvim_buf_changedtick_event', {b, tick})
  601. -- Close our buffer by creating a new one.
  602. command('set hidden')
  603. command('enew')
  604. -- Assert that no nvim_buf_detach_event is sent.
  605. eval('rpcnotify('..channel..', "Hello There")')
  606. expectn('Hello There', {})
  607. -- Reopen the original buffer, assert that buffer events are still active.
  608. command('b1')
  609. command('normal! x')
  610. tick = tick + 1
  611. expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false})
  612. end)
  613. it('detaches if the buffer is unloaded/deleted/wiped', function()
  614. -- start with a blank nvim
  615. clear()
  616. -- need to make a new window with a buffer because :bunload doesn't let you
  617. -- unload the last buffer
  618. for _, cmd in ipairs({'bunload', 'bdelete', 'bwipeout'}) do
  619. command('new')
  620. -- open a brand spanking new file
  621. local b = open(true, {'AAA'})
  622. -- call :bunload or whatever the command is, and then check that we
  623. -- receive a nvim_buf_detach_event
  624. command(cmd)
  625. expectn('nvim_buf_detach_event', {b})
  626. end
  627. end)
  628. it('does not send the buffer content if not requested', function()
  629. clear()
  630. local b, tick = editoriginal(false)
  631. ok(buffer('attach', b, false, {}))
  632. expectn('nvim_buf_changedtick_event', {b, tick})
  633. end)
  634. it('returns a proper error on nonempty options dict', function()
  635. clear()
  636. local b = editoriginal(false)
  637. expect_err("dict isn't empty", buffer, 'attach', b, false, {builtin="asfd"})
  638. end)
  639. it('nvim_buf_attach returns response after delay #8634', function()
  640. clear()
  641. sleep(250)
  642. -- response
  643. eq(true, helpers.request('nvim_buf_attach', 0, false, {}))
  644. -- notification
  645. eq({
  646. [1] = 'notification',
  647. [2] = 'nvim_buf_changedtick_event',
  648. [3] = {
  649. [1] = { id = 1 },
  650. [2] = 2 }, }, next_msg())
  651. end)
  652. end)
  653. describe('API: buffer events:', function()
  654. before_each(function()
  655. clear()
  656. end)
  657. local function lines_subset(first, second)
  658. for i = 1,#first do
  659. if first[i] ~= second[i] then
  660. return false
  661. end
  662. end
  663. return true
  664. end
  665. local function lines_equal(f, s)
  666. return lines_subset(f, s) and lines_subset(s, f)
  667. end
  668. local function assert_match_somewhere(expected_lines, buffer_lines)
  669. local msg = next_msg()
  670. while(msg ~= nil) do
  671. local event = msg[2]
  672. if event == 'nvim_buf_lines_event' then
  673. local args = msg[3]
  674. local starts = args[3]
  675. local newlines = args[5]
  676. -- Size of the contained nvim instance is 23 lines, this might change
  677. -- with the test setup. Note updates are continguous.
  678. assert(#newlines <= 23)
  679. for i = 1,#newlines do
  680. buffer_lines[starts + i] = newlines[i]
  681. end
  682. -- we don't compare the msg area of the embedded nvim, it's too flakey
  683. buffer_lines[23] = nil
  684. if lines_equal(buffer_lines, expected_lines) then
  685. -- OK
  686. return
  687. end
  688. end
  689. msg = next_msg()
  690. end
  691. assert(false, 'did not match/receive expected nvim_buf_lines_event lines')
  692. end
  693. it('when :terminal lines change', function()
  694. local buffer_lines = {}
  695. local expected_lines = {}
  696. command('terminal "'..nvim_prog..'" -u NONE -i NONE -n -c "set shortmess+=A"')
  697. local b = nvim('get_current_buf')
  698. ok(buffer('attach', b, true, {}))
  699. for _ = 1,22 do
  700. table.insert(expected_lines,'~')
  701. end
  702. expected_lines[1] = ''
  703. expected_lines[22] = ('tmp_terminal_nvim'..(' '):rep(45)
  704. ..'0,0-1 All')
  705. sendkeys('i:e tmp_terminal_nvim<Enter>')
  706. assert_match_somewhere(expected_lines, buffer_lines)
  707. expected_lines[1] = 'Blarg'
  708. expected_lines[22] = ('tmp_terminal_nvim [+]'..(' '):rep(41)
  709. ..'1,6 All')
  710. sendkeys('iBlarg')
  711. assert_match_somewhere(expected_lines, buffer_lines)
  712. for i = 1,21 do
  713. expected_lines[i] = 'xyz'
  714. end
  715. expected_lines[22] = ('tmp_terminal_nvim [+]'..(' '):rep(41)
  716. ..'31,4 Bot')
  717. local s = string.rep('\nxyz', 30)
  718. sendkeys(s)
  719. assert_match_somewhere(expected_lines, buffer_lines)
  720. end)
  721. end)