docs
parent
c3bfb4c48f
commit
d7691ecaef
|
@ -0,0 +1,2 @@
|
||||||
|
.worktree
|
||||||
|
.luarc.json
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2023 Pegasust
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
143
README.md
143
README.md
|
@ -1 +1,144 @@
|
||||||
# Treesitter QL
|
# Treesitter QL
|
||||||
|
|
||||||
|
A Neovim plugin allowing users to perform workspace-wise operations (highlighting,
|
||||||
|
list processing, mutation) on existing Treesitter query in Scheme.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Buffer selection (`require('tsql').buf_match`)
|
||||||
|
|
||||||
|
* Filter logic via `buf_match.{path,filetype,ext,any}`.
|
||||||
|
|
||||||
|
#### Combinators
|
||||||
|
|
||||||
|
* With Tacit programming `BufMatch.or_(buf_match.path("world"), BufMatch.not_(buf_match.ext("txt")))`
|
||||||
|
* With method pipelines `buf_match.path("world").or(buf_match.ext("txt").not_())`
|
||||||
|
* Hybrid works too `buf_match.path("world").or(BufMatch.not(buf_match.ext("txt")))`
|
||||||
|
|
||||||
|
### Node query (`require('tsql').token_select`)
|
||||||
|
|
||||||
|
Currently support string-passthru of Treesitter query in Scheme
|
||||||
|
|
||||||
|
`token_select.from_scm("function")`
|
||||||
|
|
||||||
|
### Sink (`require('tsql').sink_by`)
|
||||||
|
|
||||||
|
* Any `{sink: fun(self, QNode[]) -> void}` works!
|
||||||
|
* Processes all workspace nodes.
|
||||||
|
* Highlight specific patterns in your text with `sink_by.highlight()`.
|
||||||
|
Clear all highlights by `require('tsql').clear_highlights()`
|
||||||
|
* Format and print your nodes with `M.sink_by.print()`. This allows you to easily inspect your nodes.
|
||||||
|
* Copy nodes to your clipboard with `M.sink_by.nvim_yank_buf()`.
|
||||||
|
|
||||||
|
#### Format (`require('tsql').format`)
|
||||||
|
|
||||||
|
- Type: `Format = fun(QNode[]): string`
|
||||||
|
- `display: Format`: Representation in a concise/DSL format. This is inspired by Rust's `Display` trait
|
||||||
|
- `dump: Format`: Pretty-print string format for Lua table. Think of this like RON for Rust,
|
||||||
|
some language-native object representation.
|
||||||
|
- `debug: Format`: Aliased from `dump` so that it's consistent with Rust's `Debug` trait
|
||||||
|
|
||||||
|
#### Pre-sink list processing
|
||||||
|
|
||||||
|
WIP
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Here's a basic example of how to use tsql.nvim:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local ts = require('tsql')
|
||||||
|
-- ts.t(<buf_match>, <ts_query>, <sink>)
|
||||||
|
-- Matches all strings in our neovim workspace.
|
||||||
|
ts.t(ts.buf_match.any(), ts.ts_query.from_scm("string"), ts.sink_by.print())
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Use your favorite package manager to install the plugin. For example, with [vim-plug](https://github.com/junegunn/vim-plug):
|
||||||
|
|
||||||
|
```vim
|
||||||
|
Plug 'pegasust/tsql.nvim'
|
||||||
|
```
|
||||||
|
|
||||||
|
Don't forget to run `:PlugInstall` to actually install the plugin.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
To configure tsql.nvim, you can provide a configuration table to the `M.setup` function. Here's an example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local tsql = require('tsql')
|
||||||
|
|
||||||
|
tsql.setup({
|
||||||
|
nvim_hl_group = "Search" -- defines the highlight group used for highlighting
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, `nvim_hl_group` is set to "Search".
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
The following commands are available:
|
||||||
|
|
||||||
|
* `:Noh` - Clear all highlights added by this plugin.
|
||||||
|
* `:lua local ts = require('tsql'); ts.t(<buf_match>, <ts_query>, <sink>)`: Perform tsql in Lua bindings
|
||||||
|
* Example: `:lua local ts = require('tsql'); ts.t(ts.buf_match.any(), ts.ts_query.from_scm("string"), ts.sink_by.print())`
|
||||||
|
* Prints all strings in all buffers reachable from `nvim`
|
||||||
|
* Note that `ts.sink_by.print()` will use `ts.format.default`, which is `ts.format.display` without additional configurations
|
||||||
|
|
||||||
|
### TDSL (Work in progress)
|
||||||
|
|
||||||
|
* `:Tdsl */scm:string/p` - DSL without interacting with Lua API. This example
|
||||||
|
prints all strings on all buffers in default (display) format
|
||||||
|
|
||||||
|
#### Advanced example (`feat:TDSL` + `feat:list_process`)
|
||||||
|
|
||||||
|
Highlight all strings within the current buffer that has more than one occurences
|
||||||
|
|
||||||
|
```
|
||||||
|
:Tdsl bufnr:0/scm:string/group_by(t:qnode:text) | values | filter(count | ge(2)) | flatten | h
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're a FP nerd, power to you! Here's the breakdown of the pre-sink processing:
|
||||||
|
- `group_by`: Group items in a list based on a key returned by a function.
|
||||||
|
|
||||||
|
Function Signature: `group_by(func: (item: T) -> K, list: T[]) -> Map<K, T[]>`
|
||||||
|
|
||||||
|
- `flatten`: Flatten a list of lists into a single list. `flatten([[a], [b, c], []]) -> [a, b, c]`
|
||||||
|
|
||||||
|
Function Signature: `flatten(list: T[][]) -> T[]`
|
||||||
|
|
||||||
|
- `values`: Creates an iterator that goes through all values of a map (created by `group_by` in this case)
|
||||||
|
|
||||||
|
Function Signature: `values(map: Map<K, V>) -> V[]`
|
||||||
|
|
||||||
|
- `filter_map`: Return a new list containing only the items where the given function maps to non-null
|
||||||
|
|
||||||
|
Function Signature: `filter_map(fn: (item: T) -> Option<T>) -> (T[] -> T[])`
|
||||||
|
|
||||||
|
- `some_if`: Lifts a predicate (`T -> bool`) into an "option predicate": `T -> Option<T>`
|
||||||
|
|
||||||
|
Function Signature: `some_if(fn: (item: T) -> bool) -> (T -> Option<T>)`
|
||||||
|
|
||||||
|
- `count`: Counts the number of elements in an interable
|
||||||
|
|
||||||
|
Function Signature: `count(list: T[]) -> number`
|
||||||
|
|
||||||
|
- `ge`: A higher-order function to compare if a number is greater or equal to a set number. `ge(2)(3) == 3 >= 2`
|
||||||
|
|
||||||
|
Function Signature: `ge(lower: number) -> (number -> bool)`
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For detailed information on each function and class, refer to the source code.
|
||||||
|
It contains extensive inline documentation that should be enough to understand each part of the plugin.
|
||||||
|
|
||||||
|
## Contribution
|
||||||
|
|
||||||
|
If you want to contribute to the development of tsql.nvim, feel free to open a pull request.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Tsql.nvim is distributed under the MIT license. See the LICENSE file in the repository for details.
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
{
|
|
||||||
"workspace.library": [
|
|
||||||
"/nix/store/7mwww77s7jads5ymvn9vv11vkywfh1sp-vim-pack-dir",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/plenary.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nlua.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-treesitter",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-treesitter-textobjects",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/telescope.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/telescope-fzf-native.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/telescope-file-browser.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-lspconfig",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-nvim-lsp",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-path",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-buffer",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-cmdline",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-cmp",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/lspkind-nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-yati",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/yang.vim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-autopairs",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-ts-autotag",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/guess-indent.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/Comment.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/gitsigns.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/vim-fugitive",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/mason.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/mason-lspconfig.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/harpoon",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/neogit",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/trouble.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/vim-dispatch",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/vim-jack-in",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/vim-dispatch-neovim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/conjure",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-jqx",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-surround",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/rust-tools.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/inlay-hints.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/gruvbox",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/lualine.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/indent-blankline.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-web-devicons",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/hlargs.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/todo-comments.nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nvim-treesitter-context",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/playground",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp_luasnip",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/LuaSnip",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/zk-nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/vim-caser",
|
|
||||||
"/Users/hungtran/.config/nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/site",
|
|
||||||
"/nix/store/2xr2f568qzslyfmb7zw3sdp8kdv0w7qi-neovim-unwrapped-236c207/share/nvim/runtime",
|
|
||||||
"/nix/store/2xr2f568qzslyfmb7zw3sdp8kdv0w7qi-neovim-unwrapped-236c207/lib/nvim",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/nlua.nvim/after",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-nvim-lsp/after",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-path/after",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-buffer/after",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp-cmdline/after",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/playground/after",
|
|
||||||
"/Users/hungtran/.local/share/nvim/plugged/cmp_luasnip/after",
|
|
||||||
"${3rd}/luassert/library"
|
|
||||||
]
|
|
||||||
}
|
|
23
lua/tsql.lua
23
lua/tsql.lua
|
@ -17,11 +17,21 @@ M.sink_by = {}
|
||||||
---@alias Format fun(nodes: QNode[]): string
|
---@alias Format fun(nodes: QNode[]): string
|
||||||
M.format = {}
|
M.format = {}
|
||||||
|
|
||||||
|
M.format.default = M.format.display
|
||||||
|
|
||||||
---@class Sink
|
---@class Sink
|
||||||
---@field sink fun(self, nodes: QNode[])
|
---@field sink fun(self, nodes: QNode[])
|
||||||
M.Sink = {}
|
M.Sink = {}
|
||||||
M.Sink.__index = M.Sink
|
M.Sink.__index = M.Sink
|
||||||
|
|
||||||
|
---@return Sink
|
||||||
|
---@param func fun(self, nodes:QNode[])
|
||||||
|
function M.sink_by.pure_fn(func)
|
||||||
|
return setmetatable({
|
||||||
|
sink = func
|
||||||
|
}, M.Sink)
|
||||||
|
end
|
||||||
|
|
||||||
---@return Sink
|
---@return Sink
|
||||||
function M.sink_by.highlight()
|
function M.sink_by.highlight()
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
|
@ -72,9 +82,14 @@ function M.format.dump(nodes)
|
||||||
return vim.inspect(nodes, { newline = '\n', indent = ' ' })
|
return vim.inspect(nodes, { newline = '\n', indent = ' ' })
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param format Format
|
M.format.debug = M.format.dump
|
||||||
|
|
||||||
|
---@param format Format | nil
|
||||||
---@return Sink
|
---@return Sink
|
||||||
function M.sink_by.print(format)
|
function M.sink_by.print(format)
|
||||||
|
if format == nil then
|
||||||
|
format = M.format.default
|
||||||
|
end
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
---@type fun(nodes: QNode[])
|
---@type fun(nodes: QNode[])
|
||||||
sink = function(nodes)
|
sink = function(nodes)
|
||||||
|
@ -86,6 +101,9 @@ end
|
||||||
---@param format Format
|
---@param format Format
|
||||||
---@return Sink
|
---@return Sink
|
||||||
function M.sink_by.nvim_yank_buf(format)
|
function M.sink_by.nvim_yank_buf(format)
|
||||||
|
if format == nil then
|
||||||
|
format = M.format.default
|
||||||
|
end
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
---@type fun(nodes: QNode[])
|
---@type fun(nodes: QNode[])
|
||||||
sink = function(nodes)
|
sink = function(nodes)
|
||||||
|
@ -209,6 +227,9 @@ function M.setup(config)
|
||||||
M.config.nvim_ns = vim.api.nvim_create_namespace("tsql")
|
M.config.nvim_ns = vim.api.nvim_create_namespace("tsql")
|
||||||
|
|
||||||
vim.api.nvim_create_user_command("Noh", M.clear_highlights)
|
vim.api.nvim_create_user_command("Noh", M.clear_highlights)
|
||||||
|
vim.api.nvim_create_user_command("Tdsl", function(cmd)
|
||||||
|
M.s(cmd.args):do_nvim(M.store)
|
||||||
|
end)
|
||||||
|
|
||||||
M.store = M.Store:new()
|
M.store = M.Store:new()
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,6 +104,10 @@ function M.buf_match.filetype(...)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M.buf_match.any()
|
||||||
|
return M.BufMatch.new(function(_) return true end)
|
||||||
|
end
|
||||||
|
|
||||||
---@vararg string OR for path
|
---@vararg string OR for path
|
||||||
---@return BufMatch
|
---@return BufMatch
|
||||||
function M.buf_match.path(...)
|
function M.buf_match.path(...)
|
||||||
|
|
|
@ -39,12 +39,12 @@ function M.TSQuery:find_nodes(files)
|
||||||
local tree = parser:parse()[1]
|
local tree = parser:parse()[1]
|
||||||
local root = tree:root()
|
local root = tree:root()
|
||||||
---@type Query
|
---@type Query
|
||||||
local query = vim.treesitter.parse_query(file.lang, self.query)
|
local query = vim.treesitter.query.parse_query(file.lang, self.query)
|
||||||
for _, match, _ in query:iter_matches(root, file.bufnr, 0, -1) do
|
for _, match, _ in query:iter_matches(root, file.bufnr, 0, -1) do
|
||||||
for id, node in pairs(match) do
|
for id, node in pairs(match) do
|
||||||
local start_row, start_col, end_row, end_col = node:range(false)
|
local start_row, start_col, end_row, end_col = node:range(false)
|
||||||
local start = { row_0 = start_row, col_0 = start_col }
|
local start = { row_0 = start_row, col_0 = start_col }
|
||||||
-- NOTE: Will need to validate that this is correct to be exclusive
|
-- 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
|
-- :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 end_ex_col = { row_0 = end_row, col_0 = end_col }
|
||||||
local qnode = { buf = file, start = start, end_ex_col = end_ex_col }
|
local qnode = { buf = file, start = start, end_ex_col = end_ex_col }
|
||||||
|
|
Loading…
Reference in New Issue