decorations_spec.lua 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local Screen = require('test.functional.ui.screen')
  3. local clear = helpers.clear
  4. local feed = helpers.feed
  5. local insert = helpers.insert
  6. local exec_lua = helpers.exec_lua
  7. local exec = helpers.exec
  8. local expect_events = helpers.expect_events
  9. local meths = helpers.meths
  10. local command = helpers.command
  11. describe('decorations providers', function()
  12. local screen
  13. before_each(function()
  14. clear()
  15. screen = Screen.new(40, 8)
  16. screen:attach()
  17. screen:set_default_attr_ids {
  18. [1] = {bold=true, foreground=Screen.colors.Blue};
  19. [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
  20. [3] = {foreground = Screen.colors.Brown};
  21. [4] = {foreground = Screen.colors.Blue1};
  22. [5] = {foreground = Screen.colors.Magenta};
  23. [6] = {bold = true, foreground = Screen.colors.Brown};
  24. [7] = {background = Screen.colors.Gray90};
  25. [8] = {bold = true, reverse = true};
  26. [9] = {reverse = true};
  27. [10] = {italic = true, background = Screen.colors.Magenta};
  28. [11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')};
  29. [12] = {foreground = tonumber('0x990000')};
  30. [13] = {background = Screen.colors.LightBlue};
  31. }
  32. end)
  33. local mulholland = [[
  34. // just to see if there was an accident
  35. // on Mulholland Drive
  36. try_start();
  37. bufref_T save_buf;
  38. switch_buffer(&save_buf, buf);
  39. posp = getmark(mark, false);
  40. restore_buffer(&save_buf); ]]
  41. local function setup_provider(code)
  42. return exec_lua ([[
  43. local a = vim.api
  44. _G.ns1 = a.nvim_create_namespace "ns1"
  45. ]] .. (code or [[
  46. beamtrace = {}
  47. local function on_do(kind, ...)
  48. table.insert(beamtrace, {kind, ...})
  49. end
  50. ]]) .. [[
  51. a.nvim_set_decoration_provider(_G.ns1, {
  52. on_start = on_do; on_buf = on_do;
  53. on_win = on_do; on_line = on_do;
  54. on_end = on_do;
  55. })
  56. return _G.ns1
  57. ]])
  58. end
  59. local function check_trace(expected)
  60. local actual = exec_lua [[ local b = beamtrace beamtrace = {} return b ]]
  61. expect_events(expected, actual, "beam trace")
  62. end
  63. it('does not OOM when inserting, rather than appending, to the decoration provider vector', function()
  64. -- Add a dummy decoration provider with a larger ns id than what setup_provider() creates.
  65. -- This forces get_decor_provider() to insert into the providers vector,
  66. -- rather than append, which used to spin in an infinite loop allocating
  67. -- memory until nvim crashed/was killed.
  68. setup_provider([[
  69. local ns2 = a.nvim_create_namespace "ns2"
  70. a.nvim_set_decoration_provider(ns2, {})
  71. ]])
  72. helpers.assert_alive()
  73. end)
  74. it('leave a trace', function()
  75. insert(mulholland)
  76. setup_provider()
  77. screen:expect{grid=[[
  78. // just to see if there was an accident |
  79. // on Mulholland Drive |
  80. try_start(); |
  81. bufref_T save_buf; |
  82. switch_buffer(&save_buf, buf); |
  83. posp = getmark(mark, false); |
  84. restore_buffer(&save_buf);^ |
  85. |
  86. ]]}
  87. check_trace {
  88. { "start", 4, 40 };
  89. { "win", 1000, 1, 0, 8 };
  90. { "line", 1000, 1, 0 };
  91. { "line", 1000, 1, 1 };
  92. { "line", 1000, 1, 2 };
  93. { "line", 1000, 1, 3 };
  94. { "line", 1000, 1, 4 };
  95. { "line", 1000, 1, 5 };
  96. { "line", 1000, 1, 6 };
  97. { "end", 4 };
  98. }
  99. feed "iü<esc>"
  100. screen:expect{grid=[[
  101. // just to see if there was an accident |
  102. // on Mulholland Drive |
  103. try_start(); |
  104. bufref_T save_buf; |
  105. switch_buffer(&save_buf, buf); |
  106. posp = getmark(mark, false); |
  107. restore_buffer(&save_buf);^ü |
  108. |
  109. ]]}
  110. check_trace {
  111. { "start", 5, 10 };
  112. { "buf", 1 };
  113. { "win", 1000, 1, 0, 8 };
  114. { "line", 1000, 1, 6 };
  115. { "end", 5 };
  116. }
  117. end)
  118. it('can have single provider', function()
  119. insert(mulholland)
  120. setup_provider [[
  121. local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
  122. local test_ns = a.nvim_create_namespace "mulholland"
  123. function on_do(event, ...)
  124. if event == "line" then
  125. local win, buf, line = ...
  126. a.nvim_buf_set_extmark(buf, test_ns, line, line,
  127. { end_line = line, end_col = line+1,
  128. hl_group = hl,
  129. ephemeral = true
  130. })
  131. end
  132. end
  133. ]]
  134. screen:expect{grid=[[
  135. {2:/}/ just to see if there was an accident |
  136. /{2:/} on Mulholland Drive |
  137. tr{2:y}_start(); |
  138. buf{2:r}ef_T save_buf; |
  139. swit{2:c}h_buffer(&save_buf, buf); |
  140. posp {2:=} getmark(mark, false); |
  141. restor{2:e}_buffer(&save_buf);^ |
  142. |
  143. ]]}
  144. end)
  145. it('can predefine highlights', function()
  146. screen:try_resize(40, 16)
  147. insert(mulholland)
  148. exec [[
  149. 3
  150. set ft=c
  151. syntax on
  152. set number cursorline
  153. split
  154. ]]
  155. local ns1 = setup_provider()
  156. for k,v in pairs {
  157. LineNr = {italic=true, bg="Magenta"};
  158. Comment = {fg="#FF0000", bg = 80*256+40};
  159. CursorLine = {link="ErrorMsg"};
  160. } do meths.set_hl(ns1, k, v) end
  161. screen:expect{grid=[[
  162. {3: 1 }{4:// just to see if there was an accid}|
  163. {3: }{4:ent} |
  164. {3: 2 }{4:// on Mulholland Drive} |
  165. {6: 3 }{7:^try_start(); }|
  166. {3: 4 }bufref_T save_buf; |
  167. {3: 5 }switch_buffer(&save_buf, buf); |
  168. {3: 6 }posp = getmark(mark, {5:false}); |
  169. {8:[No Name] [+] }|
  170. {3: 2 }{4:// on Mulholland Drive} |
  171. {6: 3 }{7:try_start(); }|
  172. {3: 4 }bufref_T save_buf; |
  173. {3: 5 }switch_buffer(&save_buf, buf); |
  174. {3: 6 }posp = getmark(mark, {5:false}); |
  175. {3: 7 }restore_buffer(&save_buf); |
  176. {9:[No Name] [+] }|
  177. |
  178. ]]}
  179. meths._set_hl_ns(ns1)
  180. screen:expect{grid=[[
  181. {10: 1 }{11:// just to see if there was an accid}|
  182. {10: }{11:ent} |
  183. {10: 2 }{11:// on Mulholland Drive} |
  184. {6: 3 }{2:^try_start(); }|
  185. {10: 4 }bufref_T save_buf; |
  186. {10: 5 }switch_buffer(&save_buf, buf); |
  187. {10: 6 }posp = getmark(mark, {5:false}); |
  188. {8:[No Name] [+] }|
  189. {10: 2 }{11:// on Mulholland Drive} |
  190. {6: 3 }{2:try_start(); }|
  191. {10: 4 }bufref_T save_buf; |
  192. {10: 5 }switch_buffer(&save_buf, buf); |
  193. {10: 6 }posp = getmark(mark, {5:false}); |
  194. {10: 7 }restore_buffer(&save_buf); |
  195. {9:[No Name] [+] }|
  196. |
  197. ]]}
  198. exec_lua [[
  199. local a = vim.api
  200. local thewin = a.nvim_get_current_win()
  201. local ns2 = a.nvim_create_namespace 'ns2'
  202. a.nvim_set_decoration_provider (ns2, {
  203. on_win = function (_, win, buf)
  204. a.nvim__set_hl_ns(win == thewin and _G.ns1 or ns2)
  205. end;
  206. })
  207. ]]
  208. screen:expect{grid=[[
  209. {10: 1 }{11:// just to see if there was an accid}|
  210. {10: }{11:ent} |
  211. {10: 2 }{11:// on Mulholland Drive} |
  212. {6: 3 }{2:^try_start(); }|
  213. {10: 4 }bufref_T save_buf; |
  214. {10: 5 }switch_buffer(&save_buf, buf); |
  215. {10: 6 }posp = getmark(mark, {5:false}); |
  216. {8:[No Name] [+] }|
  217. {3: 2 }{4:// on Mulholland Drive} |
  218. {6: 3 }{7:try_start(); }|
  219. {3: 4 }bufref_T save_buf; |
  220. {3: 5 }switch_buffer(&save_buf, buf); |
  221. {3: 6 }posp = getmark(mark, {5:false}); |
  222. {3: 7 }restore_buffer(&save_buf); |
  223. {9:[No Name] [+] }|
  224. |
  225. ]]}
  226. end)
  227. it('can break an existing link', function()
  228. insert(mulholland)
  229. local ns1 = setup_provider()
  230. exec [[
  231. highlight OriginalGroup guifg='#990000'
  232. highlight link LinkGroup OriginalGroup
  233. ]]
  234. meths.buf_set_virtual_text(0, 0, 2, {{'- not red', 'LinkGroup'}}, {})
  235. screen:expect{grid=[[
  236. // just to see if there was an accident |
  237. // on Mulholland Drive |
  238. try_start(); {12:- not red} |
  239. bufref_T save_buf; |
  240. switch_buffer(&save_buf, buf); |
  241. posp = getmark(mark, false); |
  242. restore_buffer(&save_buf);^ |
  243. |
  244. ]]}
  245. meths.set_hl(ns1, 'LinkGroup', {fg = 'Blue'})
  246. meths._set_hl_ns(ns1)
  247. screen:expect{grid=[[
  248. // just to see if there was an accident |
  249. // on Mulholland Drive |
  250. try_start(); {4:- not red} |
  251. bufref_T save_buf; |
  252. switch_buffer(&save_buf, buf); |
  253. posp = getmark(mark, false); |
  254. restore_buffer(&save_buf);^ |
  255. |
  256. ]]}
  257. end)
  258. it("with 'default': do not break an existing link", function()
  259. insert(mulholland)
  260. local ns1 = setup_provider()
  261. exec [[
  262. highlight OriginalGroup guifg='#990000'
  263. highlight link LinkGroup OriginalGroup
  264. ]]
  265. meths.buf_set_virtual_text(0, 0, 2, {{'- not red', 'LinkGroup'}}, {})
  266. screen:expect{grid=[[
  267. // just to see if there was an accident |
  268. // on Mulholland Drive |
  269. try_start(); {12:- not red} |
  270. bufref_T save_buf; |
  271. switch_buffer(&save_buf, buf); |
  272. posp = getmark(mark, false); |
  273. restore_buffer(&save_buf);^ |
  274. |
  275. ]]}
  276. meths.set_hl(ns1, 'LinkGroup', {fg = 'Blue', default=true})
  277. meths._set_hl_ns(ns1)
  278. feed 'k'
  279. screen:expect{grid=[[
  280. // just to see if there was an accident |
  281. // on Mulholland Drive |
  282. try_start(); {12:- not red} |
  283. bufref_T save_buf; |
  284. switch_buffer(&save_buf, buf); |
  285. posp = getmark(mark, false^); |
  286. restore_buffer(&save_buf); |
  287. |
  288. ]]}
  289. end)
  290. it('can have virtual text', function()
  291. insert(mulholland)
  292. setup_provider [[
  293. local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
  294. local test_ns = a.nvim_create_namespace "mulholland"
  295. function on_do(event, ...)
  296. if event == "line" then
  297. local win, buf, line = ...
  298. a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
  299. virt_text = {{'+', 'ErrorMsg'}};
  300. virt_text_pos='overlay';
  301. ephemeral = true;
  302. })
  303. end
  304. end
  305. ]]
  306. screen:expect{grid=[[
  307. {2:+}/ just to see if there was an accident |
  308. {2:+}/ on Mulholland Drive |
  309. {2:+}ry_start(); |
  310. {2:+}ufref_T save_buf; |
  311. {2:+}witch_buffer(&save_buf, buf); |
  312. {2:+}osp = getmark(mark, false); |
  313. {2:+}estore_buffer(&save_buf);^ |
  314. |
  315. ]]}
  316. end)
  317. it('can have virtual text of the style: right_align', function()
  318. insert(mulholland)
  319. setup_provider [[
  320. local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
  321. local test_ns = a.nvim_create_namespace "mulholland"
  322. function on_do(event, ...)
  323. if event == "line" then
  324. local win, buf, line = ...
  325. a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
  326. virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}};
  327. virt_text_pos='right_align';
  328. ephemeral = true;
  329. })
  330. end
  331. end
  332. ]]
  333. screen:expect{grid=[[
  334. // just to see if there was an acciden+{2: }|
  335. // on Mulholland Drive +{2: }|
  336. try_start(); +{2: }|
  337. bufref_T save_buf; +{2: }|
  338. switch_buffer(&save_buf, buf); +{2: }|
  339. posp = getmark(mark, false); +{2: }|
  340. restore_buffer(&save_buf);^ +{2: }|
  341. |
  342. ]]}
  343. end)
  344. it('can highlight beyond EOL', function()
  345. insert(mulholland)
  346. setup_provider [[
  347. local test_ns = a.nvim_create_namespace "veberod"
  348. function on_do(event, ...)
  349. if event == "line" then
  350. local win, buf, line = ...
  351. if string.find(a.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then
  352. a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
  353. end_line = line+1;
  354. hl_group = 'DiffAdd';
  355. hl_eol = true;
  356. ephemeral = true;
  357. })
  358. end
  359. end
  360. end
  361. ]]
  362. screen:expect{grid=[[
  363. // just to see if there was an accident |
  364. // on Mulholland Drive |
  365. try_start(); |
  366. {13:bufref_T save_buf; }|
  367. {13:switch_buffer(&save_buf, buf); }|
  368. posp = getmark(mark, false); |
  369. {13:restore_buffer(&save_buf);^ }|
  370. |
  371. ]]}
  372. end)
  373. end)
  374. describe('extmark decorations', function()
  375. local screen, ns
  376. before_each( function()
  377. clear()
  378. screen = Screen.new(50, 15)
  379. screen:attach()
  380. screen:set_default_attr_ids {
  381. [1] = {bold=true, foreground=Screen.colors.Blue};
  382. [2] = {foreground = Screen.colors.Brown};
  383. [3] = {bold = true, foreground = Screen.colors.SeaGreen};
  384. [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100};
  385. [5] = {foreground = Screen.colors.Brown, bold = true};
  386. [6] = {foreground = Screen.colors.DarkCyan};
  387. [7] = {foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c')};
  388. [8] = {foreground = tonumber('0x180606'), background = tonumber('0xff4c4c')};
  389. [9] = {foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true};
  390. [10] = {foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c')};
  391. [11] = {blend = 30, background = Screen.colors.Red1};
  392. [12] = {foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true};
  393. [13] = {foreground = Screen.colors.Fuchsia};
  394. [14] = {background = Screen.colors.Red1, foreground = Screen.colors.Black};
  395. [15] = {background = Screen.colors.Red1, foreground = tonumber('0xb20000')};
  396. [16] = {blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1};
  397. [17] = {bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey};
  398. [18] = {background = Screen.colors.LightGrey};
  399. [19] = {foreground = Screen.colors.Cyan4, background = Screen.colors.LightGrey};
  400. [20] = {foreground = tonumber('0x180606'), background = tonumber('0xf13f3f')};
  401. [21] = {foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f')};
  402. [22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')};
  403. [23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey};
  404. [24] = {bold = true};
  405. }
  406. ns = meths.create_namespace 'test'
  407. end)
  408. local example_text = [[
  409. for _,item in ipairs(items) do
  410. local text, hl_id_cell, count = unpack(item)
  411. if hl_id_cell ~= nil then
  412. hl_id = hl_id_cell
  413. end
  414. for _ = 1, (count or 1) do
  415. local cell = line[colpos]
  416. cell.text = text
  417. cell.hl_id = hl_id
  418. colpos = colpos+1
  419. end
  420. end]]
  421. it('can have virtual text of overlay position', function()
  422. insert(example_text)
  423. feed 'gg'
  424. for i = 1,9 do
  425. meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'})
  426. if i == 3 or (i >= 6 and i <= 9) then
  427. meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'})
  428. end
  429. end
  430. meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'})
  431. -- can "float" beyond end of line
  432. meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
  433. -- bound check: right edge of window
  434. meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
  435. screen:expect{grid=[[
  436. ^for _,item in ipairs(items) do |
  437. {2:|} local text, hl_id_cell, count = unpack(item) |
  438. {2:|} if hl_id_cell ~= nil tbork bork bork {4:bork bork}|
  439. {2:|} {1:|} hl_id = hl_id_cell |
  440. {2:|} end |
  441. {2:|} for _ = 1, (count or 1) {4:loopy} |
  442. {2:|} {1:|} local cell = line[colpos] |
  443. {2:|} {1:|} cell.text = text |
  444. {2:|} {1:|} cell.hl_id = hl_id |
  445. {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 |
  446. end |
  447. end |
  448. {1:~ }|
  449. {1:~ }|
  450. |
  451. ]]}
  452. -- handles broken lines
  453. screen:try_resize(22, 25)
  454. screen:expect{grid=[[
  455. ^for _,item in ipairs(i|
  456. tems) do |
  457. {2:|} local text, hl_id_|
  458. cell, count = unpack(i|
  459. tem) |
  460. {2:|} if hl_id_cell ~= n|
  461. il tbork bork bork {4:bor}|
  462. {2:|} {1:|} hl_id = hl_id_|
  463. cell |
  464. {2:|} end |
  465. {2:|} for _ = 1, (count |
  466. or 1) {4:loopy} |
  467. {2:|} {1:|} local cell = l|
  468. ine[colpos] |
  469. {2:|} {1:|} cell.text = te|
  470. xt |
  471. {2:|} {1:|} cell.hl_id = h|
  472. l_id |
  473. {2:|} {1:|} cofoo{3:bar}{4:!!}olpo|
  474. s+1 |
  475. end |
  476. end |
  477. {1:~ }|
  478. {1:~ }|
  479. |
  480. ]]}
  481. end)
  482. it('can have virtual text of overlay position and styling', function()
  483. insert(example_text)
  484. feed 'gg'
  485. command 'set ft=lua'
  486. command 'syntax on'
  487. screen:expect{grid=[[
  488. {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
  489. {5:local} text, hl_id_cell, count = unpack(item) |
  490. {5:if} hl_id_cell ~= {13:nil} {5:then} |
  491. hl_id = hl_id_cell |
  492. {5:end} |
  493. {5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do} |
  494. {5:local} cell = line[colpos] |
  495. cell.text = text |
  496. cell.hl_id = hl_id |
  497. colpos = colpos+{13:1} |
  498. {5:end} |
  499. {5:end} |
  500. {1:~ }|
  501. {1:~ }|
  502. |
  503. ]]}
  504. command 'hi Blendy guibg=Red blend=30'
  505. meths.buf_set_extmark(0, ns, 1, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend'})
  506. meths.buf_set_extmark(0, ns, 2, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine'})
  507. meths.buf_set_extmark(0, ns, 3, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace'})
  508. meths.buf_set_extmark(0, ns, 4, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend', virt_text_hide=true})
  509. meths.buf_set_extmark(0, ns, 5, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine', virt_text_hide=true})
  510. meths.buf_set_extmark(0, ns, 6, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace', virt_text_hide=true})
  511. screen:expect{grid=[[
  512. {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
  513. {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) |
  514. {5:i}{12:c}{11:ombining color} {13:nil} {5:then} |
  515. {11:replacing color}d_cell |
  516. {5:e}{8:bl}{14:endy}{15:i}{14:text}{15:o}{14:-}{15:o}{14:h}{7:ere} |
  517. {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
  518. {11:replacing color} line[colpos] |
  519. cell.text = text |
  520. cell.hl_id = hl_id |
  521. colpos = colpos+{13:1} |
  522. {5:end} |
  523. {5:end} |
  524. {1:~ }|
  525. {1:~ }|
  526. |
  527. ]]}
  528. feed 'V5G'
  529. screen:expect{grid=[[
  530. {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
  531. {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
  532. {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
  533. {18: }{11:replacing color}{18:d_cell} |
  534. {18: }{5:^e}{17:nd} |
  535. {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
  536. {11:replacing color} line[colpos] |
  537. cell.text = text |
  538. cell.hl_id = hl_id |
  539. colpos = colpos+{13:1} |
  540. {5:end} |
  541. {5:end} |
  542. {1:~ }|
  543. {1:~ }|
  544. {24:-- VISUAL LINE --} |
  545. ]]}
  546. feed 'jj'
  547. screen:expect{grid=[[
  548. {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
  549. {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
  550. {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
  551. {18: }{11:replacing color}{18:d_cell} |
  552. {18: }{17:end} |
  553. {18: }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} |
  554. {18: }^ {18: }{17:local}{18: cell = line[colpos]} |
  555. cell.text = text |
  556. cell.hl_id = hl_id |
  557. colpos = colpos+{13:1} |
  558. {5:end} |
  559. {5:end} |
  560. {1:~ }|
  561. {1:~ }|
  562. {24:-- VISUAL LINE --} |
  563. ]]}
  564. end)
  565. it('can have virtual text of fixed win_col position', function()
  566. insert(example_text)
  567. feed 'gg'
  568. meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
  569. meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
  570. meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
  571. meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
  572. screen:expect{grid=[[
  573. ^for _,item in ipairs(items) do |
  574. local text, hl_id_cell, cou{4:Very} unpack(item) |
  575. if hl_id_cell ~= nil then {4:Much} |
  576. hl_id = hl_id_cell {4:Error} |
  577. end |
  578. for _ = 1, (count or 1) do |
  579. local cell = line[colpos] |
  580. {1:-} cell.text = text |
  581. cell.hl_id = hl_id |
  582. colpos = colpos+1 |
  583. end |
  584. end |
  585. {1:~ }|
  586. {1:~ }|
  587. |
  588. ]]}
  589. feed '3G12|i<cr><esc>'
  590. screen:expect{grid=[[
  591. for _,item in ipairs(items) do |
  592. local text, hl_id_cell, cou{4:Very} unpack(item) |
  593. if hl_i {4:Much} |
  594. ^d_cell ~= nil then |
  595. hl_id = hl_id_cell {4:Error} |
  596. end |
  597. for _ = 1, (count or 1) do |
  598. local cell = line[colpos] |
  599. {1:-} cell.text = text |
  600. cell.hl_id = hl_id |
  601. colpos = colpos+1 |
  602. end |
  603. end |
  604. {1:~ }|
  605. |
  606. ]]}
  607. feed 'u:<cr>'
  608. screen:expect{grid=[[
  609. for _,item in ipairs(items) do |
  610. local text, hl_id_cell, cou{4:Very} unpack(item) |
  611. if hl_i^d_cell ~= nil then {4:Much} |
  612. hl_id = hl_id_cell {4:Error} |
  613. end |
  614. for _ = 1, (count or 1) do |
  615. local cell = line[colpos] |
  616. {1:-} cell.text = text |
  617. cell.hl_id = hl_id |
  618. colpos = colpos+1 |
  619. end |
  620. end |
  621. {1:~ }|
  622. {1:~ }|
  623. : |
  624. ]]}
  625. feed '8|i<cr><esc>'
  626. screen:expect{grid=[[
  627. for _,item in ipairs(items) do |
  628. local text, hl_id_cell, cou{4:Very} unpack(item) |
  629. if |
  630. ^hl_id_cell ~= nil then {4:Much} |
  631. hl_id = hl_id_cell {4:Error} |
  632. end |
  633. for _ = 1, (count or 1) do |
  634. local cell = line[colpos] |
  635. {1:-} cell.text = text |
  636. cell.hl_id = hl_id |
  637. colpos = colpos+1 |
  638. end |
  639. end |
  640. {1:~ }|
  641. |
  642. ]]}
  643. end)
  644. it('does not crash when deleting a cleared buffer #15212', function()
  645. exec_lua [[
  646. ns = vim.api.nvim_create_namespace("myplugin")
  647. vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0})
  648. ]]
  649. screen:expect{grid=[[
  650. ^ a |
  651. {1:~ }|
  652. {1:~ }|
  653. {1:~ }|
  654. {1:~ }|
  655. {1:~ }|
  656. {1:~ }|
  657. {1:~ }|
  658. {1:~ }|
  659. {1:~ }|
  660. {1:~ }|
  661. {1:~ }|
  662. {1:~ }|
  663. {1:~ }|
  664. |
  665. ]]}
  666. exec_lua [[
  667. vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
  668. vim.cmd("bdelete")
  669. ]]
  670. screen:expect{grid=[[
  671. ^ |
  672. {1:~ }|
  673. {1:~ }|
  674. {1:~ }|
  675. {1:~ }|
  676. {1:~ }|
  677. {1:~ }|
  678. {1:~ }|
  679. {1:~ }|
  680. {1:~ }|
  681. {1:~ }|
  682. {1:~ }|
  683. {1:~ }|
  684. {1:~ }|
  685. |
  686. ]]}
  687. helpers.assert_alive()
  688. end)
  689. end)