highlight_spec.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local tt = require('test.functional.testterm')
  5. local feed, clear = n.feed, n.clear
  6. local api = n.api
  7. local testprg, command = n.testprg, n.command
  8. local fn = n.fn
  9. local nvim_set = n.nvim_set
  10. local is_os = t.is_os
  11. local skip = t.skip
  12. describe(':terminal highlight', function()
  13. local screen
  14. before_each(function()
  15. clear()
  16. screen = Screen.new(50, 7, { rgb = false })
  17. screen:set_default_attr_ids({
  18. [1] = { foreground = 45 },
  19. [2] = { background = 46 },
  20. [3] = { foreground = 45, background = 46 },
  21. [4] = { bold = true, italic = true, underline = true, strikethrough = true },
  22. [5] = { bold = true },
  23. [6] = { foreground = 12 },
  24. [7] = { bold = true, reverse = true },
  25. [8] = { background = 11 },
  26. [9] = { foreground = 130 },
  27. [10] = { reverse = true },
  28. [11] = { background = 11 },
  29. [12] = { bold = true, underdouble = true },
  30. [13] = { italic = true, undercurl = true },
  31. })
  32. command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
  33. feed('i')
  34. screen:expect([[
  35. tty ready |
  36. ^ |
  37. |*4
  38. {5:-- TERMINAL --} |
  39. ]])
  40. end)
  41. local function descr(title, attr_num, set_attrs_fn)
  42. local function sub(s)
  43. local str = s:gsub('NUM', attr_num)
  44. return str
  45. end
  46. describe(title, function()
  47. before_each(function()
  48. set_attrs_fn()
  49. tt.feed_data('text')
  50. tt.clear_attrs()
  51. tt.feed_data('text')
  52. end)
  53. local function pass_attrs()
  54. skip(is_os('win'))
  55. screen:expect(sub([[
  56. tty ready |
  57. {NUM:text}text^ |
  58. |*4
  59. {5:-- TERMINAL --} |
  60. ]]))
  61. end
  62. it('will pass the corresponding attributes', pass_attrs)
  63. it('will pass the corresponding attributes on scrollback', function()
  64. skip(is_os('win'))
  65. pass_attrs()
  66. local lines = {}
  67. for i = 1, 8 do
  68. table.insert(lines, 'line' .. tostring(i))
  69. end
  70. table.insert(lines, '')
  71. tt.feed_data(lines)
  72. screen:expect([[
  73. line4 |
  74. line5 |
  75. line6 |
  76. line7 |
  77. line8 |
  78. ^ |
  79. {5:-- TERMINAL --} |
  80. ]])
  81. feed('<c-\\><c-n>gg')
  82. screen:expect(sub([[
  83. ^tty ready |
  84. {NUM:text}textline1 |
  85. line2 |
  86. line3 |
  87. line4 |
  88. line5 |
  89. |
  90. ]]))
  91. end)
  92. end)
  93. end
  94. descr('foreground', 1, function()
  95. tt.set_fg(45)
  96. end)
  97. descr('background', 2, function()
  98. tt.set_bg(46)
  99. end)
  100. descr('foreground and background', 3, function()
  101. tt.set_fg(45)
  102. tt.set_bg(46)
  103. end)
  104. descr('bold, italics, underline and strikethrough', 4, function()
  105. tt.set_bold()
  106. tt.set_italic()
  107. tt.set_underline()
  108. tt.set_strikethrough()
  109. end)
  110. descr('bold and underdouble', 12, function()
  111. tt.set_bold()
  112. tt.set_underdouble()
  113. end)
  114. descr('italics and undercurl', 13, function()
  115. tt.set_italic()
  116. tt.set_undercurl()
  117. end)
  118. end)
  119. it(':terminal highlight has lower precedence than editor #9964', function()
  120. clear()
  121. local screen = Screen.new(30, 4, { rgb = true })
  122. screen:set_default_attr_ids({
  123. -- "Normal" highlight emitted by the child nvim process.
  124. N_child = {
  125. foreground = tonumber('0x4040ff'),
  126. background = tonumber('0xffff40'),
  127. fg_indexed = true,
  128. bg_indexed = true,
  129. },
  130. -- "Search" highlight in the parent nvim process.
  131. S = { background = Screen.colors.Green, italic = true, foreground = Screen.colors.Red },
  132. -- "Question" highlight in the parent nvim process.
  133. -- note: bg is indexed as it comes from the (cterm) child, while fg isn't as it comes from (rgb) parent
  134. Q = {
  135. background = tonumber('0xffff40'),
  136. bold = true,
  137. foreground = Screen.colors.SeaGreen4,
  138. bg_indexed = true,
  139. },
  140. })
  141. -- Child nvim process in :terminal (with cterm colors).
  142. fn.jobstart({
  143. n.nvim_prog,
  144. '-n',
  145. '-u',
  146. 'NORC',
  147. '-i',
  148. 'NONE',
  149. '--cmd',
  150. nvim_set .. ' notermguicolors',
  151. '+hi Normal ctermfg=Blue ctermbg=Yellow',
  152. '+norm! ichild nvim',
  153. '+norm! oline 2',
  154. }, {
  155. term = true,
  156. env = {
  157. VIMRUNTIME = os.getenv('VIMRUNTIME'),
  158. },
  159. })
  160. screen:expect([[
  161. {N_child:^child nvim }|
  162. {N_child:line 2 }|
  163. {N_child: }|
  164. |
  165. ]])
  166. command('hi Search gui=italic guifg=Red guibg=Green cterm=italic ctermfg=Red ctermbg=Green')
  167. feed('/nvim<cr>')
  168. screen:expect([[
  169. {N_child:child }{S:^nvim}{N_child: }|
  170. {N_child:line 2 }|
  171. {N_child: }|
  172. /nvim |
  173. ]])
  174. command('syntax keyword Question line')
  175. screen:expect([[
  176. {N_child:child }{S:^nvim}{N_child: }|
  177. {Q:line}{N_child: 2 }|
  178. {N_child: }|
  179. /nvim |
  180. ]])
  181. end)
  182. it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', function()
  183. clear()
  184. local screen = Screen.new(50, 7)
  185. screen:set_default_attr_ids({
  186. [1] = { background = Screen.colors.Grey90 }, -- CursorLine, CursorColumn
  187. [2] = { reverse = true },
  188. [3] = { bold = true }, -- ModeMsg
  189. [4] = { background = Screen.colors.Grey90, reverse = true },
  190. [5] = { background = Screen.colors.Red },
  191. })
  192. command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
  193. screen:expect([[
  194. ^tty ready |
  195. |*6
  196. ]])
  197. tt.feed_data((' foobar'):rep(30))
  198. screen:expect([[
  199. ^tty ready |
  200. foobar foobar foobar foobar foobar foobar foobar |
  201. foobar foobar foobar foobar foobar foobar foobar f|
  202. oobar foobar foobar foobar foobar foobar foobar fo|
  203. obar foobar foobar foobar foobar foobar foobar foo|
  204. bar foobar |
  205. |
  206. ]])
  207. command('set cursorline cursorcolumn')
  208. feed('j10w')
  209. screen:expect([[
  210. tty ready {1: } |
  211. foobar foobar{1: }foobar foobar foobar foobar foobar |
  212. {1:foobar foobar ^foobar foobar foobar foobar foobar f}|
  213. oobar foobar f{1:o}obar foobar foobar foobar foobar fo|
  214. obar foobar fo{1:o}bar foobar foobar foobar foobar foo|
  215. bar foobar {1: } |
  216. |
  217. ]])
  218. -- Entering terminal mode disables 'cursorline' and 'cursorcolumn'.
  219. feed('i')
  220. screen:expect([[
  221. tty ready |
  222. foobar foobar foobar foobar foobar foobar foobar |
  223. foobar foobar foobar foobar foobar foobar foobar f|
  224. oobar foobar foobar foobar foobar foobar foobar fo|
  225. obar foobar foobar foobar foobar foobar foobar foo|
  226. bar foobar^ |
  227. {3:-- TERMINAL --} |
  228. ]])
  229. -- Leaving terminal mode restores old values.
  230. feed([[<C-\><C-N>]])
  231. screen:expect([[
  232. tty ready{1: } |
  233. foobar f{1:o}obar foobar foobar foobar foobar foobar |
  234. foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
  235. oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
  236. obar foob{1:a}r foobar foobar foobar foobar foobar foo|
  237. {1:bar fooba^r }|
  238. |
  239. ]])
  240. -- Skip the rest of these tests on Windows #31587
  241. if is_os('win') then
  242. return
  243. end
  244. -- CursorLine and CursorColumn are combined with terminal colors.
  245. tt.set_reverse()
  246. tt.feed_data(' foobar')
  247. tt.clear_attrs()
  248. screen:expect([[
  249. tty ready{1: } |
  250. foobar f{1:o}obar foobar foobar foobar foobar foobar |
  251. foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
  252. oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
  253. obar foob{1:a}r foobar foobar foobar foobar foobar foo|
  254. {1:bar fooba^r}{4: foobar}{1: }|
  255. |
  256. ]])
  257. feed('2gg15|')
  258. screen:expect([[
  259. tty ready {1: } |
  260. {1: foobar foobar^ foobar foobar foobar foobar foobar }|
  261. foobar foobar {1:f}oobar foobar foobar foobar foobar f|
  262. oobar foobar f{1:o}obar foobar foobar foobar foobar fo|
  263. obar foobar fo{1:o}bar foobar foobar foobar foobar foo|
  264. bar foobar{2: foo}{4:b}{2:ar} |
  265. |
  266. ]])
  267. -- Set bg color to red
  268. tt.feed_csi('48;2;255:0:0m')
  269. tt.feed_data(' foobar')
  270. tt.clear_attrs()
  271. feed('2gg20|')
  272. -- Terminal color has higher precedence
  273. screen:expect([[
  274. tty ready {1: } |
  275. {1: foobar foobar foob^ar foobar foobar foobar foobar }|
  276. foobar foobar fooba{1:r} foobar foobar foobar foobar f|
  277. oobar foobar foobar{1: }foobar foobar foobar foobar fo|
  278. obar foobar foobar {1:f}oobar foobar foobar foobar foo|
  279. bar foobar{2: foobar}{5: foobar} |
  280. |
  281. ]])
  282. feed('G$')
  283. screen:expect([[
  284. tty ready {1: } |
  285. foobar foobar foobar f{1:o}obar foobar foobar foobar |
  286. foobar foobar foobar fo{1:o}bar foobar foobar foobar f|
  287. oobar foobar foobar foo{1:b}ar foobar foobar foobar fo|
  288. obar foobar foobar foob{1:a}r foobar foobar foobar foo|
  289. {1:bar foobar}{4: foobar}{5: fooba^r}{1: }|
  290. |
  291. ]])
  292. end)
  293. describe(':terminal highlight forwarding', function()
  294. local screen
  295. before_each(function()
  296. clear()
  297. screen = Screen.new(50, 7)
  298. screen:set_rgb_cterm(true)
  299. screen:set_default_attr_ids({
  300. [1] = { { bold = true }, { bold = true } },
  301. [2] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
  302. [3] = { { foreground = tonumber('0xff8000') }, {} },
  303. })
  304. command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
  305. feed('i')
  306. screen:expect([[
  307. tty ready |
  308. ^ |
  309. |*4
  310. {1:-- TERMINAL --} |
  311. ]])
  312. end)
  313. it('will handle cterm and rgb attributes', function()
  314. skip(is_os('win'))
  315. tt.set_fg(3)
  316. tt.feed_data('text')
  317. tt.feed_termcode('[38:2:255:128:0m')
  318. tt.feed_data('color')
  319. tt.clear_attrs()
  320. tt.feed_data('text')
  321. screen:expect {
  322. grid = [[
  323. tty ready |
  324. {2:text}{3:color}text^ |
  325. |*4
  326. {1:-- TERMINAL --} |
  327. ]],
  328. }
  329. end)
  330. end)
  331. describe(':terminal highlight with custom palette', function()
  332. local screen
  333. before_each(function()
  334. clear()
  335. screen = Screen.new(50, 7, { rgb = true })
  336. screen:set_default_attr_ids({
  337. [1] = { foreground = tonumber('0x123456') }, -- no fg_indexed when overridden
  338. [2] = { foreground = 12 },
  339. [3] = { bold = true, reverse = true },
  340. [5] = { background = 11 },
  341. [6] = { foreground = 130 },
  342. [7] = { reverse = true },
  343. [8] = { background = 11 },
  344. [9] = { bold = true },
  345. })
  346. api.nvim_set_var('terminal_color_3', '#123456')
  347. command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
  348. feed('i')
  349. screen:expect([[
  350. tty ready |
  351. ^ |
  352. |*4
  353. {9:-- TERMINAL --} |
  354. ]])
  355. end)
  356. it('will use the custom color', function()
  357. skip(is_os('win'))
  358. tt.set_fg(3)
  359. tt.feed_data('text')
  360. tt.clear_attrs()
  361. tt.feed_data('text')
  362. screen:expect([[
  363. tty ready |
  364. {1:text}text^ |
  365. |*4
  366. {9:-- TERMINAL --} |
  367. ]])
  368. end)
  369. end)
  370. describe(':terminal', function()
  371. before_each(clear)
  372. it('can display URLs', function()
  373. local screen = Screen.new(50, 7)
  374. screen:add_extra_attr_ids {
  375. [100] = { url = 'https://example.com' },
  376. }
  377. local chan = api.nvim_open_term(0, {})
  378. api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\')
  379. screen:expect({
  380. grid = [[
  381. {100:^Example} |
  382. |*6
  383. ]],
  384. })
  385. end)
  386. end)