2024-04-20 08:44:13 -07:00
|
|
|
local t = require('test.testutil')
|
|
|
|
local n = require('test.functional.testnvim')()
|
2021-01-03 06:38:12 -07:00
|
|
|
local Screen = require('test.functional.ui.screen')
|
|
|
|
|
2024-04-20 08:44:13 -07:00
|
|
|
local clear = n.clear
|
|
|
|
local insert = n.insert
|
|
|
|
local exec_lua = n.exec_lua
|
|
|
|
local feed = n.feed
|
|
|
|
local command = n.command
|
|
|
|
local api = n.api
|
2024-07-02 17:40:55 -07:00
|
|
|
local fn = n.fn
|
2024-04-08 02:03:20 -07:00
|
|
|
local eq = t.eq
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2023-04-30 08:11:38 -07:00
|
|
|
local hl_query_c = [[
|
2024-12-11 05:34:24 -07:00
|
|
|
; query
|
2022-08-24 14:48:52 -07:00
|
|
|
(ERROR) @error
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
"if" @keyword
|
|
|
|
"else" @keyword
|
|
|
|
"for" @keyword
|
|
|
|
"return" @keyword
|
|
|
|
|
|
|
|
"const" @type
|
|
|
|
"static" @type
|
|
|
|
"struct" @type
|
|
|
|
"enum" @type
|
|
|
|
"extern" @type
|
|
|
|
|
2022-08-24 14:48:52 -07:00
|
|
|
; nonexistent specializer for string should fallback to string
|
|
|
|
(string_literal) @string.nonexistent_specializer
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
(number_literal) @number
|
|
|
|
(char_literal) @string
|
|
|
|
|
|
|
|
(type_identifier) @type
|
2022-08-24 14:48:52 -07:00
|
|
|
((type_identifier) @constant.builtin (#eq? @constant.builtin "LuaRef"))
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
(primitive_type) @type
|
|
|
|
(sized_type_specifier) @type
|
|
|
|
|
|
|
|
; Use lua regexes
|
2022-08-24 14:48:52 -07:00
|
|
|
((identifier) @function (#contains? @function "lua_"))
|
2021-01-03 06:38:12 -07:00
|
|
|
((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$"))
|
2022-08-24 14:48:52 -07:00
|
|
|
((identifier) @Normal (#vim-match? @Normal "^lstate$"))
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2022-08-24 14:48:52 -07:00
|
|
|
((binary_expression left: (identifier) @warning.left right: (identifier) @warning.right) (#eq? @warning.left @warning.right))
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
(comment) @comment
|
|
|
|
]]
|
|
|
|
|
2023-04-30 08:11:38 -07:00
|
|
|
local hl_text_c = [[
|
2021-01-03 06:38:12 -07:00
|
|
|
/// Schedule Lua callback on main loop's event queue
|
|
|
|
static int nlua_schedule(lua_State *const lstate)
|
|
|
|
{
|
|
|
|
if (lua_type(lstate, 1) != LUA_TFUNCTION
|
|
|
|
|| lstate != lstate) {
|
|
|
|
lua_pushliteral(lstate, "vim.schedule: expected function");
|
|
|
|
return lua_error(lstate);
|
|
|
|
}
|
|
|
|
|
|
|
|
LuaRef cb = nlua_ref(lstate, 1);
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, nlua_schedule_event,
|
|
|
|
1, (void *)(ptrdiff_t)cb);
|
|
|
|
return 0;
|
|
|
|
}]]
|
|
|
|
|
2024-07-02 17:40:55 -07:00
|
|
|
local hl_grid_legacy_c = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:^/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{6:static} {6:int} nlua_schedule(lua_State *{6:const} lstate) |
|
2024-07-02 17:40:55 -07:00
|
|
|
{ |
|
2024-12-02 07:08:26 -07:00
|
|
|
{15:if} (lua_type(lstate, {26:1}) != LUA_TFUNCTION |
|
2024-07-02 17:40:55 -07:00
|
|
|
|| lstate != lstate) { |
|
2024-12-02 07:08:26 -07:00
|
|
|
lua_pushliteral(lstate, {26:"vim.schedule: expected function"}); |
|
|
|
|
{15:return} lua_error(lstate); |
|
2024-07-02 17:40:55 -07:00
|
|
|
} |
|
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
LuaRef cb = nlua_ref(lstate, {26:1}); |
|
2024-07-02 17:40:55 -07:00
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, nlua_schedule_event, |
|
2024-12-02 07:08:26 -07:00
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
2024-07-02 17:40:55 -07:00
|
|
|
} |
|
|
|
|
{1:~ }|*2
|
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
local hl_grid_ts_c = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:^/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
2024-07-02 17:40:55 -07:00
|
|
|
{ |
|
2024-12-02 07:08:26 -07:00
|
|
|
{15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
|
|
|
|
|| {19:lstate} != {19:lstate}) { |
|
|
|
|
{25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
|
|
|
|
{15:return} {25:lua_error}(lstate); |
|
2024-07-02 17:40:55 -07:00
|
|
|
} |
|
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
2024-07-02 17:40:55 -07:00
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
2024-07-02 17:40:55 -07:00
|
|
|
} |
|
|
|
|
{1:~ }|*2
|
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
2023-04-30 08:11:38 -07:00
|
|
|
local test_text_c = [[
|
2021-01-03 06:38:12 -07:00
|
|
|
void ui_refresh(void)
|
|
|
|
{
|
|
|
|
int width = INT_MAX, height = INT_MAX;
|
|
|
|
bool ext_widgets[kUIExtCount];
|
|
|
|
for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
|
|
|
|
ext_widgets[i] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool inclusive = ui_override();
|
|
|
|
for (size_t i = 0; i < ui_count; i++) {
|
|
|
|
UI *ui = uis[i];
|
|
|
|
width = MIN(ui->width, width);
|
|
|
|
height = MIN(ui->height, height);
|
|
|
|
foo = BAR(ui->bazaar, bazaar);
|
|
|
|
for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
|
|
|
|
ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]]
|
|
|
|
|
2023-09-13 16:51:54 -07:00
|
|
|
local injection_text_c = [[
|
|
|
|
int x = INT_MAX;
|
|
|
|
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
|
|
|
|
#define foo void main() { \
|
|
|
|
return 42; \
|
|
|
|
}
|
|
|
|
]]
|
|
|
|
|
|
|
|
local injection_grid_c = [[
|
|
|
|
int x = INT_MAX; |
|
|
|
|
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) |
|
|
|
|
#define foo void main() { \ |
|
|
|
|
return 42; \ |
|
|
|
|
} |
|
|
|
|
^ |
|
2023-12-09 05:42:00 -07:00
|
|
|
{1:~ }|*11
|
2023-09-13 16:51:54 -07:00
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
local injection_grid_expected_c = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{6:int} x = {26:INT_MAX}; |
|
|
|
|
#define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) |
|
|
|
|
#define foo {6:void} main() { \ |
|
|
|
|
{15:return} {26:42}; \ |
|
2023-09-13 16:51:54 -07:00
|
|
|
} |
|
|
|
|
^ |
|
2023-12-09 05:42:00 -07:00
|
|
|
{1:~ }|*11
|
2023-09-13 16:51:54 -07:00
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
2023-04-30 08:11:38 -07:00
|
|
|
describe('treesitter highlighting (C)', function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local screen --- @type test.functional.ui.screen
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
before_each(function()
|
2024-07-02 16:40:42 -07:00
|
|
|
clear()
|
2021-01-03 06:38:12 -07:00
|
|
|
screen = Screen.new(65, 18)
|
2022-09-04 08:58:33 -07:00
|
|
|
command [[ hi link @error ErrorMsg ]]
|
2022-08-24 14:48:52 -07:00
|
|
|
command [[ hi link @warning WarningMsg ]]
|
2021-01-03 06:38:12 -07:00
|
|
|
end)
|
|
|
|
|
2024-07-02 17:40:55 -07:00
|
|
|
it('starting and stopping treesitter highlight works', function()
|
|
|
|
command('setfiletype c | syntax on')
|
|
|
|
fn.setreg('r', hl_text_c)
|
|
|
|
feed('i<C-R><C-O>r<Esc>gg')
|
|
|
|
-- legacy syntax highlighting is used by default
|
|
|
|
screen:expect(hl_grid_legacy_c)
|
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
|
|
|
vim.treesitter.query.set('c', 'highlights', hl_query_c)
|
2024-07-02 17:40:55 -07:00
|
|
|
vim.treesitter.start()
|
2024-08-11 01:27:48 -07:00
|
|
|
end)
|
2024-07-02 17:40:55 -07:00
|
|
|
-- treesitter highlighting is used
|
|
|
|
screen:expect(hl_grid_ts_c)
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
|
|
|
vim.treesitter.stop()
|
|
|
|
end)
|
2024-07-02 17:40:55 -07:00
|
|
|
-- legacy syntax highlighting is used
|
|
|
|
screen:expect(hl_grid_legacy_c)
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
|
|
|
vim.treesitter.start()
|
|
|
|
end)
|
2024-07-02 17:40:55 -07:00
|
|
|
-- treesitter highlighting is used
|
|
|
|
screen:expect(hl_grid_ts_c)
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
|
|
|
vim.treesitter.stop()
|
|
|
|
end)
|
2024-07-02 17:40:55 -07:00
|
|
|
-- legacy syntax highlighting is used
|
|
|
|
screen:expect(hl_grid_legacy_c)
|
|
|
|
end)
|
|
|
|
|
2021-01-03 06:38:12 -07:00
|
|
|
it('is updated with edits', function()
|
2023-04-30 08:11:38 -07:00
|
|
|
insert(hl_text_c)
|
2024-07-02 17:40:55 -07:00
|
|
|
feed('gg')
|
2021-01-03 06:38:12 -07:00
|
|
|
screen:expect {
|
|
|
|
grid = [[
|
2024-07-02 17:40:55 -07:00
|
|
|
^/// Schedule Lua callback on main loop's event queue |
|
2021-01-03 06:38:12 -07:00
|
|
|
static int nlua_schedule(lua_State *const lstate) |
|
|
|
|
{ |
|
|
|
|
if (lua_type(lstate, 1) != LUA_TFUNCTION |
|
|
|
|
|| lstate != lstate) { |
|
|
|
|
lua_pushliteral(lstate, "vim.schedule: expected function"); |
|
|
|
|
return lua_error(lstate); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LuaRef cb = nlua_ref(lstate, 1); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, nlua_schedule_event, |
|
|
|
|
1, (void *)(ptrdiff_t)cb); |
|
|
|
|
return 0; |
|
2024-07-02 17:40:55 -07:00
|
|
|
} |
|
2023-12-09 05:42:00 -07:00
|
|
|
{1:~ }|*2
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
|
]],
|
|
|
|
}
|
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local parser = vim.treesitter.get_parser(0, 'c')
|
2021-01-03 06:38:12 -07:00
|
|
|
local highlighter = vim.treesitter.highlighter
|
2024-08-11 01:27:48 -07:00
|
|
|
highlighter.new(parser, { queries = { c = hl_query_c } })
|
|
|
|
end)
|
2024-07-02 17:40:55 -07:00
|
|
|
screen:expect(hl_grid_ts_c)
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
feed('5Goc<esc>dd')
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
|
|
|
{ |
|
|
|
|
{15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
|
|
|
|
|| {19:lstate} != {19:lstate}) { |
|
|
|
|
{25:^lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
|
|
|
|
{15:return} {25:lua_error}(lstate); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
} |
|
|
|
|
{1:~ }|*2
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
feed('7Go*/<esc>')
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
|
|
|
{ |
|
|
|
|
{15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
|
|
|
|
|| {19:lstate} != {19:lstate}) { |
|
|
|
|
{25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
|
|
|
|
{15:return} {25:lua_error}(lstate); |
|
|
|
|
{9:*^/} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
} |
|
|
|
|
{1:~ }|
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
feed('3Go/*<esc>')
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
|
|
|
{ |
|
|
|
|
{18:/^*} |
|
|
|
|
{18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
|
|
|
|
{18: || lstate != lstate) {} |
|
|
|
|
{18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
|
|
|
|
{18: return lua_error(lstate);} |
|
|
|
|
{18:*/} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
{9:}} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
feed('gg$')
|
|
|
|
feed('~')
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:/// Schedule Lua callback on main loop's event queu^E} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
|
|
|
{ |
|
|
|
|
{18:/*} |
|
|
|
|
{18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
|
|
|
|
{18: || lstate != lstate) {} |
|
|
|
|
{18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
|
|
|
|
{18: return lua_error(lstate);} |
|
|
|
|
{18:*/} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
{9:}} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
feed('re')
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:/// Schedule Lua callback on main loop's event queu^e} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
|
|
|
{ |
|
|
|
|
{18:/*} |
|
|
|
|
{18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
|
|
|
|
{18: || lstate != lstate) {} |
|
|
|
|
{18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
|
|
|
|
{18: return lua_error(lstate);} |
|
|
|
|
{18:*/} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
{9:}} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
end)
|
|
|
|
|
2021-01-02 03:05:30 -07:00
|
|
|
it('is updated with :sort', function()
|
2023-04-30 08:11:38 -07:00
|
|
|
insert(test_text_c)
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local parser = vim.treesitter.get_parser(0, 'c')
|
2024-08-11 01:27:48 -07:00
|
|
|
vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
|
|
|
|
end)
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-02 03:05:30 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
|
|
|
|
{6:bool} ext_widgets[kUIExtCount]; |
|
|
|
|
{15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
|
|
|
|
ext_widgets[i] = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{6:bool} inclusive = ui_override(); |
|
|
|
|
{15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
|
|
|
|
{6:UI} *ui = uis[i]; |
|
|
|
|
width = {26:MIN}(ui->width, width); |
|
|
|
|
height = {26:MIN}(ui->height, height); |
|
|
|
|
foo = {26:BAR}(ui->bazaar, bazaar); |
|
|
|
|
{15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
|
|
|
|
ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
^} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-02 03:05:30 -07:00
|
|
|
|
|
|
|
feed ':sort<cr>'
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-02 03:05:30 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
^ |
|
|
|
|
ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
|
|
|
|
{6:UI} *ui = uis[i]; |
|
|
|
|
ext_widgets[i] = true; |
|
|
|
|
foo = {26:BAR}(ui->bazaar, bazaar); |
|
|
|
|
{15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
|
|
|
|
height = {26:MIN}(ui->height, height); |
|
|
|
|
width = {26:MIN}(ui->width, width); |
|
|
|
|
} |
|
|
|
|
{6:bool} ext_widgets[kUIExtCount]; |
|
|
|
|
{6:bool} inclusive = ui_override(); |
|
|
|
|
{15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
|
|
|
|
{15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
|
|
|
|
{6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
|
|
|
|
} |*2
|
|
|
|
{6:void} ui_refresh({6:void}) |
|
|
|
|
:sort |
|
|
|
|
]],
|
|
|
|
})
|
2021-01-02 03:05:30 -07:00
|
|
|
|
2024-12-04 08:31:08 -07:00
|
|
|
feed 'u:<esc>'
|
2021-01-02 03:05:30 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-02 03:05:30 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
|
|
|
|
{6:bool} ext_widgets[kUIExtCount]; |
|
|
|
|
{15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
|
|
|
|
ext_widgets[i] = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{6:bool} inclusive = ui_override(); |
|
|
|
|
{15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
|
|
|
|
{6:UI} *ui = uis[i]; |
|
|
|
|
width = {26:MIN}(ui->width, width); |
|
|
|
|
height = {26:MIN}(ui->height, height); |
|
|
|
|
foo = {26:BAR}(ui->bazaar, bazaar); |
|
|
|
|
{15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
|
|
|
|
ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
^} |
|
2024-12-04 08:31:08 -07:00
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
]],
|
|
|
|
})
|
2021-01-02 03:05:30 -07:00
|
|
|
end)
|
|
|
|
|
2021-01-03 06:38:12 -07:00
|
|
|
it('supports with custom parser', function()
|
2023-04-30 08:11:38 -07:00
|
|
|
insert(test_text_c)
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
screen:expect {
|
|
|
|
grid = [[
|
|
|
|
int width = INT_MAX, height = INT_MAX; |
|
|
|
|
bool ext_widgets[kUIExtCount]; |
|
|
|
|
for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
|
|
|
|
ext_widgets[i] = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool inclusive = ui_override(); |
|
|
|
|
for (size_t i = 0; i < ui_count; i++) { |
|
|
|
|
UI *ui = uis[i]; |
|
|
|
|
width = MIN(ui->width, width); |
|
|
|
|
height = MIN(ui->height, height); |
|
|
|
|
foo = BAR(ui->bazaar, bazaar); |
|
|
|
|
for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
|
|
|
|
ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
^} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
}
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
|
|
|
local parser = vim.treesitter.get_parser(0, 'c')
|
|
|
|
local query = vim.treesitter.query.parse('c', '(declaration) @decl')
|
2021-01-03 06:38:12 -07:00
|
|
|
|
|
|
|
local nodes = {}
|
|
|
|
for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
|
|
|
|
table.insert(nodes, node)
|
|
|
|
end
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
parser:set_included_regions({ nodes })
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } })
|
|
|
|
end)
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
int {6:width} = {6:INT_MAX}, {6:height} = {6:INT_MAX}; |
|
|
|
|
bool {6:ext_widgets}[{6:kUIExtCount}]; |
|
|
|
|
for (UIExtension {6:i} = 0; (int)i < kUIExtCount; i++) { |
|
|
|
|
ext_widgets[i] = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool {6:inclusive} = {6:ui_override}(); |
|
|
|
|
for (size_t {6:i} = 0; i < ui_count; i++) { |
|
|
|
|
UI *{6:ui} = {6:uis}[{6:i}]; |
|
|
|
|
width = MIN(ui->width, width); |
|
|
|
|
height = MIN(ui->height, height); |
|
|
|
|
foo = BAR(ui->bazaar, bazaar); |
|
|
|
|
for (UIExtension {6:j} = 0; (int)j < kUIExtCount; j++) { |
|
|
|
|
ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
^} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('supports injected languages', function()
|
2023-09-13 16:51:54 -07:00
|
|
|
insert(injection_text_c)
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2023-09-13 16:51:54 -07:00
|
|
|
screen:expect { grid = injection_grid_c }
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local parser = vim.treesitter.get_parser(0, 'c', {
|
|
|
|
injections = {
|
|
|
|
c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))',
|
|
|
|
},
|
2021-01-03 06:38:12 -07:00
|
|
|
})
|
|
|
|
local highlighter = vim.treesitter.highlighter
|
2024-08-11 01:27:48 -07:00
|
|
|
highlighter.new(parser, { queries = { c = hl_query_c } })
|
|
|
|
end)
|
2021-01-03 06:38:12 -07:00
|
|
|
|
2023-09-13 16:51:54 -07:00
|
|
|
screen:expect { grid = injection_grid_expected_c }
|
|
|
|
end)
|
|
|
|
|
|
|
|
it("supports injecting by ft name in metadata['injection.language']", function()
|
|
|
|
insert(injection_text_c)
|
|
|
|
|
|
|
|
screen:expect { grid = injection_grid_c }
|
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
vim.treesitter.language.register('c', 'foo')
|
|
|
|
local parser = vim.treesitter.get_parser(0, 'c', {
|
|
|
|
injections = {
|
|
|
|
c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))',
|
|
|
|
},
|
2023-09-13 16:51:54 -07:00
|
|
|
})
|
|
|
|
local highlighter = vim.treesitter.highlighter
|
2024-08-11 01:27:48 -07:00
|
|
|
highlighter.new(parser, { queries = { c = hl_query_c } })
|
|
|
|
end)
|
2023-09-13 16:51:54 -07:00
|
|
|
|
|
|
|
screen:expect { grid = injection_grid_expected_c }
|
2021-03-30 07:57:38 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('supports overriding queries, like ', function()
|
|
|
|
insert([[
|
|
|
|
int x = INT_MAX;
|
2023-04-02 01:11:42 -07:00
|
|
|
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
|
2021-03-30 07:57:38 -07:00
|
|
|
#define foo void main() { \
|
|
|
|
return 42; \
|
|
|
|
}
|
|
|
|
]])
|
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local injection_query =
|
|
|
|
'(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
|
2024-08-11 01:27:48 -07:00
|
|
|
vim.treesitter.query.set('c', 'highlights', hl_query_c)
|
2024-07-29 03:20:15 -07:00
|
|
|
vim.treesitter.query.set('c', 'injections', injection_query)
|
2021-03-30 07:57:38 -07:00
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
|
2024-08-11 01:27:48 -07:00
|
|
|
end)
|
2021-03-30 07:57:38 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-01-03 06:38:12 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{6:int} x = {26:INT_MAX}; |
|
|
|
|
#define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) |
|
|
|
|
#define foo {6:void} main() { \ |
|
|
|
|
{15:return} {26:42}; \ |
|
|
|
|
} |
|
|
|
|
^ |
|
|
|
|
{1:~ }|*11
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-01-03 06:38:12 -07:00
|
|
|
end)
|
2021-03-29 13:07:21 -07:00
|
|
|
|
|
|
|
it('supports highlighting with custom highlight groups', function()
|
2023-04-30 08:11:38 -07:00
|
|
|
insert(hl_text_c)
|
2024-07-02 17:40:55 -07:00
|
|
|
feed('gg')
|
2021-03-29 13:07:21 -07:00
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local parser = vim.treesitter.get_parser(0, 'c')
|
2024-08-11 01:27:48 -07:00
|
|
|
vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
|
|
|
|
end)
|
2021-03-29 13:07:21 -07:00
|
|
|
|
2024-07-02 17:40:55 -07:00
|
|
|
screen:expect(hl_grid_ts_c)
|
2021-03-29 13:07:21 -07:00
|
|
|
|
|
|
|
-- This will change ONLY the literal strings to look like comments
|
|
|
|
-- The only literal string is the "vim.schedule: expected function" in this test.
|
2022-08-24 14:48:52 -07:00
|
|
|
exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]]
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2021-03-29 13:07:21 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:^/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
|
|
|
|
{ |
|
|
|
|
{15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
|
|
|
|
|| {19:lstate} != {19:lstate}) { |
|
|
|
|
{25:lua_pushliteral}(lstate, {18:"vim.schedule: expected function"}); |
|
|
|
|
{15:return} {25:lua_error}(lstate); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
} |
|
|
|
|
{1:~ }|*2
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2021-03-29 13:07:21 -07:00
|
|
|
screen:expect { unchanged = true }
|
|
|
|
end)
|
2021-07-17 05:41:17 -07:00
|
|
|
|
|
|
|
it('supports highlighting with priority', function()
|
|
|
|
insert([[
|
|
|
|
int x = INT_MAX;
|
2023-04-02 01:11:42 -07:00
|
|
|
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
|
2021-07-17 05:41:17 -07:00
|
|
|
#define foo void main() { \
|
|
|
|
return 42; \
|
|
|
|
}
|
|
|
|
]])
|
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local parser = vim.treesitter.get_parser(0, 'c')
|
|
|
|
vim.treesitter.highlighter.new(parser, {
|
|
|
|
queries = {
|
2024-08-11 01:27:48 -07:00
|
|
|
c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n',
|
2024-07-29 03:20:15 -07:00
|
|
|
},
|
|
|
|
})
|
2024-08-11 01:27:48 -07:00
|
|
|
end)
|
2023-04-01 03:11:24 -07:00
|
|
|
-- expect everything to have Constant highlight
|
2021-07-17 05:41:17 -07:00
|
|
|
screen:expect {
|
|
|
|
grid = [[
|
|
|
|
{12:int}{8: x = INT_MAX;} |
|
2023-08-12 09:12:49 -07:00
|
|
|
{8:#define READ_STRING(x, y) (}{12:char}{8: *)read_string((x), (}{12:size_t}{8:)(y))} |
|
|
|
|
{8:#define foo }{12:void}{8: main() { \} |
|
|
|
|
{8: }{12:return}{8: 42; \} |
|
2021-07-17 05:41:17 -07:00
|
|
|
{8: }} |
|
|
|
|
^ |
|
2023-12-09 05:42:00 -07:00
|
|
|
{1:~ }|*11
|
2021-07-17 05:41:17 -07:00
|
|
|
|
|
|
|
|
]],
|
|
|
|
attr_ids = {
|
|
|
|
[1] = { bold = true, foreground = Screen.colors.Blue1 },
|
2023-04-01 03:11:24 -07:00
|
|
|
[8] = { foreground = Screen.colors.Magenta1 },
|
2021-07-17 05:41:17 -07:00
|
|
|
-- bold will not be overwritten at the moment
|
2023-04-01 03:11:24 -07:00
|
|
|
[12] = { bold = true, foreground = Screen.colors.Magenta1 },
|
2024-01-02 18:09:18 -07:00
|
|
|
},
|
2021-07-17 05:41:17 -07:00
|
|
|
}
|
2022-08-25 12:41:52 -07:00
|
|
|
|
|
|
|
eq({
|
2024-12-11 05:34:24 -07:00
|
|
|
{ capture = 'constant', metadata = { priority = '101' }, lang = 'c', id = 14 },
|
|
|
|
{ capture = 'type', metadata = {}, lang = 'c', id = 3 },
|
2022-09-24 15:45:15 -07:00
|
|
|
}, exec_lua [[ return vim.treesitter.get_captures_at_pos(0, 0, 2) ]])
|
2021-07-17 05:41:17 -07:00
|
|
|
end)
|
2022-02-16 11:38:19 -07:00
|
|
|
|
|
|
|
it(
|
|
|
|
"allows to use captures with dots (don't use fallback when specialization of foo exists)",
|
|
|
|
function()
|
|
|
|
insert([[
|
|
|
|
char* x = "Will somebody ever read this?";
|
|
|
|
]])
|
|
|
|
|
|
|
|
screen:expect {
|
|
|
|
grid = [[
|
|
|
|
char* x = "Will somebody ever read this?"; |
|
|
|
|
^ |
|
2023-12-09 05:42:00 -07:00
|
|
|
{1:~ }|*15
|
2022-02-16 11:38:19 -07:00
|
|
|
|
|
|
|
|
]],
|
|
|
|
}
|
|
|
|
|
2022-08-24 14:48:52 -07:00
|
|
|
command [[
|
|
|
|
hi link @foo.bar Type
|
|
|
|
hi link @foo String
|
|
|
|
]]
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
|
|
|
local parser = vim.treesitter.get_parser(0, 'c', {})
|
|
|
|
local highlighter = vim.treesitter.highlighter
|
|
|
|
highlighter.new(
|
|
|
|
parser,
|
|
|
|
{ queries = { c = '(primitive_type) @foo.bar (string_literal) @foo' } }
|
|
|
|
)
|
|
|
|
end)
|
2022-02-16 11:38:19 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2022-02-16 11:38:19 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{6:char}* x = {26:"Will somebody ever read this?"}; |
|
|
|
|
^ |
|
|
|
|
{1:~ }|*15
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2022-08-24 14:48:52 -07:00
|
|
|
|
|
|
|
-- clearing specialization reactivates fallback
|
|
|
|
command [[ hi clear @foo.bar ]]
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2022-08-24 14:48:52 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{26:char}* x = {26:"Will somebody ever read this?"}; |
|
|
|
|
^ |
|
|
|
|
{1:~ }|*15
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2022-03-19 05:48:03 -07:00
|
|
|
end
|
|
|
|
)
|
|
|
|
|
|
|
|
it('supports conceal attribute', function()
|
2023-04-30 08:11:38 -07:00
|
|
|
insert(hl_text_c)
|
2022-03-19 05:48:03 -07:00
|
|
|
|
|
|
|
-- conceal can be empty or a single cchar.
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
2022-03-19 05:48:03 -07:00
|
|
|
vim.opt.cole = 2
|
2024-07-29 03:20:15 -07:00
|
|
|
local parser = vim.treesitter.get_parser(0, 'c')
|
|
|
|
vim.treesitter.highlighter.new(parser, {
|
|
|
|
queries = {
|
|
|
|
c = [[
|
2022-03-19 05:48:03 -07:00
|
|
|
("static" @keyword
|
2024-02-21 11:58:17 -07:00
|
|
|
(#set! conceal "R"))
|
2022-03-19 05:48:03 -07:00
|
|
|
|
|
|
|
((identifier) @Identifier
|
2024-02-21 11:58:17 -07:00
|
|
|
(#set! conceal "")
|
|
|
|
(#eq? @Identifier "lstate"))
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
|
|
|
|
((call_expression
|
|
|
|
function: (identifier) @function
|
|
|
|
arguments: (argument_list) @arguments)
|
|
|
|
(#eq? @function "multiqueue_put")
|
|
|
|
(#set! @function conceal "V"))
|
2024-07-29 03:20:15 -07:00
|
|
|
]],
|
|
|
|
},
|
|
|
|
})
|
|
|
|
end)
|
2022-03-19 05:48:03 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2022-03-19 05:48:03 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
/// Schedule Lua callback on main loop's event queue |
|
|
|
|
{15:R} int nlua_schedule(lua_State *const ) |
|
|
|
|
{ |
|
|
|
|
if (lua_type(, 1) != LUA_TFUNCTION |
|
|
|
|
|| != ) { |
|
|
|
|
lua_pushliteral(, "vim.schedule: expected function"); |
|
|
|
|
return lua_error(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LuaRef cb = nlua_ref(, 1); |
|
|
|
|
|
|
|
|
|
{25:V}(main_loop.events, nlua_schedule_event, |
|
|
|
|
1, (void *)(ptrdiff_t)cb); |
|
|
|
|
return 0; |
|
|
|
|
^} |
|
|
|
|
{1:~ }|*2
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2022-02-16 11:38:19 -07:00
|
|
|
end)
|
|
|
|
|
2022-08-24 14:48:52 -07:00
|
|
|
it('@foo.bar groups has the correct fallback behavior', function()
|
|
|
|
local get_hl = function(name)
|
2024-01-12 10:59:57 -07:00
|
|
|
return api.nvim_get_hl_by_name(name, 1).foreground
|
2022-08-24 14:48:52 -07:00
|
|
|
end
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_hl(0, '@foo', { fg = 1 })
|
|
|
|
api.nvim_set_hl(0, '@foo.bar', { fg = 2 })
|
|
|
|
api.nvim_set_hl(0, '@foo.bar.baz', { fg = 3 })
|
2024-01-02 18:09:18 -07:00
|
|
|
|
2022-08-24 14:48:52 -07:00
|
|
|
eq(1, get_hl '@foo')
|
|
|
|
eq(1, get_hl '@foo.a.b.c.d')
|
|
|
|
eq(2, get_hl '@foo.bar')
|
|
|
|
eq(2, get_hl '@foo.bar.a.b.c.d')
|
|
|
|
eq(3, get_hl '@foo.bar.baz')
|
|
|
|
eq(3, get_hl '@foo.bar.baz.d')
|
|
|
|
|
|
|
|
-- lookup is case insensitive
|
|
|
|
eq(2, get_hl '@FOO.BAR.SPAM')
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_hl(0, '@foo.missing.exists', { fg = 3 })
|
2022-08-24 14:48:52 -07:00
|
|
|
eq(1, get_hl '@foo.missing')
|
|
|
|
eq(3, get_hl '@foo.missing.exists')
|
|
|
|
eq(3, get_hl '@foo.missing.exists.bar')
|
|
|
|
eq(nil, get_hl '@total.nonsense.but.a.lot.of.dots')
|
2022-02-16 11:38:19 -07:00
|
|
|
end)
|
2024-02-16 10:54:47 -07:00
|
|
|
|
|
|
|
it('supports multiple nodes assigned to the same capture #17060', function()
|
|
|
|
insert([[
|
|
|
|
int x = 4;
|
|
|
|
int y = 5;
|
|
|
|
int z = 6;
|
|
|
|
]])
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
2024-02-16 10:54:47 -07:00
|
|
|
local query = '((declaration)+ @string)'
|
|
|
|
vim.treesitter.query.set('c', 'highlights', query)
|
|
|
|
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
|
2024-07-29 03:20:15 -07:00
|
|
|
end)
|
2024-02-16 10:54:47 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2024-02-16 10:54:47 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{26:int x = 4;} |
|
|
|
|
{26:int y = 5;} |
|
|
|
|
{26:int z = 6;} |
|
|
|
|
^ |
|
|
|
|
{1:~ }|*13
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2024-02-16 10:54:47 -07:00
|
|
|
end)
|
2024-03-17 11:02:40 -07:00
|
|
|
|
|
|
|
it('gives higher priority to more specific captures #27895', function()
|
|
|
|
insert([[
|
|
|
|
void foo(int *bar);
|
|
|
|
]])
|
|
|
|
|
|
|
|
local query = [[
|
|
|
|
"*" @operator
|
|
|
|
|
|
|
|
(parameter_declaration
|
|
|
|
declarator: (pointer_declarator) @variable.parameter)
|
|
|
|
]]
|
|
|
|
|
2024-08-11 01:27:48 -07:00
|
|
|
exec_lua(function()
|
|
|
|
vim.treesitter.query.set('c', 'highlights', query)
|
2024-03-17 11:02:40 -07:00
|
|
|
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
|
2024-08-11 01:27:48 -07:00
|
|
|
end)
|
2024-03-17 11:02:40 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2024-03-17 19:34:27 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
void foo(int {15:*}{25:bar}); |
|
|
|
|
^ |
|
|
|
|
{1:~ }|*15
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('highlights applied to first line of closed fold', function()
|
|
|
|
insert(hl_text_c)
|
|
|
|
exec_lua(function()
|
|
|
|
vim.treesitter.query.set('c', 'highlights', hl_query_c)
|
|
|
|
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
|
|
|
|
end)
|
|
|
|
feed('ggjzfj')
|
|
|
|
command('set foldtext=')
|
|
|
|
screen:add_extra_attr_ids({
|
|
|
|
[100] = {
|
|
|
|
bold = true,
|
|
|
|
background = Screen.colors.LightGray,
|
|
|
|
foreground = Screen.colors.SeaGreen4,
|
|
|
|
},
|
|
|
|
[101] = { background = Screen.colors.LightGray, foreground = Screen.colors.DarkCyan },
|
|
|
|
})
|
|
|
|
screen:expect({
|
|
|
|
grid = [[
|
|
|
|
{18:/// Schedule Lua callback on main loop's event queue} |
|
|
|
|
{100:^static}{13: }{100:int}{13: }{101:nlua_schedule}{13:(}{100:lua_State}{13: *}{100:const}{13: lstate)················}|
|
|
|
|
{15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
|
|
|
|
|| {19:lstate} != {19:lstate}) { |
|
|
|
|
{25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
|
|
|
|
{15:return} {25:lua_error}(lstate); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
|
|
|
|
|
|
|
|
multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
|
|
|
|
{26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
|
|
|
|
{15:return} {26:0}; |
|
|
|
|
} |
|
|
|
|
{1:~ }|*3
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2024-03-17 11:02:40 -07:00
|
|
|
end)
|
2021-01-03 06:38:12 -07:00
|
|
|
end)
|
2023-04-30 08:11:38 -07:00
|
|
|
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
describe('treesitter highlighting (lua)', function()
|
|
|
|
local screen
|
|
|
|
|
|
|
|
before_each(function()
|
2024-07-02 16:40:42 -07:00
|
|
|
clear()
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
screen = Screen.new(65, 18)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('supports language injections', function()
|
|
|
|
insert [[
|
|
|
|
local ffi = require('ffi')
|
|
|
|
ffi.cdef("int (*fun)(int, char *);")
|
|
|
|
]]
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
vim.bo.filetype = 'lua'
|
|
|
|
vim.treesitter.start()
|
2024-07-29 03:20:15 -07:00
|
|
|
end)
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{15:local} {25:ffi} {15:=} {16:require(}{26:'ffi'}{16:)} |
|
|
|
|
{25:ffi}{16:.}{25:cdef}{16:(}{26:"}{16:int}{26: }{16:(}{15:*}{26:fun}{16:)(int,}{26: }{16:char}{26: }{15:*}{16:);}{26:"}{16:)} |
|
|
|
|
^ |
|
|
|
|
{1:~ }|*14
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
2023-04-30 08:11:38 -07:00
|
|
|
describe('treesitter highlighting (help)', function()
|
|
|
|
local screen
|
|
|
|
|
|
|
|
before_each(function()
|
2024-07-02 16:40:42 -07:00
|
|
|
clear()
|
2023-04-30 08:11:38 -07:00
|
|
|
screen = Screen.new(40, 6)
|
|
|
|
end)
|
|
|
|
|
2024-09-27 08:53:30 -07:00
|
|
|
it('defaults in vimdoc/highlights.scm', function()
|
|
|
|
-- Avoid regressions when syncing upstream vimdoc queries.
|
|
|
|
|
|
|
|
insert [[
|
|
|
|
==============================================================================
|
|
|
|
NVIM DOCUMENTATION
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
ABOUT NVIM *tag-1* *tag-2*
|
|
|
|
|
|
|
|
|news| News
|
|
|
|
|nvim| NVim
|
|
|
|
]]
|
|
|
|
|
|
|
|
feed('gg')
|
|
|
|
exec_lua(function()
|
|
|
|
vim.wo.wrap = false
|
|
|
|
vim.bo.filetype = 'help'
|
|
|
|
vim.treesitter.start()
|
|
|
|
end)
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:add_extra_attr_ids({
|
|
|
|
[100] = { nocombine = true, underdouble = true },
|
|
|
|
[101] = { foreground = Screen.colors.Fuchsia, bold = true },
|
|
|
|
[102] = { underline = true, nocombine = true },
|
|
|
|
})
|
2024-09-27 08:53:30 -07:00
|
|
|
screen:expect({
|
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{100:^========================================}|
|
|
|
|
{101:NVIM DOCUMENTATION} |
|
2024-09-27 08:53:30 -07:00
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
{102:----------------------------------------}|
|
|
|
|
{101:ABOUT NVIM} |
|
2024-09-27 08:53:30 -07:00
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
|
|
|
end)
|
|
|
|
|
2023-04-30 08:11:38 -07:00
|
|
|
it('correctly redraws added/removed injections', function()
|
|
|
|
insert [[
|
|
|
|
>ruby
|
|
|
|
-- comment
|
|
|
|
local this_is = 'actually_lua'
|
|
|
|
<
|
|
|
|
]]
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
2023-04-30 08:11:38 -07:00
|
|
|
vim.bo.filetype = 'help'
|
|
|
|
vim.treesitter.start()
|
2024-07-29 03:20:15 -07:00
|
|
|
end)
|
2023-04-30 08:11:38 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2023-04-30 08:11:38 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:>}{15:ruby} |
|
|
|
|
{18: -- comment} |
|
|
|
|
{18: local this_is = 'actually_lua'} |
|
|
|
|
{18:<} |
|
|
|
|
^ |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2023-04-30 08:11:38 -07:00
|
|
|
|
2024-04-20 08:44:13 -07:00
|
|
|
n.api.nvim_buf_set_text(0, 0, 1, 0, 5, { 'lua' })
|
2023-04-30 08:11:38 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2023-04-30 08:11:38 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:>}{15:lua} |
|
|
|
|
{18: -- comment} |
|
|
|
|
{18: }{15:local}{18: }{25:this_is}{18: }{15:=}{18: }{26:'actually_lua'} |
|
|
|
|
{18:<} |
|
|
|
|
^ |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2023-04-30 08:11:38 -07:00
|
|
|
|
2024-04-20 08:44:13 -07:00
|
|
|
n.api.nvim_buf_set_text(0, 0, 1, 0, 4, { 'ruby' })
|
2023-04-30 08:11:38 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2023-04-30 08:11:38 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{18:>}{15:ruby} |
|
|
|
|
{18: -- comment} |
|
|
|
|
{18: local this_is = 'actually_lua'} |
|
|
|
|
{18:<} |
|
|
|
|
^ |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
2023-04-30 08:11:38 -07:00
|
|
|
end)
|
2024-03-13 07:40:41 -07:00
|
|
|
|
|
|
|
it('correctly redraws injections subpriorities', function()
|
|
|
|
-- The top level string node will be highlighted first
|
|
|
|
-- with an extmark spanning multiple lines.
|
|
|
|
-- When the next line is drawn, which includes an injection,
|
|
|
|
-- make sure the highlight appears above the base tree highlight
|
|
|
|
|
|
|
|
insert([=[
|
|
|
|
local s = [[
|
|
|
|
local also = lua
|
|
|
|
]]
|
|
|
|
]=])
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
|
|
|
local parser = vim.treesitter.get_parser(0, 'lua', {
|
2024-03-13 07:40:41 -07:00
|
|
|
injections = {
|
2024-07-29 03:20:15 -07:00
|
|
|
lua = '(string content: (_) @injection.content (#set! injection.language lua))',
|
|
|
|
},
|
2024-03-13 07:40:41 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
vim.treesitter.highlighter.new(parser)
|
2024-07-29 03:20:15 -07:00
|
|
|
end)
|
2024-03-13 07:40:41 -07:00
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
2024-03-13 07:40:41 -07:00
|
|
|
grid = [=[
|
2024-12-02 07:08:26 -07:00
|
|
|
{15:local} {25:s} {15:=} {26:[[} |
|
|
|
|
{26: }{15:local}{26: }{25:also}{26: }{15:=}{26: }{25:lua} |
|
|
|
|
{26:]]} |
|
|
|
|
^ |
|
|
|
|
{1:~ }|
|
|
|
|
|
|
|
|
|
]=],
|
|
|
|
})
|
2024-03-13 07:40:41 -07:00
|
|
|
end)
|
2023-04-30 08:11:38 -07:00
|
|
|
end)
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
|
|
|
|
describe('treesitter highlighting (nested injections)', function()
|
2024-07-29 03:20:15 -07:00
|
|
|
local screen --- @type test.functional.ui.screen
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
|
|
|
|
before_each(function()
|
2024-07-02 16:40:42 -07:00
|
|
|
clear()
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
screen = Screen.new(80, 7)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('correctly redraws nested injections (GitHub #25252)', function()
|
|
|
|
insert [=[
|
|
|
|
function foo() print("Lua!") end
|
|
|
|
|
|
|
|
local lorem = {
|
|
|
|
ipsum = {},
|
|
|
|
bar = {},
|
|
|
|
}
|
|
|
|
vim.cmd([[
|
|
|
|
augroup RustLSP
|
|
|
|
autocmd CursorHold silent! lua vim.lsp.buf.document_highlight()
|
|
|
|
augroup END
|
|
|
|
]])
|
|
|
|
]=]
|
|
|
|
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
vim.opt.scrolloff = 0
|
|
|
|
vim.bo.filetype = 'lua'
|
|
|
|
vim.treesitter.start()
|
2024-07-29 03:20:15 -07:00
|
|
|
end)
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
|
|
|
|
-- invalidate the language tree
|
|
|
|
feed('ggi--[[<ESC>04x')
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{15:^function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} |
|
|
|
|
|
|
|
|
|
{15:local} {25:lorem} {15:=} {16:{} |
|
|
|
|
{25:ipsum} {15:=} {16:{},} |
|
|
|
|
{25:bar} {15:=} {16:{},} |
|
|
|
|
{16:}} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
|
|
|
|
-- spam newline insert/delete to invalidate Lua > Vim > Lua region
|
|
|
|
feed('3jo<ESC>ddko<ESC>ddko<ESC>ddko<ESC>ddk0')
|
|
|
|
|
2024-12-02 07:08:26 -07:00
|
|
|
screen:expect({
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
grid = [[
|
2024-12-02 07:08:26 -07:00
|
|
|
{15:function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} |
|
|
|
|
|
|
|
|
|
{15:local} {25:lorem} {15:=} {16:{} |
|
|
|
|
^ {25:ipsum} {15:=} {16:{},} |
|
|
|
|
{25:bar} {15:=} {16:{},} |
|
|
|
|
{16:}} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
2023-09-19 21:41:07 -07:00
|
|
|
end)
|
|
|
|
end)
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
|
|
|
|
describe('treesitter highlighting (markdown)', function()
|
|
|
|
local screen
|
|
|
|
|
|
|
|
before_each(function()
|
2024-07-02 16:40:42 -07:00
|
|
|
clear()
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
screen = Screen.new(40, 6)
|
2024-07-29 03:20:15 -07:00
|
|
|
exec_lua(function()
|
2024-06-23 04:50:21 -07:00
|
|
|
vim.bo.filetype = 'markdown'
|
|
|
|
vim.treesitter.start()
|
2024-07-29 03:20:15 -07:00
|
|
|
end)
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('supports hyperlinks', function()
|
|
|
|
local url = 'https://example.com'
|
|
|
|
insert(string.format('[This link text](%s) is a hyperlink.', url))
|
2024-06-23 04:50:21 -07:00
|
|
|
screen:add_extra_attr_ids({
|
|
|
|
[100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' },
|
2024-07-24 06:06:01 -07:00
|
|
|
[101] = {
|
|
|
|
foreground = Screen.colors.SlateBlue,
|
|
|
|
url = 'https://example.com',
|
|
|
|
underline = true,
|
|
|
|
},
|
2024-06-23 04:50:21 -07:00
|
|
|
})
|
|
|
|
screen:expect({
|
|
|
|
grid = [[
|
2024-11-19 01:46:55 -07:00
|
|
|
{100:[This link text](}{101:https://example.com}{100:)} is|
|
2024-06-23 04:50:21 -07:00
|
|
|
a hyperlink^. |
|
|
|
|
{1:~ }|*3
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
|
|
|
end)
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
|
2024-06-23 04:50:21 -07:00
|
|
|
it('works with spellchecked and smoothscrolled topline', function()
|
|
|
|
insert([[
|
|
|
|
- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$.
|
|
|
|
|
|
|
|
```c
|
|
|
|
printf('Hello World!');
|
|
|
|
```
|
|
|
|
]])
|
|
|
|
command('set spell smoothscroll')
|
|
|
|
feed('gg<C-E>')
|
|
|
|
screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } })
|
|
|
|
screen:expect({
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
grid = [[
|
2024-06-23 04:50:21 -07:00
|
|
|
{1:<<<}k^{2}}+\{100:lim}_{w \to 0}x$^. |
|
|
|
|
|
|
|
|
|
{18:```}{15:c} |
|
|
|
|
{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
|
|
|
{18:```} |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
})
|
feat(treesitter): support URLs (#27132)
Tree-sitter queries can add URLs to a capture using the `#set!`
directive, e.g.
(inline_link
(link_text) @text.reference
(link_destination) @text.uri
(#set! @text.reference "url" @text.uri))
The pattern above is included by default in the `markdown_inline`
highlight query so that users with supporting terminals will see
hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of
the pattern [link text](link url), even if `link url` does not contain
a valid protocol (e.g. if `link url` is a path to a file). We may wish to
change this in the future to only linkify when the URL has a valid
protocol scheme, but for now we delegate handling this to the terminal
emulator.
In order to support directives which reference other nodes, the
highlighter must be updated to use `iter_matches` rather than
`iter_captures`. The former provides the `match` table which maps
capture IDs to nodes. However, this has its own challenges:
- `iter_matches` does not guarantee the order in which patterns are
iterated matches the order in the query file. So we must enforce
ordering manually using "subpriorities" (#27131). The pattern index of
each match dictates the extmark's subpriority.
- When injections are used, the highlighter contains multiple trees. The
pattern indices of each tree must be offset relative to the maximum
pattern index from all previous trees to ensure that extmarks appear
in the correct order.
- The `iter_captures` implementation currently has a bug where the
"match" table is only returned for the first capture within a pattern
(see #27274). This bug means that `#set!` directives in a query
apply only to the first capture within a pattern. Unfortunately, many
queries in the wild have come to depend on this behavior.
`iter_matches` does not share this flaw, so switching to
`iter_matches` exposed bugs in existing highlight queries. These
queries have been updated in this repo, but may still need to be
updated by users. The `#set!` directive applies to the _entire_ query
pattern when used without a capture argument. To make `#set!`
apply only to a single capture, the capture must be given as an
argument.
2024-03-12 07:32:17 -07:00
|
|
|
end)
|
|
|
|
end)
|
2024-07-02 16:40:42 -07:00
|
|
|
|
|
|
|
it('starting and stopping treesitter highlight in init.lua works #29541', function()
|
|
|
|
t.write_file(
|
|
|
|
'Xinit.lua',
|
|
|
|
[[
|
|
|
|
vim.bo.ft = 'c'
|
|
|
|
vim.treesitter.start()
|
|
|
|
vim.treesitter.stop()
|
|
|
|
]]
|
|
|
|
)
|
|
|
|
finally(function()
|
|
|
|
os.remove('Xinit.lua')
|
|
|
|
end)
|
|
|
|
clear({ args = { '-u', 'Xinit.lua' } })
|
|
|
|
eq('', api.nvim_get_vvar('errmsg'))
|
2024-07-02 17:40:55 -07:00
|
|
|
|
|
|
|
local screen = Screen.new(65, 18)
|
|
|
|
fn.setreg('r', hl_text_c)
|
|
|
|
feed('i<C-R><C-O>r<Esc>gg')
|
|
|
|
-- legacy syntax highlighting is used
|
|
|
|
screen:expect(hl_grid_legacy_c)
|
2024-07-02 16:40:42 -07:00
|
|
|
end)
|