mirror of
https://github.com/nvim-treesitter/nvim-treesitter.git
synced 2026-07-18 11:20:07 -04:00
style: fill in missing code docs wherever applicable
This commit is contained in:
parent
fceb4ed0ec
commit
853b1ab39a
17 changed files with 431 additions and 191 deletions
|
|
@ -2,20 +2,26 @@ local api = vim.api
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
--- Creates a cache table for buffers keyed by a type name.
|
-- Creates a cache table for buffers keyed by a type name.
|
||||||
--- Cache entries attach to the buffer and cleanup entries
|
-- Cache entries attach to the buffer and cleanup entries
|
||||||
--- as buffers are detached.
|
-- as buffers are detached.
|
||||||
function M.create_buffer_cache()
|
function M.create_buffer_cache()
|
||||||
local cache = {}
|
local cache = {}
|
||||||
|
|
||||||
|
---@type table<string, table<string, any>>
|
||||||
local items = setmetatable({}, {
|
local items = setmetatable({}, {
|
||||||
__index = function(tbl, key)
|
__index = function(tbl, key)
|
||||||
rawset(tbl, key, {})
|
rawset(tbl, key, {})
|
||||||
return rawget(tbl, key)
|
return rawget(tbl, key)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
---@type table<integer|string, boolean>
|
||||||
local loaded_buffers = {}
|
local loaded_buffers = {}
|
||||||
|
|
||||||
|
---@param type_name string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param value any
|
||||||
function cache.set(type_name, bufnr, value)
|
function cache.set(type_name, bufnr, value)
|
||||||
if not loaded_buffers[bufnr] then
|
if not loaded_buffers[bufnr] then
|
||||||
loaded_buffers[bufnr] = true
|
loaded_buffers[bufnr] = true
|
||||||
|
|
@ -34,18 +40,27 @@ function M.create_buffer_cache()
|
||||||
items[tostring(bufnr)][type_name] = value
|
items[tostring(bufnr)][type_name] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param type_name string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return any
|
||||||
function cache.get(type_name, bufnr)
|
function cache.get(type_name, bufnr)
|
||||||
return items[tostring(bufnr)][type_name]
|
return items[tostring(bufnr)][type_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param type_name string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return boolean
|
||||||
function cache.has(type_name, bufnr)
|
function cache.has(type_name, bufnr)
|
||||||
return cache.get(type_name, bufnr) ~= nil
|
return cache.get(type_name, bufnr) ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param type_name string
|
||||||
|
---@param bufnr integer
|
||||||
function cache.remove(type_name, bufnr)
|
function cache.remove(type_name, bufnr)
|
||||||
items[tostring(bufnr)][type_name] = nil
|
items[tostring(bufnr)][type_name] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
function cache.clear_buffer(bufnr)
|
function cache.clear_buffer(bufnr)
|
||||||
items[tostring(bufnr)] = nil
|
items[tostring(bufnr)] = nil
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,9 @@ local config = {
|
||||||
update_strategy = "lockfile",
|
update_strategy = "lockfile",
|
||||||
parser_install_dir = nil,
|
parser_install_dir = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- List of modules that need to be setup on initialization.
|
-- List of modules that need to be setup on initialization.
|
||||||
|
---@type TSModule[][]
|
||||||
local queued_modules_defs = {}
|
local queued_modules_defs = {}
|
||||||
-- Whether we've initialized the plugin yet.
|
-- Whether we've initialized the plugin yet.
|
||||||
local is_initialized = false
|
local is_initialized = false
|
||||||
|
|
@ -36,10 +38,12 @@ local is_initialized = false
|
||||||
---@field module_path string
|
---@field module_path string
|
||||||
---@field enable boolean|string[]|function(string): boolean
|
---@field enable boolean|string[]|function(string): boolean
|
||||||
---@field disable boolean|string[]|function(string): boolean
|
---@field disable boolean|string[]|function(string): boolean
|
||||||
|
---@field keymaps table<string, string>
|
||||||
---@field is_supported function(string): boolean
|
---@field is_supported function(string): boolean
|
||||||
---@field attach function(string)
|
---@field attach function(string)
|
||||||
---@field detach function(string)
|
---@field detach function(string)
|
||||||
---@field enabled_buffers table<integer, boolean>
|
---@field enabled_buffers table<integer, boolean>
|
||||||
|
---@field additional_vim_regex_highlighting boolean|string[]
|
||||||
|
|
||||||
---@type {[string]: TSModule}
|
---@type {[string]: TSModule}
|
||||||
local builtin_modules = {
|
local builtin_modules = {
|
||||||
|
|
@ -248,7 +252,7 @@ local function recurse_modules(accumulator, root, path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---Shows current configuration of all nvim-treesitter modules
|
-- Shows current configuration of all nvim-treesitter modules
|
||||||
---@param process_function function used as the `process` parameter
|
---@param process_function function used as the `process` parameter
|
||||||
--- for vim.inspect (https://github.com/kikito/inspect.lua#optionsprocess)
|
--- for vim.inspect (https://github.com/kikito/inspect.lua#optionsprocess)
|
||||||
local function config_info(process_function)
|
local function config_info(process_function)
|
||||||
|
|
@ -369,7 +373,7 @@ M.commands = {
|
||||||
|
|
||||||
---@param mod string module
|
---@param mod string module
|
||||||
---@param lang string the language of the buffer
|
---@param lang string the language of the buffer
|
||||||
---@param bufnr integer the bufnr
|
---@param bufnr integer the buffer
|
||||||
function M.is_enabled(mod, lang, bufnr)
|
function M.is_enabled(mod, lang, bufnr)
|
||||||
if not parsers.has_parser(lang) then
|
if not parsers.has_parser(lang) then
|
||||||
return false
|
return false
|
||||||
|
|
@ -438,8 +442,8 @@ function M.setup(user_data)
|
||||||
end, config.modules)
|
end, config.modules)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Defines a table of modules that can be attached/detached to buffers
|
-- Defines a table of modules that can be attached/detached to buffers
|
||||||
---based on language support. A module consist of the following properties:
|
-- based on language support. A module consist of the following properties:
|
||||||
---* @enable Whether the modules is enabled. Can be true or false.
|
---* @enable Whether the modules is enabled. Can be true or false.
|
||||||
---* @disable A list of languages to disable the module for. Only relevant if enable is true.
|
---* @disable A list of languages to disable the module for. Only relevant if enable is true.
|
||||||
---* @keymaps A list of user mappings for a given module if relevant.
|
---* @keymaps A list of user mappings for a given module if relevant.
|
||||||
|
|
@ -451,9 +455,11 @@ end
|
||||||
--- if a `module_path` is not specified.
|
--- if a `module_path` is not specified.
|
||||||
---* @detach A detach function that is called for each buffer that the module is enabled for. This is required
|
---* @detach A detach function that is called for each buffer that the module is enabled for. This is required
|
||||||
--- if a `module_path` is not specified.
|
--- if a `module_path` is not specified.
|
||||||
---Modules are not setup until `init` is invoked by the plugin. This allows modules to be defined in any order
|
--
|
||||||
---and can be loaded lazily.
|
-- Modules are not setup until `init` is invoked by the plugin. This allows modules to be defined in any order
|
||||||
---@example
|
-- and can be loaded lazily.
|
||||||
|
--
|
||||||
|
---* @example
|
||||||
---require"nvim-treesitter".define_modules {
|
---require"nvim-treesitter".define_modules {
|
||||||
--- my_cool_module = {
|
--- my_cool_module = {
|
||||||
--- attach = function()
|
--- attach = function()
|
||||||
|
|
@ -493,7 +499,7 @@ end
|
||||||
|
|
||||||
---Attaches a module to a buffer
|
---Attaches a module to a buffer
|
||||||
---@param mod_name string the module name
|
---@param mod_name string the module name
|
||||||
---@param bufnr integer the bufnr
|
---@param bufnr integer the buffer
|
||||||
---@param lang string the language of the buffer
|
---@param lang string the language of the buffer
|
||||||
function M.attach_module(mod_name, bufnr, lang)
|
function M.attach_module(mod_name, bufnr, lang)
|
||||||
bufnr = bufnr or api.nvim_get_current_buf()
|
bufnr = bufnr or api.nvim_get_current_buf()
|
||||||
|
|
@ -506,9 +512,9 @@ function M.attach_module(mod_name, bufnr, lang)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---Detaches a module to a buffer
|
-- Detaches a module to a buffer
|
||||||
---@param mod_name string the module name
|
---@param mod_name string the module name
|
||||||
---@param bufnr integer the bufnr
|
---@param bufnr integer the buffer
|
||||||
function M.detach_module(mod_name, bufnr)
|
function M.detach_module(mod_name, bufnr)
|
||||||
local resolved_mod = resolve_module(mod_name)
|
local resolved_mod = resolve_module(mod_name)
|
||||||
bufnr = bufnr or api.nvim_get_current_buf()
|
bufnr = bufnr or api.nvim_get_current_buf()
|
||||||
|
|
@ -519,17 +525,18 @@ function M.detach_module(mod_name, bufnr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---Same as attach_module, but if the module is already attached, detach it first.
|
-- Same as attach_module, but if the module is already attached, detach it first.
|
||||||
---@param mod_name string the module name
|
---@param mod_name string the module name
|
||||||
---@param bufnr integer the bufnr
|
---@param bufnr integer the buffer
|
||||||
---@param lang string the language of the buffer
|
---@param lang string the language of the buffer
|
||||||
function M.reattach_module(mod_name, bufnr, lang)
|
function M.reattach_module(mod_name, bufnr, lang)
|
||||||
M.detach_module(mod_name, bufnr)
|
M.detach_module(mod_name, bufnr)
|
||||||
M.attach_module(mod_name, bufnr, lang)
|
M.attach_module(mod_name, bufnr, lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Gets available modules
|
-- Gets available modules
|
||||||
---@param root {[string]:TSModule}|nil table to find modules
|
---@param root {[string]:TSModule}|nil table to find modules
|
||||||
|
---@return string[] modules list of module paths
|
||||||
function M.available_modules(root)
|
function M.available_modules(root)
|
||||||
local modules = {}
|
local modules = {}
|
||||||
|
|
||||||
|
|
@ -542,24 +549,24 @@ end
|
||||||
|
|
||||||
---Gets a module config by path
|
---Gets a module config by path
|
||||||
---@param mod_path string path to the module
|
---@param mod_path string path to the module
|
||||||
---@return TSModule|nil the module or nil
|
---@return TSModule|nil: the module or nil
|
||||||
function M.get_module(mod_path)
|
function M.get_module(mod_path)
|
||||||
local mod = utils.get_at_path(config.modules, mod_path)
|
local mod = utils.get_at_path(config.modules, mod_path)
|
||||||
|
|
||||||
return M.is_module(mod) and mod or nil
|
return M.is_module(mod) and mod or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
---Determines whether the provided table is a module.
|
-- Determines whether the provided table is a module.
|
||||||
---A module should contain an attach and detach function.
|
-- A module should contain an attach and detach function.
|
||||||
---@param mod table the module table
|
---@param mod table|nil the module table
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function M.is_module(mod)
|
function M.is_module(mod)
|
||||||
return type(mod) == "table"
|
return type(mod) == "table"
|
||||||
and ((type(mod.attach) == "function" and type(mod.detach) == "function") or type(mod.module_path) == "string")
|
and ((type(mod.attach) == "function" and type(mod.detach) == "function") or type(mod.module_path) == "string")
|
||||||
end
|
end
|
||||||
|
|
||||||
---Initializes built-in modules and any queued modules
|
-- Initializes built-in modules and any queued modules
|
||||||
---registered by plugins or the user.
|
-- registered by plugins or the user.
|
||||||
function M.init()
|
function M.init()
|
||||||
is_initialized = true
|
is_initialized = true
|
||||||
M.define_modules(builtin_modules)
|
M.define_modules(builtin_modules)
|
||||||
|
|
@ -569,22 +576,17 @@ function M.init()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---If parser_install_dir is not nil is used or created.
|
-- If parser_install_dir is not nil is used or created.
|
||||||
---If parser_install_dir is nil try the package dir of the nvim-treesitter
|
-- If parser_install_dir is nil try the package dir of the nvim-treesitter
|
||||||
---plugin first, followed by the "site" dir from "runtimepath". "site" dir will
|
-- plugin first, followed by the "site" dir from "runtimepath". "site" dir will
|
||||||
---be created if it doesn't exist. Using only the package dir won't work when
|
-- be created if it doesn't exist. Using only the package dir won't work when
|
||||||
---the plugin is installed with Nix, since the "/nix/store" is read-only.
|
-- the plugin is installed with Nix, since the "/nix/store" is read-only.
|
||||||
---@param folder_name string|nil
|
---@param folder_name string|nil
|
||||||
---@return string|nil, string|nil
|
---@return string|nil, string|nil
|
||||||
function M.get_parser_install_dir(folder_name)
|
function M.get_parser_install_dir(folder_name)
|
||||||
folder_name = folder_name or "parser"
|
folder_name = folder_name or "parser"
|
||||||
|
|
||||||
local install_dir
|
local install_dir = config.parser_install_dir or utils.get_package_path()
|
||||||
if config.parser_install_dir then
|
|
||||||
install_dir = config.parser_install_dir
|
|
||||||
else
|
|
||||||
install_dir = utils.get_package_path()
|
|
||||||
end
|
|
||||||
local parser_dir = utils.join_path(install_dir, folder_name)
|
local parser_dir = utils.join_path(install_dir, folder_name)
|
||||||
|
|
||||||
return utils.create_or_reuse_writable_dir(
|
return utils.create_or_reuse_writable_dir(
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,10 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- start..stop is an inclusive range
|
-- start..stop is an inclusive range
|
||||||
|
|
||||||
|
---@type table<number, number>
|
||||||
local start_counts = {}
|
local start_counts = {}
|
||||||
|
---@type table<number, number>
|
||||||
local stop_counts = {}
|
local stop_counts = {}
|
||||||
|
|
||||||
local prev_start = -1
|
local prev_start = -1
|
||||||
|
|
@ -40,11 +43,11 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
|
||||||
local min_fold_lines = api.nvim_win_get_option(0, "foldminlines")
|
local min_fold_lines = api.nvim_win_get_option(0, "foldminlines")
|
||||||
|
|
||||||
for _, match in ipairs(matches) do
|
for _, match in ipairs(matches) do
|
||||||
local start, stop, stop_col
|
local start, stop, stop_col ---@type integer, integer, integer
|
||||||
if match.metadata and match.metadata.range then
|
if match.metadata and match.metadata.range then
|
||||||
start, _, stop, stop_col = unpack(match.metadata.range)
|
start, _, stop, stop_col = unpack(match.metadata.range) ---@type integer, integer, integer, integer
|
||||||
else
|
else
|
||||||
start, _, stop, stop_col = match.node:range()
|
start, _, stop, stop_col = match.node:range() ---@type integer, integer, integer, integer
|
||||||
end
|
end
|
||||||
|
|
||||||
if stop_col == 0 then
|
if stop_col == 0 then
|
||||||
|
|
@ -65,6 +68,7 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type string[]
|
||||||
local levels = {}
|
local levels = {}
|
||||||
local current_level = 0
|
local current_level = 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@ local configs = require "nvim-treesitter.configs"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
---@param config table
|
---@param config TSModule
|
||||||
---@param lang string
|
---@param lang string
|
||||||
---@return boolean
|
---@return boolean
|
||||||
local function should_enable_vim_regex(config, lang)
|
local function should_enable_vim_regex(config, lang)
|
||||||
local additional_hl = config.additional_vim_regex_highlighting
|
local additional_hl = config.additional_vim_regex_highlighting
|
||||||
local is_table = type(additional_hl) == "table"
|
local is_table = type(additional_hl) == "table"
|
||||||
|
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
return additional_hl and (not is_table or vim.tbl_contains(additional_hl, lang))
|
return additional_hl and (not is_table or vim.tbl_contains(additional_hl, lang))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ local queries = require "nvim-treesitter.query"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
---@type table<integer, table<TSNode|nil>>
|
||||||
local selections = {}
|
local selections = {}
|
||||||
|
|
||||||
function M.init_selection()
|
function M.init_selection()
|
||||||
|
|
@ -17,14 +18,15 @@ function M.init_selection()
|
||||||
ts_utils.update_selection(buf, node)
|
ts_utils.update_selection(buf, node)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the range of the current visual selection.
|
-- Get the range of the current visual selection.
|
||||||
--
|
--
|
||||||
-- The range start with 1 and the ending is inclusive.
|
-- The range starts with 1 and the ending is inclusive.
|
||||||
|
---@return integer, integer, integer, integer
|
||||||
local function visual_selection_range()
|
local function visual_selection_range()
|
||||||
local _, csrow, cscol, _ = unpack(vim.fn.getpos "'<")
|
local _, csrow, cscol, _ = unpack(vim.fn.getpos "'<") ---@type integer, integer, integer, integer
|
||||||
local _, cerow, cecol, _ = unpack(vim.fn.getpos "'>")
|
local _, cerow, cecol, _ = unpack(vim.fn.getpos "'>") ---@type integer, integer, integer, integer
|
||||||
|
|
||||||
local start_row, start_col, end_row, end_col
|
local start_row, start_col, end_row, end_col ---@type integer, integer, integer, integer
|
||||||
|
|
||||||
if csrow < cerow or (csrow == cerow and cscol <= cecol) then
|
if csrow < cerow or (csrow == cerow and cscol <= cecol) then
|
||||||
start_row = csrow
|
start_row = csrow
|
||||||
|
|
@ -41,12 +43,16 @@ local function visual_selection_range()
|
||||||
return start_row, start_col, end_row, end_col
|
return start_row, start_col, end_row, end_col
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param node TSNode
|
||||||
|
---@return boolean
|
||||||
local function range_matches(node)
|
local function range_matches(node)
|
||||||
local csrow, cscol, cerow, cecol = visual_selection_range()
|
local csrow, cscol, cerow, cecol = visual_selection_range()
|
||||||
local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() }
|
local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() }
|
||||||
return srow == csrow and scol == cscol and erow == cerow and ecol == cecol
|
return srow == csrow and scol == cscol and erow == cerow and ecol == cecol
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param get_parent fun(node: TSNode): TSNode|nil
|
||||||
|
---@return fun():nil
|
||||||
local function select_incremental(get_parent)
|
local function select_incremental(get_parent)
|
||||||
return function()
|
return function()
|
||||||
local buf = api.nvim_get_current_buf()
|
local buf = api.nvim_get_current_buf()
|
||||||
|
|
@ -67,7 +73,7 @@ local function select_incremental(get_parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Find a node that changes the current selection.
|
-- Find a node that changes the current selection.
|
||||||
local node = nodes[#nodes]
|
local node = nodes[#nodes] ---@type TSNode
|
||||||
while true do
|
while true do
|
||||||
local parent = get_parent(node)
|
local parent = get_parent(node)
|
||||||
if not parent or parent == node then
|
if not parent or parent == node then
|
||||||
|
|
@ -116,7 +122,7 @@ function M.node_decremental()
|
||||||
end
|
end
|
||||||
|
|
||||||
table.remove(selections[buf])
|
table.remove(selections[buf])
|
||||||
local node = nodes[#nodes]
|
local node = nodes[#nodes] ---@type TSNode
|
||||||
ts_utils.update_selection(buf, node)
|
ts_utils.update_selection(buf, node)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -127,14 +133,16 @@ local FUNCTION_DESCRIPTIONS = {
|
||||||
node_decremental = "Shrink selection to previous named node",
|
node_decremental = "Shrink selection to previous named node",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
function M.attach(bufnr)
|
function M.attach(bufnr)
|
||||||
local config = configs.get_module "incremental_selection"
|
local config = configs.get_module "incremental_selection"
|
||||||
for funcname, mapping in pairs(config.keymaps) do
|
for funcname, mapping in pairs(config.keymaps) do
|
||||||
if mapping then
|
if mapping then
|
||||||
local mode
|
---@type string, string|function
|
||||||
local rhs
|
local mode, rhs
|
||||||
if funcname == "init_selection" then
|
if funcname == "init_selection" then
|
||||||
mode = "n"
|
mode = "n"
|
||||||
|
---@type function
|
||||||
rhs = M[funcname]
|
rhs = M[funcname]
|
||||||
else
|
else
|
||||||
mode = "x"
|
mode = "x"
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,27 @@ M.comment_parsers = {
|
||||||
phpdoc = true,
|
phpdoc = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@param root TSNode
|
||||||
|
---@param lnum integer
|
||||||
|
---@return TSNode
|
||||||
local function get_first_node_at_line(root, lnum)
|
local function get_first_node_at_line(root, lnum)
|
||||||
local col = vim.fn.indent(lnum)
|
local col = vim.fn.indent(lnum)
|
||||||
return root:descendant_for_range(lnum - 1, col, lnum - 1, col)
|
return root:descendant_for_range(lnum - 1, col, lnum - 1, col)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param root TSNode
|
||||||
|
---@param lnum integer
|
||||||
|
---@return TSNode
|
||||||
local function get_last_node_at_line(root, lnum)
|
local function get_last_node_at_line(root, lnum)
|
||||||
local col = #vim.fn.getline(lnum) - 1
|
local col = #vim.fn.getline(lnum) - 1
|
||||||
return root:descendant_for_range(lnum - 1, col, lnum - 1, col)
|
return root:descendant_for_range(lnum - 1, col, lnum - 1, col)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param node TSNode
|
||||||
|
---@param delimiter string
|
||||||
|
---@return TSNode|nil child
|
||||||
|
---@return boolean|nil is_end
|
||||||
local function find_delimiter(bufnr, node, delimiter)
|
local function find_delimiter(bufnr, node, delimiter)
|
||||||
for child, _ in node:iter_children() do
|
for child, _ in node:iter_children() do
|
||||||
if child:type() == delimiter then
|
if child:type() == delimiter then
|
||||||
|
|
@ -77,7 +88,7 @@ function M.get_indent(lnum)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get language tree with smallest range around node that's not a comment parser
|
-- Get language tree with smallest range around node that's not a comment parser
|
||||||
local root, lang_tree
|
local root, lang_tree ---@type TSNode, LanguageTree
|
||||||
parser:for_each_tree(function(tstree, tree)
|
parser:for_each_tree(function(tstree, tree)
|
||||||
if not tstree or M.comment_parsers[tree:lang()] then
|
if not tstree or M.comment_parsers[tree:lang()] then
|
||||||
return
|
return
|
||||||
|
|
@ -98,7 +109,7 @@ function M.get_indent(lnum)
|
||||||
|
|
||||||
local q = get_indents(vim.api.nvim_get_current_buf(), root, lang_tree:lang())
|
local q = get_indents(vim.api.nvim_get_current_buf(), root, lang_tree:lang())
|
||||||
local is_empty_line = string.match(vim.fn.getline(lnum), "^%s*$") ~= nil
|
local is_empty_line = string.match(vim.fn.getline(lnum), "^%s*$") ~= nil
|
||||||
local node
|
local node ---@type TSNode
|
||||||
if is_empty_line then
|
if is_empty_line then
|
||||||
local prevlnum = vim.fn.prevnonblank(lnum)
|
local prevlnum = vim.fn.prevnonblank(lnum)
|
||||||
node = get_last_node_at_line(root, prevlnum)
|
node = get_last_node_at_line(root, prevlnum)
|
||||||
|
|
@ -171,8 +182,9 @@ function M.get_indent(lnum)
|
||||||
-- do not indent for nodes that starts-and-ends on same line and starts on target line (lnum)
|
-- do not indent for nodes that starts-and-ends on same line and starts on target line (lnum)
|
||||||
if q.aligned_indent[node:id()] and srow ~= erow and (srow ~= lnum - 1) then
|
if q.aligned_indent[node:id()] and srow ~= erow and (srow ~= lnum - 1) then
|
||||||
local metadata = q.aligned_indent[node:id()]
|
local metadata = q.aligned_indent[node:id()]
|
||||||
local o_delim_node, is_last_in_line
|
local o_delim_node, is_last_in_line ---@type TSNode|nil, boolean|nil
|
||||||
if metadata.delimiter then
|
if metadata.delimiter then
|
||||||
|
---@type string
|
||||||
local opening_delimiter = metadata.delimiter and metadata.delimiter:sub(1, 1)
|
local opening_delimiter = metadata.delimiter and metadata.delimiter:sub(1, 1)
|
||||||
o_delim_node, is_last_in_line = find_delimiter(bufnr, node, opening_delimiter)
|
o_delim_node, is_last_in_line = find_delimiter(bufnr, node, opening_delimiter)
|
||||||
else
|
else
|
||||||
|
|
@ -198,8 +210,10 @@ function M.get_indent(lnum)
|
||||||
return indent
|
return indent
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type table<integer, string>
|
||||||
local indent_funcs = {}
|
local indent_funcs = {}
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
function M.attach(bufnr)
|
function M.attach(bufnr)
|
||||||
indent_funcs[bufnr] = vim.bo.indentexpr
|
indent_funcs[bufnr] = vim.bo.indentexpr
|
||||||
vim.bo.indentexpr = "nvim_treesitter#indent()"
|
vim.bo.indentexpr = "nvim_treesitter#indent()"
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ end
|
||||||
-- {'mod1', 'mod2.sub1', 'mod2.sub2', 'mod3'}
|
-- {'mod1', 'mod2.sub1', 'mod2.sub2', 'mod3'}
|
||||||
-- ->
|
-- ->
|
||||||
-- { default = {'mod1', 'mod3'}, mod2 = {'sub1', 'sub2'}}
|
-- { default = {'mod1', 'mod3'}, mod2 = {'sub1', 'sub2'}}
|
||||||
|
---@param modulelist string[]
|
||||||
|
---@return table
|
||||||
local function namespace_modules(modulelist)
|
local function namespace_modules(modulelist)
|
||||||
local modules = {}
|
local modules = {}
|
||||||
for _, module in ipairs(modulelist) do
|
for _, module in ipairs(modulelist) do
|
||||||
|
|
@ -50,6 +52,8 @@ local function namespace_modules(modulelist)
|
||||||
return modules
|
return modules
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param list string[]
|
||||||
|
---@return integer length
|
||||||
local function longest_string_length(list)
|
local function longest_string_length(list)
|
||||||
local length = 0
|
local length = 0
|
||||||
for _, value in ipairs(list) do
|
for _, value in ipairs(list) do
|
||||||
|
|
@ -60,6 +64,11 @@ local function longest_string_length(list)
|
||||||
return length
|
return length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param curbuf integer
|
||||||
|
---@param origbuf integer
|
||||||
|
---@param parserlist string[]
|
||||||
|
---@param namespace string
|
||||||
|
---@param modulelist string[]
|
||||||
local function append_module_table(curbuf, origbuf, parserlist, namespace, modulelist)
|
local function append_module_table(curbuf, origbuf, parserlist, namespace, modulelist)
|
||||||
local maxlen_parser = longest_string_length(parserlist)
|
local maxlen_parser = longest_string_length(parserlist)
|
||||||
table.sort(modulelist)
|
table.sort(modulelist)
|
||||||
|
|
@ -104,6 +113,7 @@ local function print_info_modules(parserlist, module)
|
||||||
modules = namespace_modules(configs.available_modules())
|
modules = namespace_modules(configs.available_modules())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type string[]
|
||||||
local namespaces = {}
|
local namespaces = {}
|
||||||
for k, _ in pairs(modules) do
|
for k, _ in pairs(modules) do
|
||||||
table.insert(namespaces, k)
|
table.insert(namespaces, k)
|
||||||
|
|
@ -150,6 +160,7 @@ local function module_info(module)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@return string[]
|
||||||
function M.installed_parsers()
|
function M.installed_parsers()
|
||||||
local installed = {}
|
local installed = {}
|
||||||
for _, p in pairs(parsers.available_parsers()) do
|
for _, p in pairs(parsers.available_parsers()) do
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@ local configs = require "nvim-treesitter.configs"
|
||||||
local shell = require "nvim-treesitter.shell_command_selectors"
|
local shell = require "nvim-treesitter.shell_command_selectors"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
---@class LockfileInfo
|
||||||
|
---@field revision string
|
||||||
|
|
||||||
|
---@type table<string, LockfileInfo>
|
||||||
local lockfile = {}
|
local lockfile = {}
|
||||||
|
|
||||||
M.compilers = { vim.fn.getenv "CC", "cc", "gcc", "clang", "cl", "zig" }
|
M.compilers = { vim.fn.getenv "CC", "cc", "gcc", "clang", "cl", "zig" }
|
||||||
|
|
@ -96,8 +101,8 @@ local function is_ignored_parser(lang)
|
||||||
return vim.tbl_contains(configs.get_ignored_parser_installs(), lang)
|
return vim.tbl_contains(configs.get_ignored_parser_installs(), lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param lang string
|
---@param lang string
|
||||||
--- @return string|nil
|
---@return string|nil
|
||||||
local function get_revision(lang)
|
local function get_revision(lang)
|
||||||
if #lockfile == 0 then
|
if #lockfile == 0 then
|
||||||
load_lockfile()
|
load_lockfile()
|
||||||
|
|
@ -123,8 +128,8 @@ local function get_installed_revision(lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Clean path for use in a prefix comparison
|
-- Clean path for use in a prefix comparison
|
||||||
-- @param input string
|
---@param input string
|
||||||
-- @return string
|
---@return string
|
||||||
local function clean_path(input)
|
local function clean_path(input)
|
||||||
local pth = vim.fn.fnamemodify(input, ":p")
|
local pth = vim.fn.fnamemodify(input, ":p")
|
||||||
if fn.has "win32" == 1 then
|
if fn.has "win32" == 1 then
|
||||||
|
|
@ -133,7 +138,7 @@ local function clean_path(input)
|
||||||
return pth
|
return pth
|
||||||
end
|
end
|
||||||
|
|
||||||
---Checks if parser is installed with nvim-treesitter
|
-- Checks if parser is installed with nvim-treesitter
|
||||||
---@param lang string
|
---@param lang string
|
||||||
---@return boolean
|
---@return boolean
|
||||||
local function is_installed(lang)
|
local function is_installed(lang)
|
||||||
|
|
@ -159,9 +164,9 @@ local function needs_update(lang)
|
||||||
return not revision or revision ~= get_installed_revision(lang)
|
return not revision or revision ~= get_installed_revision(lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@return table
|
---@return string[]
|
||||||
local function outdated_parsers()
|
local function outdated_parsers()
|
||||||
return vim.tbl_filter(function(lang)
|
return vim.tbl_filter(function(lang) ---@param lang string
|
||||||
return is_installed(lang) and needs_update(lang)
|
return is_installed(lang) and needs_update(lang)
|
||||||
end, info.installed_parsers())
|
end, info.installed_parsers())
|
||||||
end
|
end
|
||||||
|
|
@ -252,6 +257,8 @@ function M.iter_cmd(cmd_list, i, lang, success_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param cmd Command
|
||||||
|
---@return string command
|
||||||
local function get_command(cmd)
|
local function get_command(cmd)
|
||||||
local options = ""
|
local options = ""
|
||||||
if cmd.opts and cmd.opts.args then
|
if cmd.opts and cmd.opts.args then
|
||||||
|
|
@ -263,13 +270,15 @@ local function get_command(cmd)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local final = string.format("%s %s", cmd.cmd, options)
|
local command = string.format("%s %s", cmd.cmd, options)
|
||||||
if cmd.opts and cmd.opts.cwd then
|
if cmd.opts and cmd.opts.cwd then
|
||||||
final = shell.make_directory_change_for_command(cmd.opts.cwd, final)
|
command = shell.make_directory_change_for_command(cmd.opts.cwd, command)
|
||||||
end
|
end
|
||||||
return final
|
return command
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param cmd_list Command[]
|
||||||
|
---@return boolean
|
||||||
local function iter_cmd_sync(cmd_list)
|
local function iter_cmd_sync(cmd_list)
|
||||||
for _, cmd in ipairs(cmd_list) do
|
for _, cmd in ipairs(cmd_list) do
|
||||||
if cmd.info then
|
if cmd.info then
|
||||||
|
|
@ -311,7 +320,7 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
|
||||||
repo.url = maybe_local_path
|
repo.url = maybe_local_path
|
||||||
end
|
end
|
||||||
|
|
||||||
-- compile_location only needed for typescript installs.
|
---@type string compile_location only needed for typescript installs.
|
||||||
local compile_location
|
local compile_location
|
||||||
if from_local_path then
|
if from_local_path then
|
||||||
compile_location = repo.url
|
compile_location = repo.url
|
||||||
|
|
@ -355,7 +364,7 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
|
||||||
local cc = shell.select_executable(M.compilers)
|
local cc = shell.select_executable(M.compilers)
|
||||||
if not cc then
|
if not cc then
|
||||||
api.nvim_err_writeln('No C compiler found! "' .. table.concat(
|
api.nvim_err_writeln('No C compiler found! "' .. table.concat(
|
||||||
vim.tbl_filter(function(c)
|
vim.tbl_filter(function(c) ---@param c string
|
||||||
return type(c) == "string"
|
return type(c) == "string"
|
||||||
end, M.compilers),
|
end, M.compilers),
|
||||||
'", "'
|
'", "'
|
||||||
|
|
@ -368,6 +377,17 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
|
||||||
revision = get_revision(lang)
|
revision = get_revision(lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@class Command
|
||||||
|
---@field cmd string
|
||||||
|
---@field info string
|
||||||
|
---@field err string
|
||||||
|
---@field opts CmdOpts
|
||||||
|
|
||||||
|
---@class CmdOpts
|
||||||
|
---@field args string[]
|
||||||
|
---@field cwd string
|
||||||
|
|
||||||
|
---@type Command[]
|
||||||
local command_list = {}
|
local command_list = {}
|
||||||
if not from_local_path then
|
if not from_local_path then
|
||||||
vim.list_extend(command_list, { shell.select_install_rm_cmd(cache_folder, project_name) })
|
vim.list_extend(command_list, { shell.select_install_rm_cmd(cache_folder, project_name) })
|
||||||
|
|
@ -411,7 +431,7 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
|
||||||
shell.select_mv_cmd("parser.so", parser_lib_name, compile_location),
|
shell.select_mv_cmd("parser.so", parser_lib_name, compile_location),
|
||||||
{
|
{
|
||||||
cmd = function()
|
cmd = function()
|
||||||
vim.fn.writefile({ revision or "" }, utils.join_path(configs.get_parser_info_dir(), lang .. ".revision"))
|
vim.fn.writefile({ revision or "" }, utils.join_path(configs.get_parser_info_dir() or "", lang .. ".revision"))
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
{ -- auto-attach modules after installation
|
{ -- auto-attach modules after installation
|
||||||
|
|
@ -432,7 +452,7 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param lang string
|
---@param lang string
|
||||||
---@param ask_reinstall boolean
|
---@param ask_reinstall boolean|string
|
||||||
---@param cache_folder string
|
---@param cache_folder string
|
||||||
---@param install_folder string
|
---@param install_folder string
|
||||||
---@param with_sync boolean
|
---@param with_sync boolean
|
||||||
|
|
@ -465,6 +485,14 @@ local function install_lang(lang, ask_reinstall, cache_folder, install_folder, w
|
||||||
run_install(cache_folder, install_folder, lang, install_info, with_sync, generate_from_grammar)
|
run_install(cache_folder, install_folder, lang, install_info, with_sync, generate_from_grammar)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@class InstallOptions
|
||||||
|
---@field with_sync boolean
|
||||||
|
---@field ask_reinstall boolean|string
|
||||||
|
---@field generate_from_grammar boolean
|
||||||
|
---@field exclude_configured_parsers boolean
|
||||||
|
|
||||||
|
-- Install a parser
|
||||||
|
---@param options? InstallOptions
|
||||||
---@return function
|
---@return function
|
||||||
local function install(options)
|
local function install(options)
|
||||||
options = options or {}
|
options = options or {}
|
||||||
|
|
@ -491,8 +519,8 @@ local function install(options)
|
||||||
end
|
end
|
||||||
assert(install_folder)
|
assert(install_folder)
|
||||||
|
|
||||||
local languages
|
local languages ---@type string[]
|
||||||
local ask
|
local ask ---@type boolean|string
|
||||||
if ... == "all" then
|
if ... == "all" then
|
||||||
languages = parsers.available_parsers()
|
languages = parsers.available_parsers()
|
||||||
ask = false
|
ask = false
|
||||||
|
|
@ -533,6 +561,7 @@ function M.update(options)
|
||||||
M.lockfile = {}
|
M.lockfile = {}
|
||||||
reset_progress_counter()
|
reset_progress_counter()
|
||||||
if ... and ... ~= "all" then
|
if ... and ... ~= "all" then
|
||||||
|
---@type string[]
|
||||||
local languages = vim.tbl_flatten { ... }
|
local languages = vim.tbl_flatten { ... }
|
||||||
local installed = 0
|
local installed = 0
|
||||||
for _, lang in ipairs(languages) do
|
for _, lang in ipairs(languages) do
|
||||||
|
|
@ -578,6 +607,7 @@ function M.uninstall(...)
|
||||||
end
|
end
|
||||||
ensure_installed_parsers = utils.difference(ensure_installed_parsers, configs.get_ignored_parser_installs())
|
ensure_installed_parsers = utils.difference(ensure_installed_parsers, configs.get_ignored_parser_installs())
|
||||||
|
|
||||||
|
---@type string[]
|
||||||
local languages = vim.tbl_flatten { ... }
|
local languages = vim.tbl_flatten { ... }
|
||||||
for _, lang in ipairs(languages) do
|
for _, lang in ipairs(languages) do
|
||||||
local install_dir, err = configs.get_parser_install_dir()
|
local install_dir, err = configs.get_parser_install_dir()
|
||||||
|
|
@ -634,7 +664,7 @@ function M.uninstall(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.write_lockfile(verbose, skip_langs)
|
function M.write_lockfile(verbose, skip_langs)
|
||||||
local sorted_parsers = {}
|
local sorted_parsers = {} ---@type Parser[]
|
||||||
-- Load previous lockfile
|
-- Load previous lockfile
|
||||||
load_lockfile()
|
load_lockfile()
|
||||||
skip_langs = skip_langs or {}
|
skip_langs = skip_langs or {}
|
||||||
|
|
@ -643,6 +673,8 @@ function M.write_lockfile(verbose, skip_langs)
|
||||||
table.insert(sorted_parsers, { name = k, parser = v })
|
table.insert(sorted_parsers, { name = k, parser = v })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param a Parser
|
||||||
|
---@param b Parser
|
||||||
table.sort(sorted_parsers, function(a, b)
|
table.sort(sorted_parsers, function(a, b)
|
||||||
return a.name < b.name
|
return a.name < b.name
|
||||||
end)
|
end)
|
||||||
|
|
@ -650,7 +682,7 @@ function M.write_lockfile(verbose, skip_langs)
|
||||||
for _, v in ipairs(sorted_parsers) do
|
for _, v in ipairs(sorted_parsers) do
|
||||||
if not vim.tbl_contains(skip_langs, v.name) then
|
if not vim.tbl_contains(skip_langs, v.name) then
|
||||||
-- I'm sure this can be done in aync way with iter_cmd
|
-- I'm sure this can be done in aync way with iter_cmd
|
||||||
local sha
|
local sha ---@type string
|
||||||
if v.parser.install_info.branch then
|
if v.parser.install_info.branch then
|
||||||
sha = vim.split(
|
sha = vim.split(
|
||||||
vim.fn.systemlist(
|
vim.fn.systemlist(
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,16 @@ function M.iter_locals(bufnr, root)
|
||||||
return queries.iter_group_results(bufnr, "locals", root)
|
return queries.iter_group_results(bufnr, "locals", root)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return any
|
||||||
function M.get_locals(bufnr)
|
function M.get_locals(bufnr)
|
||||||
return queries.get_matches(bufnr, "locals")
|
return queries.get_matches(bufnr, "locals")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates unique id for a node based on text and range
|
-- Creates unique id for a node based on text and range
|
||||||
-- @param scope: the scope node of the definition
|
---@param scope TSNode: the scope node of the definition
|
||||||
-- @param bufnr: the buffer
|
---@param node_text string: the node text to use
|
||||||
-- @param node_text: the node text to use
|
---@return string: a string id
|
||||||
-- @returns a string id
|
|
||||||
function M.get_definition_id(scope, node_text)
|
function M.get_definition_id(scope, node_text)
|
||||||
-- Add a valid starting character in case node text doesn't start with a valid one.
|
-- Add a valid starting character in case node text doesn't start with a valid one.
|
||||||
return table.concat({ "k", node_text or "", scope:range() }, "_")
|
return table.concat({ "k", node_text or "", scope:range() }, "_")
|
||||||
|
|
@ -76,10 +77,13 @@ function M.get_references(bufnr)
|
||||||
return refs
|
return refs
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets a table with all the scopes containing a node
|
-- Gets a table with all the scopes containing a node
|
||||||
-- The order is from most specific to least (bottom up)
|
-- The order is from most specific to least (bottom up)
|
||||||
|
---@param node TSNode
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return TSNode[]
|
||||||
function M.get_scope_tree(node, bufnr)
|
function M.get_scope_tree(node, bufnr)
|
||||||
local scopes = {}
|
local scopes = {} ---@type TSNode[]
|
||||||
|
|
||||||
for scope in M.iter_scope_tree(node, bufnr) do
|
for scope in M.iter_scope_tree(node, bufnr) do
|
||||||
table.insert(scopes, scope)
|
table.insert(scopes, scope)
|
||||||
|
|
@ -88,7 +92,10 @@ function M.get_scope_tree(node, bufnr)
|
||||||
return scopes
|
return scopes
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Iterates over a nodes scopes moving from the bottom up
|
-- Iterates over a nodes scopes moving from the bottom up
|
||||||
|
---@param node TSNode
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return fun(): TSNode|nil
|
||||||
function M.iter_scope_tree(node, bufnr)
|
function M.iter_scope_tree(node, bufnr)
|
||||||
local last_node = node
|
local last_node = node
|
||||||
return function()
|
return function()
|
||||||
|
|
@ -105,12 +112,12 @@ function M.iter_scope_tree(node, bufnr)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Gets a table of all nodes and their 'kinds' from a locals list
|
-- Gets a table of all nodes and their 'kinds' from a locals list
|
||||||
-- @param local_def the local list result
|
---@param local_def any: the local list result
|
||||||
-- @returns a list of node entries
|
---@return table: a list of node entries
|
||||||
function M.get_local_nodes(local_def)
|
function M.get_local_nodes(local_def)
|
||||||
local result = {}
|
local result = {}
|
||||||
|
|
||||||
M.recurse_local_nodes(local_def, function(def, node, kind)
|
M.recurse_local_nodes(local_def, function(def, _node, kind)
|
||||||
table.insert(result, vim.tbl_extend("keep", { kind = kind }, def))
|
table.insert(result, vim.tbl_extend("keep", { kind = kind }, def))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
@ -123,10 +130,10 @@ end
|
||||||
-- * The node
|
-- * The node
|
||||||
-- * The full definition match `@definition.var.something` -> 'var.something'
|
-- * The full definition match `@definition.var.something` -> 'var.something'
|
||||||
-- * The last definition match `@definition.var.something` -> 'something'
|
-- * The last definition match `@definition.var.something` -> 'something'
|
||||||
-- @param The locals result
|
---@param local_def any The locals result
|
||||||
-- @param The accumulator function
|
---@param accumulator function The accumulator function
|
||||||
-- @param The full match path to append to
|
---@param full_match? string The full match path to append to
|
||||||
-- @param The last match
|
---@param last_match? string The last match
|
||||||
function M.recurse_local_nodes(local_def, accumulator, full_match, last_match)
|
function M.recurse_local_nodes(local_def, accumulator, full_match, last_match)
|
||||||
if type(local_def) ~= "table" then
|
if type(local_def) ~= "table" then
|
||||||
return
|
return
|
||||||
|
|
@ -141,7 +148,7 @@ function M.recurse_local_nodes(local_def, accumulator, full_match, last_match)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a single dimension table to look definition nodes.
|
-- Get a single dimension table to look definition nodes.
|
||||||
-- Keys are generated by using the range of the containing scope and the text of the definition node.
|
-- Keys are generated by using the range of the containing scope and the text of the definition node.
|
||||||
-- This makes looking up a definition for a given scope a simple key lookup.
|
-- This makes looking up a definition for a given scope a simple key lookup.
|
||||||
--
|
--
|
||||||
|
|
@ -152,8 +159,8 @@ end
|
||||||
-- Usage lookups require finding the definition of the node, so `find_definition`
|
-- Usage lookups require finding the definition of the node, so `find_definition`
|
||||||
-- is called very frequently, which is why this lookup must be fast as possible.
|
-- is called very frequently, which is why this lookup must be fast as possible.
|
||||||
--
|
--
|
||||||
-- @param bufnr: the buffer
|
---@param bufnr integer: the buffer
|
||||||
-- @returns a table for looking up definitions
|
---@return table result: a table for looking up definitions
|
||||||
M.get_definitions_lookup_table = ts_utils.memoize_by_buf_tick(function(bufnr)
|
M.get_definitions_lookup_table = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||||
local definitions = M.get_definitions(bufnr)
|
local definitions = M.get_definitions(bufnr)
|
||||||
local result = {}
|
local result = {}
|
||||||
|
|
@ -173,19 +180,19 @@ M.get_definitions_lookup_table = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||||
return result
|
return result
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--- Gets all the scopes of a definition based on the scope type
|
-- Gets all the scopes of a definition based on the scope type
|
||||||
-- Scope types can be
|
-- Scope types can be
|
||||||
--
|
--
|
||||||
-- "parent": Uses the parent of the containing scope, basically, skipping a scope
|
-- "parent": Uses the parent of the containing scope, basically, skipping a scope
|
||||||
-- "global": Uses the top most scope
|
-- "global": Uses the top most scope
|
||||||
-- "local": Uses the containing scope of the definition. This is the default
|
-- "local": Uses the containing scope of the definition. This is the default
|
||||||
--
|
--
|
||||||
-- @param node: the definition node
|
---@param node TSNode: the definition node
|
||||||
-- @param bufnr: the buffer
|
---@param bufnr integer: the buffer
|
||||||
-- @param scope_type: the scope type
|
---@param scope_type string: the scope type
|
||||||
function M.get_definition_scopes(node, bufnr, scope_type)
|
function M.get_definition_scopes(node, bufnr, scope_type)
|
||||||
local scopes = {}
|
local scopes = {}
|
||||||
local scope_count = 1
|
local scope_count = 1 ---@type integer|nil
|
||||||
|
|
||||||
-- Definition is valid for the containing scope
|
-- Definition is valid for the containing scope
|
||||||
-- and the containing scope of that scope
|
-- and the containing scope of that scope
|
||||||
|
|
@ -209,6 +216,11 @@ function M.get_definition_scopes(node, bufnr, scope_type)
|
||||||
return scopes
|
return scopes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param node TSNode
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return TSNode node
|
||||||
|
---@return TSNode scope
|
||||||
|
---@return string|nil kind
|
||||||
function M.find_definition(node, bufnr)
|
function M.find_definition(node, bufnr)
|
||||||
local def_lookup = M.get_definitions_lookup_table(bufnr)
|
local def_lookup = M.get_definitions_lookup_table(bufnr)
|
||||||
local node_text = ts_query.get_node_text(node, bufnr)
|
local node_text = ts_query.get_node_text(node, bufnr)
|
||||||
|
|
@ -227,11 +239,11 @@ function M.find_definition(node, bufnr)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Finds usages of a node in a given scope.
|
-- Finds usages of a node in a given scope.
|
||||||
-- @param node the node to find usages for
|
---@param node TSNode the node to find usages for
|
||||||
-- @param scope_node the node to look within
|
---@param scope_node TSNode the node to look within
|
||||||
-- @returns a list of nodes
|
---@return TSNode[]: a list of nodes
|
||||||
function M.find_usages(node, scope_node, bufnr)
|
function M.find_usages(node, scope_node, bufnr)
|
||||||
local bufnr = bufnr or api.nvim_get_current_buf()
|
bufnr = bufnr or api.nvim_get_current_buf()
|
||||||
local node_text = ts_query.get_node_text(node, bufnr)
|
local node_text = ts_query.get_node_text(node, bufnr)
|
||||||
|
|
||||||
if not node_text or #node_text < 1 then
|
if not node_text or #node_text < 1 then
|
||||||
|
|
@ -258,6 +270,10 @@ function M.find_usages(node, scope_node, bufnr)
|
||||||
return usages
|
return usages
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param node TSNode
|
||||||
|
---@param bufnr? integer
|
||||||
|
---@param allow_scope? boolean
|
||||||
|
---@return TSNode|nil
|
||||||
function M.containing_scope(node, bufnr, allow_scope)
|
function M.containing_scope(node, bufnr, allow_scope)
|
||||||
local bufnr = bufnr or api.nvim_get_current_buf()
|
local bufnr = bufnr or api.nvim_get_current_buf()
|
||||||
local allow_scope = allow_scope == nil or allow_scope == true
|
local allow_scope = allow_scope == nil or allow_scope == true
|
||||||
|
|
@ -284,8 +300,8 @@ function M.nested_scope(node, cursor_pos)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local row = cursor_pos.row
|
local row = cursor_pos.row ---@type integer
|
||||||
local col = cursor_pos.col
|
local col = cursor_pos.col ---@type integer
|
||||||
local scope = M.containing_scope(node)
|
local scope = M.containing_scope(node)
|
||||||
|
|
||||||
for _, child in ipairs(ts_utils.get_named_children(scope)) do
|
for _, child in ipairs(ts_utils.get_named_children(scope)) do
|
||||||
|
|
@ -321,6 +337,8 @@ function M.next_scope(node)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param node TSNode
|
||||||
|
---@return TSNode|nil
|
||||||
function M.previous_scope(node)
|
function M.previous_scope(node)
|
||||||
local bufnr = api.nvim_get_current_buf()
|
local bufnr = api.nvim_get_current_buf()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ local filetype_to_parsername = {
|
||||||
---@field filetype string
|
---@field filetype string
|
||||||
---@field maintainers string[]
|
---@field maintainers string[]
|
||||||
---@field experimental boolean|nil
|
---@field experimental boolean|nil
|
||||||
|
---@field readme_name string|nil
|
||||||
|
|
||||||
---@type ParserInfo[]
|
---@type ParserInfo[]
|
||||||
local list = setmetatable({}, {
|
local list = setmetatable({}, {
|
||||||
|
|
@ -1542,11 +1543,13 @@ function M.ft_to_lang(ft)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Get a list of all available parsers
|
||||||
|
---@return string[]
|
||||||
function M.available_parsers()
|
function M.available_parsers()
|
||||||
if vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1 then
|
if vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1 then
|
||||||
return vim.tbl_keys(M.list)
|
return vim.tbl_keys(M.list)
|
||||||
else
|
else
|
||||||
return vim.tbl_filter(function(p)
|
return vim.tbl_filter(function(p) ---@param p string
|
||||||
return not M.list[p].install_info.requires_generate_from_grammar
|
return not M.list[p].install_info.requires_generate_from_grammar
|
||||||
end, vim.tbl_keys(M.list))
|
end, vim.tbl_keys(M.list))
|
||||||
end
|
end
|
||||||
|
|
@ -1598,9 +1601,9 @@ function M.get_tree_root(bufnr)
|
||||||
return M.get_parser(bufnr):parse()[1]:root()
|
return M.get_parser(bufnr):parse()[1]:root()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get language of given buffer
|
-- Gets the language of a given buffer
|
||||||
-- @param optional buffer number or current buffer
|
---@param bufnr number? or current buffer
|
||||||
-- @returns language string of buffer
|
---@return string
|
||||||
function M.get_buf_lang(bufnr)
|
function M.get_buf_lang(bufnr)
|
||||||
bufnr = bufnr or api.nvim_get_current_buf()
|
bufnr = bufnr or api.nvim_get_current_buf()
|
||||||
return M.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft"))
|
return M.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft"))
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ local EMPTY_ITER = function() end
|
||||||
|
|
||||||
M.built_in_query_groups = { "highlights", "locals", "folds", "indents", "injections" }
|
M.built_in_query_groups = { "highlights", "locals", "folds", "indents", "injections" }
|
||||||
|
|
||||||
--- Creates a function that checks whether a given query exists
|
-- Creates a function that checks whether a given query exists
|
||||||
--- for a specific language.
|
-- for a specific language.
|
||||||
---@param query string
|
---@param query string
|
||||||
---@return function(string): boolean
|
---@return fun(string): boolean
|
||||||
local function get_query_guard(query)
|
local function get_query_guard(query)
|
||||||
return function(lang)
|
return function(lang)
|
||||||
return M.has_query_files(lang, query)
|
return M.has_query_files(lang, query)
|
||||||
|
|
@ -49,6 +49,9 @@ do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param query_group string
|
||||||
|
---@return any
|
||||||
function M.get_matches(bufnr, query_group)
|
function M.get_matches(bufnr, query_group)
|
||||||
bufnr = bufnr or api.nvim_get_current_buf()
|
bufnr = bufnr or api.nvim_get_current_buf()
|
||||||
local cached_local = query_cache.get(query_group, bufnr)
|
local cached_local = query_cache.get(query_group, bufnr)
|
||||||
|
|
@ -94,9 +97,10 @@ do
|
||||||
end
|
end
|
||||||
|
|
||||||
-- cache will auto set the table for each lang if it is nil
|
-- cache will auto set the table for each lang if it is nil
|
||||||
|
---@type table<string, table<string, Query>>
|
||||||
local cache = setmetatable({}, mt)
|
local cache = setmetatable({}, mt)
|
||||||
|
|
||||||
--- Same as `vim.treesitter.query` except will return cached values
|
-- Same as `vim.treesitter.query` except will return cached values
|
||||||
---@param lang string
|
---@param lang string
|
||||||
---@param query_name string
|
---@param query_name string
|
||||||
function M.get_query(lang, query_name)
|
function M.get_query(lang, query_name)
|
||||||
|
|
@ -107,12 +111,13 @@ do
|
||||||
return cache[lang][query_name]
|
return cache[lang][query_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Invalidates the query file cache.
|
-- Invalidates the query file cache.
|
||||||
--- If lang and query_name is both present, will reload for only the lang and query_name.
|
--
|
||||||
--- If only lang is present, will reload all query_names for that lang
|
-- If lang and query_name is both present, will reload for only the lang and query_name.
|
||||||
--- If none are present, will reload everything
|
-- If only lang is present, will reload all query_names for that lang
|
||||||
---@param lang string
|
-- If none are present, will reload everything
|
||||||
---@param query_name string
|
---@param lang? string
|
||||||
|
---@param query_name? string
|
||||||
function M.invalidate_query_cache(lang, query_name)
|
function M.invalidate_query_cache(lang, query_name)
|
||||||
if lang and query_name then
|
if lang and query_name then
|
||||||
cache[lang][query_name] = nil
|
cache[lang][query_name] = nil
|
||||||
|
|
@ -137,7 +142,7 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- This function is meant for an autocommand and not to be used. Only use if file is a query file.
|
-- This function is meant for an autocommand and not to be used. Only use if file is a query file.
|
||||||
---@param fname string
|
---@param fname string
|
||||||
function M.invalidate_query_file(fname)
|
function M.invalidate_query_file(fname)
|
||||||
local fnamemodify = vim.fn.fnamemodify
|
local fnamemodify = vim.fn.fnamemodify
|
||||||
|
|
@ -145,14 +150,14 @@ function M.invalidate_query_file(fname)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class QueryInfo
|
---@class QueryInfo
|
||||||
---@field root LanguageTree
|
---@field root TSNode
|
||||||
---@field source integer
|
---@field source integer
|
||||||
---@field start integer
|
---@field start integer
|
||||||
---@field stop integer
|
---@field stop integer
|
||||||
|
|
||||||
---@param bufnr integer
|
---@param bufnr integer
|
||||||
---@param query_name string
|
---@param query_name string
|
||||||
---@param root LanguageTree
|
---@param root TSNode
|
||||||
---@param root_lang string|nil
|
---@param root_lang string|nil
|
||||||
---@return Query|nil, QueryInfo|nil
|
---@return Query|nil, QueryInfo|nil
|
||||||
local function prepare_query(bufnr, query_name, root, root_lang)
|
local function prepare_query(bufnr, query_name, root, root_lang)
|
||||||
|
|
@ -214,15 +219,21 @@ end
|
||||||
---@param end_row integer
|
---@param end_row integer
|
||||||
function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
|
function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
|
||||||
-- A function that splits a string on '.'
|
-- A function that splits a string on '.'
|
||||||
local function split(string)
|
---@param to_split string
|
||||||
|
---@return string[]
|
||||||
|
local function split(to_split)
|
||||||
local t = {}
|
local t = {}
|
||||||
for str in string.gmatch(string, "([^.]+)") do
|
for str in string.gmatch(to_split, "([^.]+)") do
|
||||||
table.insert(t, str)
|
table.insert(t, str)
|
||||||
end
|
end
|
||||||
|
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Given a path (i.e. a List(String)) this functions inserts value at path
|
-- Given a path (i.e. a List(String)) this functions inserts value at path
|
||||||
|
---@param object any
|
||||||
|
---@param path string[]
|
||||||
|
---@param value any
|
||||||
local function insert_to_path(object, path, value)
|
local function insert_to_path(object, path, value)
|
||||||
local curr_obj = object
|
local curr_obj = object
|
||||||
|
|
||||||
|
|
@ -256,6 +267,7 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add some predicates for testing
|
-- Add some predicates for testing
|
||||||
|
---@type string[][] ( TODO: make pred type so this can be pred[])
|
||||||
local preds = query.info.patterns[pattern]
|
local preds = query.info.patterns[pattern]
|
||||||
if preds then
|
if preds then
|
||||||
for _, pred in pairs(preds) do
|
for _, pred in pairs(preds) do
|
||||||
|
|
@ -279,22 +291,22 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
|
||||||
return iterator
|
return iterator
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return all nodes corresponding to a specific capture path (like @definition.var, @reference.type)
|
-- Return all nodes corresponding to a specific capture path (like @definition.var, @reference.type)
|
||||||
---Works like M.get_references or M.get_scopes except you can choose the capture
|
-- Works like M.get_references or M.get_scopes except you can choose the capture
|
||||||
---Can also be a nested capture like @definition.function to get all nodes defining a function.
|
-- Can also be a nested capture like @definition.function to get all nodes defining a function.
|
||||||
---
|
--
|
||||||
---@param bufnr integer the buffer
|
---@param bufnr integer the buffer
|
||||||
---@param captures string|string[]
|
---@param captures string|string[]
|
||||||
---@param query_group string the name of query group (highlights or injections for example)
|
---@param query_group string the name of query group (highlights or injections for example)
|
||||||
---@param root LanguageTree|nil node from where to start the search
|
---@param root TSNode|nil node from where to start the search
|
||||||
---@param lang string|nil the language from where to get the captures.
|
---@param lang string|nil the language from where to get the captures.
|
||||||
--- Root nodes can have several languages.
|
--- Root nodes can have several languages.
|
||||||
---@return table|nil
|
---@return table|nil
|
||||||
function M.get_capture_matches(bufnr, captures, query_group, root, lang)
|
function M.get_capture_matches(bufnr, captures, query_group, root, lang)
|
||||||
if type(captures) == "string" then
|
if type(captures) == "string" then
|
||||||
captures = { captures }
|
captures = { captures }
|
||||||
end
|
end
|
||||||
local strip_captures = {}
|
local strip_captures = {} ---@type string[]
|
||||||
for i, capture in ipairs(captures) do
|
for i, capture in ipairs(captures) do
|
||||||
if capture:sub(1, 1) ~= "@" then
|
if capture:sub(1, 1) ~= "@" then
|
||||||
error 'Captures must start with "@"'
|
error 'Captures must start with "@"'
|
||||||
|
|
@ -342,14 +354,21 @@ function M.iter_captures(bufnr, query_name, root, lang)
|
||||||
return wrapped_iter
|
return wrapped_iter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param capture_string string
|
||||||
|
---@param query_group string
|
||||||
|
---@param filter_predicate fun(match: table): boolean
|
||||||
|
---@param scoring_function fun(match: table): number
|
||||||
|
---@param root TSNode
|
||||||
|
---@return table|unknown
|
||||||
function M.find_best_match(bufnr, capture_string, query_group, filter_predicate, scoring_function, root)
|
function M.find_best_match(bufnr, capture_string, query_group, filter_predicate, scoring_function, root)
|
||||||
if string.sub(capture_string, 1, 1) == "@" then
|
if string.sub(capture_string, 1, 1) == "@" then
|
||||||
--remove leading "@"
|
--remove leading "@"
|
||||||
capture_string = string.sub(capture_string, 2)
|
capture_string = string.sub(capture_string, 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
local best
|
local best ---@type table|nil
|
||||||
local best_score
|
local best_score ---@type number
|
||||||
|
|
||||||
for maybe_match in M.iter_group_results(bufnr, query_group, root) do
|
for maybe_match in M.iter_group_results(bufnr, query_group, root) do
|
||||||
local match = utils.get_at_path(maybe_match, capture_string)
|
local match = utils.get_at_path(maybe_match, capture_string)
|
||||||
|
|
@ -372,8 +391,8 @@ end
|
||||||
---Iterates matches from a query file.
|
---Iterates matches from a query file.
|
||||||
---@param bufnr integer the buffer
|
---@param bufnr integer the buffer
|
||||||
---@param query_group string the query file to use
|
---@param query_group string the query file to use
|
||||||
---@param root LanguageTree the root node
|
---@param root TSNode the root node
|
||||||
---@param root_lang string|nil the root node lang, if known
|
---@param root_lang? string the root node lang, if known
|
||||||
function M.iter_group_results(bufnr, query_group, root, root_lang)
|
function M.iter_group_results(bufnr, query_group, root, root_lang)
|
||||||
local query, params = prepare_query(bufnr, query_group, root, root_lang)
|
local query, params = prepare_query(bufnr, query_group, root, root_lang)
|
||||||
if not query then
|
if not query then
|
||||||
|
|
@ -396,13 +415,14 @@ end
|
||||||
|
|
||||||
---@alias CaptureResFn function(string, LanguageTree, LanguageTree): string, string
|
---@alias CaptureResFn function(string, LanguageTree, LanguageTree): string, string
|
||||||
|
|
||||||
--- Same as get_capture_matches except this will recursively get matches for every language in the tree.
|
-- Same as get_capture_matches except this will recursively get matches for every language in the tree.
|
||||||
---@param bufnr integer The bufnr
|
---@param bufnr integer The buffer
|
||||||
---@param capture_or_fn string|CaptureResFn The capture to get. If a function is provided then that
|
---@param capture_or_fn string|CaptureResFn The capture to get. If a function is provided then that
|
||||||
--- function will be used to resolve both the capture and query argument.
|
--- function will be used to resolve both the capture and query argument.
|
||||||
--- The function can return `nil` to ignore that tree.
|
--- The function can return `nil` to ignore that tree.
|
||||||
---@param query_type string The query to get the capture from. This is ignore if a function is provided
|
---@param query_type string? The query to get the capture from. This is ignored if a function is provided
|
||||||
--- for the captuer argument.
|
--- for the capture argument.
|
||||||
|
---@return table[]
|
||||||
function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
|
function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
|
||||||
---@type CaptureResFn
|
---@type CaptureResFn
|
||||||
local type_fn
|
local type_fn
|
||||||
|
|
@ -422,7 +442,7 @@ function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
|
||||||
local capture, type_ = type_fn(lang, tree, lang_tree)
|
local capture, type_ = type_fn(lang, tree, lang_tree)
|
||||||
|
|
||||||
if capture then
|
if capture then
|
||||||
vim.list_extend(matches, M.get_capture_matches(bufnr, capture, type_, tree:root(), lang))
|
vim.list_extend(matches, M.get_capture_matches(bufnr, capture, type_, tree:root(), lang) or {})
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,17 @@ local function valid_args(name, pred, count, strict_count)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
query.add_predicate("nth?", function(match, pattern, bufnr, pred)
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _pattern string
|
||||||
|
---@param _bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@return boolean|nil
|
||||||
|
query.add_predicate("nth?", function(match, _pattern, _bufnr, pred)
|
||||||
if not valid_args("nth?", pred, 2, true) then
|
if not valid_args("nth?", pred, 2, true) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local node = match[pred[2]]
|
local node = match[pred[2]] ---@type TSNode
|
||||||
local n = tonumber(pred[3])
|
local n = tonumber(pred[3])
|
||||||
if node and node:parent() and node:parent():named_child_count() > n then
|
if node and node:parent() and node:parent():named_child_count() > n then
|
||||||
return node:parent():named_child(n) == node
|
return node:parent():named_child(n) == node
|
||||||
|
|
@ -34,7 +39,12 @@ query.add_predicate("nth?", function(match, pattern, bufnr, pred)
|
||||||
return false
|
return false
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local function has_ancestor(match, pattern, bufnr, pred)
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _pattern string
|
||||||
|
---@param _bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@return boolean|nil
|
||||||
|
local function has_ancestor(match, _pattern, _bufnr, pred)
|
||||||
if not valid_args(pred[1], pred, 2) then
|
if not valid_args(pred[1], pred, 2) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -65,7 +75,12 @@ query.add_predicate("has-ancestor?", has_ancestor)
|
||||||
|
|
||||||
query.add_predicate("has-parent?", has_ancestor)
|
query.add_predicate("has-parent?", has_ancestor)
|
||||||
|
|
||||||
query.add_predicate("is?", function(match, pattern, bufnr, pred)
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _pattern string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@return boolean|nil
|
||||||
|
query.add_predicate("is?", function(match, _pattern, bufnr, pred)
|
||||||
if not valid_args("is?", pred, 2) then
|
if not valid_args("is?", pred, 2) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -84,7 +99,12 @@ query.add_predicate("is?", function(match, pattern, bufnr, pred)
|
||||||
return vim.tbl_contains(types, kind)
|
return vim.tbl_contains(types, kind)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
query.add_predicate("has-type?", function(match, pattern, bufnr, pred)
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _pattern string
|
||||||
|
---@param _bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@return boolean|nil
|
||||||
|
query.add_predicate("has-type?", function(match, _pattern, _bufnr, pred)
|
||||||
if not valid_args(pred[1], pred, 2) then
|
if not valid_args(pred[1], pred, 2) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -102,8 +122,14 @@ end)
|
||||||
-- Just avoid some annoying warnings for this directive
|
-- Just avoid some annoying warnings for this directive
|
||||||
query.add_directive("make-range!", function() end)
|
query.add_directive("make-range!", function() end)
|
||||||
|
|
||||||
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _ string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@param metadata table
|
||||||
|
---@return boolean|nil
|
||||||
query.add_directive("downcase!", function(match, _, bufnr, pred, metadata)
|
query.add_directive("downcase!", function(match, _, bufnr, pred, metadata)
|
||||||
local text, key, value
|
local text, key, value ---@type string|string[], string, string|integer
|
||||||
|
|
||||||
if #pred == 3 then
|
if #pred == 3 then
|
||||||
-- (#downcase! @capture "key")
|
-- (#downcase! @capture "key")
|
||||||
|
|
@ -129,13 +155,19 @@ query.add_directive("downcase!", function(match, _, bufnr, pred, metadata)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _pattern string
|
||||||
|
---@param _bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@param metadata table
|
||||||
|
---@return boolean|nil
|
||||||
query.add_directive("exclude_children!", function(match, _pattern, _bufnr, pred, metadata)
|
query.add_directive("exclude_children!", function(match, _pattern, _bufnr, pred, metadata)
|
||||||
local capture_id = pred[2]
|
local capture_id = pred[2]
|
||||||
local node = match[capture_id]
|
local node = match[capture_id]
|
||||||
local start_row, start_col, end_row, end_col = node:range()
|
local start_row, start_col, end_row, end_col = node:range()
|
||||||
local ranges = {}
|
local ranges = {}
|
||||||
for i = 0, node:named_child_count() - 1 do
|
for i = 0, node:named_child_count() - 1 do
|
||||||
local child = node:named_child(i)
|
local child = node:named_child(i) ---@type TSNode
|
||||||
local child_start_row, child_start_col, child_end_row, child_end_col = child:range()
|
local child_start_row, child_start_col, child_end_row, child_end_col = child:range()
|
||||||
if child_start_row > start_row or child_start_col > start_col then
|
if child_start_row > start_row or child_start_col > start_col then
|
||||||
table.insert(ranges, {
|
table.insert(ranges, {
|
||||||
|
|
@ -156,6 +188,11 @@ end)
|
||||||
|
|
||||||
-- Trim blank lines from end of the region
|
-- Trim blank lines from end of the region
|
||||||
-- Arguments are the captures to trim.
|
-- Arguments are the captures to trim.
|
||||||
|
---@param match (TSNode|nil)[]
|
||||||
|
---@param _ string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param pred string[]
|
||||||
|
---@param metadata table
|
||||||
query.add_directive("trim!", function(match, _, bufnr, pred, metadata)
|
query.add_directive("trim!", function(match, _, bufnr, pred, metadata)
|
||||||
for _, id in ipairs { select(2, unpack(pred)) } do
|
for _, id in ipairs { select(2, unpack(pred)) } do
|
||||||
local node = match[id]
|
local node = match[id]
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ local utils = require "nvim-treesitter.utils"
|
||||||
|
|
||||||
-- Convert path for cmd.exe on Windows.
|
-- Convert path for cmd.exe on Windows.
|
||||||
-- This is needed when vim.opt.shellslash is in use.
|
-- This is needed when vim.opt.shellslash is in use.
|
||||||
|
---@param p string
|
||||||
|
---@return string
|
||||||
local function cmdpath(p)
|
local function cmdpath(p)
|
||||||
if vim.opt.shellslash:get() then
|
if vim.opt.shellslash:get() then
|
||||||
local r = p:gsub("/", "\\")
|
local r = p:gsub("/", "\\")
|
||||||
|
|
@ -14,6 +16,10 @@ end
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
---@param directory string
|
||||||
|
---@param cwd string
|
||||||
|
---@param info_msg string
|
||||||
|
---@return table
|
||||||
function M.select_mkdir_cmd(directory, cwd, info_msg)
|
function M.select_mkdir_cmd(directory, cwd, info_msg)
|
||||||
if fn.has "win32" == 1 then
|
if fn.has "win32" == 1 then
|
||||||
return {
|
return {
|
||||||
|
|
@ -38,6 +44,9 @@ function M.select_mkdir_cmd(directory, cwd, info_msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param file string
|
||||||
|
---@param info_msg string
|
||||||
|
---@return table
|
||||||
function M.select_rm_file_cmd(file, info_msg)
|
function M.select_rm_file_cmd(file, info_msg)
|
||||||
if fn.has "win32" == 1 then
|
if fn.has "win32" == 1 then
|
||||||
return {
|
return {
|
||||||
|
|
@ -60,13 +69,17 @@ function M.select_rm_file_cmd(file, info_msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param executables string[]
|
||||||
---@return string|nil
|
---@return string|nil
|
||||||
function M.select_executable(executables)
|
function M.select_executable(executables)
|
||||||
return vim.tbl_filter(function(c)
|
return vim.tbl_filter(function(c) ---@param c string
|
||||||
return c ~= vim.NIL and fn.executable(c) == 1
|
return c ~= vim.NIL and fn.executable(c) == 1
|
||||||
end, executables)[1]
|
end, executables)[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param repo InstallInfo
|
||||||
|
---@param compiler string
|
||||||
|
---@return string[]
|
||||||
function M.select_compiler_args(repo, compiler)
|
function M.select_compiler_args(repo, compiler)
|
||||||
if string.match(compiler, "cl$") or string.match(compiler, "cl.exe$") then
|
if string.match(compiler, "cl$") or string.match(compiler, "cl.exe$") then
|
||||||
return {
|
return {
|
||||||
|
|
@ -98,7 +111,7 @@ function M.select_compiler_args(repo, compiler)
|
||||||
"-Os",
|
"-Os",
|
||||||
}
|
}
|
||||||
if
|
if
|
||||||
#vim.tbl_filter(function(file)
|
#vim.tbl_filter(function(file) ---@param file string
|
||||||
local ext = vim.fn.fnamemodify(file, ":e")
|
local ext = vim.fn.fnamemodify(file, ":e")
|
||||||
return ext == "cc" or ext == "cpp" or ext == "cxx"
|
return ext == "cc" or ext == "cpp" or ext == "cxx"
|
||||||
end, repo.files) > 0
|
end, repo.files) > 0
|
||||||
|
|
@ -186,6 +199,12 @@ function M.select_mv_cmd(from, to, cwd)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param repo InstallInfo
|
||||||
|
---@param project_name string
|
||||||
|
---@param cache_folder string
|
||||||
|
---@param revision string|nil
|
||||||
|
---@param prefer_git boolean
|
||||||
|
---@return table
|
||||||
function M.select_download_commands(repo, project_name, cache_folder, revision, prefer_git)
|
function M.select_download_commands(repo, project_name, cache_folder, revision, prefer_git)
|
||||||
local can_use_tar = vim.fn.executable "tar" == 1 and vim.fn.executable "curl" == 1
|
local can_use_tar = vim.fn.executable "tar" == 1 and vim.fn.executable "curl" == 1
|
||||||
local is_github = repo.url:find("github.com", 1, true)
|
local is_github = repo.url:find("github.com", 1, true)
|
||||||
|
|
@ -277,6 +296,9 @@ function M.select_download_commands(repo, project_name, cache_folder, revision,
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param dir string
|
||||||
|
---@param command string
|
||||||
|
---@return string command
|
||||||
function M.make_directory_change_for_command(dir, command)
|
function M.make_directory_change_for_command(dir, command)
|
||||||
if fn.has "win32" == 1 then
|
if fn.has "win32" == 1 then
|
||||||
return string.format("pushd %s & %s & popd", cmdpath(dir), command)
|
return string.format("pushd %s & %s & popd", cmdpath(dir), command)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,11 @@ local function get_node_text(node, bufnr)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
|
---@param node TSNode
|
||||||
|
---@param type_patterns string[]
|
||||||
|
---@param transform_fn fun(line: string): string
|
||||||
|
---@param bufnr integer
|
||||||
|
---@return string
|
||||||
function M._get_line_for_node(node, type_patterns, transform_fn, bufnr)
|
function M._get_line_for_node(node, type_patterns, transform_fn, bufnr)
|
||||||
local node_type = node:type()
|
local node_type = node:type()
|
||||||
local is_valid = false
|
local is_valid = false
|
||||||
|
|
@ -51,7 +56,7 @@ function M._get_line_for_node(node, type_patterns, transform_fn, bufnr)
|
||||||
return line:gsub("%%", "%%%%")
|
return line:gsub("%%", "%%%%")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the actual text content of a node
|
-- Gets the actual text content of a node
|
||||||
-- @deprecated Use vim.treesitter.query.get_node_text
|
-- @deprecated Use vim.treesitter.query.get_node_text
|
||||||
-- @param node the node to get the text from
|
-- @param node the node to get the text from
|
||||||
-- @param bufnr the buffer containing the node
|
-- @param bufnr the buffer containing the node
|
||||||
|
|
@ -64,7 +69,7 @@ function M.get_node_text(node, bufnr)
|
||||||
return get_node_text(node, bufnr)
|
return get_node_text(node, bufnr)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Determines whether a node is the parent of another
|
-- Determines whether a node is the parent of another
|
||||||
-- @param dest the possible parent
|
-- @param dest the possible parent
|
||||||
-- @param source the possible child node
|
-- @param source the possible child node
|
||||||
function M.is_parent(dest, source)
|
function M.is_parent(dest, source)
|
||||||
|
|
@ -84,12 +89,12 @@ function M.is_parent(dest, source)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get next node with same parent
|
-- Get next node with same parent
|
||||||
-- @param node node
|
---@param node TSNode
|
||||||
-- @param allow_switch_parents allow switching parents if last node
|
---@param allow_switch_parents? boolean allow switching parents if last node
|
||||||
-- @param allow_next_parent allow next parent if last node and next parent without children
|
---@param allow_next_parent? boolean allow next parent if last node and next parent without children
|
||||||
function M.get_next_node(node, allow_switch_parents, allow_next_parent)
|
function M.get_next_node(node, allow_switch_parents, allow_next_parent)
|
||||||
local destination_node
|
local destination_node ---@type TSNode
|
||||||
local parent = node:parent()
|
local parent = node:parent()
|
||||||
|
|
||||||
if not parent then
|
if not parent then
|
||||||
|
|
@ -116,12 +121,12 @@ function M.get_next_node(node, allow_switch_parents, allow_next_parent)
|
||||||
return destination_node
|
return destination_node
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get previous node with same parent
|
-- Get previous node with same parent
|
||||||
-- @param node node
|
---@param node TSNode
|
||||||
-- @param allow_switch_parents allow switching parents if first node
|
---@param allow_switch_parents? boolean allow switching parents if first node
|
||||||
-- @param allow_previous_parent allow previous parent if first node and previous parent without children
|
---@param allow_previous_parent? boolean allow previous parent if first node and previous parent without children
|
||||||
function M.get_previous_node(node, allow_switch_parents, allow_previous_parent)
|
function M.get_previous_node(node, allow_switch_parents, allow_previous_parent)
|
||||||
local destination_node
|
local destination_node ---@type TSNode
|
||||||
local parent = node:parent()
|
local parent = node:parent()
|
||||||
if not parent then
|
if not parent then
|
||||||
return
|
return
|
||||||
|
|
@ -148,7 +153,7 @@ function M.get_previous_node(node, allow_switch_parents, allow_previous_parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.get_named_children(node)
|
function M.get_named_children(node)
|
||||||
local nodes = {}
|
local nodes = {} ---@type TSNode[]
|
||||||
for i = 0, node:named_child_count() - 1, 1 do
|
for i = 0, node:named_child_count() - 1, 1 do
|
||||||
nodes[i + 1] = node:named_child(i)
|
nodes[i + 1] = node:named_child(i)
|
||||||
end
|
end
|
||||||
|
|
@ -166,7 +171,7 @@ function M.get_node_at_cursor(winnr, ignore_injected_langs)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local root
|
local root ---@type TSNode|nil
|
||||||
if ignore_injected_langs then
|
if ignore_injected_langs then
|
||||||
for _, tree in ipairs(root_lang_tree:trees()) do
|
for _, tree in ipairs(root_lang_tree:trees()) do
|
||||||
local tree_root = tree:root()
|
local tree_root = tree:root()
|
||||||
|
|
@ -209,6 +214,9 @@ function M.get_root_for_position(line, col, root_lang_tree)
|
||||||
return nil, nil, lang_tree
|
return nil, nil, lang_tree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---comment
|
||||||
|
---@param node TSNode
|
||||||
|
---@return TSNode result
|
||||||
function M.get_root_for_node(node)
|
function M.get_root_for_node(node)
|
||||||
local parent = node
|
local parent = node
|
||||||
local result = node
|
local result = node
|
||||||
|
|
@ -228,12 +236,17 @@ function M.highlight_node(node, buf, hl_namespace, hl_group)
|
||||||
M.highlight_range({ node:range() }, buf, hl_namespace, hl_group)
|
M.highlight_range({ node:range() }, buf, hl_namespace, hl_group)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a compatible vim range (1 index based) from a TS node range.
|
-- Get a compatible vim range (1 index based) from a TS node range.
|
||||||
--
|
--
|
||||||
-- TS nodes start with 0 and the end col is ending exclusive.
|
-- TS nodes start with 0 and the end col is ending exclusive.
|
||||||
-- They also treat a EOF/EOL char as a char ending in the first
|
-- They also treat a EOF/EOL char as a char ending in the first
|
||||||
-- col of the next row.
|
-- col of the next row.
|
||||||
|
---comment
|
||||||
|
---@param range integer[]
|
||||||
|
---@param buf integer|nil
|
||||||
|
---@return integer, integer, integer, integer
|
||||||
function M.get_vim_range(range, buf)
|
function M.get_vim_range(range, buf)
|
||||||
|
---@type integer, integer, integer, integer
|
||||||
local srow, scol, erow, ecol = unpack(range)
|
local srow, scol, erow, ecol = unpack(range)
|
||||||
srow = srow + 1
|
srow = srow + 1
|
||||||
scol = scol + 1
|
scol = scol + 1
|
||||||
|
|
@ -253,7 +266,9 @@ function M.get_vim_range(range, buf)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.highlight_range(range, buf, hl_namespace, hl_group)
|
function M.highlight_range(range, buf, hl_namespace, hl_group)
|
||||||
|
---@type integer, integer, integer, integer
|
||||||
local start_row, start_col, end_row, end_col = unpack(range)
|
local start_row, start_col, end_row, end_col = unpack(range)
|
||||||
|
---@diagnostic disable-next-line: missing-parameter
|
||||||
vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col })
|
vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -288,13 +303,15 @@ function M.update_selection(buf, node, selection_mode)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Byte length of node range
|
-- Byte length of node range
|
||||||
|
---@param node TSNode
|
||||||
|
---@return number
|
||||||
function M.node_length(node)
|
function M.node_length(node)
|
||||||
local _, _, start_byte = node:start()
|
local _, _, start_byte = node:start()
|
||||||
local _, _, end_byte = node:end_()
|
local _, _, end_byte = node:end_()
|
||||||
return end_byte - start_byte
|
return end_byte - start_byte
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @deprecated Use `vim.treesitter.is_in_node_range()` instead
|
---@deprecated Use `vim.treesitter.is_in_node_range()` instead
|
||||||
function M.is_in_node_range(node, line, col)
|
function M.is_in_node_range(node, line, col)
|
||||||
vim.notify_once(
|
vim.notify_once(
|
||||||
"nvim-treesitter.ts_utils.is_in_node_range is deprecated: use vim.treesitter.is_in_node_range",
|
"nvim-treesitter.ts_utils.is_in_node_range is deprecated: use vim.treesitter.is_in_node_range",
|
||||||
|
|
@ -303,7 +320,7 @@ function M.is_in_node_range(node, line, col)
|
||||||
return ts.is_in_node_range(node, line, col)
|
return ts.is_in_node_range(node, line, col)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @deprecated Use `vim.treesitter.get_node_range()` instead
|
---@deprecated Use `vim.treesitter.get_node_range()` instead
|
||||||
function M.get_node_range(node_or_range)
|
function M.get_node_range(node_or_range)
|
||||||
vim.notify_once(
|
vim.notify_once(
|
||||||
"nvim-treesitter.ts_utils.get_node_range is deprecated: use vim.treesitter.get_node_range",
|
"nvim-treesitter.ts_utils.get_node_range is deprecated: use vim.treesitter.get_node_range",
|
||||||
|
|
@ -312,6 +329,8 @@ function M.get_node_range(node_or_range)
|
||||||
return ts.get_node_range(node_or_range)
|
return ts.get_node_range(node_or_range)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param node TSNode
|
||||||
|
---@return table
|
||||||
function M.node_to_lsp_range(node)
|
function M.node_to_lsp_range(node)
|
||||||
local start_line, start_col, end_line, end_col = ts.get_node_range(node)
|
local start_line, start_col, end_line, end_col = ts.get_node_range(node)
|
||||||
local rtn = {}
|
local rtn = {}
|
||||||
|
|
@ -320,16 +339,18 @@ function M.node_to_lsp_range(node)
|
||||||
return rtn
|
return rtn
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Memoizes a function based on the buffer tick of the provided bufnr.
|
-- Memoizes a function based on the buffer tick of the provided bufnr.
|
||||||
-- The cache entry is cleared when the buffer is detached to avoid memory leaks.
|
-- The cache entry is cleared when the buffer is detached to avoid memory leaks.
|
||||||
-- @param fn: the fn to memoize, taking the bufnr as first argument
|
-- The options argument is a table with two optional values:
|
||||||
-- @param options:
|
|
||||||
-- - bufnr: extracts a bufnr from the given arguments.
|
-- - bufnr: extracts a bufnr from the given arguments.
|
||||||
-- - key: extracts the cache key from the given arguments.
|
-- - key: extracts the cache key from the given arguments.
|
||||||
-- @returns a memoized function
|
---@param fn function the fn to memoize, taking the buffer as first argument
|
||||||
|
---@param options? {bufnr: integer?, key: string|fun(...): string?} the memoization options
|
||||||
|
---@return function: a memoized function
|
||||||
function M.memoize_by_buf_tick(fn, options)
|
function M.memoize_by_buf_tick(fn, options)
|
||||||
options = options or {}
|
options = options or {}
|
||||||
|
|
||||||
|
---@type table<string, {result: any, last_tick: integer}>
|
||||||
local cache = {}
|
local cache = {}
|
||||||
local bufnr_fn = utils.to_func(options.bufnr or utils.identity)
|
local bufnr_fn = utils.to_func(options.bufnr or utils.identity)
|
||||||
local key_fn = utils.to_func(options.key or utils.identity)
|
local key_fn = utils.to_func(options.key or utils.identity)
|
||||||
|
|
@ -424,6 +445,7 @@ function M.goto_node(node, goto_end, avoid_set_jump)
|
||||||
utils.set_jump()
|
utils.set_jump()
|
||||||
end
|
end
|
||||||
local range = { M.get_vim_range { node:range() } }
|
local range = { M.get_vim_range { node:range() } }
|
||||||
|
---@type table<number>
|
||||||
local position
|
local position
|
||||||
if not goto_end then
|
if not goto_end then
|
||||||
position = { range[1], range[2] }
|
position = { range[1], range[2] }
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,15 @@ local luv = vim.loop
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
-- Wrapper around vim.notify with common options set.
|
-- Wrapper around vim.notify with common options set.
|
||||||
|
---@param msg string
|
||||||
|
---@param log_level number|nil
|
||||||
|
---@param opts table|nil
|
||||||
function M.notify(msg, log_level, opts)
|
function M.notify(msg, log_level, opts)
|
||||||
local default_opts = { title = "nvim-treesitter" }
|
local default_opts = { title = "nvim-treesitter" }
|
||||||
vim.notify(msg, log_level, vim.tbl_extend("force", default_opts, opts or {}))
|
vim.notify(msg, log_level, vim.tbl_extend("force", default_opts, opts or {}))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns the system specific path separator.
|
-- Returns the system-specific path separator.
|
||||||
---@return string
|
---@return string
|
||||||
function M.get_path_sep()
|
function M.get_path_sep()
|
||||||
return (fn.has "win32" == 1 and not vim.opt.shellslash:get()) and "\\" or "/"
|
return (fn.has "win32" == 1 and not vim.opt.shellslash:get()) and "\\" or "/"
|
||||||
|
|
@ -18,10 +21,13 @@ end
|
||||||
|
|
||||||
-- Returns a function that joins the given arguments with separator. Arguments
|
-- Returns a function that joins the given arguments with separator. Arguments
|
||||||
-- can't be nil. Example:
|
-- can't be nil. Example:
|
||||||
|
--
|
||||||
--[[
|
--[[
|
||||||
print(M.generate_join(" ")("foo", "bar"))
|
print(M.generate_join(" ")("foo", "bar"))
|
||||||
--]]
|
--]]
|
||||||
-- prints "foo bar"
|
--prints "foo bar"
|
||||||
|
---@param separator string
|
||||||
|
---@return fun(...: string): string
|
||||||
function M.generate_join(separator)
|
function M.generate_join(separator)
|
||||||
return function(...)
|
return function(...)
|
||||||
return table.concat({ ... }, separator)
|
return table.concat({ ... }, separator)
|
||||||
|
|
@ -32,13 +38,18 @@ M.join_path = M.generate_join(M.get_path_sep())
|
||||||
|
|
||||||
M.join_space = M.generate_join " "
|
M.join_space = M.generate_join " "
|
||||||
|
|
||||||
--- Define user defined vim command which calls nvim-treesitter module function
|
---@class Command
|
||||||
--- - If module name is 'mod', it should be defined in hierarchy 'nvim-treesitter.mod'
|
---@field run function
|
||||||
--- - A table with name 'commands' should be defined in 'mod' which needs to be passed as
|
---@field f_args string
|
||||||
--- the commands param of this function
|
---@field args string
|
||||||
---
|
|
||||||
---@param mod string, Name of the module that resides in the hierarchy - nvim-treesitter.module
|
-- Define user defined vim command which calls nvim-treesitter module function
|
||||||
---@param commands table, Command list for the module
|
-- - If module name is 'mod', it should be defined in hierarchy 'nvim-treesitter.mod'
|
||||||
|
-- - A table with name 'commands' should be defined in 'mod' which needs to be passed as
|
||||||
|
-- the commands param of this function
|
||||||
|
--
|
||||||
|
---@param mod string Name of the module that resides in the hierarchy - nvim-treesitter.module
|
||||||
|
---@param commands table<string, Command> Command list for the module
|
||||||
--- - {command_name} Name of the vim user defined command, Keys:
|
--- - {command_name} Name of the vim user defined command, Keys:
|
||||||
--- - {run}: (function) callback function that needs to be executed
|
--- - {run}: (function) callback function that needs to be executed
|
||||||
--- - {f_args}: (string, default <f-args>)
|
--- - {f_args}: (string, default <f-args>)
|
||||||
|
|
@ -46,7 +57,7 @@ M.join_space = M.generate_join " "
|
||||||
--- - {args}: (string, optional)
|
--- - {args}: (string, optional)
|
||||||
--- - vim command attributes
|
--- - vim command attributes
|
||||||
---
|
---
|
||||||
---Example:
|
---* @example
|
||||||
--- If module is nvim-treesitter.custom_mod
|
--- If module is nvim-treesitter.custom_mod
|
||||||
--- <pre>
|
--- <pre>
|
||||||
--- M.commands = {
|
--- M.commands = {
|
||||||
|
|
@ -136,18 +147,22 @@ function M.get_site_dir()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Gets a property at path
|
-- Gets a property at path
|
||||||
-- @param tbl the table to access
|
---@param tbl table the table to access
|
||||||
-- @param path the '.' separated path
|
---@param path string the '.' separated path
|
||||||
-- @returns the value at path or nil
|
---@return table|nil result the value at path or nil
|
||||||
function M.get_at_path(tbl, path)
|
function M.get_at_path(tbl, path)
|
||||||
if path == "" then
|
if path == "" then
|
||||||
return tbl
|
return tbl
|
||||||
end
|
end
|
||||||
|
|
||||||
local segments = vim.split(path, ".", true)
|
local segments = vim.split(path, ".", true)
|
||||||
|
---@type table[]|table
|
||||||
local result = tbl
|
local result = tbl
|
||||||
|
|
||||||
for _, segment in ipairs(segments) do
|
for _, segment in ipairs(segments) do
|
||||||
if type(result) == "table" then
|
if type(result) == "table" then
|
||||||
|
---@type table
|
||||||
|
-- TODO: figure out the actual type of tbl
|
||||||
result = result[segment]
|
result = result[segment]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -159,17 +174,9 @@ function M.set_jump()
|
||||||
vim.cmd "normal! m'"
|
vim.cmd "normal! m'"
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.index_of(tbl, obj)
|
|
||||||
for i, o in ipairs(tbl) do
|
|
||||||
if o == obj then
|
|
||||||
return i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Filters a list based on the given predicate
|
-- Filters a list based on the given predicate
|
||||||
-- @param tbl The list to filter
|
---@param tbl any[] The list to filter
|
||||||
-- @param predicate The predicate to filter with
|
---@param predicate fun(v:any, i:number):boolean The predicate to filter with
|
||||||
function M.filter(tbl, predicate)
|
function M.filter(tbl, predicate)
|
||||||
local result = {}
|
local result = {}
|
||||||
|
|
||||||
|
|
@ -184,8 +191,9 @@ end
|
||||||
|
|
||||||
-- Returns a list of all values from the first list
|
-- Returns a list of all values from the first list
|
||||||
-- that are not present in the second list.
|
-- that are not present in the second list.
|
||||||
-- @params tbl1 The first table
|
---@param tbl1 any[] The first table
|
||||||
-- @params tbl2 The second table
|
---@param tbl2 any[] The second table
|
||||||
|
---@return table
|
||||||
function M.difference(tbl1, tbl2)
|
function M.difference(tbl1, tbl2)
|
||||||
return M.filter(tbl1, function(v)
|
return M.filter(tbl1, function(v)
|
||||||
return not vim.tbl_contains(tbl2, v)
|
return not vim.tbl_contains(tbl2, v)
|
||||||
|
|
@ -196,12 +204,19 @@ function M.identity(a)
|
||||||
return a
|
return a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns a function returning the given value
|
||||||
|
---@param a any
|
||||||
|
---@return fun():any
|
||||||
function M.constant(a)
|
function M.constant(a)
|
||||||
return function()
|
return function()
|
||||||
return a
|
return a
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns a function that returns the given value if it is a function,
|
||||||
|
-- otherwise returns a function that returns the given value.
|
||||||
|
---@param a any
|
||||||
|
---@return fun(...):any
|
||||||
function M.to_func(a)
|
function M.to_func(a)
|
||||||
return type(a) == "function" and a or M.constant(a)
|
return type(a) == "function" and a or M.constant(a)
|
||||||
end
|
end
|
||||||
|
|
@ -209,7 +224,10 @@ end
|
||||||
---@return string|nil
|
---@return string|nil
|
||||||
function M.ts_cli_version()
|
function M.ts_cli_version()
|
||||||
if fn.executable "tree-sitter" == 1 then
|
if fn.executable "tree-sitter" == 1 then
|
||||||
local handle = io.popen "tree-sitter -V"
|
local handle = io.popen "tree-sitter -V"
|
||||||
|
if not handle then
|
||||||
|
return
|
||||||
|
end
|
||||||
local result = handle:read "*a"
|
local result = handle:read "*a"
|
||||||
handle:close()
|
handle:close()
|
||||||
return vim.split(result, "\n")[1]:match "[^tree%psitter ].*"
|
return vim.split(result, "\n")[1]:match "[^tree%psitter ].*"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
-- Execute as `nvim --headless -c "luafile ./scripts/update-readme.lua"`
|
-- Execute as `nvim --headless -c "luafile ./scripts/update-readme.lua"`
|
||||||
|
|
||||||
|
---@class Parser
|
||||||
|
---@field name string
|
||||||
|
---@field parser ParserInfo
|
||||||
|
|
||||||
local parsers = require("nvim-treesitter.parsers").get_parser_configs()
|
local parsers = require("nvim-treesitter.parsers").get_parser_configs()
|
||||||
local sorted_parsers = {}
|
local sorted_parsers = {}
|
||||||
|
|
||||||
|
|
@ -6,12 +11,15 @@ for k, v in pairs(parsers) do
|
||||||
table.insert(sorted_parsers, { name = k, parser = v })
|
table.insert(sorted_parsers, { name = k, parser = v })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param a Parser
|
||||||
|
---@param b Parser
|
||||||
table.sort(sorted_parsers, function(a, b)
|
table.sort(sorted_parsers, function(a, b)
|
||||||
return a.name < b.name
|
return a.name < b.name
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local generated_text = ""
|
local generated_text = ""
|
||||||
|
|
||||||
|
---@param v Parser
|
||||||
for _, v in ipairs(sorted_parsers) do
|
for _, v in ipairs(sorted_parsers) do
|
||||||
local link = "[" .. (v.parser.readme_name or v.name) .. "](" .. v.parser.install_info.url .. ")"
|
local link = "[" .. (v.parser.readme_name or v.name) .. "](" .. v.parser.install_info.url .. ")"
|
||||||
|
|
||||||
|
|
@ -41,7 +49,7 @@ local new_readme_text = string.gsub(
|
||||||
)
|
)
|
||||||
vim.fn.writefile(vim.fn.split(new_readme_text, "\n"), "README.md")
|
vim.fn.writefile(vim.fn.split(new_readme_text, "\n"), "README.md")
|
||||||
|
|
||||||
if string.find(readme_text, generated_text, 1, "plain") then
|
if string.find(readme_text, generated_text, 1, true) then
|
||||||
print "README.md is up-to-date!"
|
print "README.md is up-to-date!"
|
||||||
vim.cmd "q"
|
vim.cmd "q"
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
-- Execute as `nvim --headless -c "luafile ./scripts/write-lockfile.lua"`
|
-- Execute as `nvim --headless -c "luafile ./scripts/write-lockfile.lua"`
|
||||||
|
|
||||||
|
---@type string|any[]
|
||||||
local skip_langs = vim.fn.getenv "SKIP_LOCKFILE_UPDATE_FOR_LANGS"
|
local skip_langs = vim.fn.getenv "SKIP_LOCKFILE_UPDATE_FOR_LANGS"
|
||||||
|
|
||||||
if skip_langs == vim.NIL then
|
if skip_langs == vim.NIL then
|
||||||
skip_langs = {}
|
skip_langs = {}
|
||||||
else
|
else
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
skip_langs = vim.fn.split(skip_langs, ",")
|
skip_langs = vim.fn.split(skip_langs, ",")
|
||||||
end
|
end
|
||||||
|
|
||||||
print("Skipping languages: " .. vim.inspect(skip_langs))
|
print("Skipping languages: " .. vim.inspect(skip_langs))
|
||||||
require("nvim-treesitter.install").write_lockfile("verbose", skip_langs)
|
require("nvim-treesitter.install").write_lockfile("verbose", skip_langs)
|
||||||
vim.cmd "q"
|
vim.cmd "q"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue