feat: probably first prototype

master
Pegasust 2023-05-30 00:29:49 -07:00
parent 606f654a54
commit 25d824714e
5 changed files with 162 additions and 60 deletions

View File

@ -1,55 +1,114 @@
---@type mod_buf_select
local buf_select = require('tsql.buf_select')
---@type mod_token_select
local token_select = require('tsql.token_select')
---@module 'tsql'
local M = {}
M.ts_query = {}
---@class TSQuery
M.TSQuery = {}
---@class mod_sink_by
M.sink_by = {}
---@module 'tsql.format'
---@alias Format fun(self, nodes: QNode[])
---@class mod_format
---@alias Format fun(nodes: QNode[]): string
M.format = {}
---@class Tsql
M.Tsql = {}
M.nvim_ns = vim.api.nvim_create_namespace("tsql")
M.nvim_hl_group = "Search"
---@class Sink
---@field sink fun(self, nodes: QNode[])
M.Sink = {}
M.Sink.__index = M.Sink
---@return Sink
function M.sink_by.highlight()
return setmetatable({
---@type fun(nodes: QNode[])
sink = function(nodes)
for _, node in ipairs(nodes) do
vim.highlight.range(
node.buf.bufnr,
M.nvim_ns,
M.nvim_hl_group,
{ node.start.row_0, node.start.col_0 },
{ node.end_ex_col.row_0, node.end_ex_col.col_0 },
{}
)
end
end
}, M.Sink)
end
---@type Format
---Something that can be represented in string in a concise/DSL format.
---In the context of QNode, it should just be the text content. If it's multiline,
---just join by newline
---
---`vim.api.nvim_buf_get_text(
--- bufnr: number,
--- start_row: number,
--- start_col: number,
--- end_row: number,
--- end_col_exclusive: number,
--- opt: {}
---) -> string[]` return value is array of lines, empty array for unloaded buffer
function M.format.display(nodes)
local texts = {}
for _, node in ipairs(nodes) do
local text = vim.api.nvim_buf_get_text(node.buf.bufnr, node.start.row_0, node.start.col_0, node.end_ex_col.row_0,
node.end_ex_col.col_0)
table.insert(texts, table.concat(text, '\n'))
end
return table.concat(texts, '\n\n')
end
---@type Format
---Something like a JSON if natively possible, or RON for Rust for clarity
---Basically return a string that is pretty-printed that represents
---a Lua table onto string
function M.format.dump(nodes)
return vim.inspect(nodes, { newline = '\n', indent = ' ' })
end
---@param format Format
---@return Sink
function M.sink_by.print(format)
return setmetatable({
---@type fun(nodes: QNode[])
sink = function(nodes)
print(format(nodes))
end
}, M.Sink)
end
---@param format Format
---@return Sink
function M.sink_by.nvim_yank_buf(format)
return setmetatable({
---@type fun(nodes: QNode[])
sink = function(nodes)
local text = format(nodes)
vim.fn.setreg('"', text)
end
}, M.Sink)
end
---NOTE: re-export with implementation
M.buf_match = require('tsql.buf_select')
M.buf_match = buf_select.buf_match
M.BufMatch = buf_select.BufMatch
M.QBuf = buf_select.QBuf
M.nvim_get_qbufs = buf_select.nvim_get_qbufs
function M.ts_query.from_scm(treesitter_query)
-- TODO: implement
return M.TSQuery
end
M.ts_query = token_select.ts_query
M.TSQuery = token_select.TSQuery
function M.TSQuery:find_locs(files)
-- TODO: implement
return {}
end
function M.sink_by.highlight()
-- TODO: implement
end
---@type Format
function M.format.display()
-- TODO: implement
end
---@type Format
function M.format.dump()
-- TODO: implement
end
---@param format Format
function M.sink_by.print(format)
-- TODO: implement
end
---@param format Format
function M.sink_by.nvim_yank_buf(format)
-- TODO: implement
end
---@class Tsql
---@field buf_match BufMatch
---@field codeql TSQuery
---@field sink Sink
M.Tsql = {}
M.Tsql.__index = M.Tsql
---@return Tsql
---@param external_dsl string
@ -62,13 +121,21 @@ end
---@param codeql TSQuery
---@param sink Sink
function M.t(buf_match, codeql, sink)
-- TODO: implement
return setmetatable({
buf_match = buf_match,
codeql = codeql,
sink = sink
}, M.Tsql)
end
---NOTE: This is now exiting the functional core and entering
--- imperative shell
function M.Tsql:do_nvim()
-- TODO: implement
self.sink:sink(
self.codeql:find_nodes(
self.buf_match:filter_on(M.nvim_get_qbufs())
)
)
end
return M

View File

@ -1,8 +1,9 @@
---@module 'buf_select'
---@class mod_buf_select
---@alias MatchPredicate fun(nodes: QNode[]): boolean
local M = {}
---@alias MatchPredicate fun(nodes: QBuf): boolean
---@class QBuf
---@field bufnr number representing the vim runtime's bufnr, 0 is current buf
---@field path string the absolute path to the buffer. This uses
@ -71,7 +72,7 @@ M.buf_match = {}
---@field not_ fun(self): BufMatch
---@field or_ fun(self, q: BufMatch): BufMatch
---@field then_ fun(self, q: BufMatch): BufMatch
---@field filter_on fun(self, q: QNode[]): QNode[]
---@field filter_on fun(self, q: QBuf[]): QBuf[]
M.BufMatch = {}
function M.buf_match.is_loaded()

View File

@ -1,6 +1,5 @@
local M = {}
---@class Sink
M.Sink = {}
function M.print()

View File

@ -1,24 +1,59 @@
---@module 'tsql.token_select'
---@class mod_token_select
local M = {}
---@class FileLoc
---@field
M.FileLoc = {
}
---@class QNode
M.QNode = {}
---@class mod_ts_query
M.ts_query = {}
---@class TSQuery
---@field find_nodes fun(self: TSQuery, bufs: QBuf[]): TSNode[]
---@field query string the passthru for treesitter language parser
M.TSQuery = {}
---@param treesitter_q string Treesitter DSL for query
---TODO: some examples of `treesitter_q` here
---
---@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
---@class QNode
---@field start FileLoc
---@field end_ex_col FileLoc
---@field buf QBuf
M.QNode = {}
M.QNode.__index = M.QNode
---@param treesitter_query string the passthru for treesitter language
---parser
---@return TSQuery
function M.from_ts_scm(treesitter_q)
function M.ts_query.from_scm(treesitter_query)
return {
query = treesitter_query
}
end
---@param files QBuf[]
---@return QNode[]
function M.TSQuery:find_nodes(files)
local result = {}
for _, file in ipairs(files) do
local parser = vim.treesitter.get_parser(file.bufnr, file.filetype)
local tree = parser:parse()[1]
local root = tree:root()
---@type Query
local query = vim.treesitter.parse_query(file.lang, self.query)
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 = { row_0 = start_row, col_0 = start_col }
-- NOTE: Will need to validate that this is correct to be exclusive
-- :lua local parser = vim.treesitter.get_parser(0, 'lua'); local tree = parser:parse()[1]; local query = vim.treesitter.parse_query('lua', '(identifier) @name'); for id, node in query:iter_captures(tree:root(), 0) do local name = query.captures[id]; if name == 'name' and vim.treesitter.get_node_text(node, 0) == 'TSQuery' then local sr, sc, er, ec = node:range(); print(string.format("TSQuery Start: (%d, %d), End: (%d, %d)", sr, sc, er, ec)); end; end
local end_ex_col = { row_0 = end_row, col_0 = end_col }
local qnode = { buf = file, start = start, end_ex_col = end_ex_col }
setmetatable(qnode, M.QNode)
table.insert(result, qnode)
end
end
end
return result
end
return M

View File