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