summaryrefslogtreecommitdiff
path: root/lua/nvim-treesitter/health.lua
blob: f68a8c010b0f60a6172bd2e3ef89eda258e4c82f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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 health_start = vim.fn["health#report_start"]
local health_ok = vim.fn["health#report_ok"]
local health_error = vim.fn["health#report_error"]
local health_warn = vim.fn["health#report_warn"]

local M = {}

local NVIM_TREESITTER_MINIMUM_ABI = 13

local function install_health()
  health_start "Installation"

  if fn.executable "tree-sitter" == 0 then
    health_warn(
      "`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar,"
        .. " not required for :TSInstall)"
    )
  else
    local handle = io.popen "tree-sitter  -V"
    local result = handle:read "*a"
    handle:close()
    local version = vim.split(result, "\n")[1]:match "[^tree%psitter].*"
    health_ok(
      "`tree-sitter` found "
        .. (version or "(unknown version)")
        .. " (parser generator, only needed for :TSInstallFromGrammar)"
    )
  end

  if fn.executable "node" == 0 then
    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"
    handle:close()
    local version = vim.split(result, "\n")[1]
    health_ok("`node` found " .. version .. " (only needed for :TSInstallFromGrammar)")
  end

  if fn.executable "git" == 0 then
    health_error("`git` executable not found.", {
      "Install it with your package manager.",
      "Check that your `$PATH` is set correctly.",
    })
  else
    health_ok "`git` executable found."
  end

  local cc = shell.select_executable(install.compilers)
  if not cc then
    health_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
    health_ok("`" .. cc .. "` executable found. Selected from " .. vim.inspect(install.compilers))
  end
  if vim.treesitter.language_version then
    if vim.treesitter.language_version >= NVIM_TREESITTER_MINIMUM_ABI then
      health_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
      health_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
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.checkhealth()
  local error_collection = {}
  -- Installation dependency checks
  install_health()
  queries.invalidate_query_cache()
  health_start "Parser/Features H L F I J"
  -- Parser installation checks
  for _, parser_name in pairs(info.installed_parsers()) do
    local installed = #api.nvim_get_runtime_file("parser/" .. parser_name .. ".so", false)

    -- Only print informations about installed parsers
    if installed >= 1 then
      local multiple_parsers = installed > 1 and "+" or ""
      local out = "  - " .. parser_name .. multiple_parsers .. string.rep(" ", 15 - (#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
      print(out)
    end
  end
  print [[

 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}]]
  if #error_collection > 0 then
    print "\nThe following errors have been detected:"
    for _, p in ipairs(error_collection) do
      local lang, type, err = unpack(p)
      health_error(lang .. "(" .. type .. "): " .. err)
    end
  end
end

return M