mirror of
https://github.com/neovim/neovim.git
synced 2026-04-22 07:15:34 +00:00
tree-sitter: implement query functionality and highlighting prototype [skip.lint]
This commit is contained in:
@@ -12,9 +12,13 @@ function Parser:parse()
|
||||
if self.valid then
|
||||
return self.tree
|
||||
end
|
||||
self.tree = self._parser:parse_buf(self.bufnr)
|
||||
local changes
|
||||
self.tree, changes = self._parser:parse_buf(self.bufnr)
|
||||
self.valid = true
|
||||
return self.tree
|
||||
for _, cb in ipairs(self.change_cbs) do
|
||||
cb(changes)
|
||||
end
|
||||
return self.tree, changes
|
||||
end
|
||||
|
||||
function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_size)
|
||||
@@ -26,17 +30,28 @@ function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_
|
||||
self.valid = false
|
||||
end
|
||||
|
||||
local module = {
|
||||
local M = {
|
||||
add_language=vim._ts_add_language,
|
||||
inspect_language=vim._ts_inspect_language,
|
||||
parse_query = vim._ts_parse_query,
|
||||
}
|
||||
|
||||
function module.create_parser(bufnr, ft, id)
|
||||
setmetatable(M, {
|
||||
__index = function (t, k)
|
||||
if k == "TSHighlighter" then
|
||||
t[k] = require'vim.tshighlighter'
|
||||
return t[k]
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
function M.create_parser(bufnr, ft, id)
|
||||
if bufnr == 0 then
|
||||
bufnr = a.nvim_get_current_buf()
|
||||
end
|
||||
local self = setmetatable({bufnr=bufnr, valid=false}, Parser)
|
||||
local self = setmetatable({bufnr=bufnr, lang=ft, valid=false}, Parser)
|
||||
self._parser = vim._create_ts_parser(ft)
|
||||
self.change_cbs = {}
|
||||
self:parse()
|
||||
-- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is
|
||||
-- using it.
|
||||
@@ -55,7 +70,7 @@ function module.create_parser(bufnr, ft, id)
|
||||
return self
|
||||
end
|
||||
|
||||
function module.get_parser(bufnr, ft)
|
||||
function M.get_parser(bufnr, ft, cb)
|
||||
if bufnr == nil or bufnr == 0 then
|
||||
bufnr = a.nvim_get_current_buf()
|
||||
end
|
||||
@@ -65,9 +80,98 @@ function module.get_parser(bufnr, ft)
|
||||
local id = tostring(bufnr)..'_'..ft
|
||||
|
||||
if parsers[id] == nil then
|
||||
parsers[id] = module.create_parser(bufnr, ft, id)
|
||||
parsers[id] = M.create_parser(bufnr, ft, id)
|
||||
end
|
||||
if cb ~= nil then
|
||||
table.insert(parsers[id].change_cbs, cb)
|
||||
end
|
||||
return parsers[id]
|
||||
end
|
||||
|
||||
return module
|
||||
-- query: pattern matching on trees
|
||||
-- predicate matching is implemented in lua
|
||||
local Query = {}
|
||||
Query.__index = Query
|
||||
|
||||
function M.parse_query(lang, query)
|
||||
local self = setmetatable({}, Query)
|
||||
self.query = vim._ts_parse_query(lang, query)
|
||||
self.info = self.query:inspect()
|
||||
self.captures = self.info.captures
|
||||
return self
|
||||
end
|
||||
|
||||
local function get_node_text(node, bufnr)
|
||||
local start_row, start_col, end_row, end_col = node:range()
|
||||
if start_row ~= end_row then
|
||||
return nil
|
||||
end
|
||||
local line = a.nvim_buf_get_lines(bufnr, start_row, start_row+1, true)[1]
|
||||
return string.sub(line, start_col+1, end_col)
|
||||
end
|
||||
|
||||
local function match_preds(match, preds, bufnr)
|
||||
for _, pred in pairs(preds) do
|
||||
if pred[1] == "eq?" then
|
||||
local node = match[pred[2]]
|
||||
local node_text = get_node_text(node, bufnr)
|
||||
|
||||
local str
|
||||
if type(pred[3]) == "string" then
|
||||
-- (eq? @aa "foo")
|
||||
str = pred[3]
|
||||
else
|
||||
-- (eq? @aa @bb)
|
||||
str = get_node_text(match[pred[3]], bufnr)
|
||||
end
|
||||
|
||||
if node_text ~= str or str == nil then
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Query:iter_captures(node, bufnr, start, stop)
|
||||
if bufnr == 0 then
|
||||
bufnr = vim.api.nvim_get_current_buf()
|
||||
end
|
||||
local raw_iter = node:_rawquery(self.query,true,start,stop)
|
||||
local function iter()
|
||||
local capture, captured_node, match = raw_iter()
|
||||
if match ~= nil then
|
||||
local preds = self.info.patterns[match.pattern]
|
||||
local active = match_preds(match, preds, bufnr)
|
||||
match.active = active
|
||||
if not active then
|
||||
return iter() -- tail call: try next match
|
||||
end
|
||||
end
|
||||
return capture, captured_node
|
||||
end
|
||||
return iter
|
||||
end
|
||||
|
||||
function Query:iter_matches(node, bufnr, start, stop)
|
||||
if bufnr == 0 then
|
||||
bufnr = vim.api.nvim_get_current_buf()
|
||||
end
|
||||
local raw_iter = node:_rawquery(self.query,false,start,stop)
|
||||
local function iter()
|
||||
local pattern, match = raw_iter()
|
||||
if match ~= nil then
|
||||
local preds = self.info.patterns[pattern]
|
||||
local active = (not preds) or match_preds(match, preds, bufnr)
|
||||
if not active then
|
||||
return iter() -- tail call: try next match
|
||||
end
|
||||
end
|
||||
return pattern, match
|
||||
end
|
||||
return iter
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user