highlight_spec.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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 nvim_prog_abs = n.nvim_prog_abs
  9. local fn = n.fn
  10. local nvim_set = n.nvim_set
  11. local is_os = t.is_os
  12. local skip = t.skip
  13. describe(':terminal highlight', function()
  14. local screen
  15. before_each(function()
  16. clear()
  17. screen = Screen.new(50, 7, { rgb = false })
  18. screen:set_default_attr_ids({
  19. [1] = { foreground = 45 },
  20. [2] = { background = 46 },
  21. [3] = { foreground = 45, background = 46 },
  22. [4] = { bold = true, italic = true, underline = true, strikethrough = true },
  23. [5] = { bold = true },
  24. [6] = { foreground = 12 },
  25. [7] = { bold = true, reverse = true },
  26. [8] = { background = 11 },
  27. [9] = { foreground = 130 },
  28. [10] = { reverse = true },
  29. [11] = { background = 11 },
  30. [12] = { bold = true, underdouble = true },
  31. [13] = { italic = true, undercurl = true },
  32. })
  33. command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
  34. feed('i')
  35. screen:expect([[
  36. tty ready |
  37. {10: } |
  38. |*4
  39. {5:-- TERMINAL --} |
  40. ]])
  41. end)
  42. local function descr(title, attr_num, set_attrs_fn)
  43. local function sub(s)
  44. local str = s:gsub('NUM', attr_num)
  45. return str
  46. end
  47. describe(title, function()
  48. before_each(function()
  49. set_attrs_fn()
  50. tt.feed_data('text')
  51. tt.clear_attrs()
  52. tt.feed_data('text')
  53. end)
  54. local function pass_attrs()
  55. skip(is_os('win'))
  56. screen:expect(sub([[
  57. tty ready |
  58. {NUM:text}text{10: } |
  59. |*4
  60. {5:-- TERMINAL --} |
  61. ]]))
  62. end
  63. it('will pass the corresponding attributes', pass_attrs)
  64. it('will pass the corresponding attributes on scrollback', function()
  65. skip(is_os('win'))
  66. pass_attrs()
  67. local lines = {}
  68. for i = 1, 8 do
  69. table.insert(lines, 'line' .. tostring(i))
  70. end
  71. table.insert(lines, '')
  72. tt.feed_data(lines)
  73. screen:expect([[
  74. line4 |
  75. line5 |
  76. line6 |
  77. line7 |
  78. line8 |
  79. {10: } |
  80. {5:-- TERMINAL --} |
  81. ]])
  82. feed('<c-\\><c-n>gg')
  83. screen:expect(sub([[
  84. ^tty ready |
  85. {NUM:text}textline1 |
  86. line2 |
  87. line3 |
  88. line4 |
  89. line5 |
  90. |
  91. ]]))
  92. end)
  93. end)
  94. end
  95. descr('foreground', 1, function()
  96. tt.set_fg(45)
  97. end)
  98. descr('background', 2, function()
  99. tt.set_bg(46)
  100. end)
  101. descr('foreground and background', 3, function()
  102. tt.set_fg(45)
  103. tt.set_bg(46)
  104. end)
  105. descr('bold, italics, underline and strikethrough', 4, function()
  106. tt.set_bold()
  107. tt.set_italic()
  108. tt.set_underline()
  109. tt.set_strikethrough()
  110. end)
  111. descr('bold and underdouble', 12, function()
  112. tt.set_bold()
  113. tt.set_underdouble()
  114. end)
  115. descr('italics and undercurl', 13, function()
  116. tt.set_italic()
  117. tt.set_undercurl()
  118. end)
  119. end)
  120. it(':terminal highlight has lower precedence than editor #9964', function()
  121. clear()
  122. local screen = Screen.new(30, 4, { rgb = true })
  123. screen:set_default_attr_ids({
  124. -- "Normal" highlight emitted by the child nvim process.
  125. N_child = {
  126. foreground = tonumber('0x4040ff'),
  127. background = tonumber('0xffff40'),
  128. fg_indexed = true,
  129. bg_indexed = true,
  130. },
  131. -- "Search" highlight in the parent nvim process.
  132. S = { background = Screen.colors.Green, italic = true, foreground = Screen.colors.Red },
  133. -- "Question" highlight in the parent nvim process.
  134. -- note: bg is indexed as it comes from the (cterm) child, while fg isn't as it comes from (rgb) parent
  135. Q = {
  136. background = tonumber('0xffff40'),
  137. bold = true,
  138. foreground = Screen.colors.SeaGreen4,
  139. bg_indexed = true,
  140. },
  141. })
  142. -- Child nvim process in :terminal (with cterm colors).
  143. fn.termopen({
  144. nvim_prog_abs(),
  145. '-n',
  146. '-u',
  147. 'NORC',
  148. '-i',
  149. 'NONE',
  150. '--cmd',
  151. nvim_set .. ' notermguicolors',
  152. '+hi Normal ctermfg=Blue ctermbg=Yellow',
  153. '+norm! ichild nvim',
  154. '+norm! oline 2',
  155. }, {
  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 }, -- TermCursor
  188. [3] = { bold = true }, -- ModeMsg
  189. [4] = { background = Screen.colors.Grey90, reverse = true },
  190. [5] = { background = Screen.colors.Red },
  191. })
  192. command(("enew | call termopen(['%s'])"):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{2: } |
  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. -- CursorLine and CursorColumn are combined with TermCursorNC.
  241. command('highlight TermCursorNC gui=reverse')
  242. screen:expect([[
  243. tty ready{1: } |
  244. foobar f{1:o}obar foobar foobar foobar foobar foobar |
  245. foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
  246. oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
  247. obar foob{1:a}r foobar foobar foobar foobar foobar foo|
  248. {1:bar fooba^r}{4: }{1: }|
  249. |
  250. ]])
  251. feed('2gg11|')
  252. screen:expect([[
  253. tty ready {1: } |
  254. {1: foobar fo^obar foobar foobar foobar foobar foobar }|
  255. foobar foo{1:b}ar foobar foobar foobar foobar foobar f|
  256. oobar foob{1:a}r foobar foobar foobar foobar foobar fo|
  257. obar fooba{1:r} foobar foobar foobar foobar foobar foo|
  258. bar foobar{4: } |
  259. |
  260. ]])
  261. -- TermCursorNC has higher precedence.
  262. command('highlight TermCursorNC gui=NONE guibg=Red')
  263. screen:expect([[
  264. tty ready {1: } |
  265. {1: foobar fo^obar foobar foobar foobar foobar foobar }|
  266. foobar foo{1:b}ar foobar foobar foobar foobar foobar f|
  267. oobar foob{1:a}r foobar foobar foobar foobar foobar fo|
  268. obar fooba{1:r} foobar foobar foobar foobar foobar foo|
  269. bar foobar{5: } |
  270. |
  271. ]])
  272. feed('G$')
  273. screen:expect([[
  274. tty ready{1: } |
  275. foobar f{1:o}obar foobar foobar foobar foobar foobar |
  276. foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
  277. oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
  278. obar foob{1:a}r foobar foobar foobar foobar foobar foo|
  279. {1:bar fooba^r}{5: }{1: }|
  280. |
  281. ]])
  282. end)
  283. describe(':terminal highlight forwarding', function()
  284. local screen
  285. before_each(function()
  286. clear()
  287. screen = Screen.new(50, 7)
  288. screen:set_rgb_cterm(true)
  289. screen:set_default_attr_ids({
  290. [1] = { { reverse = true }, { reverse = true } },
  291. [2] = { { bold = true }, { bold = true } },
  292. [3] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
  293. [4] = { { foreground = tonumber('0xff8000') }, {} },
  294. })
  295. command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
  296. feed('i')
  297. screen:expect([[
  298. tty ready |
  299. {1: } |
  300. |*4
  301. {2:-- TERMINAL --} |
  302. ]])
  303. end)
  304. it('will handle cterm and rgb attributes', function()
  305. skip(is_os('win'))
  306. tt.set_fg(3)
  307. tt.feed_data('text')
  308. tt.feed_termcode('[38:2:255:128:0m')
  309. tt.feed_data('color')
  310. tt.clear_attrs()
  311. tt.feed_data('text')
  312. screen:expect {
  313. grid = [[
  314. tty ready |
  315. {3:text}{4:color}text{1: } |
  316. |*4
  317. {2:-- TERMINAL --} |
  318. ]],
  319. }
  320. end)
  321. end)
  322. describe(':terminal highlight with custom palette', function()
  323. local screen
  324. before_each(function()
  325. clear()
  326. screen = Screen.new(50, 7, { rgb = true })
  327. screen:set_default_attr_ids({
  328. [1] = { foreground = tonumber('0x123456') }, -- no fg_indexed when overridden
  329. [2] = { foreground = 12 },
  330. [3] = { bold = true, reverse = true },
  331. [5] = { background = 11 },
  332. [6] = { foreground = 130 },
  333. [7] = { reverse = true },
  334. [8] = { background = 11 },
  335. [9] = { bold = true },
  336. })
  337. api.nvim_set_var('terminal_color_3', '#123456')
  338. command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
  339. feed('i')
  340. screen:expect([[
  341. tty ready |
  342. {7: } |
  343. |*4
  344. {9:-- TERMINAL --} |
  345. ]])
  346. end)
  347. it('will use the custom color', function()
  348. skip(is_os('win'))
  349. tt.set_fg(3)
  350. tt.feed_data('text')
  351. tt.clear_attrs()
  352. tt.feed_data('text')
  353. screen:expect([[
  354. tty ready |
  355. {1:text}text{7: } |
  356. |*4
  357. {9:-- TERMINAL --} |
  358. ]])
  359. end)
  360. end)
  361. describe(':terminal', function()
  362. before_each(clear)
  363. it('can display URLs', function()
  364. local screen = Screen.new(50, 7)
  365. screen:add_extra_attr_ids {
  366. [100] = { url = 'https://example.com' },
  367. }
  368. local chan = api.nvim_open_term(0, {})
  369. api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\')
  370. screen:expect({
  371. grid = [[
  372. {100:^Example} |
  373. |*6
  374. ]],
  375. })
  376. end)
  377. end)