Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions lua/mini/ai.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1608,22 +1608,24 @@ H.get_matched_ranges_builtin = function(captures)
-- Get parser (LanguageTree) at cursor (important for injected languages)
local pos = vim.api.nvim_win_get_cursor(0)
local lang_tree = parser:language_for_range({ pos[1] - 1, pos[2], pos[1] - 1, pos[2] })
local init_lang_tree = lang_tree

local missing_query_langs = {}
local res = {}
-- Maybe go up parent trees to work with injected languages
while vim.tbl_isempty(res) and lang_tree ~= nil do
local lang = lang_tree:lang()
-- Get query file depending on the local language
local query = vim.treesitter.query.get(lang, 'textobjects')
H.append_lang_ranges(res, missing_query_langs, buf_id, captures, lang_tree)

if query ~= nil then H.append_ranges(res, buf_id, query, captures, lang_tree) end
if query == nil then missing_query_langs[lang] = true end

-- `LanguageTree:parent()` was added in Neovim<0.10
-- `LanguageTree:parent()` was added in Neovim=0.10
-- TODO: Drop extra check after compatibility with Neovim=0.9 is dropped
lang_tree = lang_tree.parent and lang_tree:parent() or nil
end
-- Fallback to direct children trees for injected languages
if vim.tbl_isempty(res) then
for _, child in pairs(init_lang_tree:children()) do
H.append_lang_ranges(res, missing_query_langs, buf_id, captures, child)
end
end

if vim.tbl_isempty(res) and not vim.tbl_isempty(missing_query_langs) then
H.error_treesitter('query', vim.tbl_keys(missing_query_langs))
Expand All @@ -1632,6 +1634,14 @@ H.get_matched_ranges_builtin = function(captures)
return res
end

H.append_lang_ranges = function(res, missing_query_langs, buf_id, captures, lang_tree)
local lang = lang_tree:lang()
local query = vim.treesitter.query.get(lang, 'textobjects')

if query ~= nil then H.append_ranges(res, buf_id, query, captures, lang_tree) end
if query == nil then missing_query_langs[lang] = true end
end

H.append_ranges = function(res, buf_id, query, captures, lang_tree)
-- Compute ranges of matched captures
local capture_is_requested = vim.tbl_map(function(c) return vim.tbl_contains(captures, '@' .. c) end, query.captures)
Expand Down
44 changes: 28 additions & 16 deletions lua/mini/surround.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1545,35 +1545,31 @@ H.get_matched_range_pairs_builtin = function(captures)
-- Get parser (LanguageTree) at cursor (important for injected languages)
local pos = vim.api.nvim_win_get_cursor(0)
local lang_tree = parser:language_for_range({ pos[1] - 1, pos[2], pos[1] - 1, pos[2] })
local init_lang_tree = lang_tree

local missing_query_langs = {}
-- Compute matched ranges for both outer and inner captures
-- Maybe go up parent trees to work with injected languages
local outer_ranges, inner_ranges = {}, {}
while (vim.tbl_isempty(inner_ranges) or vim.tbl_isempty(outer_ranges)) and lang_tree ~= nil do
local lang = lang_tree:lang()
-- Get query file depending on the local language
local query = vim.treesitter.query.get(lang, 'textobjects')

if query ~= nil then
for _, tree in ipairs(lang_tree:trees()) do
local root = tree:root()
vim.list_extend(outer_ranges, H.get_match_ranges_builtin(root, buf_id, query, captures.outer:sub(2)))
vim.list_extend(inner_ranges, H.get_match_ranges_builtin(root, buf_id, query, captures.inner:sub(2)))
end
end
if query == nil then missing_query_langs[lang] = true end
local outer, inner = {}, {}
while (vim.tbl_isempty(inner) or vim.tbl_isempty(outer)) and lang_tree ~= nil do
H.append_lang_ranges(outer, inner, missing_query_langs, buf_id, captures, lang_tree)

-- `LanguageTree:parent()` was added in Neovim<0.10
-- TODO: Drop extra check after compatibility with Neovim=0.9 is dropped
lang_tree = lang_tree.parent and lang_tree:parent() or nil
end
-- Fallback to direct children trees for injected languages
if vim.tbl_isempty(inner) or vim.tbl_isempty(outer) then
for _, child in pairs(init_lang_tree:children()) do
H.append_lang_ranges(outer, inner, missing_query_langs, buf_id, captures, child)
end
end

-- Match outer and inner ranges: for each outer range pick the biggest inner
-- range that lies within outer
local res = {}
for i, outer in ipairs(outer_ranges) do
res[i] = { outer = outer, inner = H.get_biggest_nested_range(inner_ranges, outer) }
for i, outer in ipairs(outer) do
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outer is redefined here.

res[i] = { outer = outer, inner = H.get_biggest_nested_range(inner, outer) }
end

if vim.tbl_isempty(res) and not vim.tbl_isempty(missing_query_langs) then
Expand All @@ -1583,6 +1579,22 @@ H.get_matched_range_pairs_builtin = function(captures)
return res
end

H.append_lang_ranges = function(outer, inner, missing_query_langs, buf_id, captures, lang_tree)
local lang = lang_tree:lang()
local query = vim.treesitter.query.get(lang, 'textobjects')

if query ~= nil then H.append_ranges(outer, inner, buf_id, query, captures, lang_tree) end
if query == nil then missing_query_langs[lang] = true end
end

H.append_ranges = function(outer, inner, buf_id, query, captures, lang_tree)
for _, tree in ipairs(lang_tree:trees()) do
local root = tree:root()
vim.list_extend(outer, H.get_match_ranges_builtin(root, buf_id, query, captures.outer:sub(2)))
vim.list_extend(inner, H.get_match_ranges_builtin(root, buf_id, query, captures.inner:sub(2)))
end
end

H.get_match_ranges_builtin = function(root, buf_id, query, capture)
local res = {}
-- TODO: Remove `opts.all`after compatibility with Neovim=0.10 is dropped
Expand Down
10 changes: 10 additions & 0 deletions tests/test_ai.lua
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,16 @@ T['gen_spec']['treesitter()']['works with parent of injected language'] = functi
validate_find(lines, { 3, 0 }, { 'a', 'F' }, { { 1, 13 }, { 5, 3 } })
end

T['gen_spec']['treesitter()']['works with direct injected child language'] = function()
local lines = {
'vim.cmd([[',
'set cursorline',
'lua local a = function () end',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'lua local a = function () end',
'lua local a = function() return true end',

This should make it more robust: no space between function and () is usual (unless it is intentional?) and non-empty body (as empty function might be problematic).

']])',
}
validate_find(lines, { 2, 0 }, { 'a', 'F' }, { { 3, 15 }, { 3, 29 } })
end

T['gen_spec']['treesitter()']['works with row-exclusive, col-0 end range'] = function()
child.lua([[MiniAi.config.custom_textobjects = {
c = MiniAi.gen_spec.treesitter({ a = '@chunk.outer', i = '@chunk.outer' }),
Expand Down
Loading