tsql.nvim/lua/tsql/token_select.lua

98 lines
2.7 KiB
Lua

---@module 'tsql.token_select'
---@class mod_token_select
local M = {}
---@class mod_ts_query
M.ts_query = {}
---@class TSQuery
---@field query string the passthru for treesitter language parser
M.TSQuery = {}
M.TSQuery.__index = M.TSQuery
---@type Ctor<{query: string}, TSQuery>
function M.TSQuery.new(q)
local self = q
setmetatable(self, M.TSQuery)
self.__index = M.TSQuery
return self
end
---@class FileLoc
---@field row_0 number 0-index row location
---@field col_0 number 0-index col location
M.FileLoc = {}
M.FileLoc.__index = M.FileLoc
---@type Ctor<{row_0: number, col_0: number}, FileLoc>
function M.FileLoc.new(file_loc)
assert(file_loc ~= nil)
local self = file_loc
setmetatable(self, M.FileLoc)
self.__index = M.FileLoc
return self
end
---@class QNode
---@field start FileLoc
---@field end_ex_col FileLoc
---@field buf QBuf
M.QNode = {}
M.QNode.__index = M.QNode
---@type Ctor<{start: FileLoc, end_ex_col: FileLoc, buf: QBuf}, QNode>
function M.QNode.new(qnode)
assert(qnode ~= nil)
local self = qnode
setmetatable(self, M.QNode)
self.__index = M.QNode
return self
end
---@param treesitter_query string the passthru for treesitter language
---parser
---@return TSQuery
function M.ts_query.from_scm(treesitter_query)
return M.TSQuery.new {
query = treesitter_query
}
end
---@param files QBuf[]
---@return QNode[]
function M.TSQuery:find_nodes(files)
local result = {}
for _, file in ipairs(files) do
if file.lang == nil then
goto continue
end
local sts, parser = pcall(vim.treesitter.get_parser, file.bufnr, file.filetype)
if not sts then
-- NOTE: no parser for language
goto continue
end
local tree = parser:parse()[1]
local root = tree:root()
---@type Query
local sts, query = pcall(vim.treesitter.query.parse, file.lang, self.query)
if not sts then
error("Error parsing query \"" .. self.query .. "\" on lang " .. file.lang .. " for file " .. file.path)
end
for _, match, _ in query:iter_matches(root, file.bufnr, 0, -1) do
for id, node in pairs(match) do
local start_row, start_col, end_row, end_col = node:range(false)
local start = M.FileLoc.new { row_0 = start_row, col_0 = start_col }
-- CORRECTNESS, see repl.md
local end_ex_col = M.FileLoc.new { row_0 = end_row, col_0 = end_col }
local qnode = M.QNode.new { buf = file, start = start, end_ex_col = end_ex_col }
table.insert(result, qnode)
end
end
::continue::
end
return result
end
return M