fix: prototype now works! check repl.md
parent
2440a208d1
commit
63567fa9fd
28
lua/tsql.lua
28
lua/tsql.lua
|
@ -1,5 +1,4 @@
|
|||
---TODO: how does this work with changing texts?
|
||||
---TODO: add reducer as formatter
|
||||
---TODO: how does this work with changing texts? TODO: add reducer as formatter
|
||||
---TODO: Add reducer as buf_select predicate
|
||||
|
||||
---@type mod_buf_select
|
||||
|
@ -96,12 +95,11 @@ function M.sink_by.print(format)
|
|||
if format == nil then
|
||||
format = M.format.default
|
||||
end
|
||||
return setmetatable({
|
||||
---@type fun(nodes: QNode[])
|
||||
sink = function(nodes)
|
||||
return M.sink_by.pure_fn(
|
||||
function(nodes)
|
||||
print(format(nodes))
|
||||
end
|
||||
}, M.Sink)
|
||||
)
|
||||
end
|
||||
|
||||
---@param format Format
|
||||
|
@ -110,13 +108,12 @@ function M.sink_by.nvim_yank_buf(format)
|
|||
if format == nil then
|
||||
format = M.format.default
|
||||
end
|
||||
return setmetatable({
|
||||
---@type fun(nodes: QNode[])
|
||||
sink = function(nodes)
|
||||
return M.sink.pure_fn(
|
||||
function(nodes)
|
||||
local text = format(nodes)
|
||||
vim.fn.setreg('"', text)
|
||||
end
|
||||
}, M.Sink)
|
||||
)
|
||||
end
|
||||
|
||||
---NOTE: re-export with implementation
|
||||
|
@ -155,9 +152,11 @@ end
|
|||
|
||||
---NOTE: requires nvim runtime
|
||||
function M.Tsql:q_nodes()
|
||||
return self.codeql:find_nodes(
|
||||
self.buf_match.filter_on(self.buf_match, M.nvim_get_qbufs())
|
||||
)
|
||||
return self.codeql:find_nodes(self:qbufs())
|
||||
end
|
||||
|
||||
function M.Tsql:qbufs()
|
||||
return self.buf_match.filter_on(self.buf_match, M.nvim_get_qbufs())
|
||||
end
|
||||
|
||||
---NOTE: This is now exiting the functional core and entering
|
||||
|
@ -220,7 +219,7 @@ end
|
|||
function M.Store:new()
|
||||
local o = { highlighting = {} }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
o.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
|
@ -240,7 +239,6 @@ function M.setup(config)
|
|||
end, { nargs = "?", desc = "tsql DSL invocation" })
|
||||
|
||||
M.store = M.Store:new()
|
||||
print("tsql v0.0.1")
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
|
@ -11,9 +11,9 @@ local M = {}
|
|||
---Assume [""] if it's erroneous (like a terminal buffer)
|
||||
---@field filetype string the associated filetypes gotten from. This uses
|
||||
---`vim.api.nvim_buf_get_option(bufnr: number, 'filetype')`
|
||||
---@field lang string The language of the treesitter parser. This is gotten
|
||||
---from `vim.treesitter.get_parser(bufnr: number):lang() -> string [may fail]`
|
||||
---@field is_loaded boolean whether it is loaded
|
||||
---@field lang string | nil The language of the treesitter parser. This is gotten
|
||||
---from `pcall of vim.treesitter.get_parser(bufnr: number):lang() -> string | nil`
|
||||
---@field is_loaded boolean whether it is loaded (`vim.api.nvim_buf_is_loaded`)
|
||||
M.QBuf = {}
|
||||
M.QBuf.__index = M.QBuf
|
||||
|
||||
|
@ -24,6 +24,7 @@ local function get_lang(bufnr)
|
|||
return vim.treesitter.get_parser(bufnr):lang()
|
||||
end)
|
||||
|
||||
-- PURPOSE: enriches the message
|
||||
if not status then
|
||||
local path = vim.api.nvim_buf_get_name(bufnr)
|
||||
error(string.format("Error determining language for buffer %d: %s", bufnr, path))
|
||||
|
@ -35,15 +36,13 @@ end
|
|||
---@param bufnr number
|
||||
---@param path string
|
||||
---@param filetype string
|
||||
---@param lang string
|
||||
---@param lang string | nil
|
||||
---@param is_loaded boolean
|
||||
---@return QBuf
|
||||
function M.QBuf:new(bufnr, path, filetype, lang, is_loaded)
|
||||
assert(type(bufnr) == "number", "bufnr must be a number")
|
||||
assert(type(path) == "string", "path must be a string")
|
||||
assert(type(filetype) == "string", "filetype must be a string")
|
||||
assert(type(lang) == "string", "lang must be a string")
|
||||
assert(type(is_loaded) == "boolean", "is_loaded must be a boolean")
|
||||
|
||||
local qbuf = {
|
||||
bufnr = bufnr,
|
||||
|
@ -58,14 +57,33 @@ function M.QBuf:new(bufnr, path, filetype, lang, is_loaded)
|
|||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@return QBuf | nil
|
||||
function M.QBuf.from_nvim_bufnr(bufnr)
|
||||
local path = vim.api.nvim_buf_get_name(bufnr)
|
||||
local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
|
||||
local status, lang = pcall(get_lang, bufnr)
|
||||
local is_loaded = status
|
||||
assert(type(filetype) == "string")
|
||||
|
||||
return M.QBuf:new(bufnr, path, filetype, lang, is_loaded)
|
||||
if #filetype == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local sts, _lang = pcall(get_lang, bufnr)
|
||||
---@type nil | string
|
||||
local lang = nil
|
||||
if sts then
|
||||
lang = _lang
|
||||
end
|
||||
|
||||
local is_loaded = vim.api.nvim_buf_is_loaded(bufnr)
|
||||
|
||||
return M.QBuf:new(
|
||||
bufnr,
|
||||
path,
|
||||
filetype,
|
||||
lang,
|
||||
is_loaded
|
||||
)
|
||||
end
|
||||
|
||||
M.buf_match = {}
|
||||
|
@ -75,6 +93,7 @@ M.buf_match = {}
|
|||
---@field then_ fun(self, q: BufMatch): BufMatch
|
||||
---@field filter_on fun(self, q: QBuf[]): QBuf[]
|
||||
M.BufMatch = {}
|
||||
M.BufMatch.__index = M.BufMatch
|
||||
|
||||
function M.buf_match.is_loaded()
|
||||
return M.BufMatch.new(function(buf)
|
||||
|
@ -201,27 +220,16 @@ local function list_bufs()
|
|||
return vim.api.nvim_list_bufs()
|
||||
end
|
||||
|
||||
---@return QBuf[]
|
||||
---@return QBuf[] qbufs
|
||||
function M.nvim_get_qbufs()
|
||||
local bufnrs = list_bufs()
|
||||
local qbufs = {}
|
||||
|
||||
for _, bufnr in ipairs(bufnrs) do
|
||||
local path = vim.api.nvim_buf_get_name(bufnr)
|
||||
local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
|
||||
local status, lang = pcall(get_lang, bufnr)
|
||||
local is_loaded = status
|
||||
|
||||
local qbuf = {
|
||||
bufnr = bufnr,
|
||||
path = path,
|
||||
filetype = filetype,
|
||||
lang = lang,
|
||||
is_loaded = is_loaded
|
||||
}
|
||||
|
||||
table.insert(qbufs, qbuf)
|
||||
local qbuf = M.QBuf.from_nvim_bufnr(bufnr)
|
||||
if qbuf ~= nil then
|
||||
table.insert(qbufs, qbuf)
|
||||
end
|
||||
end
|
||||
|
||||
return qbufs
|
||||
|
|
|
@ -7,6 +7,15 @@ 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
|
||||
|
@ -14,6 +23,15 @@ M.TSQuery = {}
|
|||
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
|
||||
|
@ -21,11 +39,20 @@ M.FileLoc.__index = M.FileLoc
|
|||
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 {
|
||||
return M.TSQuery.new {
|
||||
query = treesitter_query
|
||||
}
|
||||
end
|
||||
|
@ -35,23 +62,35 @@ end
|
|||
function M.TSQuery:find_nodes(files)
|
||||
local result = {}
|
||||
for _, file in ipairs(files) do
|
||||
local parser = vim.treesitter.get_parser(file.bufnr, file.filetype)
|
||||
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 query = vim.treesitter.query.parse_query(file.lang, self.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 = { row_0 = start_row, col_0 = start_col }
|
||||
local start = M.FileLoc.new { row_0 = start_row, col_0 = start_col }
|
||||
-- CORRECTNESS:
|
||||
-- :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)
|
||||
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
|
||||
|
|
35
repl.md
35
repl.md
|
@ -1,13 +1,30 @@
|
|||
# Simple location for me to use as a neovim repl
|
||||
|
||||
```lua
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.any(), ts.ts_query.from_scm("string"), ts.sink_by.print()):do_nvim();
|
||||
|
||||
:lua local ts = require('tsql'); local tsql = ts.t(ts.buf_match.any(), ts.ts_query.from_scm("string"), ts.sink_by.print()); print(vim.inspect(tsql.buf_match));
|
||||
|
||||
-- print found bufs
|
||||
:lua local t = require('tsql'); print(vim.inspect(t.nvim_get_qbufs()))
|
||||
|
||||
-- check that buf filter works
|
||||
:lua local t = require('tsql'); print(vim.inspect(t.buf_match.any():filter_on(t.nvim_get_qbufs())))
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("(string) @_"), ts.sink_by.print()):do_nvim(ts.store);
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("(string) @_"), ts.sink_by.highlight()):do_nvim(ts.store);
|
||||
:Noh
|
||||
-- QNodes from current buffer
|
||||
:lua local ts = require('tsql'); print(vim.inspect(ts.ts_query.from_scm("(string) @_"):find_nodes({ts.QBuf.from_nvim_bufnr(0)})))
|
||||
```
|
||||
|
||||
Non-tsql poc
|
||||
```lua
|
||||
: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
|
||||
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("(string) @_"), ts.sink_by.highlight()):do_nvim(ts.store);
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("(identifier) @_"), ts.sink_by.highlight()):do_nvim(ts.store);
|
||||
-- Highlight all function calls `hello.world("what the heck!")`
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("(function_call) @_"), ts.sink_by.highlight()):do_nvim(ts.store);
|
||||
-- Highlight only function calls that are "pure": Not `hello.world` but `world`
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("(function_call (identifier) @_)"), ts.sink_by.highlight()):do_nvim(ts.store);
|
||||
-- Highlight function calls, but only the function identifier
|
||||
:lua local ts = require('tsql'); ts.t(ts.buf_match.filetype("lua"), ts.ts_query.from_scm("[(function_call name: (dot_index_expression) @_) (function_call name: (identifier) @_) (function_call name: (method_index_expression) @_)]"), ts.sink_by.highlight()):do_nvim(ts.store);
|
||||
|
||||
:Noh
|
||||
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue