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 M = {} local NVIM_TREESITTER_MINIMUM_ABI = 13 local function install_health() _start "Installation" if fn.has "nvim-0.8.3" ~= 1 then _error "Nvim-treesitter requires Neovim 0.8.3+" end if fn.executable "tree-sitter" == 0 then _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)" ) end if fn.executable "node" == 0 then _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" handle:close() local version = vim.split(result, "\n")[1] _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.", }) else _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.inspect(install.compilers) .. " 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( "`" .. cc .. "` executable found. Selected from " .. vim.inspect(install.compilers) .. (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.treesitter.language_version .. " (required >=" .. NVIM_TREESITTER_MINIMUM_ABI .. "). Parsers must be compatible with runtime ABI." ) else _error( "Neovim was compiled with tree-sitter runtime ABI version " .. vim.treesitter.language_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." ) end end _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) if not ok then return "x", err elseif not err then return "." else return "✓" end end 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 end table.insert(parser_installation, vim.fn.trim(out, " ", 2)) end 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}]] table.insert(parser_installation, legend) -- Finally call the report function _start(table.concat(parser_installation, "\n")) if #error_collection > 0 then _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) if #files > 0 then table.insert(lines, lang .. "(" .. type .. ") is concatenated from the following files:") for _, file in ipairs(files) do local fd = io.open(file, "r") if fd then local ok, file_err = pcall(ts.parse_query, lang, fd:read "*a") if ok then table.insert(lines, '| [OK]:"' .. file .. '"') else table.insert(lines, '| [ERROR]:"' .. file .. '", failed to load: ' .. file_err) end fd:close() end end end _error(table.concat(lines, "\n")) end end end return M