highlight_spec.lua 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local clear = n.clear
  5. local eq, eval = t.eq, n.eval
  6. local command = n.command
  7. local exec_capture = n.exec_capture
  8. local api = n.api
  9. local fn = n.fn
  10. local pcall_err = t.pcall_err
  11. local ok = t.ok
  12. local assert_alive = n.assert_alive
  13. describe('API: highlight', function()
  14. clear()
  15. Screen.new() -- initialize Screen.colors
  16. local expected_rgb = {
  17. background = Screen.colors.Yellow,
  18. foreground = Screen.colors.Red,
  19. special = Screen.colors.Blue,
  20. bold = true,
  21. }
  22. local expected_cterm = {
  23. background = 10,
  24. underline = true,
  25. }
  26. local expected_rgb2 = {
  27. background = Screen.colors.Yellow,
  28. foreground = Screen.colors.Red,
  29. special = Screen.colors.Blue,
  30. bold = true,
  31. italic = true,
  32. reverse = true,
  33. underline = true,
  34. strikethrough = true,
  35. altfont = true,
  36. nocombine = true,
  37. }
  38. local expected_undercurl = {
  39. background = Screen.colors.Yellow,
  40. foreground = Screen.colors.Red,
  41. special = Screen.colors.Blue,
  42. undercurl = true,
  43. }
  44. before_each(function()
  45. clear()
  46. command(
  47. 'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold'
  48. )
  49. end)
  50. it('nvim_get_hl_by_id', function()
  51. local hl_id = eval("hlID('NewHighlight')")
  52. eq(expected_cterm, api.nvim_get_hl_by_id(hl_id, false))
  53. hl_id = eval("hlID('NewHighlight')")
  54. -- Test valid id.
  55. eq(expected_rgb, api.nvim_get_hl_by_id(hl_id, true))
  56. -- Test invalid id.
  57. eq('Invalid highlight id: 30000', pcall_err(api.nvim_get_hl_by_id, 30000, false))
  58. -- Test all highlight properties.
  59. command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
  60. eq(expected_rgb2, api.nvim_get_hl_by_id(hl_id, true))
  61. -- Test undercurl
  62. command('hi NewHighlight gui=undercurl')
  63. eq(expected_undercurl, api.nvim_get_hl_by_id(hl_id, true))
  64. -- Test nil argument.
  65. eq(
  66. 'Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer',
  67. pcall_err(api.nvim_get_hl_by_id, { nil }, false)
  68. )
  69. -- Test 0 argument.
  70. eq('Invalid highlight id: 0', pcall_err(api.nvim_get_hl_by_id, 0, false))
  71. -- Test -1 argument.
  72. eq('Invalid highlight id: -1', pcall_err(api.nvim_get_hl_by_id, -1, false))
  73. -- Test highlight group without ctermbg value.
  74. command('hi Normal ctermfg=red ctermbg=yellow')
  75. command('hi NewConstant ctermfg=green guifg=white guibg=blue')
  76. hl_id = eval("hlID('NewConstant')")
  77. eq({ foreground = 10 }, api.nvim_get_hl_by_id(hl_id, false))
  78. -- Test highlight group without ctermfg value.
  79. command('hi clear NewConstant')
  80. command('hi NewConstant ctermbg=Magenta guifg=white guibg=blue')
  81. eq({ background = 13 }, api.nvim_get_hl_by_id(hl_id, false))
  82. -- Test highlight group with ctermfg and ctermbg values.
  83. command('hi clear NewConstant')
  84. command('hi NewConstant ctermfg=green ctermbg=Magenta guifg=white guibg=blue')
  85. eq({ foreground = 10, background = 13 }, api.nvim_get_hl_by_id(hl_id, false))
  86. end)
  87. it('nvim_get_hl_by_name', function()
  88. local expected_normal = { background = Screen.colors.Yellow, foreground = Screen.colors.Red }
  89. -- Test `Normal` default values.
  90. eq({}, api.nvim_get_hl_by_name('Normal', true))
  91. eq(expected_cterm, api.nvim_get_hl_by_name('NewHighlight', false))
  92. eq(expected_rgb, api.nvim_get_hl_by_name('NewHighlight', true))
  93. -- Test `Normal` modified values.
  94. command('hi Normal guifg=red guibg=yellow')
  95. eq(expected_normal, api.nvim_get_hl_by_name('Normal', true))
  96. -- Test invalid name.
  97. eq(
  98. "Invalid highlight name: 'unknown_highlight'",
  99. pcall_err(api.nvim_get_hl_by_name, 'unknown_highlight', false)
  100. )
  101. -- Test nil argument.
  102. eq(
  103. 'Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String',
  104. pcall_err(api.nvim_get_hl_by_name, { nil }, false)
  105. )
  106. -- Test empty string argument.
  107. eq('Invalid highlight name', pcall_err(api.nvim_get_hl_by_name, '', false))
  108. -- Test "standout" attribute. #8054
  109. eq({ underline = true }, api.nvim_get_hl_by_name('cursorline', 0))
  110. command('hi CursorLine cterm=standout,underline term=standout,underline gui=standout,underline')
  111. command('set cursorline')
  112. eq({ underline = true, standout = true }, api.nvim_get_hl_by_name('cursorline', 0))
  113. -- Test cterm & Normal values. #18024 (tail) & #18980
  114. -- Ensure Normal, and groups that match Normal return their fg & bg cterm values
  115. api.nvim_set_hl(0, 'Normal', { ctermfg = 17, ctermbg = 213 })
  116. api.nvim_set_hl(0, 'NotNormal', { ctermfg = 17, ctermbg = 213, nocombine = true })
  117. -- Note colors are "cterm" values, not rgb-as-ints
  118. eq({ foreground = 17, background = 213 }, api.nvim_get_hl_by_name('Normal', false))
  119. eq(
  120. { foreground = 17, background = 213, nocombine = true },
  121. api.nvim_get_hl_by_name('NotNormal', false)
  122. )
  123. end)
  124. it('nvim_get_hl_id_by_name', function()
  125. -- precondition: use a hl group that does not yet exist
  126. eq("Invalid highlight name: 'Shrubbery'", pcall_err(api.nvim_get_hl_by_name, 'Shrubbery', true))
  127. eq(0, fn.hlID('Shrubbery'))
  128. local hl_id = api.nvim_get_hl_id_by_name('Shrubbery')
  129. ok(hl_id > 0)
  130. eq(hl_id, fn.hlID('Shrubbery'))
  131. command('hi Shrubbery guifg=#888888 guibg=#888888')
  132. eq(
  133. { foreground = tonumber('0x888888'), background = tonumber('0x888888') },
  134. api.nvim_get_hl_by_id(hl_id, true)
  135. )
  136. eq(
  137. { foreground = tonumber('0x888888'), background = tonumber('0x888888') },
  138. api.nvim_get_hl_by_name('Shrubbery', true)
  139. )
  140. end)
  141. it("nvim_buf_add_highlight to other buffer doesn't crash if undo is disabled #12873", function()
  142. command('vsplit file')
  143. local err, _ = pcall(api.nvim_set_option_value, 'undofile', false, { buf = 1 })
  144. eq(true, err)
  145. err, _ = pcall(api.nvim_set_option_value, 'undolevels', -1, { buf = 1 })
  146. eq(true, err)
  147. err, _ = pcall(api.nvim_buf_add_highlight, 1, -1, 'Question', 0, 0, -1)
  148. eq(true, err)
  149. assert_alive()
  150. end)
  151. end)
  152. describe('API: set highlight', function()
  153. local highlight_color = {
  154. fg = tonumber('0xff0000'),
  155. bg = tonumber('0x0032aa'),
  156. ctermfg = 8,
  157. ctermbg = 15,
  158. }
  159. local highlight1 = {
  160. background = highlight_color.bg,
  161. foreground = highlight_color.fg,
  162. bold = true,
  163. italic = true,
  164. }
  165. local highlight2_config = {
  166. ctermbg = highlight_color.ctermbg,
  167. ctermfg = highlight_color.ctermfg,
  168. underline = true,
  169. reverse = true,
  170. }
  171. local highlight2_result = {
  172. background = highlight_color.ctermbg,
  173. foreground = highlight_color.ctermfg,
  174. underline = true,
  175. reverse = true,
  176. }
  177. local highlight3_config = {
  178. background = highlight_color.bg,
  179. foreground = highlight_color.fg,
  180. ctermbg = highlight_color.ctermbg,
  181. ctermfg = highlight_color.ctermfg,
  182. bold = true,
  183. italic = true,
  184. reverse = true,
  185. underdashed = true,
  186. strikethrough = true,
  187. altfont = true,
  188. cterm = {
  189. italic = true,
  190. reverse = true,
  191. strikethrough = true,
  192. altfont = true,
  193. nocombine = true,
  194. },
  195. }
  196. local highlight3_result_gui = {
  197. background = highlight_color.bg,
  198. foreground = highlight_color.fg,
  199. bold = true,
  200. italic = true,
  201. reverse = true,
  202. underdashed = true,
  203. strikethrough = true,
  204. altfont = true,
  205. }
  206. local highlight3_result_cterm = {
  207. background = highlight_color.ctermbg,
  208. foreground = highlight_color.ctermfg,
  209. italic = true,
  210. reverse = true,
  211. strikethrough = true,
  212. altfont = true,
  213. nocombine = true,
  214. }
  215. local function get_ns()
  216. local ns = api.nvim_create_namespace('Test_set_hl')
  217. api.nvim_set_hl_ns(ns)
  218. return ns
  219. end
  220. before_each(clear)
  221. it('validation', function()
  222. eq(
  223. "Invalid 'blend': out of range",
  224. pcall_err(api.nvim_set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = 999 })
  225. )
  226. eq(
  227. "Invalid 'blend': expected Integer, got Array",
  228. pcall_err(api.nvim_set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = {} })
  229. )
  230. end)
  231. it('can set gui highlight', function()
  232. local ns = get_ns()
  233. api.nvim_set_hl(ns, 'Test_hl', highlight1)
  234. eq(highlight1, api.nvim_get_hl_by_name('Test_hl', true))
  235. end)
  236. it('can set cterm highlight', function()
  237. local ns = get_ns()
  238. api.nvim_set_hl(ns, 'Test_hl', highlight2_config)
  239. eq(highlight2_result, api.nvim_get_hl_by_name('Test_hl', false))
  240. end)
  241. it('can set empty cterm attr', function()
  242. local ns = get_ns()
  243. api.nvim_set_hl(ns, 'Test_hl', { cterm = {} })
  244. eq({}, api.nvim_get_hl_by_name('Test_hl', false))
  245. end)
  246. it('cterm attr defaults to gui attr', function()
  247. local ns = get_ns()
  248. api.nvim_set_hl(ns, 'Test_hl', highlight1)
  249. eq({
  250. bold = true,
  251. italic = true,
  252. }, api.nvim_get_hl_by_name('Test_hl', false))
  253. end)
  254. it('can overwrite attr for cterm', function()
  255. local ns = get_ns()
  256. api.nvim_set_hl(ns, 'Test_hl', highlight3_config)
  257. eq(highlight3_result_gui, api.nvim_get_hl_by_name('Test_hl', true))
  258. eq(highlight3_result_cterm, api.nvim_get_hl_by_name('Test_hl', false))
  259. end)
  260. it('only allows one underline attribute #22371', function()
  261. local ns = get_ns()
  262. api.nvim_set_hl(ns, 'Test_hl', {
  263. underdouble = true,
  264. underdotted = true,
  265. cterm = {
  266. underline = true,
  267. undercurl = true,
  268. },
  269. })
  270. eq({ undercurl = true }, api.nvim_get_hl_by_name('Test_hl', false))
  271. eq({ underdotted = true }, api.nvim_get_hl_by_name('Test_hl', true))
  272. end)
  273. it('can set all underline cterm attributes #31385', function()
  274. local ns = get_ns()
  275. local attrs = { 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed' }
  276. for _, attr in ipairs(attrs) do
  277. api.nvim_set_hl(ns, 'Test_' .. attr, { cterm = { [attr] = true } })
  278. eq({ [attr] = true }, api.nvim_get_hl_by_name('Test_' .. attr, false))
  279. end
  280. end)
  281. it('can set a highlight in the global namespace', function()
  282. api.nvim_set_hl(0, 'Test_hl', highlight2_config)
  283. eq(
  284. 'Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse',
  285. exec_capture('highlight Test_hl')
  286. )
  287. api.nvim_set_hl(0, 'Test_hl', { background = highlight_color.bg })
  288. eq('Test_hl xxx guibg=#0032aa', exec_capture('highlight Test_hl'))
  289. api.nvim_set_hl(0, 'Test_hl2', highlight3_config)
  290. eq(
  291. 'Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underdashed,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa',
  292. exec_capture('highlight Test_hl2')
  293. )
  294. -- Colors are stored with the name they are defined, but
  295. -- with canonical casing
  296. api.nvim_set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue' })
  297. eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3'))
  298. end)
  299. it('can modify a highlight in the global namespace', function()
  300. api.nvim_set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue' })
  301. eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3'))
  302. api.nvim_set_hl(0, 'Test_hl3', { bg = 'red' })
  303. eq('Test_hl3 xxx guibg=Red', exec_capture('highlight Test_hl3'))
  304. api.nvim_set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12 })
  305. eq('Test_hl3 xxx ctermfg=12 ctermbg=9', exec_capture('highlight Test_hl3'))
  306. api.nvim_set_hl(0, 'Test_hl3', { ctermbg = 'red', ctermfg = 'blue' })
  307. eq('Test_hl3 xxx ctermfg=12 ctermbg=9', exec_capture('highlight Test_hl3'))
  308. api.nvim_set_hl(0, 'Test_hl3', { ctermbg = 9 })
  309. eq('Test_hl3 xxx ctermbg=9', exec_capture('highlight Test_hl3'))
  310. eq(
  311. "Invalid highlight color: 'redd'",
  312. pcall_err(api.nvim_set_hl, 0, 'Test_hl3', { fg = 'redd' })
  313. )
  314. eq(
  315. "Invalid highlight color: 'bleu'",
  316. pcall_err(api.nvim_set_hl, 0, 'Test_hl3', { ctermfg = 'bleu' })
  317. )
  318. api.nvim_set_hl(0, 'Test_hl3', { fg = '#FF00FF' })
  319. eq('Test_hl3 xxx guifg=#ff00ff', exec_capture('highlight Test_hl3'))
  320. eq(
  321. "Invalid highlight color: '#FF00FF'",
  322. pcall_err(api.nvim_set_hl, 0, 'Test_hl3', { ctermfg = '#FF00FF' })
  323. )
  324. for _, fg_val in ipairs { nil, 'NONE', 'nOnE', '', -1 } do
  325. api.nvim_set_hl(0, 'Test_hl3', { fg = fg_val })
  326. eq('Test_hl3 xxx cleared', exec_capture('highlight Test_hl3'))
  327. end
  328. api.nvim_set_hl(0, 'Test_hl3', { fg = '#FF00FF', blend = 50 })
  329. eq('Test_hl3 xxx guifg=#ff00ff blend=50', exec_capture('highlight Test_hl3'))
  330. end)
  331. it("correctly sets 'Normal' internal properties", function()
  332. -- Normal has some special handling internally. #18024
  333. api.nvim_set_hl(0, 'Normal', { fg = '#000083', bg = '#0000F3' })
  334. eq({ foreground = 131, background = 243 }, api.nvim_get_hl_by_name('Normal', true))
  335. end)
  336. it('does not segfault on invalid group name #20009', function()
  337. eq(
  338. "Invalid highlight name: 'foo bar'",
  339. pcall_err(api.nvim_set_hl, 0, 'foo bar', { bold = true })
  340. )
  341. assert_alive()
  342. end)
  343. end)
  344. describe('API: get highlight', function()
  345. local highlight_color = {
  346. fg = tonumber('0xff0000'),
  347. bg = tonumber('0x0032aa'),
  348. ctermfg = 8,
  349. ctermbg = 15,
  350. }
  351. local highlight1 = {
  352. bg = highlight_color.bg,
  353. fg = highlight_color.fg,
  354. bold = true,
  355. italic = true,
  356. cterm = { bold = true, italic = true },
  357. }
  358. local highlight2 = {
  359. ctermbg = highlight_color.ctermbg,
  360. ctermfg = highlight_color.ctermfg,
  361. underline = true,
  362. reverse = true,
  363. cterm = { underline = true, reverse = true },
  364. }
  365. local highlight3_config = {
  366. bg = highlight_color.bg,
  367. fg = highlight_color.fg,
  368. ctermbg = highlight_color.ctermbg,
  369. ctermfg = highlight_color.ctermfg,
  370. bold = true,
  371. italic = true,
  372. reverse = true,
  373. underdashed = true,
  374. strikethrough = true,
  375. altfont = true,
  376. cterm = {
  377. italic = true,
  378. reverse = true,
  379. strikethrough = true,
  380. altfont = true,
  381. nocombine = true,
  382. },
  383. }
  384. local highlight3_result = {
  385. bg = highlight_color.bg,
  386. fg = highlight_color.fg,
  387. ctermbg = highlight_color.ctermbg,
  388. ctermfg = highlight_color.ctermfg,
  389. bold = true,
  390. italic = true,
  391. reverse = true,
  392. underdashed = true,
  393. strikethrough = true,
  394. altfont = true,
  395. cterm = {
  396. italic = true,
  397. nocombine = true,
  398. reverse = true,
  399. strikethrough = true,
  400. altfont = true,
  401. },
  402. }
  403. local function get_ns()
  404. -- Test namespace filtering behavior
  405. local ns2 = api.nvim_create_namespace('Another_namespace')
  406. api.nvim_set_hl(ns2, 'Test_hl', { ctermfg = 23 })
  407. api.nvim_set_hl(ns2, 'Test_another_hl', { link = 'Test_hl' })
  408. api.nvim_set_hl(ns2, 'Test_hl_link', { link = 'Test_another_hl' })
  409. api.nvim_set_hl(ns2, 'Test_another_hl_link', { link = 'Test_hl_link' })
  410. local ns = api.nvim_create_namespace('Test_set_hl')
  411. api.nvim_set_hl_ns(ns)
  412. return ns
  413. end
  414. before_each(clear)
  415. it('validation', function()
  416. eq(
  417. "Invalid 'name': expected String, got Integer",
  418. pcall_err(api.nvim_get_hl, 0, { name = 177 })
  419. )
  420. eq('Highlight id out of bounds', pcall_err(api.nvim_get_hl, 0, { name = 'Test set hl' }))
  421. end)
  422. it('nvim_get_hl with create flag', function()
  423. eq({}, api.nvim_get_hl(0, { name = 'Foo', create = false }))
  424. eq(0, fn.hlexists('Foo'))
  425. api.nvim_get_hl(0, { name = 'Bar', create = true })
  426. eq(1, fn.hlexists('Bar'))
  427. api.nvim_get_hl(0, { name = 'FooBar' })
  428. eq(1, fn.hlexists('FooBar'))
  429. end)
  430. it('can get all highlights in current namespace', function()
  431. local ns = get_ns()
  432. api.nvim_set_hl(ns, 'Test_hl', { bg = '#B4BEFE' })
  433. api.nvim_set_hl(ns, 'Test_hl_link', { link = 'Test_hl' })
  434. eq({
  435. Test_hl = {
  436. bg = 11845374,
  437. },
  438. Test_hl_link = {
  439. link = 'Test_hl',
  440. },
  441. }, api.nvim_get_hl(ns, {}))
  442. end)
  443. it('can get gui highlight', function()
  444. local ns = get_ns()
  445. api.nvim_set_hl(ns, 'Test_hl', highlight1)
  446. eq(highlight1, api.nvim_get_hl(ns, { name = 'Test_hl' }))
  447. end)
  448. it('can get cterm highlight', function()
  449. local ns = get_ns()
  450. api.nvim_set_hl(ns, 'Test_hl', highlight2)
  451. eq(highlight2, api.nvim_get_hl(ns, { name = 'Test_hl' }))
  452. end)
  453. it('can get empty cterm attr', function()
  454. local ns = get_ns()
  455. api.nvim_set_hl(ns, 'Test_hl', { cterm = {} })
  456. eq({}, api.nvim_get_hl(ns, { name = 'Test_hl' }))
  457. end)
  458. it('cterm attr defaults to gui attr', function()
  459. local ns = get_ns()
  460. api.nvim_set_hl(ns, 'Test_hl', highlight1)
  461. eq(highlight1, api.nvim_get_hl(ns, { name = 'Test_hl' }))
  462. end)
  463. it('can overwrite attr for cterm', function()
  464. local ns = get_ns()
  465. api.nvim_set_hl(ns, 'Test_hl', highlight3_config)
  466. eq(highlight3_result, api.nvim_get_hl(ns, { name = 'Test_hl' }))
  467. end)
  468. it('only allows one underline attribute #22371', function()
  469. local ns = get_ns()
  470. api.nvim_set_hl(ns, 'Test_hl', {
  471. underdouble = true,
  472. underdotted = true,
  473. cterm = {
  474. underline = true,
  475. undercurl = true,
  476. },
  477. })
  478. eq(
  479. { underdotted = true, cterm = { undercurl = true } },
  480. api.nvim_get_hl(ns, { name = 'Test_hl' })
  481. )
  482. end)
  483. it('can get a highlight in the global namespace', function()
  484. api.nvim_set_hl(0, 'Test_hl', highlight2)
  485. eq(highlight2, api.nvim_get_hl(0, { name = 'Test_hl' }))
  486. api.nvim_set_hl(0, 'Test_hl', { background = highlight_color.bg })
  487. eq({
  488. bg = 12970,
  489. }, api.nvim_get_hl(0, { name = 'Test_hl' }))
  490. api.nvim_set_hl(0, 'Test_hl2', highlight3_config)
  491. eq(highlight3_result, api.nvim_get_hl(0, { name = 'Test_hl2' }))
  492. -- Colors are stored with the name they are defined, but
  493. -- with canonical casing
  494. api.nvim_set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue' })
  495. eq({
  496. bg = 16711680,
  497. fg = 255,
  498. }, api.nvim_get_hl(0, { name = 'Test_hl3' }))
  499. end)
  500. it('nvim_get_hl by id', function()
  501. local hl_id = api.nvim_get_hl_id_by_name('NewHighlight')
  502. command(
  503. 'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold'
  504. )
  505. eq({
  506. fg = 16711680,
  507. bg = 16776960,
  508. sp = 255,
  509. bold = true,
  510. ctermbg = 10,
  511. cterm = { underline = true },
  512. }, api.nvim_get_hl(0, { id = hl_id }))
  513. -- Test 0 argument
  514. eq('Highlight id out of bounds', pcall_err(api.nvim_get_hl, 0, { id = 0 }))
  515. eq(
  516. "Invalid 'id': expected Integer, got String",
  517. pcall_err(api.nvim_get_hl, 0, { id = 'Test_set_hl' })
  518. )
  519. -- Test all highlight properties.
  520. command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
  521. eq({
  522. fg = 16711680,
  523. bg = 16776960,
  524. sp = 255,
  525. altfont = true,
  526. bold = true,
  527. italic = true,
  528. nocombine = true,
  529. reverse = true,
  530. strikethrough = true,
  531. underline = true,
  532. ctermbg = 10,
  533. cterm = { underline = true },
  534. }, api.nvim_get_hl(0, { id = hl_id }))
  535. -- Test undercurl
  536. command('hi NewHighlight gui=undercurl')
  537. eq({
  538. fg = 16711680,
  539. bg = 16776960,
  540. sp = 255,
  541. undercurl = true,
  542. ctermbg = 10,
  543. cterm = { underline = true },
  544. }, api.nvim_get_hl(0, { id = hl_id }))
  545. end)
  546. it('can correctly detect links', function()
  547. command('hi String guifg=#a6e3a1 ctermfg=NONE')
  548. command('hi link @string string')
  549. command('hi link @string.cpp @string')
  550. eq({ fg = 10937249 }, api.nvim_get_hl(0, { name = 'String' }))
  551. eq({ link = 'String' }, api.nvim_get_hl(0, { name = '@string' }))
  552. eq({ fg = 10937249 }, api.nvim_get_hl(0, { name = '@string.cpp', link = false }))
  553. end)
  554. it('can get all attributes for a linked group', function()
  555. command('hi Bar guifg=red')
  556. command('hi Foo guifg=#00ff00 gui=bold,underline')
  557. command('hi! link Foo Bar')
  558. eq(
  559. { link = 'Bar', fg = tonumber('00ff00', 16), bold = true, underline = true },
  560. api.nvim_get_hl(0, { name = 'Foo', link = true })
  561. )
  562. end)
  563. it('can set link as well as other attributes', function()
  564. command('hi Bar guifg=red')
  565. local hl = { link = 'Bar', fg = tonumber('00ff00', 16), bold = true, cterm = { bold = true } }
  566. api.nvim_set_hl(0, 'Foo', hl)
  567. eq(hl, api.nvim_get_hl(0, { name = 'Foo', link = true }))
  568. end)
  569. it("doesn't contain unset groups", function()
  570. local id = api.nvim_get_hl_id_by_name '@foobar.hubbabubba'
  571. ok(id > 0)
  572. local data = api.nvim_get_hl(0, {})
  573. eq(nil, data['@foobar.hubbabubba'])
  574. eq(nil, data['@foobar'])
  575. command 'hi @foobar.hubbabubba gui=bold'
  576. data = api.nvim_get_hl(0, {})
  577. eq({ bold = true }, data['@foobar.hubbabubba'])
  578. eq(nil, data['@foobar'])
  579. -- @foobar.hubbabubba was explicitly cleared and thus shows up
  580. -- but @foobar was never touched, and thus doesn't
  581. command 'hi clear @foobar.hubbabubba'
  582. data = api.nvim_get_hl(0, {})
  583. eq({}, data['@foobar.hubbabubba'])
  584. eq(nil, data['@foobar'])
  585. end)
  586. it('should return default flag', function()
  587. api.nvim_set_hl(0, 'Tried', { fg = '#00ff00', default = true })
  588. eq({ fg = tonumber('00ff00', 16), default = true }, api.nvim_get_hl(0, { name = 'Tried' }))
  589. end)
  590. it('should not output empty gui and cterm #23474', function()
  591. api.nvim_set_hl(0, 'Foo', { default = true })
  592. api.nvim_set_hl(0, 'Bar', { default = true, fg = '#ffffff' })
  593. api.nvim_set_hl(0, 'FooBar', { default = true, fg = '#ffffff', cterm = { bold = true } })
  594. api.nvim_set_hl(
  595. 0,
  596. 'FooBarA',
  597. { default = true, fg = '#ffffff', cterm = { bold = true, italic = true } }
  598. )
  599. eq('Foo xxx cleared', exec_capture('highlight Foo'))
  600. eq({ default = true }, api.nvim_get_hl(0, { name = 'Foo' }))
  601. eq('Bar xxx guifg=#ffffff', exec_capture('highlight Bar'))
  602. eq('FooBar xxx cterm=bold guifg=#ffffff', exec_capture('highlight FooBar'))
  603. eq('FooBarA xxx cterm=bold,italic guifg=#ffffff', exec_capture('highlight FooBarA'))
  604. end)
  605. it('can override exist highlight group by force #20323', function()
  606. local white = tonumber('ffffff', 16)
  607. local green = tonumber('00ff00', 16)
  608. api.nvim_set_hl(0, 'Foo', { fg = white })
  609. api.nvim_set_hl(0, 'Foo', { fg = green, force = true })
  610. eq({ fg = green }, api.nvim_get_hl(0, { name = 'Foo' }))
  611. api.nvim_set_hl(0, 'Bar', { link = 'Comment', default = true })
  612. api.nvim_set_hl(0, 'Bar', { link = 'Foo', default = true, force = true })
  613. eq({ link = 'Foo', default = true }, api.nvim_get_hl(0, { name = 'Bar' }))
  614. end)
  615. end)
  616. describe('API: set/get highlight namespace', function()
  617. it('set/get highlight namespace', function()
  618. eq(0, api.nvim_get_hl_ns({}))
  619. local ns = api.nvim_create_namespace('')
  620. api.nvim_set_hl_ns(ns)
  621. eq(ns, api.nvim_get_hl_ns({}))
  622. end)
  623. it('set/get window highlight namespace', function()
  624. eq(-1, api.nvim_get_hl_ns({ winid = 0 }))
  625. local ns = api.nvim_create_namespace('')
  626. api.nvim_win_set_hl_ns(0, ns)
  627. eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
  628. end)
  629. it('setting namespace takes priority over &winhighlight', function()
  630. command('set winhighlight=Visual:Search')
  631. n.insert('foobar')
  632. local ns = api.nvim_create_namespace('')
  633. api.nvim_win_set_hl_ns(0, ns)
  634. eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
  635. command('enew') -- switching buffer keeps namespace #30904
  636. eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
  637. command('set winhighlight=')
  638. eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
  639. command('set winhighlight=Visual:Search')
  640. eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
  641. end)
  642. end)