From 692b051b09935653befdb8f7ba8afdb640adf17b Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 12 Jun 2023 09:54:30 -0600 Subject: feat!: drop modules, general refactor and cleanup --- lua/nvim-treesitter.lua | 22 - lua/nvim-treesitter/caching.lua | 71 - lua/nvim-treesitter/compat.lua | 39 - lua/nvim-treesitter/config.lua | 144 + lua/nvim-treesitter/configs.lua | 616 ---- lua/nvim-treesitter/fold.lua | 123 - lua/nvim-treesitter/health.lua | 181 +- lua/nvim-treesitter/highlight.lua | 49 - lua/nvim-treesitter/incremental_selection.lua | 176 - lua/nvim-treesitter/indent.lua | 121 +- lua/nvim-treesitter/info.lua | 190 - lua/nvim-treesitter/init.lua | 11 + lua/nvim-treesitter/install.lua | 846 ++--- lua/nvim-treesitter/locals.lua | 125 +- lua/nvim-treesitter/parsers.lua | 4370 +++++++++++------------ lua/nvim-treesitter/query.lua | 304 +- lua/nvim-treesitter/query_predicates.lua | 167 - lua/nvim-treesitter/shell_cmds.lua | 255 ++ lua/nvim-treesitter/shell_command_selectors.lua | 368 -- lua/nvim-treesitter/statusline.lua | 53 - lua/nvim-treesitter/ts_utils.lua | 482 --- lua/nvim-treesitter/tsrange.lua | 154 - lua/nvim-treesitter/utils.lua | 235 +- 23 files changed, 3155 insertions(+), 5947 deletions(-) delete mode 100644 lua/nvim-treesitter.lua delete mode 100644 lua/nvim-treesitter/caching.lua delete mode 100644 lua/nvim-treesitter/compat.lua create mode 100644 lua/nvim-treesitter/config.lua delete mode 100644 lua/nvim-treesitter/configs.lua delete mode 100644 lua/nvim-treesitter/fold.lua delete mode 100644 lua/nvim-treesitter/highlight.lua delete mode 100644 lua/nvim-treesitter/incremental_selection.lua delete mode 100644 lua/nvim-treesitter/info.lua create mode 100644 lua/nvim-treesitter/init.lua delete mode 100644 lua/nvim-treesitter/query_predicates.lua create mode 100644 lua/nvim-treesitter/shell_cmds.lua delete mode 100644 lua/nvim-treesitter/shell_command_selectors.lua delete mode 100644 lua/nvim-treesitter/statusline.lua delete mode 100644 lua/nvim-treesitter/ts_utils.lua delete mode 100644 lua/nvim-treesitter/tsrange.lua (limited to 'lua') diff --git a/lua/nvim-treesitter.lua b/lua/nvim-treesitter.lua deleted file mode 100644 index 963fe7309..000000000 --- a/lua/nvim-treesitter.lua +++ /dev/null @@ -1,22 +0,0 @@ -local install = require "nvim-treesitter.install" -local utils = require "nvim-treesitter.utils" -local info = require "nvim-treesitter.info" -local configs = require "nvim-treesitter.configs" -local statusline = require "nvim-treesitter.statusline" - --- Registers all query predicates -require "nvim-treesitter.query_predicates" - -local M = {} - -function M.setup() - utils.setup_commands("install", install.commands) - utils.setup_commands("info", info.commands) - utils.setup_commands("configs", configs.commands) - configs.init() -end - -M.define_modules = configs.define_modules -M.statusline = statusline.statusline - -return M diff --git a/lua/nvim-treesitter/caching.lua b/lua/nvim-treesitter/caching.lua deleted file mode 100644 index 7733202ed..000000000 --- a/lua/nvim-treesitter/caching.lua +++ /dev/null @@ -1,71 +0,0 @@ -local api = vim.api - -local M = {} - --- Creates a cache table for buffers keyed by a type name. --- Cache entries attach to the buffer and cleanup entries --- as buffers are detached. -function M.create_buffer_cache() - local cache = {} - - ---@type table> - local items = setmetatable({}, { - __index = function(tbl, key) - rawset(tbl, key, {}) - return rawget(tbl, key) - end, - }) - - ---@type table - local loaded_buffers = {} - - ---@param type_name string - ---@param bufnr integer - ---@param value any - function cache.set(type_name, bufnr, value) - if not loaded_buffers[bufnr] then - loaded_buffers[bufnr] = true - -- Clean up the cache if the buffer is detached - -- to avoid memory leaks - api.nvim_buf_attach(bufnr, false, { - on_detach = function() - cache.clear_buffer(bufnr) - loaded_buffers[bufnr] = nil - return true - end, - on_reload = function() end, -- this is needed to prevent on_detach being called on buffer reload - }) - end - - items[bufnr][type_name] = value - end - - ---@param type_name string - ---@param bufnr integer - ---@return any - function cache.get(type_name, bufnr) - return items[bufnr][type_name] - end - - ---@param type_name string - ---@param bufnr integer - ---@return boolean - function cache.has(type_name, bufnr) - return cache.get(type_name, bufnr) ~= nil - end - - ---@param type_name string - ---@param bufnr integer - function cache.remove(type_name, bufnr) - items[bufnr][type_name] = nil - end - - ---@param bufnr integer - function cache.clear_buffer(bufnr) - items[bufnr] = nil - end - - return cache -end - -return M diff --git a/lua/nvim-treesitter/compat.lua b/lua/nvim-treesitter/compat.lua deleted file mode 100644 index 0ad010030..000000000 --- a/lua/nvim-treesitter/compat.lua +++ /dev/null @@ -1,39 +0,0 @@ --- Shim module to address deprecations across nvim versions -local ts = vim.treesitter -local tsq = ts.query - -local M = {} - -function M.get_query_files(lang, query_group, is_included) - return (tsq.get_files or tsq.get_query_files)(lang, query_group, is_included) -end - -function M.get_query(lang, query_name) - return (tsq.get or tsq.get_query)(lang, query_name) -end - -function M.parse_query(lang, query) - return (tsq.parse or tsq.parse_query)(lang, query) -end - -function M.get_range(node, source, metadata) - return (ts.get_range or tsq.get_range)(node, source, metadata) -end - -function M.get_node_text(node, bufnr) - return (ts.get_node_text or tsq.get_node_text)(node, bufnr) -end - -function M.require_language(lang, opts) - return (ts.language.add or ts.language.require_language)(lang, opts) -end - -function M.flatten(t) - if vim.fn.has "nvim-0.11" == 1 then - return vim.iter(t):flatten():totable() - else - return vim.tbl_flatten(t) - end -end - -return M diff --git a/lua/nvim-treesitter/config.lua b/lua/nvim-treesitter/config.lua new file mode 100644 index 000000000..e43ad13c2 --- /dev/null +++ b/lua/nvim-treesitter/config.lua @@ -0,0 +1,144 @@ +local utils = require('nvim-treesitter.utils') + +local M = {} + +---@class TSConfig +---@field sync_install boolean +---@field auto_install boolean +---@field ensure_install string[] +---@field ignore_install string[] +---@field install_dir string + +---@type TSConfig +local config = { + sync_install = false, + auto_install = false, + ensure_install = {}, + ignore_install = {}, + install_dir = utils.join_path(vim.fn.stdpath('data'), 'site'), +} + +---Setup call for users to override configuration configurations. +---@param user_data TSConfig|nil user configuration table +function M.setup(user_data) + if user_data then + if user_data.install_dir then + user_data.install_dir = vim.fs.normalize(user_data.install_dir) + --TODO(clason): insert after/before site, or leave to user? + vim.opt.runtimepath:append(user_data.install_dir) + end + config = vim.tbl_deep_extend('force', config, user_data) + end + + if config.auto_install then + vim.api.nvim_create_autocmd('FileType', { + callback = function(args) + local ft = vim.bo[args.buf].filetype + local lang = vim.treesitter.language.get_lang(ft) or ft + if + require('nvim-treesitter.parsers').configs[lang] + and not vim.list_contains(M.installed_parsers(), lang) + and not vim.list_contains(config.ignore_install, lang) + then + require('nvim-treesitter.install').install(lang) + end + end, + }) + end + + if #config.ensure_install > 0 then + local to_install = M.norm_languages(config.ensure_install, { ignored = true, installed = true }) + + if #to_install > 0 then + require('nvim-treesitter.install').install(to_install, { + with_sync = config.sync_install, + }) + end + end +end + +-- Returns the install path for parsers, parser info, and queries. +-- If the specified directory does not exist, it is created. +---@param dir_name string +---@return string +function M.get_install_dir(dir_name) + local dir = utils.join_path(config.install_dir, dir_name) + + if not vim.loop.fs_stat(dir) then + local ok, error = pcall(vim.fn.mkdir, dir, 'p', '0755') + if not ok then + vim.notify(error, vim.log.levels.ERROR) + end + end + return dir +end + +---@return string[] +function M.installed_parsers() + local install_dir = M.get_install_dir('parser') + + local installed = {} --- @type string[] + for f in vim.fs.dir(install_dir) do + local lang = assert(f:match('(.*)%..*')) + installed[#installed + 1] = lang + end + + return installed +end + +---Normalize languages +---@param languages? string[]|string +---@param skip? table +---@return string[] +function M.norm_languages(languages, skip) + if not languages then + return {} + end + local parsers = require('nvim-treesitter.parsers') + + -- Turn into table + if type(languages) == 'string' then + languages = { languages } + end + + if vim.list_contains(languages, 'all') then + if skip and skip.missing then + return M.installed_parsers() + end + languages = parsers.get_available() + end + + for i, tier in ipairs(parsers.tiers) do + if vim.list_contains(languages, tier) then + languages = vim.iter.filter(function(l) + return l ~= tier + end, languages) + vim.list_extend(languages, parsers.get_available(i)) + end + end + + if skip and skip.ignored then + local ignored = config.ignore_install + languages = vim.iter.filter(function(v) + return not vim.list_contains(ignored, v) + end, languages) + end + + if skip and skip.installed then + local installed = M.installed_parsers() + languages = vim.iter.filter(function(v) + return not vim.list_contains(installed, v) + end, languages) + end + + if skip and skip.missing then + local installed = M.installed_parsers() + languages = vim.iter.filter(function(v) + return vim.list_contains(installed, v) + end, languages) + end + + return languages +end + +return M diff --git a/lua/nvim-treesitter/configs.lua b/lua/nvim-treesitter/configs.lua deleted file mode 100644 index a3ec30fb2..000000000 --- a/lua/nvim-treesitter/configs.lua +++ /dev/null @@ -1,616 +0,0 @@ -local api = vim.api - -local queries = require "nvim-treesitter.query" -local ts = require "nvim-treesitter.compat" -local parsers = require "nvim-treesitter.parsers" -local utils = require "nvim-treesitter.utils" -local caching = require "nvim-treesitter.caching" - -local M = {} - ----@class TSConfig ----@field modules {[string]:TSModule} ----@field sync_install boolean ----@field ensure_installed string[]|string ----@field ignore_install string[] ----@field auto_install boolean ----@field parser_install_dir string|nil - ----@type TSConfig -local config = { - modules = {}, - sync_install = false, - ensure_installed = {}, - auto_install = false, - ignore_install = {}, - parser_install_dir = nil, -} - --- List of modules that need to be setup on initialization. ----@type TSModule[][] -local queued_modules_defs = {} --- Whether we've initialized the plugin yet. -local is_initialized = false - ----@class TSModule ----@field module_path string ----@field enable boolean|string[]|function(string): boolean ----@field disable boolean|string[]|function(string): boolean ----@field keymaps table ----@field is_supported function(string): boolean ----@field attach function(string) ----@field detach function(string) ----@field enabled_buffers table ----@field additional_vim_regex_highlighting boolean|string[] - ----@type {[string]: TSModule} -local builtin_modules = { - highlight = { - module_path = "nvim-treesitter.highlight", - -- @deprecated: use `highlight.set_custom_captures` instead - custom_captures = {}, - enable = false, - is_supported = function(lang) - return queries.has_highlights(lang) - end, - additional_vim_regex_highlighting = false, - }, - incremental_selection = { - module_path = "nvim-treesitter.incremental_selection", - enable = false, - keymaps = { - init_selection = "gnn", -- set to `false` to disable one of the mappings - node_incremental = "grn", - scope_incremental = "grc", - node_decremental = "grm", - }, - is_supported = function() - return true - end, - }, - indent = { - module_path = "nvim-treesitter.indent", - enable = false, - is_supported = queries.has_indents, - }, -} - -local attached_buffers_by_module = caching.create_buffer_cache() - ----Resolves a module by requiring the `module_path` or using the module definition. ----@param mod_name string ----@return TSModule|nil -local function resolve_module(mod_name) - local config_mod = M.get_module(mod_name) - - if not config_mod then - return - end - - if type(config_mod.attach) == "function" and type(config_mod.detach) == "function" then - return config_mod - elseif type(config_mod.module_path) == "string" then - return require(config_mod.module_path) - end -end - ----Enables and attaches the module to a buffer for lang. ----@param mod string path to module ----@param bufnr integer|nil buffer number, defaults to current buffer ----@param lang string|nil language, defaults to current language -local function enable_module(mod, bufnr, lang) - local module = M.get_module(mod) - if not module then - return - end - - bufnr = bufnr or api.nvim_get_current_buf() - lang = lang or parsers.get_buf_lang(bufnr) - - if not module.enable then - if module.enabled_buffers then - module.enabled_buffers[bufnr] = true - else - module.enabled_buffers = { [bufnr] = true } - end - end - - M.attach_module(mod, bufnr, lang) -end - ----Enables autocomands for the module. ----After the module is loaded `loaded` will be set to true for the module. ----@param mod string path to module -local function enable_mod_conf_autocmd(mod) - local config_mod = M.get_module(mod) - if not config_mod or config_mod.loaded then - return - end - - api.nvim_create_autocmd("FileType", { - group = api.nvim_create_augroup("NvimTreesitter-" .. mod, {}), - callback = function(args) - require("nvim-treesitter.configs").reattach_module(mod, args.buf) - end, - desc = "Reattach module", - }) - - config_mod.loaded = true -end - ----Enables the module globally and for all current buffers. ----After enabled, `enable` will be set to true for the module. ----@param mod string path to module -local function enable_all(mod) - local config_mod = M.get_module(mod) - if not config_mod then - return - end - - enable_mod_conf_autocmd(mod) - config_mod.enable = true - config_mod.enabled_buffers = nil - - for _, bufnr in pairs(api.nvim_list_bufs()) do - enable_module(mod, bufnr) - end -end - ----Disables and detaches the module for a buffer. ----@param mod string path to module ----@param bufnr integer buffer number, defaults to current buffer -local function disable_module(mod, bufnr) - local module = M.get_module(mod) - if not module then - return - end - - bufnr = bufnr or api.nvim_get_current_buf() - if module.enabled_buffers then - module.enabled_buffers[bufnr] = false - end - M.detach_module(mod, bufnr) -end - ----Disables autocomands for the module. ----After the module is unloaded `loaded` will be set to false for the module. ----@param mod string path to module -local function disable_mod_conf_autocmd(mod) - local config_mod = M.get_module(mod) - if not config_mod or not config_mod.loaded then - return - end - api.nvim_clear_autocmds { event = "FileType", group = "NvimTreesitter-" .. mod } - config_mod.loaded = false -end - ----Disables the module globally and for all current buffers. ----After disabled, `enable` will be set to false for the module. ----@param mod string path to module -local function disable_all(mod) - local config_mod = M.get_module(mod) - if not config_mod then - return - end - - config_mod.enabled_buffers = nil - disable_mod_conf_autocmd(mod) - config_mod.enable = false - - for _, bufnr in pairs(api.nvim_list_bufs()) do - disable_module(mod, bufnr) - end -end - ----Toggles a module for a buffer ----@param mod string path to module ----@param bufnr integer buffer number, defaults to current buffer ----@param lang string language, defaults to current language -local function toggle_module(mod, bufnr, lang) - bufnr = bufnr or api.nvim_get_current_buf() - lang = lang or parsers.get_buf_lang(bufnr) - - if attached_buffers_by_module.has(mod, bufnr) then - disable_module(mod, bufnr) - else - enable_module(mod, bufnr, lang) - end -end - --- Toggles the module globally and for all current buffers. --- @param mod path to module -local function toggle_all(mod) - local config_mod = M.get_module(mod) - if not config_mod then - return - end - - if config_mod.enable then - disable_all(mod) - else - enable_all(mod) - end -end - ----Recurses through all modules including submodules ----@param accumulator function called for each module ----@param root {[string]: TSModule}|nil root configuration table to start at ----@param path string|nil prefix path -local function recurse_modules(accumulator, root, path) - root = root or config.modules - - for name, module in pairs(root) do - local new_path = path and (path .. "." .. name) or name - - if M.is_module(module) then - accumulator(name, module, new_path, root) - elseif type(module) == "table" then - recurse_modules(accumulator, module, new_path) - end - end -end - --- Shows current configuration of all nvim-treesitter modules ----@param process_function function used as the `process` parameter ---- for vim.inspect (https://github.com/kikito/inspect.lua#optionsprocess) -local function config_info(process_function) - process_function = process_function - or function(item, path) - if path[#path] == vim.inspect.METATABLE then - return - end - if path[#path] == "is_supported" then - return - end - return item - end - print(vim.inspect(config, { process = process_function })) -end - ----@param query_group string ----@param lang string -function M.edit_query_file(query_group, lang) - lang = lang or parsers.get_buf_lang() - local files = ts.get_query_files(lang, query_group, true) - if #files == 0 then - utils.notify "No query file found! Creating a new one!" - M.edit_query_file_user_after(query_group, lang) - elseif #files == 1 then - vim.cmd(":edit " .. files[1]) - else - vim.ui.select(files, { prompt = "Select a file:" }, function(file) - if file then - vim.cmd(":edit " .. file) - end - end) - end -end - ----@param query_group string ----@param lang string -function M.edit_query_file_user_after(query_group, lang) - lang = lang or parsers.get_buf_lang() - local folder = utils.join_path(vim.fn.stdpath "config", "after", "queries", lang) - local file = utils.join_path(folder, query_group .. ".scm") - if vim.fn.isdirectory(folder) ~= 1 then - vim.ui.select({ "Yes", "No" }, { prompt = '"' .. folder .. '" does not exist. Create it?' }, function(choice) - if choice == "Yes" then - vim.fn.mkdir(folder, "p", "0755") - vim.cmd(":edit " .. file) - end - end) - else - vim.cmd(":edit " .. file) - end -end - -M.commands = { - TSBufEnable = { - run = enable_module, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, - TSBufDisable = { - run = disable_module, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, - TSBufToggle = { - run = toggle_module, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, - TSEnable = { - run = enable_all, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, - TSDisable = { - run = disable_all, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, - TSToggle = { - run = toggle_all, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, - TSConfigInfo = { - run = config_info, - args = { - "-nargs=0", - }, - }, - TSEditQuery = { - run = M.edit_query_file, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter#available_query_groups", - }, - }, - TSEditQueryUserAfter = { - run = M.edit_query_file_user_after, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter#available_query_groups", - }, - }, -} - ----@param mod string module ----@param lang string the language of the buffer ----@param bufnr integer the buffer -function M.is_enabled(mod, lang, bufnr) - if not parsers.has_parser(lang) then - return false - end - - local module_config = M.get_module(mod) - if not module_config then - return false - end - - local buffer_enabled = module_config.enabled_buffers and module_config.enabled_buffers[bufnr] - local config_enabled = module_config.enable or buffer_enabled - if not config_enabled or not module_config.is_supported(lang) then - return false - end - - local disable = module_config.disable - if type(disable) == "function" then - if disable(lang, bufnr) then - return false - end - elseif type(disable) == "table" then - -- Otherwise it's a list of languages - for _, parser in pairs(disable) do - if lang == parser then - return false - end - end - end - - return true -end - ----Setup call for users to override module configurations. ----@param user_data TSConfig module overrides -function M.setup(user_data) - config.modules = vim.tbl_deep_extend("force", config.modules, user_data) - config.ignore_install = user_data.ignore_install or {} - config.parser_install_dir = user_data.parser_install_dir or nil - if config.parser_install_dir then - config.parser_install_dir = vim.fn.expand(config.parser_install_dir, ":p") - end - - config.auto_install = user_data.auto_install or false - if config.auto_install then - require("nvim-treesitter.install").setup_auto_install() - end - - local ensure_installed = user_data.ensure_installed or {} - if #ensure_installed > 0 then - if user_data.sync_install then - require("nvim-treesitter.install").ensure_installed_sync(ensure_installed) - else - require("nvim-treesitter.install").ensure_installed(ensure_installed) - end - end - - config.modules.ensure_installed = nil - config.ensure_installed = ensure_installed - - recurse_modules(function(_, _, new_path) - local data = utils.get_at_path(config.modules, new_path) - if data.enable then - enable_all(new_path) - end - end, config.modules) -end - --- Defines a table of modules that can be attached/detached to buffers --- based on language support. A module consist of the following properties: ----* @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. ----* @keymaps A list of user mappings for a given module if relevant. ----* @is_supported A function which, given a ft, will return true if the ft works on the module. ----* @module_path A string path to a module file using `require`. The exported module must contain ---- an `attach` and `detach` function. This path is not required if `attach` and `detach` ---- functions are provided directly on the module definition. ----* @attach An attach function that is called for each buffer that the module is enabled for. This is required ---- 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 ---- 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. --- ----* @example ----require"nvim-treesitter".define_modules { ---- my_cool_module = { ---- attach = function() ---- do_some_cool_setup() ---- end, ---- detach = function() ---- do_some_cool_teardown() ---- end ---- } ----} ----@param mod_defs TSModule[] -function M.define_modules(mod_defs) - if not is_initialized then - table.insert(queued_modules_defs, mod_defs) - return - end - - recurse_modules(function(key, mod, _, group) - group[key] = vim.tbl_extend("keep", mod, { - enable = false, - disable = {}, - is_supported = function() - return true - end, - }) - end, mod_defs) - - config.modules = vim.tbl_deep_extend("keep", config.modules, mod_defs) - - for _, mod in ipairs(M.available_modules(mod_defs)) do - local module_config = M.get_module(mod) - if module_config and module_config.enable then - enable_mod_conf_autocmd(mod) - end - end -end - ----Attaches a module to a buffer ----@param mod_name string the module name ----@param bufnr integer the buffer ----@param lang string the language of the buffer -function M.attach_module(mod_name, bufnr, lang) - bufnr = bufnr or api.nvim_get_current_buf() - lang = lang or parsers.get_buf_lang(bufnr) - local resolved_mod = resolve_module(mod_name) - - if resolved_mod and not attached_buffers_by_module.has(mod_name, bufnr) and M.is_enabled(mod_name, lang, bufnr) then - attached_buffers_by_module.set(mod_name, bufnr, true) - resolved_mod.attach(bufnr, lang) - end -end - --- Detaches a module to a buffer ----@param mod_name string the module name ----@param bufnr integer the buffer -function M.detach_module(mod_name, bufnr) - local resolved_mod = resolve_module(mod_name) - bufnr = bufnr or api.nvim_get_current_buf() - - if resolved_mod and attached_buffers_by_module.has(mod_name, bufnr) then - attached_buffers_by_module.remove(mod_name, bufnr) - resolved_mod.detach(bufnr) - end -end - --- Same as attach_module, but if the module is already attached, detach it first. ----@param mod_name string the module name ----@param bufnr integer the buffer ----@param lang string the language of the buffer -function M.reattach_module(mod_name, bufnr, lang) - M.detach_module(mod_name, bufnr) - M.attach_module(mod_name, bufnr, lang) -end - --- Gets available modules ----@param root {[string]:TSModule}|nil table to find modules ----@return string[] modules list of module paths -function M.available_modules(root) - local modules = {} - - recurse_modules(function(_, _, path) - table.insert(modules, path) - end, root) - - return modules -end - ----Gets a module config by path ----@param mod_path string path to the module ----@return TSModule|nil: the module or nil -function M.get_module(mod_path) - local mod = utils.get_at_path(config.modules, mod_path) - - return M.is_module(mod) and mod or nil -end - --- Determines whether the provided table is a module. --- A module should contain an attach and detach function. ----@param mod table|nil the module table ----@return boolean -function M.is_module(mod) - return type(mod) == "table" - and ((type(mod.attach) == "function" and type(mod.detach) == "function") or type(mod.module_path) == "string") -end - --- Initializes built-in modules and any queued modules --- registered by plugins or the user. -function M.init() - is_initialized = true - M.define_modules(builtin_modules) - - for _, mod_def in ipairs(queued_modules_defs) do - M.define_modules(mod_def) - end -end - --- 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 --- 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 --- the plugin is installed with Nix, since the "/nix/store" is read-only. ----@param folder_name string|nil ----@return string|nil, string|nil -function M.get_parser_install_dir(folder_name) - folder_name = folder_name or "parser" - - local install_dir = config.parser_install_dir or utils.get_package_path() - local parser_dir = utils.join_path(install_dir, folder_name) - - return utils.create_or_reuse_writable_dir( - parser_dir, - utils.join_space("Could not create parser dir '", parser_dir, "': "), - utils.join_space( - "Parser dir '", - parser_dir, - "' should be read/write (see README on how to configure an alternative install location)" - ) - ) -end - -function M.get_parser_info_dir() - return M.get_parser_install_dir "parser-info" -end - -function M.get_ignored_parser_installs() - return config.ignore_install or {} -end - -function M.get_ensure_installed_parsers() - if type(config.ensure_installed) == "string" then - return { config.ensure_installed } - end - return config.ensure_installed or {} -end - -return M diff --git a/lua/nvim-treesitter/fold.lua b/lua/nvim-treesitter/fold.lua deleted file mode 100644 index 759599876..000000000 --- a/lua/nvim-treesitter/fold.lua +++ /dev/null @@ -1,123 +0,0 @@ -local api = vim.api -local tsutils = require "nvim-treesitter.ts_utils" -local query = require "nvim-treesitter.query" -local parsers = require "nvim-treesitter.parsers" - -local M = {} - --- This is cached on buf tick to avoid computing that multiple times --- Especially not for every line in the file when `zx` is hit -local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr) - local max_fold_level = api.nvim_win_get_option(0, "foldnestmax") - local trim_level = function(level) - if level > max_fold_level then - return max_fold_level - end - return level - end - - local parser = parsers.get_parser(bufnr) - - if not parser then - return {} - end - - local matches = query.get_capture_matches_recursively(bufnr, function(lang) - if query.has_folds(lang) then - return "@fold", "folds" - elseif query.has_locals(lang) then - return "@scope", "locals" - end - end) - - -- start..stop is an inclusive range - - ---@type table - local start_counts = {} - ---@type table - local stop_counts = {} - - local prev_start = -1 - local prev_stop = -1 - - local min_fold_lines = api.nvim_win_get_option(0, "foldminlines") - - for _, match in ipairs(matches) do - local start, stop, stop_col ---@type integer, integer, integer - if match.metadata and match.metadata.range then - start, _, stop, stop_col = unpack(match.metadata.range) ---@type integer, integer, integer, integer - else - start, _, stop, stop_col = match.node:range() ---@type integer, integer, integer, integer - end - - if stop_col == 0 then - stop = stop - 1 - end - - local fold_length = stop - start + 1 - local should_fold = fold_length > min_fold_lines - - -- Fold only multiline nodes that are not exactly the same as previously met folds - -- Checking against just the previously found fold is sufficient if nodes - -- are returned in preorder or postorder when traversing tree - if should_fold and not (start == prev_start and stop == prev_stop) then - start_counts[start] = (start_counts[start] or 0) + 1 - stop_counts[stop] = (stop_counts[stop] or 0) + 1 - prev_start = start - prev_stop = stop - end - end - - ---@type string[] - local levels = {} - local current_level = 0 - - -- We now have the list of fold opening and closing, fill the gaps and mark where fold start - for lnum = 0, api.nvim_buf_line_count(bufnr) do - local prefix = "" - - local last_trimmed_level = trim_level(current_level) - current_level = current_level + (start_counts[lnum] or 0) - local trimmed_level = trim_level(current_level) - current_level = current_level - (stop_counts[lnum] or 0) - local next_trimmed_level = trim_level(current_level) - - -- Determine if it's the start/end of a fold - -- NB: vim's fold-expr interface does not have a mechanism to indicate that - -- two (or more) folds start at this line, so it cannot distinguish between - -- ( \n ( \n )) \n (( \n ) \n ) - -- versus - -- ( \n ( \n ) \n ( \n ) \n ) - -- If it did have such a mechanism, (trimmed_level - last_trimmed_level) - -- would be the correct number of starts to pass on. - if trimmed_level - last_trimmed_level > 0 then - prefix = ">" - elseif trimmed_level - next_trimmed_level > 0 then - -- Ending marks tend to confuse vim more than it helps, particularly when - -- the fold level changes by at least 2; we can uncomment this if - -- vim's behavior gets fixed. - -- prefix = "<" - prefix = "" - end - - levels[lnum + 1] = prefix .. tostring(trimmed_level) - end - - return levels -end) - ----@param lnum integer ----@return string -function M.get_fold_indic(lnum) - if not parsers.has_parser() or not lnum then - return "0" - end - - local buf = api.nvim_get_current_buf() - - local levels = folds_levels(buf) or {} - - return levels[lnum] or "0" -end - -return M diff --git a/lua/nvim-treesitter/health.lua b/lua/nvim-treesitter/health.lua index 32741b136..e8c945f6c 100644 --- a/lua/nvim-treesitter/health.lua +++ b/lua/nvim-treesitter/health.lua @@ -1,116 +1,119 @@ -local api = vim.api -local fn = vim.fn - -local queries = require "nvim-treesitter.query" -local info = require "nvim-treesitter.info" -local shell = require "nvim-treesitter.shell_command_selectors" -local install = require "nvim-treesitter.install" -local utils = require "nvim-treesitter.utils" -local ts = require "nvim-treesitter.compat" - -local health = vim.health or require "health" - --- "report_" prefix has been deprecated, use the recommended replacements if they exist. -local _start = health.start or health.report_start -local _ok = health.ok or health.report_ok -local _warn = health.warn or health.report_warn -local _error = health.error or health.report_error +local shell = require('nvim-treesitter.shell_cmds') +local install = require('nvim-treesitter.install') +local config = require('nvim-treesitter.config') +local tsq = vim.treesitter.query local M = {} local NVIM_TREESITTER_MINIMUM_ABI = 13 +---@return string|nil +local function ts_cli_version() + if vim.fn.executable('tree-sitter') == 1 then + local handle = io.popen('tree-sitter -V') + if not handle then + return + end + local result = handle:read('*a') + handle:close() + return vim.split(result, '\n')[1]:match('[^tree%psitter ].*') + end +end + local function install_health() - _start "Installation" + vim.health.start('Installation') - if fn.has "nvim-0.10" ~= 1 then - _error "Nvim-treesitter requires Nvim 0.10 or newer" + if vim.fn.has('nvim-0.10') ~= 1 then + vim.health.error('Nvim-treesitter requires Neovim Nightly') end - if fn.executable "tree-sitter" == 0 then - _warn( - "`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar," - .. " not required for :TSInstall)" + if vim.fn.executable('tree-sitter') == 0 then + vim.health.warn( + '`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar,' + .. ' not required for :TSInstall)' ) else - _ok( - "`tree-sitter` found " - .. (utils.ts_cli_version() or "(unknown version)") - .. " (parser generator, only needed for :TSInstallFromGrammar)" + vim.health.ok( + '`tree-sitter` found ' + .. (ts_cli_version() or '(unknown version)') + .. ' (parser generator, only needed for :TSInstallFromGrammar)' ) end - if fn.executable "node" == 0 then - _warn("`node` executable not found (only needed for :TSInstallFromGrammar," .. " not required for :TSInstall)") + if vim.fn.executable('node') == 0 then + vim.health.warn( + '`node` executable not found (only needed for :TSInstallFromGrammar,' + .. ' not required for :TSInstall)' + ) else - local handle = io.popen "node --version" - local result = handle:read "*a" + local handle = assert(io.popen('node --version')) + local result = handle:read('*a') handle:close() - local version = vim.split(result, "\n")[1] - _ok("`node` found " .. version .. " (only needed for :TSInstallFromGrammar)") + local version = vim.split(result, '\n')[1] + vim.health.ok('`node` found ' .. version .. ' (only needed for :TSInstallFromGrammar)') end - if fn.executable "git" == 0 then - _error("`git` executable not found.", { - "Install it with your package manager.", - "Check that your `$PATH` is set correctly.", + if vim.fn.executable('git') == 0 then + vim.health.error('`git` executable not found.', { + 'Install it with your package manager.', + 'Check that your `$PATH` is set correctly.', }) else - _ok "`git` executable found." + vim.health.ok('`git` executable found.') end local cc = shell.select_executable(install.compilers) if not cc then - _error("`cc` executable not found.", { - "Check that any of " + vim.health.error('`cc` executable not found.', { + 'Check that any of ' .. vim.inspect(install.compilers) - .. " is in your $PATH" + .. ' is in your $PATH' .. ' or set the environment variable CC or `require"nvim-treesitter.install".compilers` explicitly!', }) else - local version = vim.fn.systemlist(cc .. (cc == "cl" and "" or " --version"))[1] - _ok( - "`" + local version = vim.fn.systemlist(cc .. (cc == 'cl' and '' or ' --version'))[1] + vim.health.ok( + '`' .. cc - .. "` executable found. Selected from " + .. '` executable found. Selected from ' .. vim.inspect(install.compilers) - .. (version and ("\nVersion: " .. version) or "") + .. (version and ('\nVersion: ' .. version) or '') ) end if vim.treesitter.language_version then if vim.treesitter.language_version >= NVIM_TREESITTER_MINIMUM_ABI then - _ok( - "Neovim was compiled with tree-sitter runtime ABI version " + vim.health.ok( + 'Neovim was compiled with tree-sitter runtime ABI version ' .. vim.treesitter.language_version - .. " (required >=" + .. ' (required >=' .. NVIM_TREESITTER_MINIMUM_ABI - .. "). Parsers must be compatible with runtime ABI." + .. '). Parsers must be compatible with runtime ABI.' ) else - _error( - "Neovim was compiled with tree-sitter runtime ABI version " + vim.health.error( + 'Neovim was compiled with tree-sitter runtime ABI version ' .. vim.treesitter.language_version - .. ".\n" - .. "nvim-treesitter expects at least ABI version " + .. '.\n' + .. 'nvim-treesitter expects at least ABI version ' .. NVIM_TREESITTER_MINIMUM_ABI - .. "\n" - .. "Please make sure that Neovim is linked against are recent tree-sitter runtime when building" - .. " or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI." + .. '\n' + .. 'Please make sure that Neovim is linked against are recent tree-sitter runtime when building' + .. ' or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI.' ) end end - _start("OS Info:\n" .. vim.inspect(vim.loop.os_uname())) + vim.health.start('OS Info:\n' .. vim.inspect(vim.loop.os_uname())) end local function query_status(lang, query_group) - local ok, err = pcall(queries.get_query, lang, query_group) + local ok, err = pcall(tsq.get, lang, query_group) if not ok then - return "x", err + return 'x', err elseif not err then - return "." + return '.' else - return "✓" + return '✓' end end @@ -118,59 +121,53 @@ function M.check() local error_collection = {} -- Installation dependency checks install_health() - queries.invalidate_query_cache() -- Parser installation checks - local parser_installation = { "Parser/Features" .. string.rep(" ", 9) .. "H L F I J" } - for _, parser_name in pairs(info.installed_parsers()) do - local installed = #api.nvim_get_runtime_file("parser/" .. parser_name .. ".so", false) - - -- Only append information about installed parsers - if installed >= 1 then - local multiple_parsers = installed > 1 and "+" or "" - local out = " - " .. parser_name .. multiple_parsers .. string.rep(" ", 20 - (#parser_name + #multiple_parsers)) - for _, query_group in pairs(queries.built_in_query_groups) do - local status, err = query_status(parser_name, query_group) - out = out .. status .. " " - if err then - table.insert(error_collection, { parser_name, query_group, err }) - end + local parser_installation = { 'Parser/Features' .. string.rep(' ', 9) .. 'H L F I J' } + for _, parser_name in pairs(config.installed_parsers()) do + local out = ' - ' .. parser_name .. string.rep(' ', 20 - #parser_name) + for _, query_group in pairs(M.bundled_queries) do + local status, err = query_status(parser_name, query_group) + out = out .. status .. ' ' + if err then + table.insert(error_collection, { parser_name, query_group, err }) end - table.insert(parser_installation, vim.fn.trim(out, " ", 2)) end + table.insert(parser_installation, vim.fn.trim(out, ' ', 2)) end local legend = [[ - Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections - +) multiple parsers found, only one will be used - x) errors found in the query, try to run :TSUpdate {lang}]] + Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[J]ections + x) errors found in the query, try to run :TSUpdate {lang}]] table.insert(parser_installation, legend) -- Finally call the report function - _start(table.concat(parser_installation, "\n")) + vim.health.start(table.concat(parser_installation, '\n')) if #error_collection > 0 then - _start "The following errors have been detected:" + vim.health.start('The following errors have been detected:') for _, p in ipairs(error_collection) do local lang, type, err = unpack(p) local lines = {} - table.insert(lines, lang .. "(" .. type .. "): " .. err) - local files = ts.get_query_files(lang, type) + table.insert(lines, lang .. '(' .. type .. '): ' .. err) + local files = tsq.get_files(lang, type) if #files > 0 then - table.insert(lines, lang .. "(" .. type .. ") is concatenated from the following files:") + table.insert(lines, lang .. '(' .. type .. ') is concatenated from the following files:') for _, file in ipairs(files) do - local fd = io.open(file, "r") + local fd = io.open(file, 'r') if fd then - local ok, file_err = pcall(ts.parse_query, lang, fd:read "*a") + local ok, file_err = pcall(tsq.parse, lang, fd:read('*a')) if ok then - table.insert(lines, '| [OK]:"' .. file .. '"') + table.insert(lines, '| [OK]:"' .. file .. '"') else - table.insert(lines, '| [ERROR]:"' .. file .. '", failed to load: ' .. file_err) + table.insert(lines, '| [ERR]:"' .. file .. '", failed to load: ' .. file_err) end fd:close() end end end - _error(table.concat(lines, "\n")) + vim.health.error(table.concat(lines, '\n')) end end end +M.bundled_queries = { 'highlights', 'locals', 'folds', 'indents', 'injections' } + return M diff --git a/lua/nvim-treesitter/highlight.lua b/lua/nvim-treesitter/highlight.lua deleted file mode 100644 index 5a3cc2e86..000000000 --- a/lua/nvim-treesitter/highlight.lua +++ /dev/null @@ -1,49 +0,0 @@ -local configs = require "nvim-treesitter.configs" - -local M = {} - ----@param config TSModule ----@param lang string ----@return boolean -local function should_enable_vim_regex(config, lang) - local additional_hl = config.additional_vim_regex_highlighting - 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)) -end - ----@param bufnr integer ----@param lang string -function M.attach(bufnr, lang) - local config = configs.get_module "highlight" - vim.treesitter.start(bufnr, lang) - if config and should_enable_vim_regex(config, lang) then - vim.bo[bufnr].syntax = "ON" - end -end - ----@param bufnr integer -function M.detach(bufnr) - vim.treesitter.stop(bufnr) -end - ----@deprecated -function M.start(...) - vim.notify( - "`nvim-treesitter.highlight.start` is deprecated: use `nvim-treesitter.highlight.attach` or `vim.treesitter.start`", - vim.log.levels.WARN - ) - M.attach(...) -end - ----@deprecated -function M.stop(...) - vim.notify( - "`nvim-treesitter.highlight.stop` is deprecated: use `nvim-treesitter.highlight.detach` or `vim.treesitter.stop`", - vim.log.levels.WARN - ) - M.detach(...) -end - -return M diff --git a/lua/nvim-treesitter/incremental_selection.lua b/lua/nvim-treesitter/incremental_selection.lua deleted file mode 100644 index 570f9eed9..000000000 --- a/lua/nvim-treesitter/incremental_selection.lua +++ /dev/null @@ -1,176 +0,0 @@ -local api = vim.api - -local configs = require "nvim-treesitter.configs" -local ts_utils = require "nvim-treesitter.ts_utils" -local locals = require "nvim-treesitter.locals" -local parsers = require "nvim-treesitter.parsers" -local queries = require "nvim-treesitter.query" -local utils = require "nvim-treesitter.utils" - -local M = {} - ----@type table> -local selections = {} - -function M.init_selection() - local buf = api.nvim_get_current_buf() - parsers.get_parser():parse { vim.fn.line "w0" - 1, vim.fn.line "w$" } - local node = ts_utils.get_node_at_cursor() - selections[buf] = { [1] = node } - ts_utils.update_selection(buf, node) -end - --- Get the range of the current visual selection. --- --- The range starts with 1 and the ending is inclusive. ----@return integer, integer, integer, integer -local function visual_selection_range() - local _, csrow, cscol, _ = unpack(vim.fn.getpos "v") ---@type integer, integer, integer, integer - local _, cerow, cecol, _ = unpack(vim.fn.getpos ".") ---@type integer, integer, integer, integer - - local start_row, start_col, end_row, end_col ---@type integer, integer, integer, integer - - if csrow < cerow or (csrow == cerow and cscol <= cecol) then - start_row = csrow - start_col = cscol - end_row = cerow - end_col = cecol - else - start_row = cerow - start_col = cecol - end_row = csrow - end_col = cscol - end - - return start_row, start_col, end_row, end_col -end - ----@param node TSNode ----@return boolean -local function range_matches(node) - local csrow, cscol, cerow, cecol = visual_selection_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 -end - ----@param get_parent fun(node: TSNode): TSNode|nil ----@return fun():nil -local function select_incremental(get_parent) - return function() - local buf = api.nvim_get_current_buf() - local nodes = selections[buf] - - local csrow, cscol, cerow, cecol = visual_selection_range() - -- Initialize incremental selection with current selection - if not nodes or #nodes == 0 or not range_matches(nodes[#nodes]) then - local parser = parsers.get_parser() - parser:parse { vim.fn.line "w0" - 1, vim.fn.line "w$" } - local node = parser:named_node_for_range( - { csrow - 1, cscol - 1, cerow - 1, cecol }, - { ignore_injections = false } - ) - ts_utils.update_selection(buf, node) - if nodes and #nodes > 0 then - table.insert(selections[buf], node) - else - selections[buf] = { [1] = node } - end - return - end - - -- Find a node that changes the current selection. - local node = nodes[#nodes] ---@type TSNode - while true do - local parent = get_parent(node) - if not parent or parent == node then - -- Keep searching in the parent tree - local root_parser = parsers.get_parser() - root_parser:parse { vim.fn.line "w0" - 1, vim.fn.line "w$" } - local current_parser = root_parser:language_for_range { csrow - 1, cscol - 1, cerow - 1, cecol } - if root_parser == current_parser then - node = root_parser:named_node_for_range { csrow - 1, cscol - 1, cerow - 1, cecol } - ts_utils.update_selection(buf, node) - return - end - -- NOTE: parent() method is private - local parent_parser = current_parser:parent() - parent = parent_parser:named_node_for_range { csrow - 1, cscol - 1, cerow - 1, cecol } - end - node = parent - local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() } - local same_range = (srow == csrow and scol == cscol and erow == cerow and ecol == cecol) - if not same_range then - table.insert(selections[buf], node) - if node ~= nodes[#nodes] then - table.insert(nodes, node) - end - ts_utils.update_selection(buf, node) - return - end - end - end -end - -M.node_incremental = select_incremental(function(node) - return node:parent() or node -end) - -M.scope_incremental = select_incremental(function(node) - local lang = parsers.get_buf_lang() - if queries.has_locals(lang) then - return locals.containing_scope(node:parent() or node) - else - return node - end -end) - -function M.node_decremental() - local buf = api.nvim_get_current_buf() - local nodes = selections[buf] - if not nodes or #nodes < 2 then - return - end - - table.remove(selections[buf]) - local node = nodes[#nodes] ---@type TSNode - ts_utils.update_selection(buf, node) -end - -local FUNCTION_DESCRIPTIONS = { - init_selection = "Start selecting nodes with nvim-treesitter", - node_incremental = "Increment selection to named node", - scope_incremental = "Increment selection to surrounding scope", - node_decremental = "Shrink selection to previous named node", -} - ----@param bufnr integer -function M.attach(bufnr) - local config = configs.get_module "incremental_selection" - for funcname, mapping in pairs(config.keymaps) do - if mapping then - local mode = funcname == "init_selection" and "n" or "x" - local rhs = M[funcname] ---@type function - - if not rhs then - utils.notify("Unknown keybinding: " .. funcname .. debug.traceback(), vim.log.levels.ERROR) - else - vim.keymap.set(mode, mapping, rhs, { buffer = bufnr, silent = true, desc = FUNCTION_DESCRIPTIONS[funcname] }) - end - end - end -end - -function M.detach(bufnr) - local config = configs.get_module "incremental_selection" - for f, mapping in pairs(config.keymaps) do - if mapping then - local mode = f == "init_selection" and "n" or "x" - local ok, err = pcall(vim.keymap.del, mode, mapping, { buffer = bufnr }) - if not ok then - utils.notify(string.format('%s "%s" for mode %s', err, mapping, mode), vim.log.levels.ERROR) - end - end - end -end - -return M diff --git a/lua/nvim-treesitter/indent.lua b/lua/nvim-treesitter/indent.lua index 19e7ef1ee..6b674dc63 100644 --- a/lua/nvim-treesitter/indent.lua +++ b/lua/nvim-treesitter/indent.lua @@ -1,5 +1,4 @@ local ts = vim.treesitter -local parsers = require "nvim-treesitter.parsers" local M = {} @@ -14,13 +13,13 @@ M.comment_parsers = { } local function getline(lnum) - return vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or "" + return vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or '' end ---@param lnum integer ---@return integer local function get_indentcols_at_line(lnum) - local _, indentcols = getline(lnum):find "^%s*" + local _, indentcols = getline(lnum):find('^%s*') return indentcols or 0 end @@ -62,8 +61,8 @@ local function find_delimiter(bufnr, node, delimiter) local line = vim.api.nvim_buf_get_lines(bufnr, linenr, linenr + 1, false)[1] local end_char = { child:end_() } local trimmed_after_delim - local escaped_delimiter = delimiter:gsub("[%-%.%+%[%]%(%)%$%^%%%?%*]", "%%%1") - trimmed_after_delim, _ = line:sub(end_char[2] + 1):gsub("[%s" .. escaped_delimiter .. "]*", "") + local escaped_delimiter = delimiter:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]', '%%%1') + trimmed_after_delim = line:sub(end_char[2] + 1):gsub('[%s' .. escaped_delimiter .. ']*', '') return child, #trimmed_after_delim == 0 end end @@ -75,7 +74,7 @@ end ---@param hash_fn fun(...): any ---@return F local function memoize(fn, hash_fn) - local cache = setmetatable({}, { __mode = "kv" }) ---@type table + local cache = setmetatable({}, { __mode = 'kv' }) ---@type table return function(...) local key = hash_fn(...) @@ -91,47 +90,47 @@ end local get_indents = memoize(function(bufnr, root, lang) local map = { - ["indent.auto"] = {}, - ["indent.begin"] = {}, - ["indent.end"] = {}, - ["indent.dedent"] = {}, - ["indent.branch"] = {}, - ["indent.ignore"] = {}, - ["indent.align"] = {}, - ["indent.zero"] = {}, + ['indent.auto'] = {}, + ['indent.begin'] = {}, + ['indent.end'] = {}, + ['indent.dedent'] = {}, + ['indent.branch'] = {}, + ['indent.ignore'] = {}, + ['indent.align'] = {}, + ['indent.zero'] = {}, } - --TODO(clason): remove when dropping Nvim 0.8 compat - local query = (ts.query.get or ts.get_query)(lang, "indents") + local query = ts.query.get(lang, 'indents') if not query then return map end for id, node, metadata in query:iter_captures(root, bufnr) do - if query.captures[id]:sub(1, 1) ~= "_" then + if query.captures[id]:sub(1, 1) ~= '_' then map[query.captures[id]][node:id()] = metadata or {} end end return map end, function(bufnr, root, lang) - return tostring(bufnr) .. root:id() .. "_" .. lang + return tostring(bufnr) .. root:id() .. '_' .. lang end) ---@param lnum number (1-indexed) +---@return integer function M.get_indent(lnum) local bufnr = vim.api.nvim_get_current_buf() - local parser = parsers.get_parser(bufnr) + local parser = ts.get_parser(bufnr) if not parser or not lnum then return -1 end - --TODO(clason): replace when dropping Nvim 0.8 compat - local root_lang = parsers.get_buf_lang(bufnr) + local ft = vim.bo[bufnr].filetype + local root_lang = vim.treesitter.language.get_lang(ft) or ft -- some languages like Python will actually have worse results when re-parsing at opened new line if not M.avoid_force_reparsing[root_lang] then -- Reparse in case we got triggered by ":h indentkeys" - parser:parse { vim.fn.line "w0" - 1, vim.fn.line "w$" } + parser:parse({ vim.fn.line('w0') - 1, vim.fn.line('w$') }) end -- Get language tree with smallest range around node that's not a comment parser @@ -155,15 +154,14 @@ function M.get_indent(lnum) end local q = get_indents(vim.api.nvim_get_current_buf(), root, lang_tree:lang()) - local is_empty_line = string.match(getline(lnum), "^%s*$") ~= nil local node ---@type TSNode - if is_empty_line then + if getline(lnum):find('^%s*$') then local prevlnum = vim.fn.prevnonblank(lnum) local indentcols = get_indentcols_at_line(prevlnum) local prevline = vim.trim(getline(prevlnum)) -- The final position can be trailing spaces, which should not affect indentation node = get_last_node_at_line(root, prevlnum, indentcols + #prevline - 1) - if node:type():match "comment" then + if node:type():match('comment') then -- The final node we capture of the previous line can be a comment node, which should also be ignored -- Unless the last line is an entire line of comment, ignore the comment range and find the last node again local first_node = get_first_node_at_line(root, prevlnum, indentcols) @@ -176,7 +174,7 @@ function M.get_indent(lnum) node = get_last_node_at_line(root, prevlnum, col) end end - if q["indent.end"][node:id()] then + if q['indent.end'][node:id()] then node = get_first_node_at_line(root, lnum) end else @@ -192,18 +190,18 @@ function M.get_indent(lnum) end -- tracks to ensure multiple indent levels are not applied for same line - local is_processed_by_row = {} + local is_processed_by_row = {} --- @type table - if q["indent.zero"][node:id()] then + if q['indent.zero'][node:id()] then return 0 end while node do -- do 'autoindent' if not marked as @indent if - not q["indent.begin"][node:id()] - and not q["indent.align"][node:id()] - and q["indent.auto"][node:id()] + not q['indent.begin'][node:id()] + and not q['indent.align'][node:id()] + and q['indent.auto'][node:id()] and node:start() < lnum - 1 and lnum - 1 <= node:end_() then @@ -214,8 +212,8 @@ function M.get_indent(lnum) -- If a node spans from L1,C1 to L2,C2, we know that lines where L1 < line <= L2 would -- have their indentations contained by the node. if - not q["indent.begin"][node:id()] - and q["indent.ignore"][node:id()] + not q['indent.begin'][node:id()] + and q['indent.ignore'][node:id()] and node:start() < lnum - 1 and lnum - 1 <= node:end_() then @@ -228,7 +226,10 @@ function M.get_indent(lnum) if not is_processed_by_row[srow] - and ((q["indent.branch"][node:id()] and srow == lnum - 1) or (q["indent.dedent"][node:id()] and srow ~= lnum - 1)) + and ( + (q['indent.branch'][node:id()] and srow == lnum - 1) + or (q['indent.dedent'][node:id()] and srow ~= lnum - 1) + ) then indent = indent - indent_size is_processed = true @@ -244,16 +245,16 @@ function M.get_indent(lnum) if should_process and ( - q["indent.begin"][node:id()] - and (srow ~= erow or is_in_err or q["indent.begin"][node:id()]["indent.immediate"]) - and (srow ~= lnum - 1 or q["indent.begin"][node:id()]["indent.start_at_same_line"]) + q['indent.begin'][node:id()] + and (srow ~= erow or is_in_err or q['indent.begin'][node:id()]['indent.immediate']) + and (srow ~= lnum - 1 or q['indent.begin'][node:id()]['indent.start_at_same_line']) ) then indent = indent + indent_size is_processed = true end - if is_in_err and not q["indent.align"][node:id()] then + if is_in_err and not q['indent.align'][node:id()] then -- only when the node is in error, promote the -- first child's aligned indent to the error node -- to work around ((ERROR "X" . (_)) @aligned_indent (#set! "delimiter" "AB")) @@ -261,34 +262,41 @@ function M.get_indent(lnum) -- (ERROR "X" @aligned_indent (#set! "delimiter" "AB") . (_)) -- and we will fish it out here. for c in node:iter_children() do - if q["indent.align"][c:id()] then - q["indent.align"][node:id()] = q["indent.align"][c:id()] + if q['indent.align'][c:id()] then + q['indent.align'][node:id()] = q['indent.align'][c:id()] break end end end -- do not indent for nodes that starts-and-ends on same line and starts on target line (lnum) - if should_process and q["indent.align"][node:id()] and (srow ~= erow or is_in_err) and (srow ~= lnum - 1) then - local metadata = q["indent.align"][node:id()] + if + should_process + and q['indent.align'][node:id()] + and (srow ~= erow or is_in_err) + and (srow ~= lnum - 1) + then + local metadata = q['indent.align'][node:id()] local o_delim_node, o_is_last_in_line ---@type TSNode|nil, boolean|nil local c_delim_node, c_is_last_in_line ---@type TSNode|nil, boolean|nil, boolean|nil local indent_is_absolute = false - if metadata["indent.open_delimiter"] then - o_delim_node, o_is_last_in_line = find_delimiter(bufnr, node, metadata["indent.open_delimiter"]) + if metadata['indent.open_delimiter'] then + o_delim_node, o_is_last_in_line = + find_delimiter(bufnr, node, metadata['indent.open_delimiter']) else o_delim_node = node end - if metadata["indent.close_delimiter"] then - c_delim_node, c_is_last_in_line = find_delimiter(bufnr, node, metadata["indent.close_delimiter"]) + if metadata['indent.close_delimiter'] then + c_delim_node, c_is_last_in_line = + find_delimiter(bufnr, node, metadata['indent.close_delimiter']) else c_delim_node = node end if o_delim_node then local o_srow, o_scol = o_delim_node:start() - local c_srow = nil + local c_srow = nil --- @type integer? if c_delim_node then - c_srow, _ = c_delim_node:start() + c_srow = c_delim_node:start() end if o_is_last_in_line then -- hanging indent (previous line ended with starting delimiter) @@ -310,7 +318,7 @@ function M.get_indent(lnum) -- Then its indent level shouldn't be affected by `@aligned_indent` node indent = math.max(indent - indent_size, 0) else - indent = o_scol + (metadata["indent.increment"] or 1) + indent = o_scol + (metadata['indent.increment'] or 1) indent_is_absolute = true end end @@ -321,7 +329,7 @@ function M.get_indent(lnum) -- then this last line may need additional indent to avoid clashes -- with the next. `indent.avoid_last_matching_next` controls this behavior, -- for example this is needed for function parameters. - avoid_last_matching_next = metadata["indent.avoid_last_matching_next"] or false + avoid_last_matching_next = metadata['indent.avoid_last_matching_next'] or false end if avoid_last_matching_next then -- last line must be indented more in cases where @@ -350,17 +358,4 @@ function M.get_indent(lnum) return indent end ----@type table -local indent_funcs = {} - ----@param bufnr integer -function M.attach(bufnr) - indent_funcs[bufnr] = vim.bo.indentexpr - vim.bo.indentexpr = "nvim_treesitter#indent()" -end - -function M.detach(bufnr) - vim.bo.indentexpr = indent_funcs[bufnr] -end - return M diff --git a/lua/nvim-treesitter/info.lua b/lua/nvim-treesitter/info.lua deleted file mode 100644 index 6e94b357d..000000000 --- a/lua/nvim-treesitter/info.lua +++ /dev/null @@ -1,190 +0,0 @@ -local api = vim.api -local configs = require "nvim-treesitter.configs" -local parsers = require "nvim-treesitter.parsers" - -local M = {} - -local function install_info() - local max_len = 0 - for _, ft in pairs(parsers.available_parsers()) do - if #ft > max_len then - max_len = #ft - end - end - - local parser_list = parsers.available_parsers() - table.sort(parser_list) - for _, lang in pairs(parser_list) do - local is_installed = #api.nvim_get_runtime_file("parser/" .. lang .. ".so", false) > 0 - api.nvim_out_write(lang .. string.rep(" ", max_len - #lang + 1)) - if is_installed then - api.nvim_out_write "[✓] installed\n" - elseif pcall(vim.treesitter.inspect_lang, lang) then - api.nvim_out_write "[✗] not installed (but still loaded. Restart Neovim!)\n" - else - api.nvim_out_write "[✗] not installed\n" - end - end -end - --- Sort a list of modules into namespaces. --- {'mod1', 'mod2.sub1', 'mod2.sub2', 'mod3'} --- -> --- { default = {'mod1', 'mod3'}, mod2 = {'sub1', 'sub2'}} ----@param modulelist string[] ----@return table -local function namespace_modules(modulelist) - local modules = {} - for _, module in ipairs(modulelist) do - if module:find "%." then - local namespace, submodule = module:match "^(.*)%.(.*)$" - if not modules[namespace] then - modules[namespace] = {} - end - table.insert(modules[namespace], submodule) - else - if not modules.default then - modules.default = {} - end - table.insert(modules.default, module) - end - end - return modules -end - ----@param list string[] ----@return integer length -local function longest_string_length(list) - local length = 0 - for _, value in ipairs(list) do - if #value > length then - length = #value - end - end - return length -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 maxlen_parser = longest_string_length(parserlist) - table.sort(modulelist) - - -- header - local header = ">> " .. namespace .. string.rep(" ", maxlen_parser - #namespace - 1) - for _, module in pairs(modulelist) do - header = header .. module .. " " - end - api.nvim_buf_set_lines(curbuf, -1, -1, true, { header }) - - -- actual table - for _, parser in ipairs(parserlist) do - local padding = string.rep(" ", maxlen_parser - #parser + 2) - local line = parser .. padding - local namespace_prefix = (namespace == "default") and "" or namespace .. "." - for _, module in pairs(modulelist) do - local modlen = #module - module = namespace_prefix .. module - if configs.is_enabled(module, parser, origbuf) then - line = line .. "✓" - else - line = line .. "✗" - end - line = line .. string.rep(" ", modlen + 1) - end - api.nvim_buf_set_lines(curbuf, -1, -1, true, { line }) - end - - api.nvim_buf_set_lines(curbuf, -1, -1, true, { "" }) -end - -local function print_info_modules(parserlist, module) - local origbuf = api.nvim_get_current_buf() - api.nvim_command "enew" - local curbuf = api.nvim_get_current_buf() - - local modules - if module then - modules = namespace_modules { module } - else - modules = namespace_modules(configs.available_modules()) - end - - ---@type string[] - local namespaces = {} - for k, _ in pairs(modules) do - table.insert(namespaces, k) - end - table.sort(namespaces) - - table.sort(parserlist) - for _, namespace in ipairs(namespaces) do - append_module_table(curbuf, origbuf, parserlist, namespace, modules[namespace]) - end - - api.nvim_buf_set_option(curbuf, "modified", false) - api.nvim_buf_set_option(curbuf, "buftype", "nofile") - vim.cmd [[ - syntax match TSModuleInfoGood /✓/ - syntax match TSModuleInfoBad /✗/ - syntax match TSModuleInfoHeader /^>>.*$/ contains=TSModuleInfoNamespace - syntax match TSModuleInfoNamespace /^>> \w*/ contained - syntax match TSModuleInfoParser /^[^> ]*\ze / - ]] - - local highlights = { - TSModuleInfoGood = { fg = "LightGreen", bold = true, default = true }, - TSModuleInfoBad = { fg = "Crimson", default = true }, - TSModuleInfoHeader = { link = "Type", default = true }, - TSModuleInfoNamespace = { link = "Statement", default = true }, - TSModuleInfoParser = { link = "Identifier", default = true }, - } - for k, v in pairs(highlights) do - api.nvim_set_hl(0, k, v) - end -end - -local function module_info(module) - if module and not configs.get_module(module) then - return - end - - local parserlist = parsers.available_parsers() - if module then - print_info_modules(parserlist, module) - else - print_info_modules(parserlist) - end -end - ----@return string[] -function M.installed_parsers() - local installed = {} - for _, p in pairs(parsers.available_parsers()) do - if parsers.has_parser(p) then - table.insert(installed, p) - end - end - return installed -end - -M.commands = { - TSInstallInfo = { - run = install_info, - args = { - "-nargs=0", - }, - }, - TSModuleInfo = { - run = module_info, - args = { - "-nargs=?", - "-complete=custom,nvim_treesitter#available_modules", - }, - }, -} - -return M diff --git a/lua/nvim-treesitter/init.lua b/lua/nvim-treesitter/init.lua new file mode 100644 index 000000000..aac1c6ba6 --- /dev/null +++ b/lua/nvim-treesitter/init.lua @@ -0,0 +1,11 @@ +local M = {} + +function M.setup(...) + require('nvim-treesitter.config').setup(...) +end + +function M.indentexpr() + return require('nvim-treesitter.indent').get_indent(vim.v.lnum) +end + +return M diff --git a/lua/nvim-treesitter/install.lua b/lua/nvim-treesitter/install.lua index cd12dbb81..745c2dd1f 100644 --- a/lua/nvim-treesitter/install.lua +++ b/lua/nvim-treesitter/install.lua @@ -1,13 +1,10 @@ local api = vim.api -local fn = vim.fn -local luv = vim.loop +local uv = vim.loop -local utils = require "nvim-treesitter.utils" -local parsers = require "nvim-treesitter.parsers" -local info = require "nvim-treesitter.info" -local configs = require "nvim-treesitter.configs" -local shell = require "nvim-treesitter.shell_command_selectors" -local compat = require "nvim-treesitter.compat" +local utils = require('nvim-treesitter.utils') +local parsers = require('nvim-treesitter.parsers') +local config = require('nvim-treesitter.config') +local shell = require('nvim-treesitter.shell_cmds') local M = {} @@ -17,16 +14,20 @@ local M = {} ---@type table local lockfile = {} -M.compilers = { vim.fn.getenv "CC", "cc", "gcc", "clang", "cl", "zig" } -M.prefer_git = fn.has "win32" == 1 +M.compilers = { uv.os_getenv('CC'), 'cc', 'gcc', 'clang', 'cl', 'zig' } +M.prefer_git = uv.os_uname().sysname == 'Windows_NT' M.command_extra_args = {} M.ts_generate_args = nil local started_commands = 0 local finished_commands = 0 local failed_commands = 0 -local complete_std_output = {} -local complete_error_output = {} +local stdout_output = {} +local stderr_output = {} + +--- +--- JOB API functions +--- local function reset_progress_counter() if started_commands ~= finished_commands then @@ -35,199 +36,104 @@ local function reset_progress_counter() started_commands = 0 finished_commands = 0 failed_commands = 0 - complete_std_output = {} - complete_error_output = {} + stdout_output = {} + stderr_output = {} end local function get_job_status() - return "[nvim-treesitter] [" + return '[nvim-treesitter] [' .. finished_commands - .. "/" + .. '/' .. started_commands - .. (failed_commands > 0 and ", failed: " .. failed_commands or "") - .. "]" + .. (failed_commands > 0 and ', failed: ' .. failed_commands or '') + .. ']' end ----@param lang string ----@return function -local function reattach_if_possible_fn(lang, error_on_fail) - return function() - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if parsers.get_buf_lang(buf) == lang then - vim._ts_remove_language(lang) - local ok, err - if vim.treesitter.language.add then - local ft = vim.bo[buf].filetype - ok, err = pcall(vim.treesitter.language.add, lang, { filetype = ft }) - else - ok, err = pcall(compat.require_language, lang) - end - if not ok and error_on_fail then - vim.notify("Could not load parser for " .. lang .. ": " .. vim.inspect(err)) - end - for _, mod in ipairs(require("nvim-treesitter.configs").available_modules()) do - if ok then - require("nvim-treesitter.configs").reattach_module(mod, buf, lang) - else - require("nvim-treesitter.configs").detach_module(mod, buf) - end - end - end +---@param cmd Command +---@return string command +local function get_command(cmd) + local options = '' + if cmd.opts and cmd.opts.args then + if M.command_extra_args[cmd.cmd] then + vim.list_extend(cmd.opts.args, M.command_extra_args[cmd.cmd]) + end + for _, opt in ipairs(cmd.opts.args) do + options = string.format('%s %s', options, opt) end end -end - ----@param lang string ----@param validate boolean|nil ----@return InstallInfo -local function get_parser_install_info(lang, validate) - local parser_config = parsers.get_parser_configs()[lang] - - if not parser_config then - error('Parser not available for language "' .. lang .. '"') - end - - local install_info = parser_config.install_info - - if validate then - vim.validate { - url = { install_info.url, "string" }, - files = { install_info.files, "table" }, - } - end - - return install_info -end - -local function load_lockfile() - local filename = utils.join_path(utils.get_package_path(), "lockfile.json") - lockfile = vim.fn.filereadable(filename) == 1 and vim.fn.json_decode(vim.fn.readfile(filename)) or {} -end - -local function is_ignored_parser(lang) - return vim.tbl_contains(configs.get_ignored_parser_installs(), lang) -end - ----@param lang string ----@return string|nil -local function get_revision(lang) - if #lockfile == 0 then - load_lockfile() - end - - local install_info = get_parser_install_info(lang) - if install_info.revision then - return install_info.revision - end - - if lockfile[lang] then - return lockfile[lang].revision - end -end - ----@param lang string ----@return string|nil -local function get_installed_revision(lang) - local lang_file = utils.join_path(configs.get_parser_info_dir(), lang .. ".revision") - if vim.fn.filereadable(lang_file) == 1 then - return vim.fn.readfile(lang_file)[1] - end -end --- Clean path for use in a prefix comparison ----@param input string ----@return string -local function clean_path(input) - local pth = vim.fn.fnamemodify(input, ":p") - if fn.has "win32" == 1 then - pth = pth:gsub("/", "\\") + local command = string.format('%s %s', cmd.cmd, options) + if cmd.opts and cmd.opts.cwd then + command = shell.make_directory_change_for_command(cmd.opts.cwd, command) end - return pth + return command end --- Checks if parser is installed with nvim-treesitter ----@param lang string +---@param cmd_list Command[] ---@return boolean -local function is_installed(lang) - local matched_parsers = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) or {} - local install_dir = configs.get_parser_install_dir() - if not install_dir then - return false - end - install_dir = clean_path(install_dir) - for _, path in ipairs(matched_parsers) do - local abspath = clean_path(path) - if vim.startswith(abspath, install_dir) then - return true +local function iter_cmd_sync(cmd_list) + for _, cmd in ipairs(cmd_list) do + if cmd.info then + vim.notify(cmd.info) end - end - return false -end ----@param lang string ----@return boolean -local function needs_update(lang) - local revision = get_revision(lang) - return not revision or revision ~= get_installed_revision(lang) -end - ----@return string[] -local function outdated_parsers() - return vim.tbl_filter(function(lang) ---@param lang string - return is_installed(lang) and needs_update(lang) - end, info.installed_parsers()) -end - ----@param handle userdata ----@param is_stderr boolean -local function onread(handle, is_stderr) - return function(_, data) - if data then - if is_stderr then - complete_error_output[handle] = (complete_error_output[handle] or "") .. data - else - complete_std_output[handle] = (complete_std_output[handle] or "") .. data + if type(cmd.cmd) == 'function' then + cmd.cmd() + else + local ret = vim.fn.system(get_command(cmd)) + if vim.v.shell_error ~= 0 then + vim.notify(ret) + api.nvim_err_writeln( + (cmd.err and cmd.err .. '\n' or '') + .. 'Failed to execute the following command:\n' + .. vim.inspect(cmd) + ) + return false end end end + + return true end -function M.iter_cmd(cmd_list, i, lang, success_message) +local function iter_cmd(cmd_list, i, lang, success_message) if i == 1 then started_commands = started_commands + 1 end if i == #cmd_list + 1 then finished_commands = finished_commands + 1 - return print(get_job_status() .. " " .. success_message) + return vim.notify(get_job_status() .. ' ' .. success_message) end local attr = cmd_list[i] if attr.info then - print(get_job_status() .. " " .. attr.info) + vim.notify(get_job_status() .. ' ' .. attr.info) end if attr.opts and attr.opts.args and M.command_extra_args[attr.cmd] then vim.list_extend(attr.opts.args, M.command_extra_args[attr.cmd]) end - if type(attr.cmd) == "function" then + if type(attr.cmd) == 'function' then local ok, err = pcall(attr.cmd) if ok then - M.iter_cmd(cmd_list, i + 1, lang, success_message) + iter_cmd(cmd_list, i + 1, lang, success_message) else failed_commands = failed_commands + 1 finished_commands = finished_commands + 1 return api.nvim_err_writeln( - (attr.err or ("Failed to execute the following command:\n" .. vim.inspect(attr))) .. "\n" .. vim.inspect(err) + (attr.err or ('Failed to execute the following command:\n' .. vim.inspect(attr))) + .. '\n' + .. vim.inspect(err) ) end else local handle - local stdout = luv.new_pipe(false) - local stderr = luv.new_pipe(false) + local stdout = uv.new_pipe(false) + local stderr = uv.new_pipe(false) attr.opts.stdio = { nil, stdout, stderr } ---@type userdata - handle = luv.spawn( + handle = uv.spawn( attr.cmd, attr.opts, vim.schedule_wrap(function(code) @@ -241,87 +147,151 @@ function M.iter_cmd(cmd_list, i, lang, success_message) if code ~= 0 then failed_commands = failed_commands + 1 finished_commands = finished_commands + 1 - if complete_std_output[handle] and complete_std_output[handle] ~= "" then - print(complete_std_output[handle]) + if stdout_output[handle] and stdout_output[handle] ~= '' then + vim.notify(stdout_output[handle]) end - local err_msg = complete_error_output[handle] or "" + local err_msg = stderr_output[handle] or '' api.nvim_err_writeln( - "nvim-treesitter[" + 'nvim-treesitter[' .. lang - .. "]: " - .. (attr.err or ("Failed to execute the following command:\n" .. vim.inspect(attr))) - .. "\n" + .. ']: ' + .. (attr.err or ('Failed to execute the following command:\n' .. vim.inspect(attr))) + .. '\n' .. err_msg ) return end - M.iter_cmd(cmd_list, i + 1, lang, success_message) + iter_cmd(cmd_list, i + 1, lang, success_message) end) ) - luv.read_start(stdout, onread(handle, false)) - luv.read_start(stderr, onread(handle, true)) + uv.read_start(stdout, function(_, data) + if data then + stdout_output[handle] = (stdout_output[handle] or '') .. data + end + end) + uv.read_start(stderr, function(_, data) + if data then + stderr_output[handle] = (stderr_output[handle] or '') .. data + end + end) end end ----@param cmd Command ----@return string command -local function get_command(cmd) - local options = "" - if cmd.opts and cmd.opts.args then - if M.command_extra_args[cmd.cmd] then - vim.list_extend(cmd.opts.args, M.command_extra_args[cmd.cmd]) - end - for _, opt in ipairs(cmd.opts.args) do - options = string.format("%s %s", options, opt) - end +--- +--- PARSER INFO +--- + +---@param lang string +---@param validate boolean|nil +---@return InstallInfo +local function get_parser_install_info(lang, validate) + local parser_config = parsers.configs[lang] + + if not parser_config then + error('Parser not available for language "' .. lang .. '"') end - local command = string.format("%s %s", cmd.cmd, options) - if cmd.opts and cmd.opts.cwd then - command = shell.make_directory_change_for_command(cmd.opts.cwd, command) + local install_info = parser_config.install_info + + if validate then + vim.validate({ + url = { install_info.url, 'string' }, + files = { install_info.files, 'table' }, + }) end - return command + + return install_info end ----@param cmd_list Command[] +---@param lang string +---@return string|nil +local function get_revision(lang) + if #lockfile == 0 then + local filename = utils.get_package_path('lockfile.json') + local file = assert(io.open(filename, 'r')) + lockfile = vim.json.decode(file:read('*all')) + file:close() + end + + local install_info = get_parser_install_info(lang) + if install_info.revision then + return install_info.revision + end + + if lockfile[lang] then + return lockfile[lang].revision + end +end + +---@param lang string +---@return string|nil +local function get_installed_revision(lang) + local lang_file = utils.join_path(config.get_install_dir('parser-info'), lang .. '.revision') + local file = assert(io.open(lang_file, 'r')) + local revision = file:read('*a') + file:close() + return revision +end + +---@param lang string ---@return boolean -local function iter_cmd_sync(cmd_list) - for _, cmd in ipairs(cmd_list) do - if cmd.info then - print(cmd.info) +local function needs_update(lang) + local revision = get_revision(lang) + return not revision or revision ~= get_installed_revision(lang) +end + +function M.info() + local installed = config.installed_parsers() + local parser_list = parsers.get_available() + + local max_len = 0 + for _, lang in pairs(parser_list) do + if #lang > max_len then + max_len = #lang end + end - if type(cmd.cmd) == "function" then - cmd.cmd() + for _, lang in pairs(parser_list) do + local parser = (lang .. string.rep(' ', max_len - #lang + 1)) + local output + if vim.list_contains(installed, lang) then + output = { parser .. '[✓] installed', 'DiagnosticOk' } + elseif #api.nvim_get_runtime_file('parser/' .. lang .. '.*', true) > 0 then + output = { parser .. '[·] not installed (but available from runtimepath)', 'DiagnosticInfo' } else - local ret = vim.fn.system(get_command(cmd)) - if vim.v.shell_error ~= 0 then - print(ret) - api.nvim_err_writeln( - (cmd.err and cmd.err .. "\n" or "") .. "Failed to execute the following command:\n" .. vim.inspect(cmd) - ) - return false - end + output = { parser .. '[✗] not installed' } end + api.nvim_echo({ output }, false, {}) end - - return true end ----@param cache_folder string ----@param install_folder string +--- +--- PARSER MANAGEMENT FUNCTIONS +--- + ---@param lang string ----@param repo InstallInfo +---@param cache_dir string +---@param install_dir string +---@param force boolean ---@param with_sync boolean ---@param generate_from_grammar boolean -local function run_install(cache_folder, install_folder, lang, repo, with_sync, generate_from_grammar) - parsers.reset_cache() +local function install_lang(lang, cache_dir, install_dir, force, with_sync, generate_from_grammar) + if vim.list_contains(config.installed_parsers(), lang) then + if not force then + local yesno = + vim.fn.input(lang .. ' parser already available: would you like to reinstall ? y/n: ') + print('\n ') + if yesno:sub(1, 1) ~= 'y' then + return + end + end + end - local path_sep = utils.get_path_sep() + local repo = get_parser_install_info(lang) - local project_name = "tree-sitter-" .. lang - local maybe_local_path = vim.fn.expand(repo.url) + local project_name = 'tree-sitter-' .. lang + local maybe_local_path = vim.fs.normalize(repo.url) local from_local_path = vim.fn.isdirectory(maybe_local_path) == 1 if from_local_path then repo.url = maybe_local_path @@ -337,48 +307,45 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync, else local repo_location = project_name if repo.location then - repo_location = repo_location .. "/" .. repo.location + repo_location = utils.join_path(repo_location, repo.location) end - repo_location = repo_location:gsub("/", path_sep) - compile_location = utils.join_path(cache_folder, repo_location) + compile_location = utils.join_path(cache_dir, repo_location) end - local parser_lib_name = utils.join_path(install_folder, lang) .. ".so" + local parser_lib_name = utils.join_path(install_dir, lang) .. '.so' generate_from_grammar = repo.requires_generate_from_grammar or generate_from_grammar - if generate_from_grammar and vim.fn.executable "tree-sitter" ~= 1 then - api.nvim_err_writeln "tree-sitter CLI not found: `tree-sitter` is not executable!" + if generate_from_grammar and vim.fn.executable('tree-sitter') ~= 1 then + api.nvim_err_writeln('tree-sitter CLI not found: `tree-sitter` is not executable') if repo.requires_generate_from_grammar then api.nvim_err_writeln( - "tree-sitter CLI is needed because `" + 'tree-sitter CLI is needed because the parser for `' .. lang - .. "` is marked that it needs " - .. "to be generated from the grammar definitions to be compatible with nvim!" + .. '` needs to be generated from grammar' ) end return else if not M.ts_generate_args then - local ts_cli_version = utils.ts_cli_version() - if ts_cli_version and vim.split(ts_cli_version, " ")[1] > "0.20.2" then - M.ts_generate_args = { "generate", "--no-bindings", "--abi", vim.treesitter.language_version } - else - M.ts_generate_args = { "generate", "--no-bindings" } - end + M.ts_generate_args = { 'generate', '--no-bindings', '--abi', vim.treesitter.language_version } end end - if generate_from_grammar and vim.fn.executable "node" ~= 1 then - api.nvim_err_writeln "Node JS not found: `node` is not executable!" + if generate_from_grammar and vim.fn.executable('node') ~= 1 then + api.nvim_err_writeln('Node JS not found: `node` is not executable') return end local cc = shell.select_executable(M.compilers) if not cc then - api.nvim_err_writeln('No C compiler found! "' .. table.concat( - vim.tbl_filter(function(c) ---@param c string - return type(c) == "string" - end, M.compilers), - '", "' - ) .. '" are not executable.') + api.nvim_err_writeln( + 'No C compiler found! "' + .. table.concat( + vim.tbl_filter(function(c) ---@param c string + return type(c) == 'string' + end, M.compilers), + '", "' + ) + .. '" are not executable.' + ) return end @@ -400,25 +367,33 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync, ---@type Command[] local command_list = {} 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, { + { + cmd = function() + vim.fn.delete(utils.join_path(cache_dir, project_name), 'rf') + end, + }, + }) vim.list_extend( command_list, - shell.select_download_commands(repo, project_name, cache_folder, revision, M.prefer_git) + shell.select_download_commands(repo, project_name, cache_dir, revision, M.prefer_git) ) end if generate_from_grammar then if repo.generate_requires_npm then - if vim.fn.executable "npm" ~= 1 then - api.nvim_err_writeln("`" .. lang .. "` requires NPM to be installed from grammar.js") + if vim.fn.executable('npm') ~= 1 then + api.nvim_err_writeln('`' .. lang .. '` requires NPM to be installed from grammar.js') return end vim.list_extend(command_list, { { - cmd = "npm", - info = "Installing NPM dependencies of " .. lang .. " parser", - err = "Error during `npm install` (required for parser generation of " .. lang .. " with npm dependencies)", + cmd = 'npm', + info = 'Installing NPM dependencies of ' .. lang .. ' parser', + err = 'Error during `npm install` (required for parser generation of ' + .. lang + .. ' with npm dependencies)', opts = { - args = { "install" }, + args = { 'install' }, cwd = compile_location, }, }, @@ -426,8 +401,8 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync, end vim.list_extend(command_list, { { - cmd = vim.fn.exepath "tree-sitter", - info = "Generating source files from grammar.js...", + cmd = vim.fn.exepath('tree-sitter'), + info = 'Generating source files from grammar.js...', err = 'Error during "tree-sitter generate"', opts = { args = M.ts_generate_args, @@ -438,344 +413,153 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync, end vim.list_extend(command_list, { shell.select_compile_command(repo, cc, compile_location), - shell.select_mv_cmd("parser.so", parser_lib_name, compile_location), { cmd = function() - vim.fn.writefile({ revision or "" }, utils.join_path(configs.get_parser_info_dir() or "", lang .. ".revision")) + uv.fs_copyfile(utils.join_path(compile_location, 'parser.so'), parser_lib_name) end, }, - { -- auto-attach modules after installation - cmd = reattach_if_possible_fn(lang, true), + { + cmd = function() + local file = assert( + io.open( + utils.join_path(config.get_install_dir('parser-info') or '', lang .. '.revision'), + 'w' + ) + ) + file:write(revision or '') + file:close() + end, }, }) 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, { + { + cmd = function() + vim.fn.delete(utils.join_path(cache_dir, project_name), 'rf') + end, + }, + }) end if with_sync then if iter_cmd_sync(command_list) == true then - print("Treesitter parser for " .. lang .. " has been installed") + vim.notify('Parser for ' .. lang .. ' has been installed') end else - M.iter_cmd(command_list, 1, lang, "Treesitter parser for " .. lang .. " has been installed") - end -end - ----@param lang string ----@param ask_reinstall boolean|string ----@param cache_folder string ----@param install_folder string ----@param with_sync boolean ----@param generate_from_grammar boolean -local function install_lang(lang, ask_reinstall, cache_folder, install_folder, with_sync, generate_from_grammar) - if is_installed(lang) and ask_reinstall ~= "force" then - if not ask_reinstall then - return - end - - local yesno = fn.input(lang .. " parser already available: would you like to reinstall ? y/n: ") - print "\n " - if not string.match(yesno, "^y.*") then - return - end + iter_cmd(command_list, 1, lang, 'Parser for ' .. lang .. ' has been installed') end - - local ok, install_info = pcall(get_parser_install_info, lang, true) - if not ok then - vim.notify("Installation not possible: " .. install_info, vim.log.levels.ERROR) - if not parsers.get_parser_configs()[lang] then - vim.notify( - "See https://github.com/nvim-treesitter/nvim-treesitter/#adding-parsers on how to add a new parser!", - vim.log.levels.INFO - ) - end - return - end - - run_install(cache_folder, install_folder, lang, install_info, with_sync, generate_from_grammar) end ---@class InstallOptions ---@field with_sync boolean ----@field ask_reinstall boolean|string +---@field force boolean ---@field generate_from_grammar boolean ----@field exclude_configured_parsers boolean +---@field skip table -- Install a parser +---@param languages? string[]|string ---@param options? InstallOptions ----@return function -local function install(options) +function M.install(languages, options) options = options or {} local with_sync = options.with_sync - local ask_reinstall = options.ask_reinstall + local force = options.force local generate_from_grammar = options.generate_from_grammar - local exclude_configured_parsers = options.exclude_configured_parsers + local skip = options.skip - return function(...) - if fn.executable "git" == 0 then - return api.nvim_err_writeln "Git is required on your system to run this command" - end + reset_progress_counter() - local cache_folder, err = utils.get_cache_dir() - if err then - return api.nvim_err_writeln(err) - end - assert(cache_folder) + if vim.fn.executable('git') == 0 then + api.nvim_err_writeln('Git is required on your system to run this command') + return + end - local install_folder - install_folder, err = configs.get_parser_install_dir() - if err then - return api.nvim_err_writeln(err) - end - install_folder = install_folder and clean_path(install_folder) - assert(install_folder) - - local languages ---@type string[] - local ask ---@type boolean|string - if ... == "all" then - languages = parsers.available_parsers() - ask = false - else - languages = compat.flatten { ... } - ask = ask_reinstall - end + local cache_dir = vim.fn.stdpath('cache') + local install_dir = config.get_install_dir('parser') - if exclude_configured_parsers then - languages = utils.difference(languages, configs.get_ignored_parser_installs()) - end + if languages == 'all' then + force = true + end - if #languages > 1 then - reset_progress_counter() - end + languages = config.norm_languages(languages, skip) - for _, lang in ipairs(languages) do - install_lang(lang, ask, cache_folder, install_folder, with_sync, generate_from_grammar) - end + for _, lang in ipairs(languages) do + install_lang(lang, cache_dir, install_dir, force, with_sync, generate_from_grammar) + uv.fs_symlink( + utils.get_package_path('runtime', 'queries', lang), + utils.join_path(config.get_install_dir('queries'), lang), + { dir = true, junction = true } -- needed on Windows (non-junction links require admin) + ) end end -function M.setup_auto_install() - local function try_install_curr_lang() - local lang = parsers.get_buf_lang() - if parsers.get_parser_configs()[lang] and not is_installed(lang) and not is_ignored_parser(lang) then - install() { lang } - end - end +---@class UpdateOptions +---@field with_sync boolean + +---@param languages? string[]|string +---@param options? UpdateOptions +function M.update(languages, options) + options = options or {} - try_install_curr_lang() + reset_progress_counter() + M.lockfile = {} - vim.api.nvim_create_autocmd("FileType", { - pattern = { "*" }, - group = vim.api.nvim_create_augroup("NvimTreesitter-auto_install", { clear = true }), - callback = try_install_curr_lang, - }) + languages = config.norm_languages(languages or 'all', { ignored = true, missing = true }) + languages = vim.iter.filter(needs_update, languages) --- @type string[] + + if #languages > 0 then + M.install(languages, { + force = true, + with_sync = options.with_sync, + }) + else + vim.notify('All parsers are up-to-date') + end end -function M.update(options) - options = options or {} - return function(...) - M.lockfile = {} - reset_progress_counter() - if ... and ... ~= "all" then - ---@type string[] - local languages = compat.flatten { ... } - local installed = 0 - for _, lang in ipairs(languages) do - if (not is_installed(lang)) or (needs_update(lang)) then - installed = installed + 1 - install { - ask_reinstall = "force", - with_sync = options.with_sync, - }(lang) - end - end - if installed == 0 then - utils.notify "Parsers are up-to-date!" - end - else - local parsers_to_update = outdated_parsers() or info.installed_parsers() - if #parsers_to_update == 0 then - utils.notify "All parsers are up-to-date!" - end - for _, lang in pairs(parsers_to_update) do - install { - ask_reinstall = "force", - exclude_configured_parsers = true, - with_sync = options.with_sync, - }(lang) - end - end +--- @param lang string +--- @param parser string +--- @param queries string +local function uninstall(lang, parser, queries) + if vim.fn.filereadable(parser) ~= 1 then + return end + + iter_cmd({ + { + cmd = function() + uv.fs_unlink(parser) + end, + }, + { + cmd = function() + uv.fs_unlink(queries) + end, + }, + }, 1, lang, 'Parser for ' .. lang .. ' has been uninstalled') end -function M.uninstall(...) - if vim.tbl_contains({ "all" }, ...) then - reset_progress_counter() - local installed = info.installed_parsers() - M.uninstall(installed) - elseif ... then - local ensure_installed_parsers = configs.get_ensure_installed_parsers() - if ensure_installed_parsers == "all" then - ensure_installed_parsers = parsers.available_parsers() - end - ensure_installed_parsers = utils.difference(ensure_installed_parsers, configs.get_ignored_parser_installs()) - - ---@type string[] - local languages = compat.flatten { ... } - for _, lang in ipairs(languages) do - local install_dir, err = configs.get_parser_install_dir() - if err then - return api.nvim_err_writeln(err) - end - install_dir = install_dir and clean_path(install_dir) +--- @param languages string[]|string +function M.uninstall(languages) + reset_progress_counter() - if vim.tbl_contains(ensure_installed_parsers, lang) then - vim.notify( - "Uninstalling " - .. lang - .. '. But the parser is still configured in "ensure_installed" setting of nvim-treesitter.' - .. " Please consider updating your config!", - vim.log.levels.ERROR - ) - end + languages = config.norm_languages(languages or 'all', { missing = true }) - local parser_lib = utils.join_path(install_dir, lang) .. ".so" - local all_parsers = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) - if vim.fn.filereadable(parser_lib) == 1 then - local command_list = { - shell.select_rm_file_cmd(parser_lib, "Uninstalling parser for " .. lang), - { - cmd = function() - local all_parsers_after_deletion = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) - if #all_parsers_after_deletion > 0 then - vim.notify( - "Tried to uninstall parser for " - .. lang - .. "! But the parser is still installed (not by nvim-treesitter):" - .. table.concat(all_parsers_after_deletion, ", "), - vim.log.levels.ERROR - ) - end - end, - }, - { -- auto-reattach or detach modules after uninstallation - cmd = reattach_if_possible_fn(lang, false), - }, - } - M.iter_cmd(command_list, 1, lang, "Treesitter parser for " .. lang .. " has been uninstalled") - elseif #all_parsers > 0 then - vim.notify( - "Parser for " - .. lang - .. " is installed! But not by nvim-treesitter! Please manually remove the following files: " - .. table.concat(all_parsers, ", "), - vim.log.levels.ERROR - ) - end - end - end -end + local parser_dir = config.get_install_dir('parser') + local query_dir = config.get_install_dir('queries') + local installed = config.installed_parsers() -function M.write_lockfile(verbose, skip_langs) - local sorted_parsers = {} ---@type Parser[] - -- Load previous lockfile - load_lockfile() - skip_langs = skip_langs or {} - - for k, v in pairs(parsers.get_parser_configs()) do - table.insert(sorted_parsers, { name = k, parser = v }) - end - - ---@param a Parser - ---@param b Parser - table.sort(sorted_parsers, function(a, b) - return a.name < b.name - end) - - for _, v in ipairs(sorted_parsers) do - if not vim.tbl_contains(skip_langs, v.name) then - -- I'm sure this can be done in aync way with iter_cmd - local sha ---@type string - if v.parser.install_info.branch then - sha = vim.split( - vim.fn.systemlist( - "git ls-remote " .. v.parser.install_info.url .. " | grep refs/heads/" .. v.parser.install_info.branch - )[1], - "\t" - )[1] - else - sha = vim.split(vim.fn.systemlist("git ls-remote " .. v.parser.install_info.url)[1], "\t")[1] - end - lockfile[v.name] = { revision = sha } - if verbose then - print(v.name .. ": " .. sha) - end + for _, lang in ipairs(languages) do + if not vim.list_contains(installed, lang) then + vim.notify( + 'Parser for ' .. lang .. ' is is not managed by nvim-treesitter', + vim.log.levels.ERROR + ) else - print("Skipping " .. v.name) + local parser = utils.join_path(parser_dir, lang) .. '.so' + local queries = utils.join_path(query_dir, lang) + uninstall(lang, parser, queries) end end - - if verbose then - print(vim.inspect(lockfile)) - end - vim.fn.writefile( - vim.fn.split(vim.fn.json_encode(lockfile), "\n"), - utils.join_path(utils.get_package_path(), "lockfile.json") - ) end -M.ensure_installed = install { exclude_configured_parsers = true } -M.ensure_installed_sync = install { with_sync = true, exclude_configured_parsers = true } - -M.commands = { - TSInstall = { - run = install { ask_reinstall = true }, - ["run!"] = install { ask_reinstall = "force" }, - args = { - "-nargs=+", - "-bang", - "-complete=custom,nvim_treesitter#installable_parsers", - }, - }, - TSInstallFromGrammar = { - run = install { generate_from_grammar = true, ask_reinstall = true }, - ["run!"] = install { generate_from_grammar = true, ask_reinstall = "force" }, - args = { - "-nargs=+", - "-bang", - "-complete=custom,nvim_treesitter#installable_parsers", - }, - }, - TSInstallSync = { - run = install { with_sync = true, ask_reinstall = true }, - ["run!"] = install { with_sync = true, ask_reinstall = "force" }, - args = { - "-nargs=+", - "-bang", - "-complete=custom,nvim_treesitter#installable_parsers", - }, - }, - TSUpdate = { - run = M.update {}, - args = { - "-nargs=*", - "-complete=custom,nvim_treesitter#installed_parsers", - }, - }, - TSUpdateSync = { - run = M.update { with_sync = true }, - args = { - "-nargs=*", - "-complete=custom,nvim_treesitter#installed_parsers", - }, - }, - TSUninstall = { - run = M.uninstall, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter#installed_parsers", - }, - }, -} - return M diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua index fed835bbd..fa8496469 100644 --- a/lua/nvim-treesitter/locals.lua +++ b/lua/nvim-treesitter/locals.lua @@ -1,29 +1,46 @@ -- Functions to handle locals -- Locals are a generalization of definition and scopes --- its the way nvim-treesitter uses to "understand" the code +-- it's the way nvim-treesitter uses to "understand" the code -local queries = require "nvim-treesitter.query" -local ts_utils = require "nvim-treesitter.ts_utils" -local ts = vim.treesitter +local query = require('nvim-treesitter.query') local api = vim.api +local ts = vim.treesitter local M = {} -function M.collect_locals(bufnr) - return queries.collect_group_results(bufnr, "locals") +local function get_named_children(node) + local nodes = {} ---@type TSNode[] + for i = 0, node:named_child_count() - 1, 1 do + nodes[i + 1] = node:named_child(i) + end + return nodes +end + +---@param node TSNode +---@return TSNode result +local function get_root_for_node(node) + local parent = node + local result = node + + while parent ~= nil do + result = parent + parent = result:parent() + end + + return result end -- Iterates matches from a locals query file. -- @param bufnr the buffer -- @param root the root node function M.iter_locals(bufnr, root) - return queries.iter_group_results(bufnr, "locals", root) + return query.iter_group_results(bufnr, 'locals', root) end ---@param bufnr integer ---@return any -function M.get_locals(bufnr) - return queries.get_matches(bufnr, "locals") +function M.collect_locals(bufnr) + return query.collect_group_results(bufnr, 'locals') end -- Creates unique id for a node based on text and range @@ -32,17 +49,17 @@ end ---@return string: a string id function M.get_definition_id(scope, node_text) -- 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() }, '_') end function M.get_definitions(bufnr) - local locals = M.get_locals(bufnr) + local locals = M.collect_locals(bufnr) local defs = {} for _, loc in ipairs(locals) do - if loc["local"]["definition"] then - table.insert(defs, loc["local"]["definition"]) + if loc['local.definition'] then + table.insert(defs, loc['local.definition']) end end @@ -50,13 +67,13 @@ function M.get_definitions(bufnr) end function M.get_scopes(bufnr) - local locals = M.get_locals(bufnr) + local locals = M.collect_locals(bufnr) local scopes = {} for _, loc in ipairs(locals) do - if loc["local"]["scope"] and loc["local"]["scope"].node then - table.insert(scopes, loc["local"]["scope"].node) + if loc['local.scope'] and loc['local.scope'].node then + table.insert(scopes, loc['local.scope'].node) end end @@ -64,13 +81,13 @@ function M.get_scopes(bufnr) end function M.get_references(bufnr) - local locals = M.get_locals(bufnr) + local locals = M.collect_locals(bufnr) local refs = {} for _, loc in ipairs(locals) do - if loc["local"]["reference"] and loc["local"]["reference"].node then - table.insert(refs, loc["local"]["reference"].node) + if loc['local.reference'] and loc['local.reference'].node then + table.insert(refs, loc['local.reference'].node) end end @@ -103,7 +120,7 @@ function M.iter_scope_tree(node, bufnr) return end - local scope = M.containing_scope(last_node, bufnr, false) or ts_utils.get_root_for_node(node) + local scope = M.containing_scope(last_node, bufnr, false) or get_root_for_node(node) last_node = scope:parent() @@ -117,8 +134,8 @@ end function M.get_local_nodes(local_def) local result = {} - M.recurse_local_nodes(local_def, function(def, _node, kind) - table.insert(result, vim.tbl_extend("keep", { kind = kind }, def)) + M.recurse_local_nodes(local_def, function(def, _, kind) + table.insert(result, vim.tbl_extend('keep', { kind = kind }, def)) end) return result @@ -135,7 +152,7 @@ end ---@param full_match? string The full match path to append to ---@param last_match? string The 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 end @@ -143,11 +160,36 @@ function M.recurse_local_nodes(local_def, accumulator, full_match, last_match) accumulator(local_def, local_def.node, full_match, last_match) else for match_key, def in pairs(local_def) do - M.recurse_local_nodes(def, accumulator, full_match and (full_match .. "." .. match_key) or match_key, match_key) + M.recurse_local_nodes( + def, + accumulator, + full_match and (full_match .. '.' .. match_key) or match_key, + match_key + ) end end end +---Memoize a function using hash_fn to hash the arguments. +---@generic F: function +---@param fn F +---@param hash_fn fun(...): any +---@return F +local function memoize(fn, hash_fn) + local cache = setmetatable({}, { __mode = 'kv' }) ---@type table + + return function(...) + local key = hash_fn(...) + if cache[key] == nil then + local v = fn(...) ---@type any + cache[key] = v ~= nil and v or vim.NIL + end + + local v = cache[key] + return v ~= vim.NIL and v or nil + end +end + -- 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. -- This makes looking up a definition for a given scope a simple key lookup. @@ -161,7 +203,7 @@ end -- ---@param bufnr integer: the buffer ---@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 = memoize(function(bufnr) local definitions = M.get_definitions(bufnr) local result = {} @@ -178,6 +220,8 @@ M.get_definitions_lookup_table = ts_utils.memoize_by_buf_tick(function(bufnr) end return result +end, function(bufnr) + return tostring(bufnr) end) -- Gets all the scopes of a definition based on the scope type @@ -196,10 +240,10 @@ function M.get_definition_scopes(node, bufnr, scope_type) -- Definition is valid for the containing scope -- and the containing scope of that scope - if scope_type == "parent" then + if scope_type == 'parent' then scope_count = 2 -- Definition is valid in all parent scopes - elseif scope_type == "global" then + elseif scope_type == 'global' then scope_count = nil end @@ -235,7 +279,7 @@ function M.find_definition(node, bufnr) end end - return node, ts_utils.get_root_for_node(node), nil + return node, get_root_for_node(node), nil end -- Finds usages of a node in a given scope. @@ -250,12 +294,15 @@ function M.find_usages(node, scope_node, bufnr) return {} end - local scope_node = scope_node or ts_utils.get_root_for_node(node) + scope_node = scope_node or get_root_for_node(node) local usages = {} for match in M.iter_locals(bufnr, scope_node) do - match = match["local"] - if match.reference and match.reference.node and ts.get_node_text(match.reference.node, bufnr) == node_text then + if + match.reference + and match.reference.node + and ts.get_node_text(match.reference.node, bufnr) == node_text + then local def_node, _, kind = M.find_definition(match.reference.node, bufnr) if kind == nil or def_node == node then @@ -272,8 +319,8 @@ end ---@param allow_scope? boolean ---@return TSNode|nil function M.containing_scope(node, bufnr, allow_scope) - local bufnr = bufnr or api.nvim_get_current_buf() - local allow_scope = allow_scope == nil or allow_scope == true + bufnr = bufnr or api.nvim_get_current_buf() + allow_scope = allow_scope == nil or allow_scope == true local scopes = M.get_scopes(bufnr) if not node or not scopes then @@ -301,7 +348,7 @@ function M.nested_scope(node, cursor_pos) local col = cursor_pos.col ---@type integer local scope = M.containing_scope(node) - for _, child in ipairs(ts_utils.get_named_children(scope)) do + for _, child in ipairs(get_named_children(scope)) do local row_, col_ = child:start() if vim.tbl_contains(scopes, child) and ((row_ + 1 == row and col_ > col) or row_ + 1 > row) then return child @@ -318,6 +365,9 @@ function M.next_scope(node) end local scope = M.containing_scope(node) + if not scope then + return + end local parent = scope:parent() if not parent then @@ -325,7 +375,7 @@ function M.next_scope(node) end local is_prev = true - for _, child in ipairs(ts_utils.get_named_children(parent)) do + for _, child in ipairs(get_named_children(parent)) do if child == scope then is_prev = false elseif not is_prev and vim.tbl_contains(scopes, child) then @@ -345,6 +395,9 @@ function M.previous_scope(node) end local scope = M.containing_scope(node) + if not scope then + return + end local parent = scope:parent() if not parent then @@ -352,7 +405,7 @@ function M.previous_scope(node) end local is_prev = true - local children = ts_utils.get_named_children(parent) + local children = get_named_children(parent) for i = #children, 1, -1 do if children[i] == scope then is_prev = false diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index 31b691209..69e9500fe 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -1,43 +1,3 @@ -local api = vim.api -local ts = vim.treesitter - -for ft, lang in pairs { - automake = "make", - javascriptreact = "javascript", - ecma = "javascript", - jsx = "javascript", - gyp = "python", - html_tags = "html", - ["typescript.tsx"] = "tsx", - ["terraform-vars"] = "terraform", - ["html.handlebars"] = "glimmer", - systemverilog = "verilog", - dosini = "ini", - confini = "ini", - svg = "xml", - xsd = "xml", - xslt = "xml", - expect = "tcl", - mysql = "sql", - sbt = "scala", - neomuttrc = "muttrc", - clientscript = "runescript", - --- short-hand list from https://github.com/helix-editor/helix/blob/master/languages.toml - rs = "rust", - ex = "elixir", - js = "javascript", - ts = "typescript", - ["c-sharp"] = "csharp", - hs = "haskell", - py = "python", - erl = "erlang", - typ = "typst", - pl = "perl", - uxn = "uxntal", -} do - ts.language.register(lang, ft) -end - ---@class InstallInfo ---@field url string ---@field branch string|nil @@ -47,2798 +7,2830 @@ end ---@field requires_generate_from_grammar boolean|nil ---@field location string|nil ---@field use_makefile boolean|nil ----@field cxx_standard string|nil ---@class ParserInfo ---@field install_info InstallInfo ----@field filetype string +---@field filetype string[] ---@field maintainers string[] ----@field experimental boolean|nil ----@field readme_name string|nil +---@field tier integer|nil +---@field readme_note string|nil ----@type ParserInfo[] -local list = setmetatable({}, { - __newindex = function(table, parsername, parserconfig) - rawset(table, parsername, parserconfig) - if parserconfig.filetype or vim.fn.has "nvim-0.11" == 0 then - ts.language.register(parsername, parserconfig.filetype or parsername) - end - end, -}) - -list.ada = { - install_info = { - url = "https://github.com/briot/tree-sitter-ada", - files = { "src/parser.c" }, - }, - maintainers = { "@briot" }, -} +local M = {} -list.agda = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-agda", - files = { "src/parser.c", "src/scanner.c" }, - }, - maintainers = { "@Decodetalkers" }, -} +M.tiers = { 'core', 'stable', 'community', 'unstable' } -list.angular = { - install_info = { - url = "https://github.com/dlvandenberg/tree-sitter-angular", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, +---@type ParserInfo[] +M.configs = { + ada = { + install_info = { + url = 'https://github.com/briot/tree-sitter-ada', + files = { 'src/parser.c' }, + }, + maintainers = { '@briot' }, }, - filetype = "htmlangular", - maintainers = { "@dlvandenberg" }, - experimental = true, -} -list.apex = { - install_info = { - url = "https://github.com/aheber/tree-sitter-sfapex", - files = { "src/parser.c" }, - location = "apex", + agda = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-agda', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@Decodetalkers' }, }, - maintainers = { "@aheber", "@xixiaofinland" }, -} -list.arduino = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-arduino", - files = { "src/parser.c", "src/scanner.c" }, + angular = { + install_info = { + url = 'https://github.com/dlvandenberg/tree-sitter-angular', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@dlvandenberg' }, + tier = 4, }, - maintainers = { "@ObserverOfTime" }, -} -list.asm = { - install_info = { - url = "https://github.com/RubixDev/tree-sitter-asm", - files = { "src/parser.c" }, + apex = { + install_info = { + url = 'https://github.com/aheber/tree-sitter-sfapex', + files = { 'src/parser.c' }, + location = 'apex', + }, + maintainers = { '@aheber', '@xixiafinland' }, + tier = 3, }, - maintainers = { "@RubixDev" }, -} -list.astro = { - install_info = { - url = "https://github.com/virchau13/tree-sitter-astro", - files = { "src/parser.c", "src/scanner.c" }, + arduino = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-arduino', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ObserverOfTime' }, }, - maintainers = { "@virchau13" }, -} -list.authzed = { - install_info = { - url = "https://github.com/mleonidas/tree-sitter-authzed", - files = { "src/parser.c" }, + asm = { + install_info = { + url = 'https://github.com/RubixDev/tree-sitter-asm', + files = { 'src/parser.c' }, + }, + maintainers = { '@RubixDev' }, + tier = 3, }, - maintainers = { "@mattpolzin" }, -} -list.awk = { - install_info = { - url = "https://github.com/Beaglefoot/tree-sitter-awk", - files = { "src/parser.c", "src/scanner.c" }, + astro = { + install_info = { + url = 'https://github.com/virchau13/tree-sitter-astro', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@virchau13' }, }, -} -list.bash = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-bash", - files = { "src/parser.c", "src/scanner.c" }, + authzed = { + install_info = { + url = 'https://github.com/mleonidas/tree-sitter-authzed', + files = { 'src/parser.c' }, + }, + maintainers = { '@mattpolzin' }, + tier = 3, }, - filetype = "sh", - maintainers = { "@TravonteD" }, -} -list.bass = { - install_info = { - url = "https://github.com/vito/tree-sitter-bass", - files = { "src/parser.c" }, + awk = { + install_info = { + url = 'https://github.com/Beaglefoot/tree-sitter-awk', + files = { 'src/parser.c', 'src/scanner.c' }, + }, }, - maintainers = { "@amaanq" }, -} -list.beancount = { - install_info = { - url = "https://github.com/polarmutex/tree-sitter-beancount", - files = { "src/parser.c", "src/scanner.c" }, + bash = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-bash', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@TravonteD' }, }, - maintainers = { "@polarmutex" }, -} -list.bibtex = { - install_info = { - url = "https://github.com/latex-lsp/tree-sitter-bibtex", - files = { "src/parser.c" }, + bass = { + install_info = { + url = 'https://github.com/vito/tree-sitter-bass', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - filetype = "bib", - maintainers = { "@theHamsta", "@clason" }, -} -list.bicep = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-bicep", - files = { "src/parser.c", "src/scanner.c" }, + beancount = { + install_info = { + url = 'https://github.com/polarmutex/tree-sitter-beancount', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@polarmutex' }, }, - maintainers = { "@amaanq" }, -} -list.bitbake = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-bitbake", - files = { "src/parser.c", "src/scanner.c" }, + bibtex = { + install_info = { + url = 'https://github.com/latex-lsp/tree-sitter-bibtex', + files = { 'src/parser.c' }, + }, + maintainers = { '@theHamsta', '@clason' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.blade = { - install_info = { - url = "https://github.com/EmranMR/tree-sitter-blade", - files = { "src/parser.c" }, + bicep = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-bicep', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@calebdw" }, -} -list.blueprint = { - install_info = { - url = "https://gitlab.com/gabmus/tree-sitter-blueprint.git", - files = { "src/parser.c" }, + bitbake = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-bitbake', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@gabmus" }, - experimental = true, -} -list.bp = { - install_info = { - url = "https://github.com/ambroisie/tree-sitter-bp", - files = { "src/parser.c" }, + blade = { + install_info = { + url = 'https://github.com/EmranMR/tree-sitter-blade', + files = { 'src/parser.c' }, + }, + maintainers = { '@calebdw' }, + tier = 2, }, - maintainers = { "@ambroisie" }, -} - -list.brightscript = { - install_info = { - url = "https://github.com/ajdelcimmuto/tree-sitter-brightscript", - files = { "src/parser.c" }, + blueprint = { + install_info = { + url = 'https://gitlab.com/gabmus/tree-sitter-blueprint.git', + files = { 'src/parser.c' }, + }, + maintainers = { '@gabmus' }, + tier = 4, }, - maintainers = { "@ajdelcimmuto" }, -} -list.c = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-c", - files = { "src/parser.c" }, + bp = { + install_info = { + url = 'https://github.com/ambroisie/tree-sitter-bp', + files = { 'src/parser.c' }, + }, + maintainers = { '@ambroisie' }, + tier = 3, + readme_note = 'Android Blueprint', + }, + brightscript = { + install_info = { + url = 'https://github.com/ajdelcimmuto/tree-sitter-brightscript', + files = { 'src/parser.c' }, + }, + maintainers = { '@ajdelcimmuto' }, + tier = 2, }, - maintainers = { "@amaanq" }, -} - -list.c_sharp = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-c-sharp", - files = { "src/parser.c", "src/scanner.c" }, + c = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-c', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 1, }, - filetype = "cs", - maintainers = { "@amaanq" }, -} -list.caddy = { - install_info = { - url = "https://github.com/opa-oz/tree-sitter-caddy", - files = { "src/parser.c", "src/scanner.c" }, + c_sharp = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-c-sharp', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@opa-oz" }, -} -list.cairo = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-cairo", - files = { "src/parser.c", "src/scanner.c" }, + cairo = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-cairo', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@amaanq" }, -} -list.capnp = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-capnp", - files = { "src/parser.c" }, + caddy = { + install_info = { + url = 'https://github.com/opa-oz/tree-sitter-caddy', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@opa-oz' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.chatito = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-chatito", - files = { "src/parser.c" }, + capnp = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-capnp', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@ObserverOfTime" }, -} -list.circom = { - install_info = { - url = "https://github.com/Decurity/tree-sitter-circom", - files = { "src/parser.c" }, + chatito = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-chatito', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, }, - maintainers = { "@alexandr-martirosyan" }, -} -list.clojure = { - install_info = { - url = "https://github.com/sogaiu/tree-sitter-clojure", - files = { "src/parser.c" }, + circom = { + install_info = { + url = 'https://github.com/Decurity/tree-sitter-circom', + files = { 'src/parser.c' }, + }, + maintainers = { '@alexandr-martirosyan' }, + tier = 3, }, - maintainers = { "@NoahTheDuke" }, -} -list.cmake = { - install_info = { - url = "https://github.com/uyha/tree-sitter-cmake", - files = { "src/parser.c", "src/scanner.c" }, + clojure = { + install_info = { + url = 'https://github.com/sogaiu/tree-sitter-clojure', + files = { 'src/parser.c' }, + }, + maintainers = { '@NoahTheDuke' }, }, - maintainers = { "@uyha" }, -} -list.comment = { - install_info = { - url = "https://github.com/stsewd/tree-sitter-comment", - files = { "src/parser.c", "src/scanner.c" }, + cmake = { + install_info = { + url = 'https://github.com/uyha/tree-sitter-cmake', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@uyha' }, }, - maintainers = { "@stsewd" }, -} -list.commonlisp = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-commonlisp", - files = { "src/parser.c" }, - generate_requires_npm = true, + comment = { + install_info = { + url = 'https://github.com/stsewd/tree-sitter-comment', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@stsewd' }, + tier = 2, }, - filetype = "lisp", - maintainers = { "@theHamsta" }, -} -list.cooklang = { - install_info = { - url = "https://github.com/addcninblue/tree-sitter-cooklang", - files = { "src/parser.c", "src/scanner.c" }, + commonlisp = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-commonlisp', + files = { 'src/parser.c' }, + generate_requires_npm = true, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@addcninblue" }, - filetype = "cook", -} -list.corn = { - install_info = { - url = "https://github.com/jakestanger/tree-sitter-corn", - files = { "src/parser.c" }, + cooklang = { + install_info = { + url = 'https://github.com/addcninblue/tree-sitter-cooklang', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@addcninblue' }, + tier = 3, }, - maintainers = { "@jakestanger" }, -} -list.cpon = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-cpon", - files = { "src/parser.c" }, + corn = { + install_info = { + url = 'https://github.com/jakestanger/tree-sitter-corn', + files = { 'src/parser.c' }, + }, + maintainers = { '@jakestanger' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.cpp = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-cpp", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + cpon = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-cpon', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@theHamsta" }, -} -list.css = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-css", - files = { "src/parser.c", "src/scanner.c" }, + cpp = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-cpp', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@TravonteD" }, -} -list.csv = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-csv", - files = { "src/parser.c" }, - location = "csv", + css = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-css', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@TravonteD' }, }, - maintainers = { "@amaanq" }, -} -list.cuda = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-cuda", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + csv = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-csv', + files = { 'src/parser.c' }, + location = 'csv', + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@theHamsta" }, -} -list.cue = { - install_info = { - url = "https://github.com/eonpatapon/tree-sitter-cue", - files = { "src/parser.c", "src/scanner.c" }, + cuda = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-cuda', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@amaanq" }, -} -list.cylc = { - install_info = { - url = "https://github.com/elliotfontaine/tree-sitter-cylc", - files = { "src/parser.c" }, + cue = { + install_info = { + url = 'https://github.com/eonpatapon/tree-sitter-cue', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@elliotfontaine" }, -} -list.d = { - install_info = { - url = "https://github.com/gdamore/tree-sitter-d", - files = { "src/parser.c", "src/scanner.c" }, + cylc = { + install_info = { + url = 'https://github.com/elliotfontaine/tree-sitter-cylc', + files = { 'src/parser.c' }, + }, + maintainers = { '@elliotfontaine' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.dart = { - install_info = { - url = "https://github.com/UserNobody14/tree-sitter-dart", - files = { "src/parser.c", "src/scanner.c" }, + d = { + install_info = { + url = 'https://github.com/gdamore/tree-sitter-d', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + tier = 2, + maintainers = { '@amaanq' }, }, - maintainers = { "@akinsho" }, -} -list.desktop = { - install_info = { - url = "https://github.com/ValdezFOmar/tree-sitter-desktop", - files = { "src/parser.c" }, + dart = { + install_info = { + url = 'https://github.com/UserNobody14/tree-sitter-dart', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@akinsho' }, }, - maintainers = { "@ValdezFOmar" }, -} -list.devicetree = { - install_info = { - url = "https://github.com/joelspadin/tree-sitter-devicetree", - files = { "src/parser.c" }, + desktop = { + install_info = { + url = 'https://github.com/ValdezFOmar/tree-sitter-desktop', + files = { 'src/parser.c' }, + }, + maintainers = { '@ValdezFOmar' }, + tier = 3, }, - filetype = "dts", - maintainers = { "@jedrzejboczar" }, -} -list.dhall = { - install_info = { - url = "https://github.com/jbellerb/tree-sitter-dhall", - files = { "src/parser.c", "src/scanner.c" }, + devicetree = { + install_info = { + url = 'https://github.com/joelspadin/tree-sitter-devicetree', + files = { 'src/parser.c' }, + }, + maintainers = { '@jedrzejboczar' }, }, - maintainers = { "@amaanq" }, -} -list.diff = { - install_info = { - url = "https://github.com/the-mikedavis/tree-sitter-diff", - files = { "src/parser.c" }, + dhall = { + install_info = { + url = 'https://github.com/jbellerb/tree-sitter-dhall', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - filetype = "gitdiff", - maintainers = { "@gbprod" }, -} -list.disassembly = { - install_info = { - url = "https://github.com/ColinKennedy/tree-sitter-disassembly", - files = { "src/parser.c", "src/scanner.c" }, + diff = { + install_info = { + url = 'https://github.com/the-mikedavis/tree-sitter-diff', + files = { 'src/parser.c' }, + }, + maintainers = { '@gbprod' }, }, - maintainers = { "@ColinKennedy" }, -} -list.djot = { - install_info = { - url = "https://github.com/treeman/tree-sitter-djot", - files = { "src/parser.c", "src/scanner.c" }, + disassembly = { + install_info = { + url = 'https://github.com/ColinKennedy/tree-sitter-disassembly', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ColinKennedy' }, + tier = 3, }, - maintainers = { "@NoahTheDuke" }, -} -list.dockerfile = { - install_info = { - url = "https://github.com/camdencheek/tree-sitter-dockerfile", - files = { "src/parser.c", "src/scanner.c" }, + djot = { + install_info = { + url = 'https://github.com/treeman/tree-sitter-djot', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@NoahTheDuke' }, + tier = 3, }, - maintainers = { "@camdencheek" }, -} -list.dot = { - install_info = { - url = "https://github.com/rydesun/tree-sitter-dot", - files = { "src/parser.c" }, + dockerfile = { + install_info = { + url = 'https://github.com/camdencheek/tree-sitter-dockerfile', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@camdencheek' }, }, - maintainers = { "@rydesun" }, -} -list.doxygen = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-doxygen", - files = { "src/parser.c", "src/scanner.c" }, + dot = { + install_info = { + url = 'https://github.com/rydesun/tree-sitter-dot', + files = { 'src/parser.c' }, + }, + maintainers = { '@rydesun' }, }, - maintainers = { "@amaanq" }, -} -list.dtd = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-xml", - files = { "src/parser.c", "src/scanner.c" }, - location = "dtd", + doxygen = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-doxygen', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@ObserverOfTime" }, -} -list.earthfile = { - install_info = { - url = "https://github.com/glehmann/tree-sitter-earthfile", - files = { "src/parser.c", "src/scanner.c" }, + dtd = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-xml', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'dtd', + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@glehmann" }, -} -list.ebnf = { - install_info = { - url = "https://github.com/RubixDev/ebnf", - files = { "src/parser.c" }, - location = "crates/tree-sitter-ebnf", + earthfile = { + install_info = { + url = 'https://github.com/glehmann/tree-sitter-earthfile', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@glehmann' }, + tier = 3, + }, + ebnf = { + install_info = { + url = 'https://github.com/RubixDev/ebnf', + files = { 'src/parser.c' }, + location = 'crates/tree-sitter-ebnf', + }, + maintainers = { '@RubixDev' }, + tier = 4, }, - maintainers = { "@RubixDev" }, - experimental = true, -} -list.editorconfig = { - install_info = { - url = "https://github.com/ValdezFOmar/tree-sitter-editorconfig", - files = { "src/parser.c", "src/scanner.c" }, + editorconfig = { + install_info = { + url = 'https://github.com/ValdezFOmar/tree-sitter-editorconfig', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ValdezFOmar' }, + tier = 3, }, - maintainers = { "@ValdezFOmar" }, -} -list.eds = { - install_info = { - url = "https://github.com/uyha/tree-sitter-eds", - files = { "src/parser.c" }, + eds = { + install_info = { + url = 'https://github.com/uyha/tree-sitter-eds', + files = { 'src/parser.c' }, + }, + maintainers = { '@uyha' }, + tier = 3, }, - maintainers = { "@uyha" }, -} -list.eex = { - install_info = { - url = "https://github.com/connorlay/tree-sitter-eex", - files = { "src/parser.c" }, + eex = { + install_info = { + url = 'https://github.com/connorlay/tree-sitter-eex', + files = { 'src/parser.c' }, + }, + maintainers = { '@connorlay' }, }, - filetype = "eelixir", - maintainers = { "@connorlay" }, -} -list.elixir = { - install_info = { - url = "https://github.com/elixir-lang/tree-sitter-elixir", - files = { "src/parser.c", "src/scanner.c" }, + elixir = { + install_info = { + url = 'https://github.com/elixir-lang/tree-sitter-elixir', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@connorlay' }, }, - maintainers = { "@connorlay" }, -} -list.elm = { - install_info = { - url = "https://github.com/elm-tooling/tree-sitter-elm", - files = { "src/parser.c", "src/scanner.c" }, + elm = { + install_info = { + url = 'https://github.com/elm-tooling/tree-sitter-elm', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@zweimach' }, }, - maintainers = { "@zweimach" }, -} -list.elsa = { - install_info = { - url = "https://github.com/glapa-grossklag/tree-sitter-elsa", - files = { "src/parser.c" }, + elsa = { + install_info = { + url = 'https://github.com/glapa-grossklag/tree-sitter-elsa', + files = { 'src/parser.c' }, + }, + maintainers = { '@glapa-grossklag', '@amaanq' }, }, - maintainers = { "@glapa-grossklag", "@amaanq" }, -} -list.elvish = { - install_info = { - url = "https://github.com/elves/tree-sitter-elvish", - files = { "src/parser.c" }, + elvish = { + install_info = { + url = 'https://github.com/elves/tree-sitter-elvish', + files = { 'src/parser.c' }, + }, + maintainers = { '@elves' }, }, - maintainers = { "@elves" }, -} -list.embedded_template = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-embedded-template", - files = { "src/parser.c" }, + embedded_template = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-embedded-template', + files = { 'src/parser.c' }, + }, }, - filetype = "eruby", -} -list.enforce = { - install_info = { - url = "https://github.com/simonvic/tree-sitter-enforce", - files = { "src/parser.c" }, + enforce = { + install_info = { + url = 'https://github.com/simonvic/tree-sitter-enforce', + files = { 'src/parser.c' }, + }, + maintainers = { '@simonvic' }, + tier = 3, }, - maintainers = { "@simonvic" }, -} -list.erlang = { - install_info = { - url = "https://github.com/WhatsApp/tree-sitter-erlang", - files = { "src/parser.c", "src/scanner.c" }, + erlang = { + install_info = { + url = 'https://github.com/WhatsApp/tree-sitter-erlang', + files = { 'src/parser.c', 'src/parser.c' }, + }, + maintainers = { '@filmor' }, }, - maintainers = { "@filmor" }, -} -list.facility = { - install_info = { - url = "https://github.com/FacilityApi/tree-sitter-facility", - files = { "src/parser.c" }, + facility = { + install_info = { + url = 'https://github.com/FacilityApi/tree-sitter-facility', + files = { 'src/parser.c' }, + }, + maintainers = { '@bryankenote' }, + tier = 3, }, - filetype = "fsd", - maintainers = { "@bryankenote" }, -} -list.faust = { - install_info = { - url = "https://github.com/khiner/tree-sitter-faust", - files = { "src/parser.c" }, + faust = { + install_info = { + url = 'https://github.com/khiner/tree-sitter-faust', + files = { 'src/parser.c' }, + }, + maintainers = { '@khiner' }, + tier = 3, }, - filetype = "dsp", - maintainers = { "@khiner" }, -} -list.fennel = { - install_info = { - url = "https://github.com/alexmozaidze/tree-sitter-fennel", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + fennel = { + install_info = { + url = 'https://github.com/alexmozaidze/tree-sitter-fennel', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@alexmozaidze' }, }, - maintainers = { "@alexmozaidze" }, -} -list.fidl = { - install_info = { - url = "https://github.com/google/tree-sitter-fidl", - files = { "src/parser.c" }, + fidl = { + install_info = { + url = 'https://github.com/google/tree-sitter-fidl', + files = { 'src/parser.c' }, + }, + maintainers = { '@chaopeng' }, + tier = 3, }, - maintainers = { "@chaopeng" }, -} -list.firrtl = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-firrtl", - files = { "src/parser.c", "src/scanner.c" }, + firrtl = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-firrtl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.fish = { - install_info = { - url = "https://github.com/ram02z/tree-sitter-fish", - files = { "src/parser.c", "src/scanner.c" }, + fish = { + install_info = { + url = 'https://github.com/ram02z/tree-sitter-fish', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ram02z' }, }, - maintainers = { "@ram02z" }, -} -list.foam = { - install_info = { - url = "https://github.com/FoamScience/tree-sitter-foam", - files = { "src/parser.c", "src/scanner.c" }, + foam = { + install_info = { + url = 'https://github.com/FoamScience/tree-sitter-foam', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@FoamScience' }, + tier = 4, }, - maintainers = { "@FoamScience" }, - -- Queries might change over time on the grammar's side - -- Otherwise everything runs fine - experimental = true, -} -list.forth = { - install_info = { - url = "https://github.com/AlexanderBrevig/tree-sitter-forth", - files = { "src/parser.c" }, + forth = { + install_info = { + url = 'https://github.com/AlexanderBrevig/tree-sitter-forth', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@amaanq" }, -} -list.fortran = { - install_info = { - url = "https://github.com/stadelmanma/tree-sitter-fortran", - files = { "src/parser.c", "src/scanner.c" }, + fortran = { + install_info = { + url = 'https://github.com/stadelmanma/tree-sitter-fortran', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.fsh = { - install_info = { - url = "https://github.com/mgramigna/tree-sitter-fsh", - files = { "src/parser.c" }, + fsh = { + install_info = { + url = 'https://github.com/mgramigna/tree-sitter-fsh', + files = { 'src/parser.c' }, + }, + maintainers = { '@mgramigna' }, }, - maintainers = { "@mgramigna" }, -} -list.fsharp = { - install_info = { - url = "https://github.com/ionide/tree-sitter-fsharp", - files = { "src/parser.c", "src/scanner.c" }, - location = "fsharp", + fsharp = { + install_info = { + url = 'https://github.com/ionide/tree-sitter-fsharp', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'fsharp', + }, + maintainers = { '@nsidorenco' }, + tier = 3, }, - maintainers = { "@nsidorenco" }, -} -list.func = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-func", - files = { "src/parser.c" }, + func = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-func', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.fusion = { - install_info = { - url = "https://gitlab.com/jirgn/tree-sitter-fusion.git", - files = { "src/parser.c", "src/scanner.c" }, + fusion = { + install_info = { + url = 'https://gitlab.com/jirgn/tree-sitter-fusion.git', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@jirgn' }, }, - maintainers = { "@jirgn" }, -} -list.gap = { - install_info = { - url = "https://github.com/gap-system/tree-sitter-gap", - files = { "src/parser.c", "src/scanner.c" }, + gap = { + install_info = { + url = 'https://github.com/gap-system/tree-sitter-gap', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@reiniscirpons' }, + readme_name = 'GAP system', + tier = 3, }, - maintainers = { "@reiniscirpons" }, - readme_name = "GAP system", -} -list.gaptst = { - install_info = { - url = "https://github.com/gap-system/tree-sitter-gaptst", - files = { "src/parser.c", "src/scanner.c" }, + gaptst = { + install_info = { + url = 'https://github.com/gap-system/tree-sitter-gaptst', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@reiniscirpons' }, + readme_name = 'GAP system test files', + requires = { 'gap' }, + tier = 3, }, - maintainers = { "@reiniscirpons" }, - readme_name = "GAP system test files", -} -list.gdscript = { - install_info = { - url = "https://github.com/PrestonKnopp/tree-sitter-gdscript", - files = { "src/parser.c", "src/scanner.c" }, + gdscript = { + install_info = { + url = 'https://github.com/PrestonKnopp/tree-sitter-gdscript', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@PrestonKnopp' }, + readme_note = 'Godot', }, - maintainers = { "@PrestonKnopp" }, - readme_name = "Godot (gdscript)", -} -list.gdshader = { - install_info = { - url = "https://github.com/GodOfAvacyn/tree-sitter-gdshader", - files = { "src/parser.c" }, + gdshader = { + install_info = { + url = 'https://github.com/GodOfAvacyn/tree-sitter-gdshader', + files = { 'src/parser.c' }, + }, + maintainers = { '@godofavacyn' }, + tier = 3, }, - filetype = "gdshaderinc", - maintainers = { "@godofavacyn" }, -} -list.git_rebase = { - install_info = { - url = "https://github.com/the-mikedavis/tree-sitter-git-rebase", - files = { "src/parser.c" }, + git_rebase = { + install_info = { + url = 'https://github.com/the-mikedavis/tree-sitter-git-rebase', + files = { 'src/parser.c' }, + }, + maintainers = { '@gbprod' }, }, - filetype = "gitrebase", - maintainers = { "@gbprod" }, -} -list.gitattributes = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-gitattributes", - files = { "src/parser.c" }, + gitattributes = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-gitattributes', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, }, - maintainers = { "@ObserverOfTime" }, -} -list.gitcommit = { - install_info = { - url = "https://github.com/gbprod/tree-sitter-gitcommit", - files = { "src/parser.c", "src/scanner.c" }, + gitcommit = { + install_info = { + url = 'https://github.com/gbprod/tree-sitter-gitcommit', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@gbprod' }, }, - maintainers = { "@gbprod" }, -} -list.git_config = { - install_info = { - url = "https://github.com/the-mikedavis/tree-sitter-git-config", - files = { "src/parser.c" }, + git_config = { + install_info = { + url = 'https://github.com/the-mikedavis/tree-sitter-git-config', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + readme_note = 'git_config', }, - filetype = "gitconfig", - maintainers = { "@amaanq" }, - readme_name = "git_config", -} -list.gitignore = { - install_info = { - url = "https://github.com/shunsambongi/tree-sitter-gitignore", - files = { "src/parser.c" }, + gitignore = { + install_info = { + url = 'https://github.com/shunsambongi/tree-sitter-gitignore', + files = { 'src/parser.c' }, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@theHamsta" }, -} -list.gleam = { - install_info = { - url = "https://github.com/gleam-lang/tree-sitter-gleam", - files = { "src/parser.c", "src/scanner.c" }, + gleam = { + install_info = { + url = 'https://github.com/gleam-lang/tree-sitter-gleam', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.glimmer = { - install_info = { - url = "https://github.com/ember-tooling/tree-sitter-glimmer", - files = { "src/parser.c", "src/scanner.c" }, + glimmer = { + install_info = { + url = 'https://github.com/ember-tooling/tree-sitter-glimmer', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@NullVoxPopuli' }, + readme_note = 'Glimmer and Ember', }, - filetype = "handlebars", - maintainers = { "@NullVoxPopuli" }, - readme_name = "Glimmer and Ember", -} -list.glimmer_javascript = { - install_info = { - url = "https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + glimmer_javascript = { + install_info = { + url = 'https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@NullVoxPopuli' }, + requires = { 'javascript' }, + tier = 3, }, - filetype = "javascript.glimmer", - maintainers = { "@NullVoxPopuli" }, -} -list.glimmer_typescript = { - install_info = { - url = "https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + glimmer_typescript = { + install_info = { + url = 'https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@NullVoxPopuli' }, + requires = { 'typescript' }, + tier = 3, }, - filetype = "typescript.glimmer", - maintainers = { "@NullVoxPopuli" }, -} -list.glsl = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-glsl", - files = { "src/parser.c" }, - generate_requires_npm = true, + glsl = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-glsl', + files = { 'src/parser.c' }, + generate_requires_npm = true, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@theHamsta" }, -} -list.gn = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-gn", - files = { "src/parser.c", "src/scanner.c" }, + gn = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-gn', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + readme_name = 'GN (Generate Ninja)', + tier = 2, }, - maintainers = { "@amaanq" }, - readme_name = "GN (Generate Ninja)", -} -list.gnuplot = { - install_info = { - url = "https://github.com/dpezto/tree-sitter-gnuplot", - files = { "src/parser.c" }, + gnuplot = { + install_info = { + url = 'https://github.com/dpezto/tree-sitter-gnuplot', + files = { 'src/parser.c' }, + }, + maintainers = { '@dpezto' }, + tier = 3, }, - maintainers = { "@dpezto" }, -} -list.go = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-go", - files = { "src/parser.c" }, + go = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-go', + files = { 'src/parser.c' }, + }, + maintainers = { '@theHamsta', '@WinWisely268' }, }, - maintainers = { "@theHamsta", "@WinWisely268" }, -} -list.goctl = { - install_info = { - url = "https://github.com/chaozwn/tree-sitter-goctl", - files = { "src/parser.c" }, + goctl = { + install_info = { + url = 'https://github.com/chaozwn/tree-sitter-goctl', + files = { 'src/parser.c' }, + }, + maintainers = { '@chaozwn' }, + tier = 3, }, - maintainers = { "@chaozwn" }, -} -list.godot_resource = { - install_info = { - url = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", - files = { "src/parser.c", "src/scanner.c" }, + godot_resource = { + install_info = { + url = 'https://github.com/PrestonKnopp/tree-sitter-godot-resource', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@pierpo' }, + readme_note = 'Godot Resources', }, - filetype = "gdresource", - maintainers = { "@pierpo" }, - readme_name = "Godot Resources (gdresource)", -} -list.gomod = { - install_info = { - url = "https://github.com/camdencheek/tree-sitter-go-mod", - files = { "src/parser.c" }, + gomod = { + install_info = { + url = 'https://github.com/camdencheek/tree-sitter-go-mod', + files = { 'src/parser.c' }, + }, + maintainers = { '@camdencheek' }, }, - maintainers = { "@camdencheek" }, -} -list.gosum = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-go-sum", - files = { "src/parser.c" }, + gosum = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-go-sum', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.gowork = { - install_info = { - url = "https://github.com/omertuc/tree-sitter-go-work", - files = { "src/parser.c" }, + gowork = { + install_info = { + url = 'https://github.com/omertuc/tree-sitter-go-work', + files = { 'src/parser.c' }, + }, + maintainers = { '@omertuc' }, }, - maintainers = { "@omertuc" }, -} -list.gotmpl = { - install_info = { - url = "https://github.com/ngalaiko/tree-sitter-go-template", - files = { "src/parser.c" }, + graphql = { + install_info = { + url = 'https://github.com/bkegley/tree-sitter-graphql', + files = { 'src/parser.c' }, + }, + maintainers = { '@bkegley' }, }, - maintainers = { "@qvalentin" }, -} -list.gpg = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-gpg-config", - files = { "src/parser.c" }, + gotmpl = { + install_info = { + url = 'https://github.com/ngalaiko/tree-sitter-go-template', + files = { 'src/parser.c' }, + }, + maintainers = { '@qvalentin' }, + tier = 3, }, - maintainers = { "@ObserverOfTime" }, -} -list.gren = { - install_info = { - files = { "src/parser.c", "src/scanner.c" }, - url = "https://github.com/MaeBrooks/tree-sitter-gren", + gpg = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-gpg-config', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@MaeBrooks" }, -} -list.groovy = { - install_info = { - url = "https://github.com/murtaza64/tree-sitter-groovy", - files = { "src/parser.c" }, + gren = { + install_info = { + files = { 'src/parser.c', 'src/scanner.c' }, + url = 'https://github.com/MaeBrooks/tree-sitter-gren', + }, + maintainers = { '@MaeBrooks' }, + tier = 3, }, - maintainers = { "@murtaza64" }, -} -list.graphql = { - install_info = { - url = "https://github.com/bkegley/tree-sitter-graphql", - files = { "src/parser.c" }, + groovy = { + install_info = { + url = 'https://github.com/murtaza64/tree-sitter-groovy', + files = { 'src/parser.c' }, + }, + maintainers = { '@murtaza64' }, + tier = 3, }, - maintainers = { "@bkegley" }, -} -list.gstlaunch = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-gstlaunch", - files = { "src/parser.c" }, + gstlaunch = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-gstlaunch', + files = { 'src/parser.c' }, + }, + maintainers = { '@theHamsta' }, + tier = 2, }, - maintainers = { "@theHamsta" }, -} -list.hack = { - install_info = { - url = "https://github.com/slackhq/tree-sitter-hack", - files = { "src/parser.c", "src/scanner.c" }, + hack = { + install_info = { + url = 'https://github.com/slackhq/tree-sitter-hack', + files = { 'src/parser.c', 'src/scanner.c' }, + }, }, -} -list.hare = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-hare", - files = { "src/parser.c" }, + hare = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-hare', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.haskell = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-haskell", - files = { "src/parser.c", "src/scanner.c" }, + haskell = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-haskell', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@mrcjkb' }, }, - maintainers = { "@mrcjkb" }, -} -list.haskell_persistent = { - install_info = { - url = "https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent", - files = { "src/parser.c", "src/scanner.c" }, + haskell_persistent = { + install_info = { + url = 'https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + filetype = 'haskell.persistent', + maintainers = { '@lykahb' }, }, - filetype = "haskellpersistent", - maintainers = { "@lykahb" }, -} -list.hcl = { - install_info = { - url = "https://github.com/MichaHoffmann/tree-sitter-hcl", - files = { "src/parser.c", "src/scanner.c" }, + hcl = { + install_info = { + url = 'https://github.com/MichaHoffmann/tree-sitter-hcl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@MichaHoffmann' }, }, - maintainers = { "@MichaHoffmann" }, -} -list.heex = { - install_info = { - url = "https://github.com/connorlay/tree-sitter-heex", - files = { "src/parser.c" }, + heex = { + install_info = { + url = 'https://github.com/connorlay/tree-sitter-heex', + files = { 'src/parser.c' }, + }, + maintainers = { '@connorlay' }, }, - maintainers = { "@connorlay" }, -} -list.helm = { - install_info = { - url = "https://github.com/ngalaiko/tree-sitter-go-template", - location = "dialects/helm", - files = { "src/parser.c" }, + helm = { + install_info = { + url = 'https://github.com/ngalaiko/tree-sitter-go-template', + location = 'dialects/helm', + files = { 'src/parser.c' }, + }, + maintainers = { '@qvalentin' }, + tier = 3, }, - maintainers = { "@qvalentin" }, -} -list.hjson = { - install_info = { - url = "https://github.com/winston0410/tree-sitter-hjson", - files = { "src/parser.c" }, - generate_requires_npm = true, + hjson = { + install_info = { + url = 'https://github.com/winston0410/tree-sitter-hjson', + files = { 'src/parser.c' }, + generate_requires_npm = true, + }, + maintainers = { '@winston0410' }, }, - maintainers = { "@winston0410" }, -} -list.hlsl = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-hlsl", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + hlsl = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-hlsl', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@theHamsta" }, -} -list.hocon = { - install_info = { - url = "https://github.com/antosha417/tree-sitter-hocon", - files = { "src/parser.c" }, - generate_requires_npm = true, + hlsplaylist = { + install_info = { + url = 'https://github.com/Freed-Wu/tree-sitter-hlsplaylist', + files = { 'src/parser.c' }, + }, + maintainers = { '@Freed-Wu' }, + tier = 3, }, - maintainers = { "@antosha417" }, -} -list.hoon = { - install_info = { - url = "https://github.com/urbit-pilled/tree-sitter-hoon", - files = { "src/parser.c", "src/scanner.c" }, + hocon = { + install_info = { + url = 'https://github.com/antosha417/tree-sitter-hocon', + files = { 'src/parser.c' }, + generate_requires_npm = true, + }, + maintainers = { '@antosha417' }, }, - maintainers = { "@urbit-pilled" }, - experimental = true, -} -list.html = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-html", - files = { "src/parser.c", "src/scanner.c" }, + hoon = { + install_info = { + url = 'https://github.com/urbit-pilled/tree-sitter-hoon', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@urbit-pilled' }, + tier = 4, }, - maintainers = { "@TravonteD" }, -} -list.htmldjango = { - install_info = { - url = "https://github.com/interdependence/tree-sitter-htmldjango", - files = { "src/parser.c" }, + html = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-html', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@TravonteD' }, }, - maintainers = { "@ObserverOfTime" }, - experimental = true, -} -list.http = { - install_info = { - url = "https://github.com/rest-nvim/tree-sitter-http", - files = { "src/parser.c" }, + htmldjango = { + install_info = { + url = 'https://github.com/interdependence/tree-sitter-htmldjango', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 4, }, - maintainers = { "@amaanq", "@NTBBloodbath" }, -} -list.hurl = { - install_info = { - url = "https://github.com/pfeiferj/tree-sitter-hurl", - files = { "src/parser.c" }, + http = { + install_info = { + url = 'https://github.com/rest-nvim/tree-sitter-http', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq', '@NTBBloodbath' }, }, - maintainers = { "@pfeiferj" }, -} -list.hyprlang = { - install_info = { - url = "https://github.com/luckasRanarison/tree-sitter-hyprlang", - files = { "src/parser.c" }, + hurl = { + install_info = { + url = 'https://github.com/pfeiferj/tree-sitter-hurl', + files = { 'src/parser.c' }, + }, + maintainers = { '@pfeiferj' }, + tier = 3, }, - maintainers = { "@luckasRanarison" }, -} -list.idl = { - install_info = { - url = "https://github.com/cathaysia/tree-sitter-idl", - files = { "src/parser.c" }, + hyprlang = { + install_info = { + url = 'https://github.com/luckasRanarison/tree-sitter-hyprlang', + files = { 'src/parser.c' }, + }, + maintainers = { '@luckasRanarison' }, + tier = 3, }, - maintainers = { "@cathaysia" }, -} -list.idris = { - install_info = { - url = "https://github.com/kayhide/tree-sitter-idris", - files = { "src/parser.c", "src/scanner.c" }, + idl = { + install_info = { + url = 'https://github.com/cathaysia/tree-sitter-idl', + files = { 'src/parser.c' }, + }, + maintainers = { '@cathaysia' }, + tier = 3, }, - filetype = "idris2", - maintainers = { "@srghma" }, -} -list.ini = { - install_info = { - url = "https://github.com/justinmk/tree-sitter-ini", - files = { "src/parser.c" }, + idris = { + install_info = { + url = 'https://github.com/kayhide/tree-sitter-idris', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@srghma' }, + tier = 3, }, - maintainers = { "@theHamsta" }, - experimental = true, -} -list.inko = { - install_info = { - url = "https://github.com/inko-lang/tree-sitter-inko", - files = { "src/parser.c" }, + ini = { + install_info = { + url = 'https://github.com/justinmk/tree-sitter-ini', + files = { 'src/parser.c' }, + }, + maintainers = { '@theHamsta' }, + tier = 4, }, - maintainers = { "@yorickpeterse" }, -} -list.ipkg = { - install_info = { - url = "https://github.com/srghma/tree-sitter-ipkg", - files = { "src/parser.c", "src/scanner.c" }, + inko = { + install_info = { + url = 'https://github.com/inko-lang/tree-sitter-inko', + files = { 'src/parser.c' }, + }, + maintainers = { '@yorickpeterse' }, + tier = 3, }, - maintainers = { "@srghma" }, -} -list.ispc = { - install_info = { - url = "https://github.com/fab4100/tree-sitter-ispc", - files = { "src/parser.c" }, - generate_requires_npm = true, + ipkg = { + install_info = { + url = 'https://github.com/srghma/tree-sitter-ipkg', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@srghma' }, + tier = 3, }, - maintainers = { "@fab4100" }, -} -list.janet_simple = { - install_info = { - url = "https://github.com/sogaiu/tree-sitter-janet-simple", - files = { "src/parser.c", "src/scanner.c" }, + ispc = { + install_info = { + url = 'https://github.com/fab4100/tree-sitter-ispc', + files = { 'src/parser.c' }, + generate_requires_npm = true, + }, + maintainers = { '@fab4100' }, }, - filetype = "janet", - maintainers = { "@sogaiu" }, -} -list.java = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-java", - files = { "src/parser.c" }, - }, - maintainers = { "@p00f" }, -} - -list.javadoc = { - install_info = { - url = "https://github.com/rmuir/tree-sitter-javadoc", - files = { "src/parser.c", "src/scanner.c" }, + janet_simple = { + install_info = { + url = 'https://github.com/sogaiu/tree-sitter-janet-simple', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@sogaiu' }, }, - maintainers = { "@rmuir" }, -} -list.javascript = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-javascript", - files = { "src/parser.c", "src/scanner.c" }, + java = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-java', + files = { 'src/parser.c' }, + }, + maintainers = { '@p00f' }, }, - maintainers = { "@steelsojka" }, -} -list.jinja = { - install_info = { - url = "https://github.com/cathaysia/tree-sitter-jinja", - location = "tree-sitter-jinja", - files = { "src/parser.c", "src/scanner.c" }, + javadoc = { + install_info = { + url = 'https://github.com/rmuir/tree-sitter-javadoc', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@rmuir' }, + tier = 2, }, - maintainers = { "@cathaysia" }, -} -list.jinja_inline = { - install_info = { - url = "https://github.com/cathaysia/tree-sitter-jinja", - location = "tree-sitter-jinja_inline", - files = { "src/parser.c", "src/scanner.c" }, + javascript = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-javascript', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@steelsojka' }, }, - maintainers = { "@cathaysia" }, -} -list.jq = { - install_info = { - url = "https://github.com/flurie/tree-sitter-jq", - files = { "src/parser.c" }, + jinja = { + install_info = { + url = 'https://github.com/cathaysia/tree-sitter-jinja', + location = 'tree-sitter-jinja', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@cathaysia' }, + readme_note = 'basic highlighting', + tier = 3, }, - maintainers = { "@ObserverOfTime" }, -} -list.jsdoc = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-jsdoc", - files = { "src/parser.c", "src/scanner.c" }, + jinja_inline = { + install_info = { + url = 'https://github.com/cathaysia/tree-sitter-jinja', + location = 'tree-sitter-jinja_inline', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@cathaysia' }, + readme_note = 'needed for full highlighting', + tier = 3, }, - maintainers = { "@steelsojka" }, -} -list.json = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-json", - files = { "src/parser.c" }, + jq = { + install_info = { + url = 'https://github.com/flurie/tree-sitter-jq', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, }, - maintainers = { "@steelsojka" }, -} -list.json5 = { - install_info = { - url = "https://github.com/Joakker/tree-sitter-json5", - files = { "src/parser.c" }, + jsdoc = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-jsdoc', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@steelsojka' }, }, - maintainers = { "@Joakker" }, -} -list.jsonc = { - install_info = { - url = "https://gitlab.com/WhyNotHugo/tree-sitter-jsonc.git", - files = { "src/parser.c" }, - generate_requires_npm = true, + json = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-json', + files = { 'src/parser.c' }, + }, + maintainers = { '@steelsojka' }, }, - maintainers = { "@WhyNotHugo" }, - readme_name = "JSON with comments", -} -list.jsonnet = { - install_info = { - url = "https://github.com/sourcegraph/tree-sitter-jsonnet", - files = { "src/parser.c", "src/scanner.c" }, + json5 = { + install_info = { + url = 'https://github.com/Joakker/tree-sitter-json5', + files = { 'src/parser.c' }, + }, + maintainers = { '@Joakker' }, }, - maintainers = { "@nawordar" }, -} -list.julia = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-julia", - files = { "src/parser.c", "src/scanner.c" }, + jsonc = { + install_info = { + url = 'https://gitlab.com/WhyNotHugo/tree-sitter-jsonc.git', + files = { 'src/parser.c' }, + generate_requires_npm = true, + }, + maintainers = { '@WhyNotHugo' }, + readme_note = 'JSON with comments', }, - maintainers = { "@fredrikekre" }, -} -list.just = { - install_info = { - url = "https://github.com/IndianBoy42/tree-sitter-just", - files = { "src/parser.c", "src/scanner.c" }, + jsonnet = { + install_info = { + url = 'https://github.com/sourcegraph/tree-sitter-jsonnet', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@nawordar' }, }, - maintainers = { "@Hubro" }, -} -list.kcl = { - install_info = { - url = "https://github.com/kcl-lang/tree-sitter-kcl", - files = { "src/parser.c", "src/scanner.c" }, + julia = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-julia', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@fredrikekre' }, + tier = 3, }, - maintainers = { "@bertbaron" }, -} -list.kconfig = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-kconfig", - files = { "src/parser.c", "src/scanner.c" }, + just = { + install_info = { + url = 'https://github.com/IndianBoy42/tree-sitter-just', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@Hubro' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.kdl = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-kdl", - files = { "src/parser.c", "src/scanner.c" }, + kcl = { + install_info = { + url = 'https://github.com/kcl-lang/tree-sitter-kcl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@bertbaron' }, + tier = 2, }, - maintainers = { "@amaanq" }, -} -list.kotlin = { - install_info = { - url = "https://github.com/fwcd/tree-sitter-kotlin", - files = { "src/parser.c", "src/scanner.c" }, + kconfig = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-kconfig', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@SalBakraa" }, -} -list.koto = { - install_info = { - url = "https://github.com/koto-lang/tree-sitter-koto", - files = { "src/parser.c", "src/scanner.c" }, + kdl = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-kdl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@irh" }, -} -list.kusto = { - install_info = { - url = "https://github.com/Willem-J-an/tree-sitter-kusto", - files = { "src/parser.c" }, + kotlin = { + install_info = { + url = 'https://github.com/fwcd/tree-sitter-kotlin', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@SalBakraa' }, }, - maintainers = { "@Willem-J-an" }, -} -list.lalrpop = { - install_info = { - url = "https://github.com/traxys/tree-sitter-lalrpop", - files = { "src/parser.c", "src/scanner.c" }, + koto = { + install_info = { + url = 'https://github.com/koto-lang/tree-sitter-koto', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@irh' }, + tier = 3, }, - maintainers = { "@traxys" }, -} -list.latex = { - install_info = { - url = "https://github.com/latex-lsp/tree-sitter-latex", - files = { "src/parser.c", "src/scanner.c" }, - requires_generate_from_grammar = true, + kusto = { + install_info = { + url = 'https://github.com/Willem-J-an/tree-sitter-kusto', + files = { 'src/parser.c' }, + }, + maintainers = { '@Willem-J-an' }, + tier = 3, }, - filetype = "tex", - maintainers = { "@theHamsta", "@clason" }, -} -list.ledger = { - install_info = { - url = "https://github.com/cbarrete/tree-sitter-ledger", - files = { "src/parser.c" }, + lalrpop = { + install_info = { + url = 'https://github.com/traxys/tree-sitter-lalrpop', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@traxys' }, }, - maintainers = { "@cbarrete" }, -} -list.leo = { - install_info = { - url = "https://github.com/r001/tree-sitter-leo", - files = { "src/parser.c" }, + latex = { + install_info = { + url = 'https://github.com/latex-lsp/tree-sitter-latex', + files = { 'src/parser.c', 'src/scanner.c' }, + requires_generate_from_grammar = true, + }, + maintainers = { '@theHamsta', '@clason' }, + tier = 3, }, - maintainers = { "@r001" }, -} -list.llvm = { - install_info = { - url = "https://github.com/benwilliamgraham/tree-sitter-llvm", - files = { "src/parser.c" }, + ledger = { + install_info = { + url = 'https://github.com/cbarrete/tree-sitter-ledger', + files = { 'src/parser.c' }, + }, + maintainers = { '@cbarrete' }, }, - maintainers = { "@benwilliamgraham" }, -} -list.linkerscript = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-linkerscript", - files = { "src/parser.c" }, + leo = { + install_info = { + url = 'https://github.com/r001/tree-sitter-leo', + files = { 'src/parser.c' }, + }, + maintainers = { '@r001' }, + tier = 3, }, - filetype = "ld", - maintainers = { "@amaanq" }, -} -list.liquid = { - install_info = { - url = "https://github.com/hankthetank27/tree-sitter-liquid", - files = { "src/parser.c", "src/scanner.c" }, + llvm = { + install_info = { + url = 'https://github.com/benwilliamgraham/tree-sitter-llvm', + files = { 'src/parser.c' }, + }, + maintainers = { '@benwilliamgraham' }, }, - maintainers = { "@hankthetank27" }, -} -list.liquidsoap = { - install_info = { - url = "https://github.com/savonet/tree-sitter-liquidsoap", - files = { "src/parser.c", "src/scanner.c" }, + linkerscript = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-linkerscript', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@toots" }, -} -list.lua = { - install_info = { - url = "https://github.com/MunifTanjim/tree-sitter-lua", - files = { "src/parser.c", "src/scanner.c" }, + liquid = { + install_info = { + url = 'https://github.com/hankthetank27/tree-sitter-liquid', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@hankthetank27' }, + tier = 3, }, - maintainers = { "@muniftanjim" }, -} -list.luadoc = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-luadoc", - files = { "src/parser.c" }, + liquidsoap = { + install_info = { + url = 'https://github.com/savonet/tree-sitter-liquidsoap', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@toots' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.luap = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-luap", - files = { "src/parser.c" }, + lua = { + install_info = { + url = 'https://github.com/MunifTanjim/tree-sitter-lua', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + tier = 1, + maintainers = { '@muniftanjim' }, }, - maintainers = { "@amaanq" }, - readme_name = "lua patterns", -} -list.luau = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-luau", - files = { "src/parser.c", "src/scanner.c" }, + luadoc = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-luadoc', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.hlsplaylist = { - install_info = { - url = "https://github.com/Freed-Wu/tree-sitter-hlsplaylist", - files = { "src/parser.c" }, + luap = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-luap', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + readme_note = 'Lua patterns', }, - maintainers = { "@Freed-Wu" }, -} -list.m68k = { - install_info = { - url = "https://github.com/grahambates/tree-sitter-m68k", - files = { "src/parser.c" }, + luau = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-luau', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - filetype = "asm68k", - maintainers = { "@grahambates" }, -} -list.make = { - install_info = { - url = "https://github.com/alemuller/tree-sitter-make", - files = { "src/parser.c" }, + m68k = { + install_info = { + url = 'https://github.com/grahambates/tree-sitter-m68k', + files = { 'src/parser.c' }, + }, + maintainers = { '@grahambates' }, }, - maintainers = { "@lewis6991" }, -} -list.markdown = { - install_info = { - url = "https://github.com/MDeiml/tree-sitter-markdown", - location = "tree-sitter-markdown", - files = { "src/parser.c", "src/scanner.c" }, + make = { + install_info = { + url = 'https://github.com/alemuller/tree-sitter-make', + files = { 'src/parser.c' }, + }, + maintainers = { '@lewis6991' }, }, - maintainers = { "@MDeiml" }, - readme_name = "markdown (basic highlighting)", - experimental = true, -} -list.markdown_inline = { - install_info = { - url = "https://github.com/MDeiml/tree-sitter-markdown", - location = "tree-sitter-markdown-inline", - files = { "src/parser.c", "src/scanner.c" }, + markdown = { + install_info = { + url = 'https://github.com/MDeiml/tree-sitter-markdown', + location = 'tree-sitter-markdown', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@MDeiml' }, + readme_note = 'basic highlighting', + tier = 1, }, - maintainers = { "@MDeiml" }, - readme_name = "markdown_inline (needed for full highlighting)", - experimental = true, -} -list.matlab = { - install_info = { - url = "https://github.com/acristoffers/tree-sitter-matlab", - files = { "src/parser.c", "src/scanner.c" }, + markdown_inline = { + install_info = { + url = 'https://github.com/MDeiml/tree-sitter-markdown', + location = 'tree-sitter-markdown-inline', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@MDeiml' }, + readme_note = 'needed for full highlighting', + tier = 1, }, - maintainers = { "@acristoffers" }, -} -list.menhir = { - install_info = { - url = "https://github.com/Kerl13/tree-sitter-menhir", - files = { "src/parser.c", "src/scanner.c" }, + matlab = { + install_info = { + url = 'https://github.com/acristoffers/tree-sitter-matlab', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@acristoffers' }, }, - maintainers = { "@Kerl13" }, -} -list.mermaid = { - install_info = { - url = "https://github.com/monaqa/tree-sitter-mermaid", - files = { "src/parser.c" }, + menhir = { + install_info = { + url = 'https://github.com/Kerl13/tree-sitter-menhir', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@Kerl13' }, }, - experimental = true, -} -list.meson = { - install_info = { - url = "https://github.com/Decodetalkers/tree-sitter-meson", - files = { "src/parser.c" }, + mermaid = { + install_info = { + url = 'https://github.com/monaqa/tree-sitter-mermaid', + files = { 'src/parser.c' }, + }, + tier = 4, }, - maintainers = { "@Decodetalkers" }, -} -list.mlir = { - install_info = { - url = "https://github.com/artagnon/tree-sitter-mlir", - files = { "src/parser.c" }, - requires_generate_from_grammar = true, + meson = { + install_info = { + url = 'https://github.com/Decodetalkers/tree-sitter-meson', + files = { 'src/parser.c' }, + }, + maintainers = { '@Decodetalkers' }, }, - experimental = true, - maintainers = { "@artagnon" }, -} -list.muttrc = { - install_info = { - url = "https://github.com/neomutt/tree-sitter-muttrc", - files = { "src/parser.c" }, + mlir = { + install_info = { + url = 'https://github.com/artagnon/tree-sitter-mlir', + files = { 'src/parser.c' }, + requires_generate_from_grammar = true, + }, + tier = 4, + maintainers = { '@artagnon' }, }, - maintainers = { "@Freed-Wu" }, -} -list.nasm = { - install_info = { - url = "https://github.com/naclsn/tree-sitter-nasm", - files = { "src/parser.c" }, + muttrc = { + install_info = { + url = 'https://github.com/neomutt/tree-sitter-muttrc', + files = { 'src/parser.c' }, + }, + maintainers = { '@Freed-Wu' }, + tier = 3, }, - maintainers = { "@ObserverOfTime" }, -} -list.nginx = { - install_info = { - url = "https://github.com/opa-oz/tree-sitter-nginx", - files = { "src/parser.c", "src/scanner.c" }, + nasm = { + install_info = { + url = 'https://github.com/naclsn/tree-sitter-nasm', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@opa-oz" }, -} -list.nickel = { - install_info = { - url = "https://github.com/nickel-lang/tree-sitter-nickel", - files = { "src/parser.c", "src/scanner.c" }, + nginx = { + install_info = { + url = 'https://github.com/opa-oz/tree-sitter-nginx', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@opa-oz' }, + tier = 3, }, -} -list.nim = { - install_info = { - url = "https://github.com/alaviss/tree-sitter-nim", - files = { "src/parser.c", "src/scanner.c" }, + nickel = { + install_info = { + url = 'https://github.com/nickel-lang/tree-sitter-nickel', + files = { 'src/parser.c', 'src/scanner.c' }, + }, }, - maintainers = { "@aMOPel" }, -} -list.nim_format_string = { - install_info = { - url = "https://github.com/aMOPel/tree-sitter-nim-format-string", - files = { "src/parser.c" }, + nim = { + install_info = { + url = 'https://github.com/alaviss/tree-sitter-nim', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@aMOPel' }, + tier = 3, }, - maintainers = { "@aMOPel" }, -} -list.ninja = { - install_info = { - url = "https://github.com/alemuller/tree-sitter-ninja", - files = { "src/parser.c" }, + nim_format_string = { + install_info = { + url = 'https://github.com/aMOPel/tree-sitter-nim-format-string', + files = { 'src/parser.c' }, + }, + maintainers = { '@aMOPel' }, + tier = 3, }, - maintainers = { "@alemuller" }, -} -list.nix = { - install_info = { - url = "https://github.com/cstrahan/tree-sitter-nix", - files = { "src/parser.c", "src/scanner.c" }, + ninja = { + install_info = { + url = 'https://github.com/alemuller/tree-sitter-ninja', + files = { 'src/parser.c' }, + }, + maintainers = { '@alemuller' }, }, - maintainers = { "@leo60228" }, -} -list.norg = { - install_info = { - url = "https://github.com/nvim-neorg/tree-sitter-norg", - files = { "src/parser.c", "src/scanner.cc" }, - cxx_standard = "c++14", - use_makefile = true, + nix = { + install_info = { + url = 'https://github.com/cstrahan/tree-sitter-nix', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@leo60228' }, }, - maintainers = { "@JoeyGrajciar", "@vhyrro" }, -} -list.nqc = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-nqc", - files = { "src/parser.c" }, + norg = { + install_info = { + url = 'https://github.com/nvim-neorg/tree-sitter-norg', + files = { 'src/parser.c', 'src/scanner.cc' }, + use_makefile = true, + }, + tier = 4, + maintainers = { '@JoeyGrajciar', '@vhyrro' }, }, - maintainers = { "@amaanq" }, -} -list.nu = { - install_info = { - url = "https://github.com/nushell/tree-sitter-nu", - files = { "src/parser.c", "src/scanner.c" }, + nqc = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-nqc', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@abhisheksingh0x558" }, -} -list.objc = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-objc", - files = { "src/parser.c" }, + nu = { + install_info = { + url = 'https://github.com/nushell/tree-sitter-nu', + files = { 'src/parser.c' }, + }, + maintainers = { '@abhisheksingh0x558' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.objdump = { - install_info = { - url = "https://github.com/ColinKennedy/tree-sitter-objdump", - files = { "src/parser.c", "src/scanner.c" }, + objc = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-objc', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@ColinKennedy" }, -} -list.ocaml = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-ocaml", - files = { "src/parser.c", "src/scanner.c" }, - location = "grammars/ocaml", + objdump = { + install_info = { + url = 'https://github.com/ColinKennedy/tree-sitter-objdump', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ColinKennedy' }, + tier = 3, }, - maintainers = { "@undu" }, -} -list.ocaml_interface = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-ocaml", - files = { "src/parser.c", "src/scanner.c" }, - location = "grammars/interface", + ocaml = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-ocaml', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'grammars/ocaml', + }, + maintainers = { '@undu' }, }, - filetype = "ocamlinterface", - maintainers = { "@undu" }, -} -list.ocamllex = { - install_info = { - url = "https://github.com/atom-ocaml/tree-sitter-ocamllex", - files = { "src/parser.c", "src/scanner.c" }, - requires_generate_from_grammar = true, + ocaml_interface = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-ocaml', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'grammars/interface', + }, + maintainers = { '@undu' }, }, - maintainers = { "@undu" }, -} -list.odin = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-odin", - files = { "src/parser.c", "src/scanner.c" }, + ocamllex = { + install_info = { + url = 'https://github.com/atom-ocaml/tree-sitter-ocamllex', + files = { 'src/parser.c', 'src/scanner.c' }, + requires_generate_from_grammar = true, + }, + maintainers = { '@undu' }, }, - maintainers = { "@amaanq" }, -} -list.pascal = { - install_info = { - url = "https://github.com/Isopod/tree-sitter-pascal", - files = { "src/parser.c" }, + odin = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-odin', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@Isopod" }, -} -list.passwd = { - install_info = { - url = "https://github.com/ath3/tree-sitter-passwd", - files = { "src/parser.c" }, + pascal = { + install_info = { + url = 'https://github.com/Isopod/tree-sitter-pascal', + files = { 'src/parser.c' }, + }, + maintainers = { '@Isopod' }, }, - maintainers = { "@amaanq" }, -} -list.pem = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-pem", - files = { "src/parser.c" }, + passwd = { + install_info = { + url = 'https://github.com/ath3/tree-sitter-passwd', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@ObserverOfTime" }, -} -list.perl = { - install_info = { - url = "https://github.com/tree-sitter-perl/tree-sitter-perl", - files = { "src/parser.c", "src/scanner.c" }, - branch = "release", + pem = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-pem', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@RabbiVeesh", "@LeoNerd" }, -} -list.php = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-php", - location = "php", - files = { "src/parser.c", "src/scanner.c" }, + perl = { + install_info = { + url = 'https://github.com/tree-sitter-perl/tree-sitter-perl', + branch = 'release', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@RabbiVeesh', '@LeoNerd' }, }, - maintainers = { "@tk-shirasaka", "@calebdw" }, -} -list.php_only = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-php", - location = "php_only", - files = { "src/parser.c", "src/scanner.c" }, + php = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-php', + location = 'php', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@tk-shirasaka', '@calebdw' }, + requires = { 'php_only' }, + readme_note = 'PHP with embedded HTML', }, - maintainers = { "@tk-shirasaka", "@calebdw" }, -} --- Parsers for injections -list.phpdoc = { - install_info = { - url = "https://github.com/claytonrcarter/tree-sitter-phpdoc", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + php_only = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-php', + location = 'php_only', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@tk-shirasaka', '@calebdw' }, + readme_note = 'PHP without embedded HTML', }, - maintainers = { "@mikehaertl" }, - experimental = true, -} -list.pioasm = { - install_info = { - url = "https://github.com/leo60228/tree-sitter-pioasm", - files = { "src/parser.c", "src/scanner.c" }, + phpdoc = { + install_info = { + url = 'https://github.com/claytonrcarter/tree-sitter-phpdoc', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@mikehaertl' }, + tier = 4, }, - maintainers = { "@leo60228" }, -} -list.po = { - install_info = { - url = "https://github.com/erasin/tree-sitter-po", - files = { "src/parser.c" }, + pioasm = { + install_info = { + url = 'https://github.com/leo60228/tree-sitter-pioasm', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@leo60228' }, }, - maintainers = { "@amaanq" }, -} -list.pod = { - install_info = { - url = "https://github.com/tree-sitter-perl/tree-sitter-pod", - files = { "src/parser.c", "src/scanner.c" }, - branch = "release", + po = { + install_info = { + url = 'https://github.com/erasin/tree-sitter-po', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@RabbiVeesh", "@LeoNerd" }, -} -list.poe_filter = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-poe-filter", - files = { "src/parser.c" }, + pod = { + install_info = { + url = 'https://github.com/tree-sitter-perl/tree-sitter-pod', + files = { 'src/parser.c', 'src/scanner.c' }, + branch = 'release', + }, + maintainers = { '@RabbiVeesh', '@LeoNerd' }, + tier = 3, }, - filetype = "poefilter", - maintainers = { "@ObserverOfTime" }, - readme_name = "Path of Exile item filter", - experimental = true, -} -list.pony = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-pony", - files = { "src/parser.c", "src/scanner.c" }, + poe_filter = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-poe-filter', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + readme_note = 'Path of Exile item filter', + tier = 4, }, - maintainers = { "@amaanq", "@mfelsche" }, -} -list.powershell = { - install_info = { - url = "https://github.com/airbus-cert/tree-sitter-powershell", - files = { "src/parser.c", "src/scanner.c" }, + pony = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-pony', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq', '@mfelsche' }, }, - filetype = "ps1", - maintainers = { "@L2jLiga" }, -} -list.printf = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-printf", - files = { "src/parser.c" }, + powershell = { + install_info = { + url = 'https://github.com/airbus-cert/tree-sitter-powershell', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + filetype = 'ps1', + maintainers = { '@L2jLiga' }, + tier = 3, }, - maintainers = { "@ObserverOfTime" }, -} -list.prisma = { - install_info = { - url = "https://github.com/victorhqc/tree-sitter-prisma", - files = { "src/parser.c" }, + printf = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-printf', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@elianiva" }, -} -list.problog = { - install_info = { - url = "https://github.com/foxyseta/tree-sitter-prolog", - files = { "src/parser.c" }, - location = "grammars/problog", + prisma = { + install_info = { + url = 'https://github.com/victorhqc/tree-sitter-prisma', + files = { 'src/parser.c' }, + }, + maintainers = { '@elianiva' }, }, - maintainers = { "@foxyseta" }, -} -list.prolog = { - install_info = { - url = "https://github.com/foxyseta/tree-sitter-prolog", - files = { "src/parser.c" }, - location = "grammars/prolog", + problog = { + install_info = { + url = 'https://github.com/foxyseta/tree-sitter-prolog', + files = { 'src/parser.c' }, + location = 'grammars/problog', + }, + maintainers = { '@foxyseta' }, + requires = { 'prolog' }, + tier = 3, }, - maintainers = { "@foxyseta" }, -} -list.promql = { - install_info = { - url = "https://github.com/MichaHoffmann/tree-sitter-promql", - files = { "src/parser.c" }, - experimental = true, + prolog = { + install_info = { + url = 'https://github.com/foxyseta/tree-sitter-prolog', + files = { 'src/parser.c' }, + location = 'grammars/prolog', + }, + maintainers = { '@foxyseta' }, + tier = 3, }, - maintainers = { "@MichaHoffmann" }, -} -list.properties = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-properties", - files = { "src/parser.c", "src/scanner.c" }, + properties = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-properties', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, + readme_note = 'Java properties files', }, - filetype = "jproperties", - maintainers = { "@ObserverOfTime" }, -} -list.proto = { - install_info = { - url = "https://github.com/treywood/tree-sitter-proto", - files = { "src/parser.c" }, + proto = { + install_info = { + url = 'https://github.com/treywood/tree-sitter-proto', + files = { 'src/parser.c' }, + }, + maintainers = { '@treywood' }, }, - maintainers = { "@treywood" }, -} -list.prql = { - install_info = { - url = "https://github.com/PRQL/tree-sitter-prql", - files = { "src/parser.c" }, + promql = { + install_info = { + url = 'https://github.com/MichaHoffmann/tree-sitter-promql', + files = { 'src/parser.c' }, + }, + maintainers = { '@MichaHoffmann' }, + tier = 4, }, - maintainers = { "@matthias-Q" }, -} -list.psv = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-csv", - files = { "src/parser.c" }, - location = "psv", + prql = { + install_info = { + url = 'https://github.com/PRQL/tree-sitter-prql', + files = { 'src/parser.c' }, + }, + maintainers = { '@matthias-Q' }, }, - maintainers = { "@amaanq" }, -} -list.pug = { - install_info = { - url = "https://github.com/zealot128/tree-sitter-pug", - files = { "src/parser.c", "src/scanner.c" }, + psv = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-csv', + files = { 'src/parser.c' }, + location = 'psv', + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@zealot128" }, - experimental = true, -} -list.puppet = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-puppet", - files = { "src/parser.c" }, + pug = { + install_info = { + url = 'https://github.com/zealot128/tree-sitter-pug', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@zealot128' }, + tier = 4, }, - maintainers = { "@amaanq" }, -} -list.purescript = { - install_info = { - url = "https://github.com/postsolar/tree-sitter-purescript", - files = { "src/parser.c", "src/scanner.c" }, + puppet = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-puppet', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@postsolar" }, -} -list.pymanifest = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-pymanifest", - files = { "src/parser.c" }, + purescript = { + install_info = { + url = 'https://github.com/postsolar/tree-sitter-purescript', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@postsolar' }, + tier = 3, }, - maintainers = { "@ObserverOfTime" }, - readme_name = "PyPA manifest", -} -list.python = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-python", - files = { "src/parser.c", "src/scanner.c" }, + pymanifest = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-pymanifest', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + readme_name = 'PyPA manifest', + tier = 2, }, - maintainers = { "@stsewd", "@theHamsta" }, -} -list.ql = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-ql", - files = { "src/parser.c" }, + python = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-python', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@stsewd', '@theHamsta' }, }, - maintainers = { "@pwntester" }, -} -list.qmldir = { - install_info = { - url = "https://github.com/Decodetalkers/tree-sitter-qmldir", - files = { "src/parser.c" }, + ql = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-ql', + files = { 'src/parser.c' }, + }, + maintainers = { '@pwntester' }, }, - maintainers = { "@amaanq" }, -} -list.qmljs = { - install_info = { - url = "https://github.com/yuja/tree-sitter-qmljs", - files = { "src/parser.c", "src/scanner.c" }, + qmldir = { + install_info = { + url = 'https://github.com/Decodetalkers/tree-sitter-qmldir', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - filetype = "qml", - maintainers = { "@Decodetalkers" }, -} -list.query = { - install_info = { - url = "https://github.com/nvim-treesitter/tree-sitter-query", - files = { "src/parser.c" }, + qmljs = { + install_info = { + url = 'https://github.com/yuja/tree-sitter-qmljs', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@Decodetalkers' }, }, - maintainers = { "@steelsojka" }, - readme_name = "Tree-Sitter query language", -} -list.r = { - install_info = { - url = "https://github.com/r-lib/tree-sitter-r", - files = { "src/parser.c", "src/scanner.c" }, + query = { + install_info = { + url = 'https://github.com/nvim-treesitter/tree-sitter-query', + files = { 'src/parser.c' }, + }, + maintainers = { '@steelsojka' }, + readme_note = 'Tree-sitter query language', + tier = 1, }, - maintainers = { "@ribru17" }, -} -list.racket = { - install_info = { - url = "https://github.com/6cdh/tree-sitter-racket", - files = { "src/parser.c", "src/scanner.c" }, + r = { + install_info = { + url = 'https://github.com/r-lib/tree-sitter-r', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ribru17' }, + tier = 3, }, -} -list.ralph = { - install_info = { - url = "https://github.com/alephium/tree-sitter-ralph", - files = { "src/parser.c" }, + racket = { + install_info = { + url = 'https://github.com/6cdh/tree-sitter-racket', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + tier = 4, }, - maintainers = { "@tdroxler" }, -} -list.rasi = { - install_info = { - url = "https://github.com/Fymyte/tree-sitter-rasi", - files = { "src/parser.c" }, + ralph = { + install_info = { + url = 'https://github.com/alephium/tree-sitter-ralph', + files = { 'src/parser.c' }, + }, + maintainers = { '@tdroxler' }, + tier = 3, }, - maintainers = { "@Fymyte" }, -} -list.razor = { - install_info = { - url = "https://github.com/tris203/tree-sitter-razor", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + rasi = { + install_info = { + url = 'https://github.com/Fymyte/tree-sitter-rasi', + files = { 'src/parser.c' }, + }, + maintainers = { '@Fymyte' }, }, - maintainers = { "@tris203" }, -} -list.rbs = { - install_info = { - url = "https://github.com/joker1007/tree-sitter-rbs", - files = { "src/parser.c" }, + razor = { + install_info = { + url = 'https://github.com/tris203/tree-sitter-razor', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@tris203' }, + tier = 3, }, - maintainers = { "@joker1007" }, -} -list.re2c = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-re2c", - files = { "src/parser.c" }, + rbs = { + install_info = { + url = 'https://github.com/joker1007/tree-sitter-rbs', + files = { 'src/parser.c' }, + }, + maintainers = { '@joker1007' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.readline = { - install_info = { - url = "https://github.com/ribru17/tree-sitter-readline", - files = { "src/parser.c" }, + re2c = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-re2c', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@ribru17" }, -} -list.regex = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-regex", - files = { "src/parser.c" }, + readline = { + install_info = { + url = 'https://github.com/ribru17/tree-sitter-readline', + files = { 'src/parser.c' }, + }, + maintainers = { '@ribru17' }, + tier = 3, }, - maintainers = { "@theHamsta" }, -} -list.rego = { - install_info = { - url = "https://github.com/FallenAngel97/tree-sitter-rego", - files = { "src/parser.c" }, + regex = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-regex', + files = { 'src/parser.c' }, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@FallenAngel97" }, -} -list.requirements = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-requirements", - files = { "src/parser.c" }, + rego = { + install_info = { + url = 'https://github.com/FallenAngel97/tree-sitter-rego', + files = { 'src/parser.c' }, + }, + maintainers = { '@FallenAngel97' }, }, - maintainers = { "@ObserverOfTime" }, - readme_name = "pip requirements", -} -list.rescript = { - install_info = { - url = "https://github.com/rescript-lang/tree-sitter-rescript", - files = { "src/parser.c", "src/scanner.c" }, + requirements = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-requirements', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + readme_name = 'pip requirements', + tier = 2, }, - maintainers = { "@ribru17" }, -} -list.rnoweb = { - install_info = { - url = "https://github.com/bamonroe/tree-sitter-rnoweb", - files = { "src/parser.c", "src/scanner.c" }, + rescript = { + install_info = { + url = 'https://github.com/rescript-lang/tree-sitter-rescript', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ribru17' }, + tier = 2, }, - maintainers = { "@bamonroe" }, -} -list.robot = { - install_info = { - url = "https://github.com/Hubro/tree-sitter-robot", - files = { "src/parser.c" }, + rnoweb = { + install_info = { + url = 'https://github.com/bamonroe/tree-sitter-rnoweb', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@bamonroe' }, }, - maintainers = { "@Hubro" }, -} -list.robots = { - install_info = { - url = "https://github.com/opa-oz/tree-sitter-robots-txt", - files = { "src/parser.c", "src/scanner.c" }, + robot = { + install_info = { + url = 'https://github.com/Hubro/tree-sitter-robot', + files = { 'src/parser.c' }, + }, + maintainers = { '@Hubro' }, + tier = 3, }, - maintainers = { "@opa-oz" }, -} -list.roc = { - install_info = { - url = "https://github.com/faldor20/tree-sitter-roc", - files = { "src/parser.c", "src/scanner.c" }, + robots = { + install_info = { + url = 'https://github.com/opa-oz/tree-sitter-robots-txt', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@opa-oz' }, + tier = 3, }, - maintainers = { "@nat-418" }, -} -list.ron = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-ron", - files = { "src/parser.c", "src/scanner.c" }, + roc = { + install_info = { + url = 'https://github.com/faldor20/tree-sitter-roc', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@nat-418' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.rst = { - install_info = { - url = "https://github.com/stsewd/tree-sitter-rst", - files = { "src/parser.c", "src/scanner.c" }, + ron = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-ron', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@stsewd" }, -} -list.ruby = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-ruby", - files = { "src/parser.c", "src/scanner.c" }, + rst = { + install_info = { + url = 'https://github.com/stsewd/tree-sitter-rst', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@stsewd' }, }, - maintainers = { "@TravonteD" }, -} -list.runescript = { - install_info = { - url = "https://github.com/2004Scape/tree-sitter-runescript", - files = { "src/parser.c", "src/scanner.c" }, + ruby = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-ruby', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@TravonteD' }, }, - maintainers = { "@2004Scape" }, -} -list.rust = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-rust", - files = { "src/parser.c", "src/scanner.c" }, + runescript = { + install_info = { + url = 'https://github.com/2004Scape/tree-sitter-runescript', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@2004Scape' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.scala = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-scala", - files = { "src/parser.c", "src/scanner.c" }, + rust = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-rust', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@stevanmilic" }, -} -list.scfg = { - install_info = { - url = "https://github.com/rockorager/tree-sitter-scfg", - files = { "src/parser.c" }, - requires_generate_from_grammar = true, + scala = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-scala', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@stevanmilic' }, }, - maintainers = { "@WhyNotHugo" }, -} -list.scheme = { - install_info = { - url = "https://github.com/6cdh/tree-sitter-scheme", - files = { "src/parser.c" }, + scfg = { + install_info = { + url = 'https://github.com/rockorager/tree-sitter-scfg', + files = { 'src/parser.c' }, + requires_generate_from_grammar = true, + }, + maintainers = { '@WhyNotHugo' }, + tier = 3, }, -} -list.scss = { - install_info = { - url = "https://github.com/serenadeai/tree-sitter-scss", - files = { "src/parser.c", "src/scanner.c" }, + scheme = { + install_info = { + url = 'https://github.com/6cdh/tree-sitter-scheme', + files = { 'src/parser.c' }, + }, + tier = 4, }, - maintainers = { "@elianiva" }, -} -list.sflog = { - install_info = { - url = "https://github.com/aheber/tree-sitter-sfapex", - files = { "src/parser.c" }, - location = "sflog", + scss = { + install_info = { + url = 'https://github.com/serenadeai/tree-sitter-scss', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@elianiva' }, }, - maintainers = { "@aheber", "@xixiaofinland" }, -} -list.slang = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-slang", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + sflog = { + install_info = { + url = 'https://github.com/aheber/tree-sitter-sfapex', + files = { 'src/parser.c' }, + location = 'sflog', + }, + maintainers = { '@aheber', '@xixiaofinland' }, + readme_note = 'Salesforce debug log', + tier = 3, + }, + slang = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-slang', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + readme_note = 'Shader Slang', + maintainers = { '@theHamsta' }, + tier = 4, }, - filetype = "shaderslang", - maintainers = { "@theHamsta" }, - experimental = true, -} -list.slim = { - install_info = { - url = "https://github.com/theoo/tree-sitter-slim", - files = { "src/parser.c", "src/scanner.c" }, + slim = { + install_info = { + url = 'https://github.com/theoo/tree-sitter-slim', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@theoo' }, + tier = 3, }, - maintainers = { "@theoo" }, -} -list.slint = { - install_info = { - url = "https://github.com/slint-ui/tree-sitter-slint", - files = { "src/parser.c" }, + slint = { + install_info = { + url = 'https://github.com/slint-ui/tree-sitter-slint', + files = { 'src/parser.c' }, + }, + maintainers = { '@hunger' }, + tier = 3, }, - maintainers = { "@hunger" }, -} -list.smali = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-smali", - files = { "src/parser.c", "src/scanner.c" }, + smali = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-smali', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.snakemake = { - install_info = { - url = "https://github.com/osthomas/tree-sitter-snakemake", - files = { "src/parser.c", "src/scanner.c" }, + snakemake = { + install_info = { + url = 'https://github.com/osthomas/tree-sitter-snakemake', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainer = { '@osthomas' }, + tier = 4, }, - maintainer = { "@osthomas" }, - experimental = true, -} -list.smithy = { - install_info = { - url = "https://github.com/indoorvivants/tree-sitter-smithy", - files = { "src/parser.c" }, + smithy = { + install_info = { + url = 'https://github.com/indoorvivants/tree-sitter-smithy', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq', '@keynmol' }, }, - maintainers = { "@amaanq", "@keynmol" }, -} -list.solidity = { - install_info = { - url = "https://github.com/JoranHonig/tree-sitter-solidity", - files = { "src/parser.c" }, + solidity = { + install_info = { + url = 'https://github.com/JoranHonig/tree-sitter-solidity', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} - -list.soql = { - install_info = { - url = "https://github.com/aheber/tree-sitter-sfapex", - files = { "src/parser.c" }, - location = "soql", + soql = { + install_info = { + url = 'https://github.com/aheber/tree-sitter-sfapex', + files = { 'src/parser.c' }, + location = 'soql', + }, + maintainers = { '@aheber', '@xixiafinland' }, + tier = 3, }, - maintainers = { "@aheber", "@xixiaofinland" }, -} -list.sosl = { - install_info = { - url = "https://github.com/aheber/tree-sitter-sfapex", - files = { "src/parser.c" }, - location = "sosl", + sosl = { + install_info = { + url = 'https://github.com/aheber/tree-sitter-sfapex', + files = { 'src/parser.c' }, + location = 'sosl', + }, + maintainers = { '@aheber', '@xixiafinland' }, }, - maintainers = { "@aheber", "@xixiaofinland" }, -} -list.sourcepawn = { - install_info = { - url = "https://github.com/nilshelmig/tree-sitter-sourcepawn", - files = { "src/parser.c", "src/scanner.c" }, + sourcepawn = { + install_info = { + url = 'https://github.com/nilshelmig/tree-sitter-sourcepawn', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@Sarrus1' }, + tier = 3, }, - maintainers = { "@Sarrus1" }, - tier = 3, -} -list.sparql = { - install_info = { - url = "https://github.com/GordianDziwis/tree-sitter-sparql", - files = { "src/parser.c" }, + sparql = { + install_info = { + url = 'https://github.com/GordianDziwis/tree-sitter-sparql', + files = { 'src/parser.c' }, + }, + maintainers = { '@GordianDziwis' }, }, - maintainers = { "@GordianDziwis" }, -} -list.sql = { - install_info = { - url = "https://github.com/derekstride/tree-sitter-sql", - files = { "src/parser.c", "src/scanner.c" }, - branch = "gh-pages", + sql = { + install_info = { + url = 'https://github.com/derekstride/tree-sitter-sql', + files = { 'src/parser.c', 'src/scanner.c' }, + branch = 'gh-pages', + }, + maintainers = { '@derekstride' }, }, - maintainers = { "@derekstride" }, -} -list.squirrel = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-squirrel", - files = { "src/parser.c", "src/scanner.c" }, + squirrel = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-squirrel', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.ssh_config = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-ssh-config", - files = { "src/parser.c" }, + ssh_config = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-ssh-config', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - filetype = "sshconfig", - maintainers = { "@ObserverOfTime" }, -} -list.starlark = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-starlark", - files = { "src/parser.c", "src/scanner.c" }, + starlark = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-starlark', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - filetype = "bzl", - maintainers = { "@amaanq" }, -} -list.strace = { - install_info = { - url = "https://github.com/sigmaSd/tree-sitter-strace", - files = { "src/parser.c" }, + strace = { + install_info = { + url = 'https://github.com/sigmaSd/tree-sitter-strace', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@amaanq" }, -} -list.styled = { - install_info = { - url = "https://github.com/mskelton/tree-sitter-styled", - files = { "src/parser.c", "src/scanner.c" }, + styled = { + install_info = { + url = 'https://github.com/mskelton/tree-sitter-styled', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@mskelton' }, + tier = 3, }, - maintainers = { "@mskelton" }, -} -list.supercollider = { - install_info = { - url = "https://github.com/madskjeldgaard/tree-sitter-supercollider", - files = { "src/parser.c", "src/scanner.c" }, + supercollider = { + install_info = { + url = 'https://github.com/madskjeldgaard/tree-sitter-supercollider', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@madskjeldgaard' }, }, - maintainers = { "@madskjeldgaard" }, -} -list.superhtml = { - install_info = { - url = "https://github.com/kristoff-it/superhtml", - files = { - "src/parser.c", - "src/scanner.c", + superhtml = { + install_info = { + url = 'https://github.com/kristoff-it/superhtml', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'tree-sitter-superhtml', }, - location = "tree-sitter-superhtml", + maintainers = { '@rockorager' }, + tier = 3, }, - maintainers = { "@rockorager" }, -} -list.surface = { - install_info = { - url = "https://github.com/connorlay/tree-sitter-surface", - files = { "src/parser.c" }, + surface = { + install_info = { + url = 'https://github.com/connorlay/tree-sitter-surface', + files = { 'src/parser.c' }, + }, + maintainers = { '@connorlay' }, }, - filetype = "sface", - maintainers = { "@connorlay" }, -} -list.svelte = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-svelte", - files = { "src/parser.c", "src/scanner.c" }, + svelte = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-svelte', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@amaanq" }, -} -list.sway = { - install_info = { - url = "https://github.com/FuelLabs/tree-sitter-sway.git", - files = { "src/parser.c", "src/scanner.c" }, + sway = { + install_info = { + url = 'https://github.com/FuelLabs/tree-sitter-sway.git', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ribru17' }, + tier = 2, }, - maintainers = { "@ribru17" }, -} -list.swift = { - install_info = { - url = "https://github.com/alex-pinkus/tree-sitter-swift", - files = { "src/parser.c", "src/scanner.c" }, - requires_generate_from_grammar = true, + swift = { + install_info = { + url = 'https://github.com/alex-pinkus/tree-sitter-swift', + files = { 'src/parser.c', 'src/scanner.c' }, + requires_generate_from_grammar = true, + }, + maintainers = { '@alex-pinkus' }, }, - maintainers = { "@alex-pinkus" }, -} -list.sxhkdrc = { - install_info = { - url = "https://github.com/RaafatTurki/tree-sitter-sxhkdrc", - files = { "src/parser.c" }, + sxhkdrc = { + install_info = { + url = 'https://github.com/RaafatTurki/tree-sitter-sxhkdrc', + files = { 'src/parser.c' }, + }, + maintainers = { '@RaafatTurki' }, }, - maintainers = { "@RaafatTurki" }, -} -list.systemtap = { - install_info = { - url = "https://github.com/ok-ryoko/tree-sitter-systemtap", - files = { "src/parser.c" }, + systemtap = { + install_info = { + url = 'https://github.com/ok-ryoko/tree-sitter-systemtap', + files = { 'src/parser.c' }, + }, + maintainers = { '@ok-ryoko' }, + tier = 3, }, - maintainers = { "@ok-ryoko" }, -} -list.t32 = { - install_info = { - url = "https://gitlab.com/xasc/tree-sitter-t32.git", - files = { "src/parser.c", "src/scanner.c" }, + t32 = { + install_info = { + url = 'https://gitlab.com/xasc/tree-sitter-t32.git', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@xasc' }, + tier = 3, }, - filetype = "trace32", - maintainers = { "@xasc" }, -} -list.tablegen = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-tablegen", - files = { "src/parser.c", "src/scanner.c" }, + tablegen = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-tablegen', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - maintainers = { "@amaanq" }, -} -list.tact = { - install_info = { - url = "https://github.com/tact-lang/tree-sitter-tact", - files = { "src/parser.c" }, + tact = { + install_info = { + url = 'https://github.com/tact-lang/tree-sitter-tact', + files = { 'src/parser.c' }, + }, + maintainers = { '@novusnota' }, + tier = 3, }, - maintainers = { "@novusnota" }, -} -list.teal = { - install_info = { - url = "https://github.com/euclidianAce/tree-sitter-teal", - files = { "src/parser.c", "src/scanner.c" }, - requires_generate_from_grammar = true, + teal = { + install_info = { + url = 'https://github.com/euclidianAce/tree-sitter-teal', + files = { 'src/parser.c', 'src/scanner.c' }, + requires_generate_from_grammar = true, + }, + maintainers = { '@euclidianAce' }, }, - maintainers = { "@euclidianAce" }, -} -list.tcl = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-tcl", - files = { "src/parser.c", "src/scanner.c" }, + templ = { + install_info = { + url = 'https://github.com/vrischmann/tree-sitter-templ', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@vrischmann' }, + tier = 3, }, - maintainers = { "@lewis6991" }, -} -list.tera = { - install_info = { - url = "https://github.com/uncenter/tree-sitter-tera", - files = { "src/parser.c", "src/scanner.c" }, + tcl = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-tcl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@lewis6991' }, + tier = 2, }, - maintainers = { "@uncenter" }, -} -list.terraform = { - install_info = { - url = "https://github.com/MichaHoffmann/tree-sitter-hcl", - files = { "src/parser.c", "src/scanner.c" }, - location = "dialects/terraform", + tera = { + install_info = { + url = 'https://github.com/uncenter/tree-sitter-tera', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@uncenter' }, + tier = 2, }, - maintainers = { "@MichaHoffmann" }, -} -list.textproto = { - install_info = { - url = "https://github.com/PorterAtGoogle/tree-sitter-textproto", - files = { "src/parser.c" }, + terraform = { + install_info = { + url = 'https://github.com/MichaHoffmann/tree-sitter-hcl', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'dialects/terraform', + }, + maintainers = { '@MichaHoffmann' }, }, - filetype = "pbtxt", - maintainers = { "@Porter" }, -} -list.thrift = { - install_info = { - url = "https://github.com/duskmoon314/tree-sitter-thrift", - files = { "src/parser.c" }, + textproto = { + install_info = { + url = 'https://github.com/PorterAtGoogle/tree-sitter-textproto', + files = { 'src/parser.c' }, + }, + maintainers = { '@Porter' }, + tier = 3, }, - maintainers = { "@amaanq", "@duskmoon314" }, -} -list.tiger = { - install_info = { - url = "https://github.com/ambroisie/tree-sitter-tiger", - files = { "src/parser.c", "src/scanner.c" }, + thrift = { + install_info = { + url = 'https://github.com/duskmoon314/tree-sitter-thrift', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq', '@duskmoon314' }, }, - maintainers = { "@ambroisie" }, -} -list.tlaplus = { - install_info = { - url = "https://github.com/tlaplus-community/tree-sitter-tlaplus", - files = { "src/parser.c", "src/scanner.c" }, + tiger = { + install_info = { + url = 'https://github.com/ambroisie/tree-sitter-tiger', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ambroisie' }, }, - filetype = "tla", - maintainers = { "@ahelwer", "@susliko" }, -} -list.tmux = { - install_info = { - url = "https://github.com/Freed-Wu/tree-sitter-tmux", - files = { "src/parser.c" }, + tlaplus = { + install_info = { + url = 'https://github.com/tlaplus-community/tree-sitter-tlaplus', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@ahelwer', '@susliko' }, }, - maintainers = { "@Freed-Wu" }, -} -list.todotxt = { - install_info = { - url = "https://github.com/arnarg/tree-sitter-todotxt", - files = { "src/parser.c" }, + tmux = { + install_info = { + url = 'https://github.com/Freed-Wu/tree-sitter-tmux', + files = { 'src/parser.c' }, + }, + maintainers = { '@Freed-Wu' }, + tier = 3, }, - maintainers = { "@arnarg" }, - experimental = true, -} -list.toml = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-toml", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + todotxt = { + install_info = { + url = 'https://github.com/arnarg/tree-sitter-todotxt', + files = { 'src/parser.c' }, + }, + maintainers = { '@arnarg' }, + tier = 4, }, - maintainers = { "@tk-shirasaka" }, -} -list.tsv = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-csv", - files = { "src/parser.c" }, - location = "tsv", + toml = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-toml', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@tk-shirasaka' }, }, - maintainers = { "@amaanq" }, -} -list.tsx = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-typescript", - files = { "src/parser.c", "src/scanner.c" }, - location = "tsx", - generate_requires_npm = true, + tsv = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-csv', + files = { 'src/parser.c' }, + location = 'tsv', + }, + maintainers = { '@amaanq' }, + tier = 2, }, - filetype = "typescriptreact", - maintainers = { "@steelsojka" }, -} -list.turtle = { - install_info = { - url = "https://github.com/GordianDziwis/tree-sitter-turtle", - files = { "src/parser.c" }, + tsx = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-typescript', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'tsx', + generate_requires_npm = true, + }, + maintainers = { '@steelsojka' }, }, - maintainers = { "@GordianDziwis" }, -} -list.twig = { - install_info = { - url = "https://github.com/gbprod/tree-sitter-twig", - files = { "src/parser.c" }, + turtle = { + install_info = { + url = 'https://github.com/GordianDziwis/tree-sitter-turtle', + files = { 'src/parser.c' }, + }, + maintainers = { '@GordianDziwis' }, }, - maintainers = { "@gbprod" }, -} -list.typescript = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-typescript", - files = { "src/parser.c", "src/scanner.c" }, - location = "typescript", - generate_requires_npm = true, + twig = { + install_info = { + url = 'https://github.com/gbprod/tree-sitter-twig', + files = { 'src/parser.c' }, + }, + maintainers = { '@gbprod' }, }, - maintainers = { "@steelsojka" }, -} -list.typespec = { - install_info = { - url = "https://github.com/happenslol/tree-sitter-typespec", - files = { "src/parser.c" }, + typescript = { + install_info = { + url = 'https://github.com/tree-sitter/tree-sitter-typescript', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'typescript', + generate_requires_npm = true, + }, + maintainers = { '@steelsojka' }, }, - maintainers = { "@happenslol" }, -} -list.typoscript = { - install_info = { - url = "https://github.com/Teddytrombone/tree-sitter-typoscript", - files = { "src/parser.c" }, + typespec = { + install_info = { + url = 'https://github.com/happenslol/tree-sitter-typespec', + files = { 'src/parser.c' }, + }, + maintainers = { '@happenslol' }, + tier = 3, }, - maintainers = { "@Teddytrombone" }, -} -list.typst = { - install_info = { - url = "https://github.com/uben0/tree-sitter-typst", - files = { "src/parser.c", "src/scanner.c" }, + typoscript = { + install_info = { + url = 'https://github.com/Teddytrombone/tree-sitter-typoscript', + files = { 'src/parser.c' }, + }, + maintainers = { '@Teddytrombone' }, + tier = 3, }, - maintainers = { "@uben0", "@RaafatTurki" }, -} -list.udev = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-udev", - files = { "src/parser.c" }, + typst = { + install_info = { + url = 'https://github.com/uben0/tree-sitter-typst', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@uben0', '@RaafatTurki' }, + tier = 3, }, - filetype = "udevrules", - maintainers = { "@ObserverOfTime" }, -} -list.ungrammar = { - install_info = { - url = "https://github.com/Philipp-M/tree-sitter-ungrammar", - files = { "src/parser.c" }, + udev = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-udev', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@Philipp-M", "@amaanq" }, -} -list.unison = { - install_info = { - url = "https://github.com/kylegoetz/tree-sitter-unison", - files = { "src/parser.c", "src/scanner.c" }, - requires_generate_from_grammar = true, + ungrammar = { + install_info = { + url = 'https://github.com/Philipp-M/tree-sitter-ungrammar', + files = { 'src/parser.c' }, + }, + maintainers = { '@Philipp-M', '@amaanq' }, }, - maintainers = { "@tapegram" }, -} -list.usd = { - install_info = { - url = "https://github.com/ColinKennedy/tree-sitter-usd", - files = { "src/parser.c" }, + unison = { + install_info = { + url = 'https://github.com/kylegoetz/tree-sitter-unison', + files = { 'src/parser.c', 'src/scanner.c' }, + requires_generate_from_grammar = true, + }, + maintainers = { '@tapegram' }, + tier = 4, }, - maintainers = { "@ColinKennedy" }, -} -list.uxntal = { - install_info = { - url = "https://github.com/amaanq/tree-sitter-uxntal", - files = { "src/parser.c", "src/scanner.c" }, + usd = { + install_info = { + url = 'https://github.com/ColinKennedy/tree-sitter-usd', + files = { 'src/parser.c' }, + }, + maintainers = { '@ColinKennedy' }, }, - filetype = "tal", - maintainers = { "@amaanq" }, - readme_name = "uxn tal", -} -list.v = { - install_info = { - url = "https://github.com/vlang/v-analyzer", - files = { "src/parser.c" }, - location = "tree_sitter_v", + uxntal = { + install_info = { + url = 'https://github.com/amaanq/tree-sitter-uxntal', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, }, - filetype = "vlang", - maintainers = { "@kkharji", "@amaanq" }, -} -list.vala = { - install_info = { - url = "https://github.com/vala-lang/tree-sitter-vala", - files = { "src/parser.c" }, + v = { + install_info = { + url = 'https://github.com/vlang/v-analyzer', + files = { 'src/parser.c' }, + location = 'tree_sitter_v', + }, + maintainers = { '@kkharji', '@amaanq' }, }, - maintainers = { "@Prince781" }, -} -list.vento = { - install_info = { - url = "https://github.com/ventojs/tree-sitter-vento", - files = { "src/parser.c", "src/scanner.c" }, + vala = { + install_info = { + url = 'https://github.com/vala-lang/tree-sitter-vala', + files = { 'src/parser.c' }, + }, + maintainers = { '@Prince781' }, }, - filetype = "vto", - maintainers = { "@wrapperup", "@oscarotero" }, -} -list.verilog = { - install_info = { - url = "https://github.com/gmlarumbe/tree-sitter-systemverilog", - files = { "src/parser.c" }, + vento = { + install_info = { + url = 'https://github.com/ventojs/tree-sitter-vento', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@wrapperup', '@oscarotero' }, + tier = 3, }, - maintainers = { "@zhangwwpeng" }, -} -list.vhdl = { - install_info = { - url = "https://github.com/jpt13653903/tree-sitter-vhdl", - files = { "src/parser.c", "src/scanner.c" }, + verilog = { + install_info = { + url = 'https://github.com/gmlarumbe/tree-sitter-systemverilog', + files = { 'src/parser.c' }, + }, + maintainers = { '@zhangwwpeng' }, }, - maintainers = { "@jpt13653903" }, -} -list.vhs = { - install_info = { - url = "https://github.com/charmbracelet/tree-sitter-vhs", - files = { "src/parser.c" }, + vhdl = { + install_info = { + url = 'https://github.com/jpt13653903/tree-sitter-vhdl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@jpt13653903' }, + tier = 3, }, - filetype = "tape", - maintainers = { "@caarlos0" }, -} -list.vim = { - install_info = { - url = "https://github.com/neovim/tree-sitter-vim", - files = { "src/parser.c", "src/scanner.c" }, + vhs = { + install_info = { + url = 'https://github.com/charmbracelet/tree-sitter-vhs', + files = { 'src/parser.c' }, + }, + maintainers = { '@caarlos0' }, }, - maintainers = { "@clason" }, -} -list.vimdoc = { - install_info = { - url = "https://github.com/neovim/tree-sitter-vimdoc", - files = { "src/parser.c" }, + vim = { + install_info = { + url = 'https://github.com/neovim/tree-sitter-vim', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@clason' }, + tier = 1, }, - filetype = "help", - maintainers = { "@clason" }, -} -list.vrl = { - install_info = { - url = "https://github.com/belltoy/tree-sitter-vrl", - files = { "src/parser.c" }, + vimdoc = { + install_info = { + url = 'https://github.com/neovim/tree-sitter-vimdoc', + files = { 'src/parser.c' }, + }, + maintainers = { '@clason' }, + tier = 1, }, - maintainers = { "@belltoy" }, -} -list.vue = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-vue", - files = { "src/parser.c", "src/scanner.c" }, - branch = "main", + vrl = { + install_info = { + url = 'https://github.com/belltoy/tree-sitter-vrl', + files = { 'src/parser.c' }, + }, + maintainers = { '@belltoy' }, + tier = 3, }, - maintainers = { "@WhyNotHugo", "@lucario387" }, -} -list.wgsl = { - install_info = { - url = "https://github.com/szebniok/tree-sitter-wgsl", - files = { "src/parser.c", "src/scanner.c" }, + vue = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-vue', + files = { 'src/parser.c', 'src/scanner.c' }, + branch = 'main', + }, + maintainers = { '@WhyNotHugo', '@lucario387' }, + tier = 2, }, - maintainers = { "@szebniok" }, -} -list.wgsl_bevy = { - install_info = { - url = "https://github.com/theHamsta/tree-sitter-wgsl-bevy", - files = { "src/parser.c", "src/scanner.c" }, - generate_requires_npm = true, + wing = { + install_info = { + url = 'https://github.com/winglang/tree-sitter-wing', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@gshpychka', '@MarkMcCulloh' }, + tier = 3, }, - maintainers = { "@theHamsta" }, -} -list.wing = { - install_info = { - url = "https://github.com/winglang/tree-sitter-wing", - files = { "src/parser.c", "src/scanner.c" }, + wgsl = { + install_info = { + url = 'https://github.com/szebniok/tree-sitter-wgsl', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@szebniok' }, }, - maintainers = { "@gshpychka", "@MarkMcCulloh" }, -} -list.wit = { - install_info = { - url = "https://github.com/liamwh/tree-sitter-wit", - files = { "src/parser.c" }, + wgsl_bevy = { + install_info = { + url = 'https://github.com/theHamsta/tree-sitter-wgsl-bevy', + files = { 'src/parser.c', 'src/scanner.c' }, + generate_requires_npm = true, + }, + maintainers = { '@theHamsta' }, }, - maintainers = { "@liamwh" }, -} -list.xcompose = { - install_info = { - url = "https://github.com/ObserverOfTime/tree-sitter-xcompose", - files = { "src/parser.c" }, + wit = { + install_info = { + url = 'https://github.com/liamwh/tree-sitter-wit', + files = { 'src/parser.c' }, + }, + maintainers = { '@liamwh' }, + tier = 3, }, - maintainers = { "@ObserverOfTime" }, -} - -list.xml = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-xml", - files = { "src/parser.c", "src/scanner.c" }, - location = "xml", + xcompose = { + install_info = { + url = 'https://github.com/ObserverOfTime/tree-sitter-xcompose', + files = { 'src/parser.c' }, + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - maintainers = { "@ObserverOfTime" }, -} -list.xresources = { - install_info = { - url = "https://github.com/ValdezFOmar/tree-sitter-xresources", - files = { "src/parser.c" }, + xml = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-xml', + files = { 'src/parser.c', 'src/scanner.c' }, + location = 'xml', + }, + maintainers = { '@ObserverOfTime' }, + tier = 2, }, - filetype = "xdefaults", - maintainers = { "@ValdezFOmar" }, -} -list.yaml = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-yaml", - files = { "src/parser.c", "src/scanner.c" }, + xresources = { + install_info = { + url = 'https://github.com/ValdezFOmar/tree-sitter-xresources', + files = { 'src/parser.c' }, + }, + filetype = 'xdefaults', + maintainers = { '@ValdezFOmar' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.yang = { - install_info = { - url = "https://github.com/Hubro/tree-sitter-yang", - files = { "src/parser.c" }, + yaml = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-yaml', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@amaanq' }, + tier = 2, }, - maintainers = { "@Hubro" }, -} -list.yuck = { - install_info = { - url = "https://github.com/Philipp-M/tree-sitter-yuck", - files = { "src/parser.c", "src/scanner.c" }, + yang = { + install_info = { + url = 'https://github.com/Hubro/tree-sitter-yang', + files = { 'src/parser.c' }, + }, + maintainers = { '@Hubro' }, }, - maintainers = { "@Philipp-M", "@amaanq" }, -} -list.zathurarc = { - install_info = { - url = "https://github.com/Freed-Wu/tree-sitter-zathurarc", - files = { "src/parser.c" }, + yuck = { + install_info = { + url = 'https://github.com/Philipp-M/tree-sitter-yuck', + files = { 'src/parser.c', 'src/scanner.c' }, + }, + maintainers = { '@Philipp-M', '@amaanq' }, }, - maintainers = { "@Freed-Wu" }, -} -list.zig = { - install_info = { - url = "https://github.com/tree-sitter-grammars/tree-sitter-zig", - files = { "src/parser.c" }, + zathurarc = { + install_info = { + url = 'https://github.com/Freed-Wu/tree-sitter-zathurarc', + files = { 'src/parser.c' }, + }, + maintainers = { '@Freed-Wu' }, + tier = 3, }, - maintainers = { "@amaanq" }, -} -list.ziggy = { - install_info = { - url = "https://github.com/kristoff-it/ziggy", - files = { "src/parser.c" }, - location = "tree-sitter-ziggy", + zig = { + install_info = { + url = 'https://github.com/tree-sitter-grammars/tree-sitter-zig', + files = { 'src/parser.c' }, + }, + maintainers = { '@amaanq' }, + tier = 1, }, - maintainers = { "@rockorager" }, -} -list.ziggy_schema = { - install_info = { - url = "https://github.com/kristoff-it/ziggy", - files = { "src/parser.c" }, - location = "tree-sitter-ziggy-schema", + ziggy = { + install_info = { + url = 'https://github.com/kristoff-it/ziggy', + files = { 'src/parser.c' }, + location = 'tree-sitter-ziggy', + }, + maintainers = { '@rockorager' }, + tier = 3, }, - maintainers = { "@rockorager" }, -} -list.templ = { - install_info = { - url = "https://github.com/vrischmann/tree-sitter-templ", - files = { "src/parser.c", "src/scanner.c" }, + ziggy_schema = { + install_info = { + url = 'https://github.com/kristoff-it/ziggy', + files = { 'src/parser.c' }, + location = 'tree-sitter-ziggy-schema', + }, + maintainers = { '@rockorager' }, + tier = 3, }, - maintainers = { "@vrischmann" }, -} - -local M = { - list = list, } -function M.ft_to_lang(ft) - local result = ts.language.get_lang(ft) - if result then - return result - else - ft = vim.split(ft, ".", { plain = true })[1] - return ts.language.get_lang(ft) or ft - end -end - -- Get a list of all available parsers +---@param tier integer? only get parsers of specified tier ---@return string[] -function M.available_parsers() - local parsers = vim.tbl_keys(M.list) +function M.get_available(tier) + local parsers = vim.tbl_keys(M.configs) table.sort(parsers) - if vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1 then - return parsers - else - return vim.tbl_filter(function(p) ---@param p string - return not M.list[p].install_info.requires_generate_from_grammar + if tier then + parsers = vim.iter.filter(function(p) + return M.configs[p].tier == tier end, parsers) end -end - -function M.get_parser_configs() - return M.list -end - -local parser_files - -function M.reset_cache() - parser_files = setmetatable({}, { - __index = function(tbl, key) - rawset(tbl, key, api.nvim_get_runtime_file("parser/" .. key .. ".*", false)) - return rawget(tbl, key) - end, - }) -end - -M.reset_cache() - -function M.has_parser(lang) - lang = lang or M.get_buf_lang(api.nvim_get_current_buf()) - - if not lang or #lang == 0 then - return false - end - -- HACK: nvim internal API - if vim._ts_has_language(lang) then - return true - end - return #parser_files[lang] > 0 -end - -function M.get_parser(bufnr, lang) - bufnr = bufnr or api.nvim_get_current_buf() - lang = lang or M.get_buf_lang(bufnr) - - if M.has_parser(lang) then - return ts.get_parser(bufnr, lang) + if vim.fn.executable('tree-sitter') == 0 or vim.fn.executable('node') == 0 then + parsers = vim.iter.filter(function(p) + return not M.configs[p].install_info.requires_generate_from_grammar + end, parsers) end -end - --- @deprecated This is only kept for legacy purposes. --- All root nodes should be accounted for. -function M.get_tree_root(bufnr) - bufnr = bufnr or api.nvim_get_current_buf() - return M.get_parser(bufnr):parse()[1]:root() -end - --- Gets the language of a given buffer ----@param bufnr number? or current buffer ----@return string -function M.get_buf_lang(bufnr) - bufnr = bufnr or api.nvim_get_current_buf() - return M.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft")) + return parsers end return M diff --git a/lua/nvim-treesitter/query.lua b/lua/nvim-treesitter/query.lua index 4aba9f2fd..f7e5205f7 100644 --- a/lua/nvim-treesitter/query.lua +++ b/lua/nvim-treesitter/query.lua @@ -1,154 +1,7 @@ -local api = vim.api -local ts = require "nvim-treesitter.compat" -local tsrange = require "nvim-treesitter.tsrange" -local utils = require "nvim-treesitter.utils" -local parsers = require "nvim-treesitter.parsers" -local caching = require "nvim-treesitter.caching" - local M = {} local EMPTY_ITER = function() end -M.built_in_query_groups = { "highlights", "locals", "folds", "indents", "injections" } - --- Creates a function that checks whether a given query exists --- for a specific language. ----@param query string ----@return fun(string): boolean -local function get_query_guard(query) - return function(lang) - return M.has_query_files(lang, query) - end -end - -for _, query in ipairs(M.built_in_query_groups) do - M["has_" .. query] = get_query_guard(query) -end - ----@return string[] -function M.available_query_groups() - local query_files = api.nvim_get_runtime_file("queries/*/*.scm", true) - local groups = {} - for _, f in ipairs(query_files) do - groups[vim.fn.fnamemodify(f, ":t:r")] = true - end - local list = {} - for k, _ in pairs(groups) do - table.insert(list, k) - end - return list -end - -do - local query_cache = caching.create_buffer_cache() - - local function update_cached_matches(bufnr, changed_tick, query_group) - query_cache.set(query_group, bufnr, { - tick = changed_tick, - cache = M.collect_group_results(bufnr, query_group) or {}, - }) - end - - ---@param bufnr integer - ---@param query_group string - ---@return any - function M.get_matches(bufnr, query_group) - bufnr = bufnr or api.nvim_get_current_buf() - local cached_local = query_cache.get(query_group, bufnr) - if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then - update_cached_matches(bufnr, api.nvim_buf_get_changedtick(bufnr), query_group) - end - - return query_cache.get(query_group, bufnr).cache - end -end - ----@param lang string ----@param query_name string ----@return string[] -local function runtime_queries(lang, query_name) - return api.nvim_get_runtime_file(string.format("queries/%s/%s.scm", lang, query_name), true) or {} -end - ----@type table> -local query_files_cache = {} - ----@param lang string ----@param query_name string ----@return boolean -function M.has_query_files(lang, query_name) - if not query_files_cache[lang] then - query_files_cache[lang] = {} - end - if query_files_cache[lang][query_name] == nil then - local files = runtime_queries(lang, query_name) - query_files_cache[lang][query_name] = files and #files > 0 - end - return query_files_cache[lang][query_name] -end - -do - local mt = {} - mt.__index = function(tbl, key) - if rawget(tbl, key) == nil then - rawset(tbl, key, {}) - end - return rawget(tbl, key) - end - - -- cache will auto set the table for each lang if it is nil - ---@type table> - local cache = setmetatable({}, mt) - - -- Same as `vim.treesitter.query` except will return cached values - ---@param lang string - ---@param query_name string - function M.get_query(lang, query_name) - if cache[lang][query_name] == nil then - cache[lang][query_name] = ts.get_query(lang, query_name) - end - - return cache[lang][query_name] - end - - -- 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 none are present, will reload everything - ---@param lang? string - ---@param query_name? string - function M.invalidate_query_cache(lang, query_name) - if lang and query_name then - cache[lang][query_name] = nil - if query_files_cache[lang] then - query_files_cache[lang][query_name] = nil - end - elseif lang and not query_name then - query_files_cache[lang] = nil - for query_name0, _ in pairs(cache[lang]) do - M.invalidate_query_cache(lang, query_name0) - end - elseif not lang and not query_name then - query_files_cache = {} - for lang0, _ in pairs(cache) do - for query_name0, _ in pairs(cache[lang0]) do - M.invalidate_query_cache(lang0, query_name0) - end - end - else - error "Cannot have query_name by itself!" - end - end -end - --- This function is meant for an autocommand and not to be used. Only use if file is a query file. ----@param fname string -function M.invalidate_query_file(fname) - local fnamemodify = vim.fn.fnamemodify - M.invalidate_query_cache(fnamemodify(fname, ":p:h:t"), fnamemodify(fname, ":t:r")) -end - ---@class QueryInfo ---@field root TSNode ---@field source integer @@ -161,13 +14,13 @@ end ---@param root_lang string|nil ---@return Query|nil, QueryInfo|nil local function prepare_query(bufnr, query_name, root, root_lang) - local buf_lang = parsers.get_buf_lang(bufnr) - + local ft = vim.bo[bufnr].filetype + local buf_lang = vim.treesitter.language.get_lang(ft) or ft if not buf_lang then return end - local parser = parsers.get_parser(bufnr, buf_lang) + local parser = vim.treesitter.get_parser(bufnr, buf_lang) if not parser then return end @@ -198,7 +51,7 @@ local function prepare_query(bufnr, query_name, root, root_lang) return end - local query = M.get_query(root_lang, query_name) + local query = vim.treesitter.query.get(root_lang, query_name) if not query then return end @@ -241,7 +94,7 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) ---@return string[] local function split(to_split) local t = {} - for str in string.gmatch(to_split, "([^.]+)") do + for str in string.gmatch(to_split, '([^.]+)') do table.insert(t, str) end @@ -259,9 +112,9 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) for id, node in pairs(match) do local name = query.captures[id] -- name of the capture in the query if name ~= nil then - local path = split(name .. ".node") + local path = split(name .. '.node') M.insert_to_path(prepared_match, path, node) - local metadata_path = split(name .. ".metadata") + local metadata_path = split(name .. '.metadata') M.insert_to_path(prepared_match, metadata_path, metadata[id]) end end @@ -272,16 +125,9 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) if preds then for _, pred in pairs(preds) do -- functions - if pred[1] == "set!" and type(pred[2]) == "string" then + if pred[1] == 'set!' and type(pred[2]) == 'string' then M.insert_to_path(prepared_match, split(pred[2]), pred[3]) end - if pred[1] == "make-range!" and type(pred[2]) == "string" and #pred == 4 then - M.insert_to_path( - prepared_match, - split(pred[2] .. ".node"), - tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]]) - ) - end end end @@ -291,103 +137,6 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) return iterator end --- 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 --- Can also be a nested capture like @definition.function to get all nodes defining a function. --- ----@param bufnr integer the buffer ----@param captures string|string[] ----@param query_group string the name of query group (highlights or injections for example) ----@param root TSNode|nil node from where to start the search ----@param lang string|nil the language from where to get the captures. ---- Root nodes can have several languages. ----@return table|nil -function M.get_capture_matches(bufnr, captures, query_group, root, lang) - if type(captures) == "string" then - captures = { captures } - end - local strip_captures = {} ---@type string[] - for i, capture in ipairs(captures) do - if capture:sub(1, 1) ~= "@" then - error 'Captures must start with "@"' - return - end - -- Remove leading "@". - strip_captures[i] = capture:sub(2) - end - - local matches = {} - for match in M.iter_group_results(bufnr, query_group, root, lang) do - for _, capture in ipairs(strip_captures) do - local insert = utils.get_at_path(match, capture) - if insert then - table.insert(matches, insert) - end - end - end - return matches -end - -function M.iter_captures(bufnr, query_name, root, lang) - local query, params = prepare_query(bufnr, query_name, root, lang) - if not query then - return EMPTY_ITER - end - assert(params) - - local iter = query:iter_captures(params.root, params.source, params.start, params.stop) - - local function wrapped_iter() - local id, node, metadata = iter() - if not id then - return - end - - local name = query.captures[id] - if string.sub(name, 1, 1) == "_" then - return wrapped_iter() - end - - return name, node, metadata - end - - return wrapped_iter -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) - if string.sub(capture_string, 1, 1) == "@" then - --remove leading "@" - capture_string = string.sub(capture_string, 2) - end - - local best ---@type table|nil - local best_score ---@type number - - for maybe_match in M.iter_group_results(bufnr, query_group, root) do - local match = utils.get_at_path(maybe_match, capture_string) - - if match and filter_predicate(match) then - local current_score = scoring_function(match) - if not best then - best = match - best_score = current_score - end - if current_score > best_score then - best = match - best_score = current_score - end - end - end - return best -end - ---Iterates matches from a query file. ---@param bufnr integer the buffer ---@param query_group string the query file to use @@ -413,41 +162,4 @@ function M.collect_group_results(bufnr, query_group, root, lang) return matches end ----@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. ----@param bufnr integer The buffer ----@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. ---- The function can return `nil` to ignore that tree. ----@param query_type string? The query to get the capture from. This is ignored if a function is provided ---- for the capture argument. ----@return table[] -function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type) - ---@type CaptureResFn - local type_fn - if type(capture_or_fn) == "function" then - type_fn = capture_or_fn - else - type_fn = function(_, _, _) - return capture_or_fn, query_type - end - end - local parser = parsers.get_parser(bufnr) - local matches = {} - - if parser then - parser:for_each_tree(function(tree, lang_tree) - local lang = lang_tree:lang() - local capture, type_ = type_fn(lang, tree, lang_tree) - - if capture then - vim.list_extend(matches, M.get_capture_matches(bufnr, capture, type_, tree:root(), lang) or {}) - end - end) - end - - return matches -end - return M diff --git a/lua/nvim-treesitter/query_predicates.lua b/lua/nvim-treesitter/query_predicates.lua deleted file mode 100644 index 7539170dc..000000000 --- a/lua/nvim-treesitter/query_predicates.lua +++ /dev/null @@ -1,167 +0,0 @@ -local query = require "vim.treesitter.query" - -local html_script_type_languages = { - ["importmap"] = "json", - ["module"] = "javascript", - ["application/ecmascript"] = "javascript", - ["text/ecmascript"] = "javascript", -} - -local non_filetype_match_injection_language_aliases = { - ex = "elixir", - pl = "perl", - sh = "bash", - uxn = "uxntal", - ts = "typescript", -} - --- compatibility shim for breaking change on nightly/0.11 -local opts = vim.fn.has "nvim-0.10" == 1 and { force = true, all = false } or true - -local function get_parser_from_markdown_info_string(injection_alias) - local match = vim.filetype.match { filename = "a." .. injection_alias } - return match or non_filetype_match_injection_language_aliases[injection_alias] or injection_alias -end - -local function error(str) - vim.api.nvim_err_writeln(str) -end - -local function valid_args(name, pred, count, strict_count) - local arg_count = #pred - 1 - - if strict_count then - if arg_count ~= count then - error(string.format("%s must have exactly %d arguments", name, count)) - return false - end - elseif arg_count < count then - error(string.format("%s must have at least %d arguments", name, count)) - return false - end - - return true -end - ----@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 - return - end - - local node = match[pred[2]] ---@type TSNode - local n = tonumber(pred[3]) - if node and node:parent() and node:parent():named_child_count() > n then - return node:parent():named_child(n) == node - end - - return false -end, opts) - ----@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 - return - end - - -- Avoid circular dependencies - local locals = require "nvim-treesitter.locals" - local node = match[pred[2]] - local types = { unpack(pred, 3) } - - if not node then - return true - end - - local _, _, kind = locals.find_definition(node, bufnr) - - return vim.tbl_contains(types, kind) -end, opts) - ----@param match (TSNode|nil)[] ----@param _pattern string ----@param _bufnr integer ----@param pred string[] ----@return boolean|nil -query.add_predicate("kind-eq?", function(match, _pattern, _bufnr, pred) - if not valid_args(pred[1], pred, 2) then - return - end - - local node = match[pred[2]] - local types = { unpack(pred, 3) } - - if not node then - return true - end - - return vim.tbl_contains(types, node:type()) -end, opts) - ----@param match (TSNode|nil)[] ----@param _ string ----@param bufnr integer ----@param pred string[] ----@return boolean|nil -query.add_directive("set-lang-from-mimetype!", function(match, _, bufnr, pred, metadata) - local capture_id = pred[2] - local node = match[capture_id] - if not node then - return - end - local type_attr_value = vim.treesitter.get_node_text(node, bufnr) - local configured = html_script_type_languages[type_attr_value] - if configured then - metadata["injection.language"] = configured - else - local parts = vim.split(type_attr_value, "/", {}) - metadata["injection.language"] = parts[#parts] - end -end, opts) - ----@param match (TSNode|nil)[] ----@param _ string ----@param bufnr integer ----@param pred string[] ----@return boolean|nil -query.add_directive("set-lang-from-info-string!", function(match, _, bufnr, pred, metadata) - local capture_id = pred[2] - local node = match[capture_id] - if not node then - return - end - local injection_alias = vim.treesitter.get_node_text(node, bufnr):lower() - metadata["injection.language"] = get_parser_from_markdown_info_string(injection_alias) -end, opts) - --- Just avoid some annoying warnings for this directive -query.add_directive("make-range!", function() end, opts) - ---- transform node text to lower case (e.g., to make @injection.language case insensitive) ---- ----@param match (TSNode|nil)[] ----@param _ string ----@param bufnr integer ----@param pred string[] ----@return boolean|nil -query.add_directive("downcase!", function(match, _, bufnr, pred, metadata) - local id = pred[2] - local node = match[id] - if not node then - return - end - - local text = vim.treesitter.get_node_text(node, bufnr, { metadata = metadata[id] }) or "" - if not metadata[id] then - metadata[id] = {} - end - metadata[id].text = string.lower(text) -end, opts) diff --git a/lua/nvim-treesitter/shell_cmds.lua b/lua/nvim-treesitter/shell_cmds.lua new file mode 100644 index 000000000..2dc7f8748 --- /dev/null +++ b/lua/nvim-treesitter/shell_cmds.lua @@ -0,0 +1,255 @@ +local uv = vim.loop +local utils = require('nvim-treesitter.utils') + +local iswin = uv.os_uname().sysname == 'Windows_NT' + +local M = {} + +---@param executables string[] +---@return string|nil +function M.select_executable(executables) + return vim.tbl_filter(function(c) ---@param c string + return c ~= vim.NIL and vim.fn.executable(c) == 1 + end, executables)[1] +end + +-- Returns the compiler arguments based on the compiler and OS +---@param repo InstallInfo +---@param compiler string +---@return string[] +function M.select_compiler_args(repo, compiler) + if compiler:find('cl$') or compiler:find('cl.exe$') then + return { + '/Fe:', + 'parser.so', + '/Isrc', + repo.files, + '-Os', + '/utf-8', + '/LD', + } + elseif compiler:find('zig$') or compiler:find('zig.exe$') then + return { + 'c++', + '-o', + 'parser.so', + repo.files, + '-lc', + '-Isrc', + '-shared', + '-Os', + } + else + local args = { + '-o', + 'parser.so', + '-I./src', + repo.files, + '-Os', + } + if uv.os_uname().sysname == 'Darwin' then + table.insert(args, '-bundle') + else + table.insert(args, '-shared') + end + if + #vim.tbl_filter(function(file) ---@param file string + local ext = vim.fn.fnamemodify(file, ':e') + return ext == 'cc' or ext == 'cpp' or ext == 'cxx' + end, repo.files) > 0 + then + table.insert(args, '-lstdc++') + end + if not iswin then + table.insert(args, '-fPIC') + end + return args + end +end + +-- Returns the compile command based on the OS and user options +---@param repo InstallInfo +---@param cc string +---@param compile_location string +---@return Command +function M.select_compile_command(repo, cc, compile_location) + local make = M.select_executable({ 'gmake', 'make' }) + if cc:find('cl$') or cc:find('cl.exe$') or not repo.use_makefile or iswin or not make then + return { + cmd = cc, + info = 'Compiling...', + err = 'Error during compilation', + opts = { + args = vim.tbl_flatten(M.select_compiler_args(repo, cc)), + cwd = compile_location, + }, + } + else + return { + cmd = make, + info = 'Compiling...', + err = 'Error during compilation', + opts = { + args = { + '--makefile=' .. utils.get_package_path('scripts', 'compile_parsers.makefile'), + 'CC=' .. cc, + }, + cwd = compile_location, + }, + } + end +end + +---@param repo InstallInfo +---@param project_name string +---@param cache_dir string +---@param revision string|nil +---@param prefer_git boolean +---@return table +function M.select_download_commands(repo, project_name, cache_dir, revision, prefer_git) + 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_gitlab = repo.url:find('gitlab.com', 1, true) + local project_dir = utils.join_path(cache_dir, project_name) + + revision = revision or repo.branch or 'master' + + if can_use_tar and (is_github or is_gitlab) and not prefer_git then + local url = repo.url:gsub('.git$', '') + + local dir_rev = revision + if is_github and revision:find('^v%d') then + dir_rev = revision:sub(2) + end + + local temp_dir = project_dir .. '-tmp' + + return { + { + cmd = function() + vim.fn.delete(temp_dir, 'rf') + end, + }, + { + cmd = 'curl', + info = 'Downloading ' .. project_name .. '...', + err = 'Error during download, please verify your internet connection', + opts = { + args = { + '--silent', + '-L', -- follow redirects + is_github and url .. '/archive/' .. revision .. '.tar.gz' + or url + .. '/-/archive/' + .. revision + .. '/' + .. project_name + .. '-' + .. revision + .. '.tar.gz', + '--output', + project_name .. '.tar.gz', + }, + cwd = cache_dir, + }, + }, + { + cmd = function() + --TODO(clason): use vim.fn.mkdir(temp_dir, 'p') in case stdpath('cache') is not created + uv.fs_mkdir(temp_dir, 493) + end, + info = 'Creating temporary directory', + err = 'Could not create ' .. project_name .. '-tmp', + }, + { + cmd = 'tar', + info = 'Extracting ' .. project_name .. '...', + err = 'Error during tarball extraction.', + opts = { + args = { + '-xvzf', + project_name .. '.tar.gz', + '-C', + project_name .. '-tmp', + }, + cwd = cache_dir, + }, + }, + { + cmd = function() + uv.fs_unlink(project_dir .. '.tar.gz') + end, + }, + { + cmd = function() + uv.fs_rename( + utils.join_path(temp_dir, url:match('[^/]-$') .. '-' .. dir_rev), + project_dir + ) + end, + }, + { + cmd = function() + vim.fn.delete(temp_dir, 'rf') + end, + }, + } + else + local git_dir = project_dir + local clone_error = 'Error during download, please verify your internet connection' + + return { + { + cmd = 'git', + info = 'Downloading ' .. project_name .. '...', + err = clone_error, + opts = { + args = { + 'clone', + repo.url, + project_name, + }, + cwd = cache_dir, + }, + }, + { + cmd = 'git', + info = 'Checking out locked revision', + err = 'Error while checking out revision', + opts = { + args = { + 'checkout', + revision, + }, + cwd = git_dir, + }, + }, + } + end +end + +--TODO(clason): only needed for iter_cmd_sync -> replace with uv.spawn? + +-- Convert path for cmd.exe on Windows (needed when shellslash is set) +---@param p string +---@return string +local function cmdpath(p) + return vim.o.shellslash and p:gsub('/', '\\') or p +end + +---@param dir string +---@param command string +---@return string command +function M.make_directory_change_for_command(dir, command) + if iswin then + if string.find(vim.o.shell, 'cmd') ~= nil then + return string.format('pushd %s & %s & popd', cmdpath(dir), command) + else + return string.format('pushd %s ; %s ; popd', cmdpath(dir), command) + end + else + return string.format('cd %s;\n %s', dir, command) + end +end + +return M diff --git a/lua/nvim-treesitter/shell_command_selectors.lua b/lua/nvim-treesitter/shell_command_selectors.lua deleted file mode 100644 index ee1d64745..000000000 --- a/lua/nvim-treesitter/shell_command_selectors.lua +++ /dev/null @@ -1,368 +0,0 @@ -local fn = vim.fn -local utils = require "nvim-treesitter.utils" -local uv = vim.uv or vim.loop - --- Convert path for cmd.exe on Windows. --- This is needed when vim.opt.shellslash is in use. ----@param p string ----@return string -local function cmdpath(p) - if vim.opt.shellslash:get() then - local r = p:gsub("/", "\\") - return r - else - return p - end -end - -local M = {} - --- Returns the mkdir command based on the OS ----@param directory string ----@param cwd string ----@param info_msg string ----@return table -function M.select_mkdir_cmd(directory, cwd, info_msg) - if fn.has "win32" == 1 then - return { - cmd = "cmd", - opts = { - args = { "/C", "mkdir", cmdpath(directory) }, - cwd = cwd, - }, - info = info_msg, - err = "Could not create " .. directory, - } - else - return { - cmd = "mkdir", - opts = { - args = { directory }, - cwd = cwd, - }, - info = info_msg, - err = "Could not create " .. directory, - } - end -end - --- Returns the remove command based on the OS ----@param file string ----@param info_msg string ----@return table -function M.select_rm_file_cmd(file, info_msg) - if fn.has "win32" == 1 then - return { - cmd = "cmd", - opts = { - args = { "/C", "if", "exist", cmdpath(file), "del", cmdpath(file) }, - }, - info = info_msg, - err = "Could not delete " .. file, - } - else - return { - cmd = "rm", - opts = { - args = { file }, - }, - info = info_msg, - err = "Could not delete " .. file, - } - end -end - ----@param executables string[] ----@return string|nil -function M.select_executable(executables) - return vim.tbl_filter(function(c) ---@param c string - return c ~= vim.NIL and fn.executable(c) == 1 - end, executables)[1] -end - --- Returns the compiler arguments based on the compiler and OS ----@param repo InstallInfo ----@param compiler string ----@return string[] -function M.select_compiler_args(repo, compiler) - if string.match(compiler, "cl$") or string.match(compiler, "cl.exe$") then - return { - "/Fe:", - "parser.so", - "/Isrc", - repo.files, - "-Os", - "/std:c11", - "/utf-8", - "/LD", - } - elseif string.match(compiler, "zig$") or string.match(compiler, "zig.exe$") then - return { - "c++", - "-o", - "parser.so", - repo.files, - "-lc", - "-Isrc", - "-shared", - "-Os", - "-std=c11", - } - else - local args = { - "-o", - "parser.so", - "-I./src", - repo.files, - "-Os", - "-std=c11", - } - if fn.has "mac" == 1 then - table.insert(args, "-bundle") - else - table.insert(args, "-shared") - end - if - #vim.tbl_filter(function(file) ---@param file string - local ext = vim.fn.fnamemodify(file, ":e") - return ext == "cc" or ext == "cpp" or ext == "cxx" - end, repo.files) > 0 - then - table.insert(args, "-lstdc++") - end - if fn.has "win32" == 0 then - table.insert(args, "-fPIC") - end - return args - end -end - --- Returns the compile command based on the OS and user options ----@param repo InstallInfo ----@param cc string ----@param compile_location string ----@return Command -function M.select_compile_command(repo, cc, compile_location) - local make = M.select_executable { "gmake", "make" } - if - string.match(cc, "cl$") - or string.match(cc, "cl.exe$") - or not repo.use_makefile - or fn.has "win32" == 1 - or not make - then - return { - cmd = cc, - info = "Compiling...", - err = "Error during compilation", - opts = { - args = require("nvim-treesitter.compat").flatten(M.select_compiler_args(repo, cc)), - cwd = compile_location, - }, - } - else - return { - cmd = make, - info = "Compiling...", - err = "Error during compilation", - opts = { - args = { - "--makefile=" .. utils.join_path(utils.get_package_path(), "scripts", "compile_parsers.makefile"), - "CC=" .. cc, - "CXX_STANDARD=" .. (repo.cxx_standard or "c++14"), - }, - cwd = compile_location, - }, - } - end -end - --- Returns the remove command based on the OS ----@param cache_folder string ----@param project_name string ----@return Command -function M.select_install_rm_cmd(cache_folder, project_name) - if fn.has "win32" == 1 then - local dir = cache_folder .. "\\" .. project_name - return { - cmd = "cmd", - opts = { - args = { "/C", "if", "exist", cmdpath(dir), "rmdir", "/s", "/q", cmdpath(dir) }, - }, - } - else - return { - cmd = "rm", - opts = { - args = { "-rf", cache_folder .. "/" .. project_name }, - }, - } - end -end - --- Returns the move command based on the OS ----@param from string ----@param to string ----@param cwd string ----@return Command -function M.select_mv_cmd(from, to, cwd) - if fn.has "win32" == 1 then - return { - cmd = "cmd", - opts = { - args = { "/C", "move", "/Y", cmdpath(from), cmdpath(to) }, - cwd = cwd, - }, - } - else - return { - cmd = "mv", - opts = { - args = { "-f", from, to }, - cwd = cwd, - }, - } - 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) - 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_gitlab = repo.url:find("gitlab.com", 1, true) - - revision = revision or repo.branch or "master" - - if can_use_tar and (is_github or is_gitlab) and not prefer_git then - local path_sep = utils.get_path_sep() - local url = repo.url:gsub(".git$", "") - - local folder_rev = revision - if is_github and revision:match "^v%d" then - folder_rev = revision:sub(2) - end - - return { - M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"), - { - cmd = "curl", - info = "Downloading " .. project_name .. "...", - err = "Error during download, please verify your internet connection", - opts = { - args = { - "--silent", - "--show-error", - "-L", -- follow redirects - is_github and url .. "/archive/" .. revision .. ".tar.gz" - or url .. "/-/archive/" .. revision .. "/" .. project_name .. "-" .. revision .. ".tar.gz", - "--output", - project_name .. ".tar.gz", - }, - cwd = cache_folder, - }, - }, - M.select_mkdir_cmd(project_name .. "-tmp", cache_folder, "Creating temporary directory"), - { - cmd = "tar", - info = "Extracting " .. project_name .. "...", - err = "Error during tarball extraction.", - opts = { - args = { - "-xvzf", - project_name .. ".tar.gz", - "-C", - project_name .. "-tmp", - }, - cwd = cache_folder, - }, - }, - M.select_rm_file_cmd(cache_folder .. path_sep .. project_name .. ".tar.gz"), - M.select_mv_cmd( - utils.join_path(project_name .. "-tmp", url:match "[^/]-$" .. "-" .. folder_rev), - project_name, - cache_folder - ), - M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"), - } - else - local git_folder = utils.join_path(cache_folder, project_name) - local clone_error = "Error during download, please verify your internet connection" - - -- Running `git clone` or `git checkout` while running under Git (such as - -- editing a `git commit` message) will likely fail to install parsers - -- (such as 'gitcommit') and can also corrupt the index file of the current - -- Git repository. Check for typical git environment variables and abort if found. - for _, k in pairs { - "GIT_ALTERNATE_OBJECT_DIRECTORIES", - "GIT_CEILING_DIRECTORIES", - "GIT_DIR", - "GIT_INDEX", - "GIT_INDEX_FILE", - "GIT_OBJECT_DIRECTORY", - "GIT_PREFIX", - "GIT_WORK_TREE", - } do - if uv.os_getenv(k) then - vim.api.nvim_err_writeln( - string.format( - "Cannot install %s with git in an active git session. Exit the session and run ':TSInstall %s' manually", - project_name, - project_name - ) - ) - return {} - end - end - - return { - { - cmd = "git", - info = "Downloading " .. project_name .. "...", - err = clone_error, - opts = { - args = { - "clone", - repo.url, - project_name, - "--filter=blob:none", - }, - cwd = cache_folder, - }, - }, - { - cmd = "git", - info = "Checking out locked revision", - err = "Error while checking out revision", - opts = { - args = { - "checkout", - revision, - }, - cwd = git_folder, - }, - }, - } - end -end - ----@param dir string ----@param command string ----@return string command -function M.make_directory_change_for_command(dir, command) - if fn.has "win32" == 1 then - if string.find(vim.o.shell, "cmd") ~= nil then - return string.format("pushd %s & %s", cmdpath(dir), command) - else - return string.format("pushd %s ; %s", cmdpath(dir), command) - end - else - return string.format("cd %s;\n%s", dir, command) - end -end - -return M diff --git a/lua/nvim-treesitter/statusline.lua b/lua/nvim-treesitter/statusline.lua deleted file mode 100644 index 68ba41aca..000000000 --- a/lua/nvim-treesitter/statusline.lua +++ /dev/null @@ -1,53 +0,0 @@ -local parsers = require "nvim-treesitter.parsers" -local ts_utils = require "nvim-treesitter.ts_utils" - -local M = {} - --- Trim spaces and opening brackets from end -local transform_line = function(line) - return line:gsub("%s*[%[%(%{]*%s*$", "") -end - -function M.statusline(opts) - if not parsers.has_parser() then - return - end - local options = opts or {} - if type(opts) == "number" then - options = { indicator_size = opts } - end - local bufnr = options.bufnr or 0 - local indicator_size = options.indicator_size or 100 - local type_patterns = options.type_patterns or { "class", "function", "method" } - local transform_fn = options.transform_fn or transform_line - local separator = options.separator or " -> " - local allow_duplicates = options.allow_duplicates or false - - local current_node = ts_utils.get_node_at_cursor() - if not current_node then - return "" - end - - local lines = {} - local expr = current_node - - while expr do - local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr) - if line ~= "" then - if allow_duplicates or not vim.tbl_contains(lines, line) then - table.insert(lines, 1, line) - end - end - expr = expr:parent() - end - - local text = table.concat(lines, separator) - local text_len = #text - if text_len > indicator_size then - return "..." .. text:sub(text_len - indicator_size, text_len) - end - - return text -end - -return M diff --git a/lua/nvim-treesitter/ts_utils.lua b/lua/nvim-treesitter/ts_utils.lua deleted file mode 100644 index ce103790c..000000000 --- a/lua/nvim-treesitter/ts_utils.lua +++ /dev/null @@ -1,482 +0,0 @@ -local api = vim.api - -local parsers = require "nvim-treesitter.parsers" -local utils = require "nvim-treesitter.utils" -local ts = vim.treesitter - -local M = {} - -local function get_node_text(node, bufnr) - bufnr = bufnr or api.nvim_get_current_buf() - if not node then - return {} - end - - -- We have to remember that end_col is end-exclusive - local start_row, start_col, end_row, end_col = ts.get_node_range(node) - - if start_row ~= end_row then - local lines = api.nvim_buf_get_lines(bufnr, start_row, end_row + 1, false) - if next(lines) == nil then - return {} - end - lines[1] = string.sub(lines[1], start_col + 1) - -- end_row might be just after the last line. In this case the last line is not truncated. - if #lines == end_row - start_row + 1 then - lines[#lines] = string.sub(lines[#lines], 1, end_col) - end - return lines - else - local line = api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1] - -- If line is nil then the line is empty - return line and { string.sub(line, start_col + 1, end_col) } or {} - end -end - ----@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) - local node_type = node:type() - local is_valid = false - for _, rgx in ipairs(type_patterns) do - if node_type:find(rgx) then - is_valid = true - break - end - end - if not is_valid then - return "" - end - local line = transform_fn(vim.trim(get_node_text(node, bufnr)[1] or ""), node) - -- Escape % to avoid statusline to evaluate content as expression - return line:gsub("%%", "%%%%") -end - --- Gets the actual text content of a node --- @deprecated Use vim.treesitter.get_node_text --- @param node the node to get the text from --- @param bufnr the buffer containing the node --- @return list of lines of text of the node -function M.get_node_text(node, bufnr) - vim.notify_once( - "nvim-treesitter.ts_utils.get_node_text is deprecated: use vim.treesitter.get_node_text", - vim.log.levels.WARN - ) - return get_node_text(node, bufnr) -end - --- Determines whether a node is the parent of another --- @param dest the possible parent --- @param source the possible child node -function M.is_parent(dest, source) - if not (dest and source) then - return false - end - - local current = source - while current ~= nil do - if current == dest then - return true - end - - current = current:parent() - end - - return false -end - --- Get next node with same parent ----@param node TSNode ----@param allow_switch_parents? boolean allow switching parents if last node ----@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) - local destination_node ---@type TSNode - local parent = node:parent() - - if not parent then - return - end - local found_pos = 0 - for i = 0, parent:named_child_count() - 1, 1 do - if parent:named_child(i) == node then - found_pos = i - break - end - end - if parent:named_child_count() > found_pos + 1 then - destination_node = parent:named_child(found_pos + 1) - elseif allow_switch_parents then - local next_node = M.get_next_node(node:parent()) - if next_node and next_node:named_child_count() > 0 then - destination_node = next_node:named_child(0) - elseif next_node and allow_next_parent then - destination_node = next_node - end - end - - return destination_node -end - --- Get previous node with same parent ----@param node TSNode ----@param allow_switch_parents? boolean allow switching parents if first node ----@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) - local destination_node ---@type TSNode - local parent = node:parent() - if not parent then - return - end - - local found_pos = 0 - for i = 0, parent:named_child_count() - 1, 1 do - if parent:named_child(i) == node then - found_pos = i - break - end - end - if 0 < found_pos then - destination_node = parent:named_child(found_pos - 1) - elseif allow_switch_parents then - local previous_node = M.get_previous_node(node:parent()) - if previous_node and previous_node:named_child_count() > 0 then - destination_node = previous_node:named_child(previous_node:named_child_count() - 1) - elseif previous_node and allow_previous_parent then - destination_node = previous_node - end - end - return destination_node -end - -function M.get_named_children(node) - local nodes = {} ---@type TSNode[] - for i = 0, node:named_child_count() - 1, 1 do - nodes[i + 1] = node:named_child(i) - end - return nodes -end - -function M.get_node_at_cursor(winnr, ignore_injected_langs) - winnr = winnr or 0 - local cursor = api.nvim_win_get_cursor(winnr) - local cursor_range = { cursor[1] - 1, cursor[2] } - - local buf = vim.api.nvim_win_get_buf(winnr) - local root_lang_tree = parsers.get_parser(buf) - if not root_lang_tree then - return - end - - local root ---@type TSNode|nil - if ignore_injected_langs then - for _, tree in pairs(root_lang_tree:trees()) do - local tree_root = tree:root() - if tree_root and ts.is_in_node_range(tree_root, cursor_range[1], cursor_range[2]) then - root = tree_root - break - end - end - else - root = M.get_root_for_position(cursor_range[1], cursor_range[2], root_lang_tree) - end - - if not root then - return - end - - return root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2]) -end - -function M.get_root_for_position(line, col, root_lang_tree) - if not root_lang_tree then - if not parsers.has_parser() then - return - end - - root_lang_tree = parsers.get_parser() - end - - local lang_tree = root_lang_tree:language_for_range { line, col, line, col } - - while true do - for _, tree in pairs(lang_tree:trees()) do - local root = tree:root() - - if root and ts.is_in_node_range(root, line, col) then - return root, tree, lang_tree - end - end - - if lang_tree == root_lang_tree then - break - end - - -- This case can happen when the cursor is at the start of a line that ends a injected region, - -- e.g., the first `]` in the following lua code: - -- ``` - -- vim.cmd[[ - -- ]] - -- ``` - lang_tree = lang_tree:parent() -- NOTE: parent() method is private - end - - -- This isn't a likely scenario, since the position must belong to a tree somewhere. - return nil, nil, lang_tree -end - ----comment ----@param node TSNode ----@return TSNode result -function M.get_root_for_node(node) - local parent = node - local result = node - - while parent ~= nil do - result = parent - parent = result:parent() - end - - return result -end - -function M.highlight_node(node, buf, hl_namespace, hl_group) - if not node then - return - end - M.highlight_range({ node:range() }, buf, hl_namespace, hl_group) -end - --- 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. --- They also treat a EOF/EOL char as a char ending in the first --- 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) - ---@type integer, integer, integer, integer - local srow, scol, erow, ecol = unpack(range) - srow = srow + 1 - scol = scol + 1 - erow = erow + 1 - - if ecol == 0 then - -- Use the value of the last col of the previous row instead. - erow = erow - 1 - if not buf or buf == 0 then - ecol = vim.fn.col { erow, "$" } - 1 - else - ecol = #api.nvim_buf_get_lines(buf, erow - 1, erow, false)[1] - end - ecol = math.max(ecol, 1) - end - return srow, scol, erow, ecol -end - -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) - ---@diagnostic disable-next-line: missing-parameter - vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col }) -end - --- Set visual selection to node --- @param selection_mode One of "charwise" (default) or "v", "linewise" or "V", --- "blockwise" or "" (as a string with 5 characters or a single character) -function M.update_selection(buf, node, selection_mode) - local start_row, start_col, end_row, end_col = M.get_vim_range({ ts.get_node_range(node) }, buf) - - local v_table = { charwise = "v", linewise = "V", blockwise = "" } - selection_mode = selection_mode or "charwise" - - -- Normalise selection_mode - if vim.tbl_contains(vim.tbl_keys(v_table), selection_mode) then - selection_mode = v_table[selection_mode] - end - - -- enter visual mode if normal or operator-pending (no) mode - -- Why? According to https://learnvimscriptthehardway.stevelosh.com/chapters/15.html - -- If your operator-pending mapping ends with some text visually selected, Vim will operate on that text. - -- Otherwise, Vim will operate on the text between the original cursor position and the new position. - local mode = api.nvim_get_mode() - if mode.mode ~= selection_mode then - -- Call to `nvim_replace_termcodes()` is needed for sending appropriate command to enter blockwise mode - selection_mode = vim.api.nvim_replace_termcodes(selection_mode, true, true, true) - api.nvim_cmd({ cmd = "normal", bang = true, args = { selection_mode } }, {}) - end - - api.nvim_win_set_cursor(0, { start_row, start_col - 1 }) - vim.cmd "normal! o" - api.nvim_win_set_cursor(0, { end_row, end_col - 1 }) -end - --- Byte length of node range ----@param node TSNode ----@return number -function M.node_length(node) - local _, _, start_byte = node:start() - local _, _, end_byte = node:end_() - return end_byte - start_byte -end - ----@deprecated Use `vim.treesitter.is_in_node_range()` instead -function M.is_in_node_range(node, line, col) - vim.notify_once( - "nvim-treesitter.ts_utils.is_in_node_range is deprecated: use vim.treesitter.is_in_node_range", - vim.log.levels.WARN - ) - return ts.is_in_node_range(node, line, col) -end - ----@deprecated Use `vim.treesitter.get_node_range()` instead -function M.get_node_range(node_or_range) - vim.notify_once( - "nvim-treesitter.ts_utils.get_node_range is deprecated: use vim.treesitter.get_node_range", - vim.log.levels.WARN - ) - return ts.get_node_range(node_or_range) -end - ----@param node TSNode ----@return table -function M.node_to_lsp_range(node) - local start_line, start_col, end_line, end_col = ts.get_node_range(node) - local rtn = {} - rtn.start = { line = start_line, character = start_col } - rtn["end"] = { line = end_line, character = end_col } - return rtn -end - --- 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 options argument is a table with two optional values: --- - bufnr: extracts a bufnr from the given arguments. --- - key: extracts the cache key from the given arguments. ----@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) - options = options or {} - - ---@type table - local cache = setmetatable({}, { __mode = "kv" }) - local bufnr_fn = utils.to_func(options.bufnr or utils.identity) - local key_fn = utils.to_func(options.key or utils.identity) - - return function(...) - local bufnr = bufnr_fn(...) - local key = key_fn(...) - local tick = api.nvim_buf_get_changedtick(bufnr) - - if cache[key] then - if cache[key].last_tick == tick then - return cache[key].result - end - else - local function detach_handler() - cache[key] = nil - end - - -- Clean up logic only! - api.nvim_buf_attach(bufnr, false, { - on_detach = detach_handler, - on_reload = detach_handler, - }) - end - - cache[key] = { - result = fn(...), - last_tick = tick, - } - - return cache[key].result - end -end - -function M.swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second) - if not node_or_range1 or not node_or_range2 then - return - end - local range1 = M.node_to_lsp_range(node_or_range1) - local range2 = M.node_to_lsp_range(node_or_range2) - - local text1 = get_node_text(node_or_range1, bufnr) - local text2 = get_node_text(node_or_range2, bufnr) - - local edit1 = { range = range1, newText = table.concat(text2, "\n") } - local edit2 = { range = range2, newText = table.concat(text1, "\n") } - bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr - vim.lsp.util.apply_text_edits({ edit1, edit2 }, bufnr, "utf-8") - - if cursor_to_second then - utils.set_jump() - - local char_delta = 0 - local line_delta = 0 - if - range1["end"].line < range2.start.line - or (range1["end"].line == range2.start.line and range1["end"].character <= range2.start.character) - then - line_delta = #text2 - #text1 - end - - if range1["end"].line == range2.start.line and range1["end"].character <= range2.start.character then - if line_delta ~= 0 then - --- why? - --correction_after_line_change = -range2.start.character - --text_now_before_range2 = #(text2[#text2]) - --space_between_ranges = range2.start.character - range1["end"].character - --char_delta = correction_after_line_change + text_now_before_range2 + space_between_ranges - --- Equivalent to: - char_delta = #text2[#text2] - range1["end"].character - - -- add range1.start.character if last line of range1 (now text2) does not start at 0 - if range1.start.line == range2.start.line + line_delta then - char_delta = char_delta + range1.start.character - end - else - char_delta = #text2[#text2] - #text1[#text1] - end - end - - api.nvim_win_set_cursor( - api.nvim_get_current_win(), - { range2.start.line + 1 + line_delta, range2.start.character + char_delta } - ) - end -end - -function M.goto_node(node, goto_end, avoid_set_jump) - if not node then - return - end - if not avoid_set_jump then - utils.set_jump() - end - local range = { M.get_vim_range { node:range() } } - ---@type table - local position - if not goto_end then - position = { range[1], range[2] } - else - position = { range[3], range[4] } - end - - -- Enter visual mode if we are in operator pending mode - -- If we don't do this, it will miss the last character. - local mode = vim.api.nvim_get_mode() - if mode.mode == "no" then - vim.cmd "normal! v" - end - - -- Position is 1, 0 indexed. - api.nvim_win_set_cursor(0, { position[1], position[2] - 1 }) -end - -return M diff --git a/lua/nvim-treesitter/tsrange.lua b/lua/nvim-treesitter/tsrange.lua deleted file mode 100644 index d41585c60..000000000 --- a/lua/nvim-treesitter/tsrange.lua +++ /dev/null @@ -1,154 +0,0 @@ -local M = {} -local TSRange = {} -TSRange.__index = TSRange - -local api = vim.api -local ts_utils = require "nvim-treesitter.ts_utils" -local parsers = require "nvim-treesitter.parsers" - -local function get_byte_offset(buf, row, col) - return api.nvim_buf_get_offset(buf, row) + vim.fn.byteidx(api.nvim_buf_get_lines(buf, row, row + 1, false)[1], col) -end - -function TSRange.new(buf, start_row, start_col, end_row, end_col) - return setmetatable({ - start_pos = { start_row, start_col, get_byte_offset(buf, start_row, start_col) }, - end_pos = { end_row, end_col, get_byte_offset(buf, end_row, end_col) }, - buf = buf, - [1] = start_row, - [2] = start_col, - [3] = end_row, - [4] = end_col, - }, TSRange) -end - -function TSRange.from_nodes(buf, start_node, end_node) - TSRange.__index = TSRange - local start_pos = start_node and { start_node:start() } or { end_node:start() } - local end_pos = end_node and { end_node:end_() } or { start_node:end_() } - return setmetatable({ - start_pos = { start_pos[1], start_pos[2], start_pos[3] }, - end_pos = { end_pos[1], end_pos[2], end_pos[3] }, - buf = buf, - [1] = start_pos[1], - [2] = start_pos[2], - [3] = end_pos[1], - [4] = end_pos[2], - }, TSRange) -end - -function TSRange.from_table(buf, range) - return setmetatable({ - start_pos = { range[1], range[2], get_byte_offset(buf, range[1], range[2]) }, - end_pos = { range[3], range[4], get_byte_offset(buf, range[3], range[4]) }, - buf = buf, - [1] = range[1], - [2] = range[2], - [3] = range[3], - [4] = range[4], - }, TSRange) -end - -function TSRange:parent() - local root_lang_tree = parsers.get_parser(self.buf) - local root = ts_utils.get_root_for_position(self[1], self[2], root_lang_tree) - - return root - and root:named_descendant_for_range(self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2]) - or nil -end - -function TSRange:field() end - -function TSRange:child_count() - return #self:collect_children() -end - -function TSRange:named_child_count() - return #self:collect_children(function(c) - return c:named() - end) -end - -function TSRange:iter_children() - local raw_iterator = self:parent().iter_children() - return function() - while true do - local node = raw_iterator() - if not node then - return - end - local _, _, start_byte = node:start() - local _, _, end_byte = node:end_() - if start_byte >= self.start_pos[3] and end_byte <= self.end_pos[3] then - return node - end - end - end -end - -function TSRange:collect_children(filter_fun) - local children = {} - for _, c in self:iter_children() do - if not filter_fun or filter_fun(c) then - table.insert(children, c) - end - end - return children -end - -function TSRange:child(index) - return self:collect_children()[index + 1] -end - -function TSRange:named_child(index) - return self:collect_children(function(c) - return c.named() - end)[index + 1] -end - -function TSRange:start() - return unpack(self.start_pos) -end - -function TSRange:end_() - return unpack(self.end_pos) -end - -function TSRange:range() - return self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2] -end - -function TSRange:type() - return "nvim-treesitter-range" -end - -function TSRange:symbol() - return -1 -end - -function TSRange:named() - return false -end - -function TSRange:missing() - return false -end - -function TSRange:has_error() - return #self:collect_children(function(c) - return c:has_error() - end) > 0 and true or false -end - -function TSRange:sexpr() - return table.concat( - vim.tbl_map(function(c) - return c:sexpr() - end, self:collect_children()), - " " - ) -end - -M.TSRange = TSRange -return M diff --git a/lua/nvim-treesitter/utils.lua b/lua/nvim-treesitter/utils.lua index d920f4a61..f9e5a2b86 100644 --- a/lua/nvim-treesitter/utils.lua +++ b/lua/nvim-treesitter/utils.lua @@ -1,237 +1,12 @@ -local api = vim.api -local fn = vim.fn -local luv = vim.loop - local M = {} --- 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) - local default_opts = { title = "nvim-treesitter" } - vim.notify(msg, log_level, vim.tbl_extend("force", default_opts, opts or {})) -end - --- Returns the system-specific path separator. ----@return string -function M.get_path_sep() - return (fn.has "win32" == 1 and not vim.opt.shellslash:get()) and "\\" or "/" -end - --- Returns a function that joins the given arguments with separator. Arguments --- can't be nil. Example: --- ---[[ - print(M.generate_join(" ")("foo", "bar")) ---]] ---prints "foo bar" ----@param separator string ----@return fun(...: string): string -function M.generate_join(separator) - return function(...) - return table.concat({ ... }, separator) - end -end - -M.join_path = M.generate_join(M.get_path_sep()) - -M.join_space = M.generate_join " " - ----@class Command ----@field run function ----@field f_args string ----@field args string - --- Define user defined vim command which calls nvim-treesitter module function --- - 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 Command list for the module ---- - {command_name} Name of the vim user defined command, Keys: ---- - {run}: (function) callback function that needs to be executed ---- - {f_args}: (string, default ) ---- - type of arguments that needs to be passed to the vim command ---- - {args}: (string, optional) ---- - vim command attributes ---- ----* @example ---- If module is nvim-treesitter.custom_mod ----
----  M.commands = {
----      custom_command = {
----          run = M.module_function,
----          f_args = "",
----          args = {
----              "-range"
----          }
----      }
----  }
----
----  utils.setup_commands("custom_mod", require("nvim-treesitter.custom_mod").commands)
----  
---- ---- Will generate command : ----
----  command! -range custom_command \
----      lua require'nvim-treesitter.custom_mod'.commands.custom_command['run']()
----  
-function M.setup_commands(mod, commands) - for command_name, def in pairs(commands) do - local f_args = def.f_args or "" - local call_fn = - string.format("lua require'nvim-treesitter.%s'.commands.%s['run'](%s)", mod, command_name, f_args) - local parts = require("nvim-treesitter.compat").flatten { - "command!", - "-bar", - def.args, - command_name, - call_fn, - } - api.nvim_command(table.concat(parts, " ")) - end -end - ----@param dir string ----@param create_err string ----@param writeable_err string ----@return string|nil, string|nil -function M.create_or_reuse_writable_dir(dir, create_err, writeable_err) - create_err = create_err or M.join_space("Could not create dir '", dir, "': ") - writeable_err = writeable_err or M.join_space("Invalid rights, '", dir, "' should be read/write") - -- Try creating and using parser_dir if it doesn't exist - if not luv.fs_stat(dir) then - local ok, error = pcall(vim.fn.mkdir, dir, "p", "0755") - if not ok then - return nil, M.join_space(create_err, error) - end - - return dir - end - - -- parser_dir exists, use it if it's read/write - if luv.fs_access(dir, "RW") then - return dir - end - - -- parser_dir exists but isn't read/write, give up - return nil, M.join_space(writeable_err, dir, "'") -end - -function M.get_package_path() - -- Path to this source file, removing the leading '@' - local source = string.sub(debug.getinfo(1, "S").source, 2) - - -- Path to the package root - return fn.fnamemodify(source, ":p:h:h:h") -end - -function M.get_cache_dir() - local cache_dir = fn.stdpath "data" - - if luv.fs_access(cache_dir, "RW") then - return cache_dir - elseif luv.fs_access("/tmp", "RW") then - return "/tmp" - end - - return nil, M.join_space("Invalid cache rights,", fn.stdpath "data", "or /tmp should be read/write") -end - --- Returns $XDG_DATA_HOME/nvim/site, but could use any directory that is in --- runtimepath -function M.get_site_dir() - return M.join_path(fn.stdpath "data", "site") -end - --- Gets a property at path ----@param tbl table the table to access ----@param path string the '.' separated path ----@return table|nil result the value at path or nil -function M.get_at_path(tbl, path) - if path == "" then - return tbl - end - - local segments = vim.split(path, ".", true) - ---@type table[]|table - local result = tbl - - for _, segment in ipairs(segments) do - if type(result) == "table" then - ---@type table - -- TODO: figure out the actual type of tbl - result = result[segment] - end - end - - return result -end - -function M.set_jump() - vim.cmd "normal! m'" -end - --- Filters a list based on the given predicate ----@param tbl any[] The list to filter ----@param predicate fun(v:any, i:number):boolean The predicate to filter with -function M.filter(tbl, predicate) - local result = {} - - for i, v in ipairs(tbl) do - if predicate(v, i) then - table.insert(result, v) - end - end - - return result -end - --- Returns a list of all values from the first list --- that are not present in the second list. ----@param tbl1 any[] The first table ----@param tbl2 any[] The second table ----@return table -function M.difference(tbl1, tbl2) - return M.filter(tbl1, function(v) - return not vim.tbl_contains(tbl2, v) - end) -end - -function M.identity(a) - return a -end - --- Returns a function returning the given value ----@param a any ----@return fun():any -function M.constant(a) - return function() - return a - 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) - return type(a) == "function" and a or M.constant(a) +--TODO(clason): replace by vim.fs._join_paths +function M.join_path(...) + return (table.concat({ ... }, '/'):gsub('//+', '/')) end ----@return string|nil -function M.ts_cli_version() - if fn.executable "tree-sitter" == 1 then - local handle = io.popen "tree-sitter -V" - if not handle then - return - end - local result = handle:read "*a" - handle:close() - return vim.split(result, "\n")[1]:match "[^tree%psitter ].*" - end +function M.get_package_path(...) + return M.join_path(vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':p:h:h:h'), ...) end return M -- cgit v1.2.3-70-g09d2