mirror of
https://github.com/nvim-treesitter/nvim-treesitter.git
synced 2026-07-05 04:50:03 -04:00
feat(install)!: generate from json instead of requiring node
Problem: Many parsers require node/npm to evaluate the `grammar.js` before being able to generate a parser from it. Solution: Generate from `grammar.json` instead, which is fully resolved. Drops `node` and `npm` as (optional) requirements for nvim-treesitter. Note that this requires parsers to commit the generated json iff the grammar requires evaluation (which is currently the case for all tracked languages).
This commit is contained in:
parent
8f8cf7144d
commit
5a38df5627
10 changed files with 502 additions and 484 deletions
|
|
@ -37,16 +37,8 @@ local function install_health()
|
|||
)
|
||||
end
|
||||
|
||||
if vim.fn.executable('node') == 0 then
|
||||
health.warn('`node` executable not found (only needed for `:TSInstallFromGrammar`.')
|
||||
else
|
||||
local result = assert(vim.system({ 'node', '--version' }):wait().stdout)
|
||||
local version = vim.split(result, '\n')[1]
|
||||
health.ok('`node` found ' .. version .. ' (only needed for `:TSInstallFromGrammar`)')
|
||||
end
|
||||
|
||||
if vim.fn.executable('git') == 0 then
|
||||
health.error(
|
||||
health.warn(
|
||||
'`git` executable not found.',
|
||||
'Install it with your package manager and check that your `$PATH` is set correctly.'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ local M = {}
|
|||
---@type table<string, LockfileInfo>
|
||||
local lockfile = {}
|
||||
|
||||
local max_jobs = 50
|
||||
local max_jobs = 10
|
||||
|
||||
local iswin = uv.os_uname().sysname == 'Windows_NT'
|
||||
local ismac = uv.os_uname().sysname == 'Darwin'
|
||||
|
|
@ -145,24 +145,17 @@ end
|
|||
--- @param repo InstallInfo
|
||||
--- @param compile_location string
|
||||
--- @return string? err
|
||||
local function do_generate_from_grammar(logger, repo, compile_location)
|
||||
local function do_generate(logger, repo, compile_location)
|
||||
if not executable('tree-sitter') then
|
||||
return logger:error('tree-sitter CLI not found: `tree-sitter` is not executable')
|
||||
end
|
||||
|
||||
if repo.generate_requires_npm then
|
||||
if not executable('npm') then
|
||||
return logger:error('NPM requires to be installed from grammar.js')
|
||||
end
|
||||
|
||||
logger:info('Installing NPM dependencies')
|
||||
local r = system({ 'npm', 'install' }, { cwd = compile_location })
|
||||
if r.code > 0 then
|
||||
return logger:error('Error during `npm install`: %s', r.stderr)
|
||||
end
|
||||
end
|
||||
|
||||
logger:info('Generating source files from grammar.js...')
|
||||
logger:info(
|
||||
string.format(
|
||||
'Generating parser.c from %s...',
|
||||
repo.generate_from_json and 'grammar.json' or 'grammar.js'
|
||||
)
|
||||
)
|
||||
|
||||
local r = system({
|
||||
fn.exepath('tree-sitter'),
|
||||
|
|
@ -170,6 +163,7 @@ local function do_generate_from_grammar(logger, repo, compile_location)
|
|||
'--no-bindings',
|
||||
'--abi',
|
||||
tostring(vim.treesitter.language_version),
|
||||
repo.generate_from_json and 'src/grammar.json',
|
||||
}, { cwd = compile_location })
|
||||
if r.code > 0 then
|
||||
return logger:error('Error during "tree-sitter generate": %s', r.stderr)
|
||||
|
|
@ -262,6 +256,10 @@ end
|
|||
---@param project_dir string
|
||||
---@return string? err
|
||||
local function do_download_git(logger, repo, project_name, cache_dir, revision, project_dir)
|
||||
if not executable('git') then
|
||||
return logger:error('git not found!')
|
||||
end
|
||||
|
||||
logger:info('Downloading ' .. project_name .. '...')
|
||||
|
||||
local r = system({
|
||||
|
|
@ -386,7 +384,7 @@ end
|
|||
---@param repo InstallInfo
|
||||
---@param cc string
|
||||
---@param compile_location string
|
||||
--- @return string? err
|
||||
---@return string? err
|
||||
local function do_compile(logger, repo, cc, compile_location)
|
||||
local args = vim.tbl_flatten(select_compiler_args(repo, cc))
|
||||
local cmd = vim.list_extend({ cc }, args)
|
||||
|
|
@ -442,7 +440,7 @@ local function install_lang0(lang, cache_dir, install_dir, generate)
|
|||
|
||||
do
|
||||
if repo.generate or generate then
|
||||
local err = do_generate_from_grammar(logger, repo, compile_location)
|
||||
local err = do_generate(logger, repo, compile_location)
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
|
|
@ -497,9 +495,9 @@ local INSTALL_TIMEOUT = 60000
|
|||
---@param cache_dir string
|
||||
---@param install_dir string
|
||||
---@param force? boolean
|
||||
---@param generate_from_grammar? boolean
|
||||
---@param generate? boolean
|
||||
---@return InstallStatus status
|
||||
local function install_lang(lang, cache_dir, install_dir, force, generate_from_grammar)
|
||||
local function install_lang(lang, cache_dir, install_dir, force, generate)
|
||||
if not force and vim.list_contains(config.installed_parsers(), lang) then
|
||||
local yesno = fn.input(lang .. ' parser already available: would you like to reinstall ? y/n: ')
|
||||
print('\n ')
|
||||
|
|
@ -518,7 +516,7 @@ local function install_lang(lang, cache_dir, install_dir, force, generate_from_g
|
|||
end
|
||||
else
|
||||
install_status[lang] = 'installing'
|
||||
local err = install_lang0(lang, cache_dir, install_dir, generate_from_grammar)
|
||||
local err = install_lang0(lang, cache_dir, install_dir, generate)
|
||||
install_status[lang] = err and 'failed' or 'installed'
|
||||
end
|
||||
|
||||
|
|
@ -529,7 +527,7 @@ end
|
|||
|
||||
---@class InstallOptions
|
||||
---@field force? boolean
|
||||
---@field generate_from_grammar? boolean
|
||||
---@field generate? boolean
|
||||
---@field skip? table
|
||||
|
||||
--- Install a parser
|
||||
|
|
@ -539,7 +537,7 @@ end
|
|||
local function install(languages, options, _callback)
|
||||
options = options or {}
|
||||
local force = options.force
|
||||
local generate_from_grammar = options.generate_from_grammar
|
||||
local generate = options.generate
|
||||
local skip = options.skip
|
||||
|
||||
local cache_dir = vim.fs.normalize(fn.stdpath('cache'))
|
||||
|
|
@ -560,7 +558,7 @@ local function install(languages, options, _callback)
|
|||
for _, lang in ipairs(languages) do
|
||||
tasks[#tasks + 1] = a.sync(function()
|
||||
a.main()
|
||||
local status = install_lang(lang, cache_dir, install_dir, force, generate_from_grammar)
|
||||
local status = install_lang(lang, cache_dir, install_dir, force, generate)
|
||||
if status ~= 'failed' then
|
||||
done = done + 1
|
||||
end
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue