mirror of
https://github.com/nvim-treesitter/nvim-treesitter.git
synced 2026-07-04 12:30:01 -04:00
feat!: use tree-sitter build
This commit is contained in:
parent
c17de56890
commit
214cfcf851
13 changed files with 443 additions and 898 deletions
|
|
@ -23,19 +23,8 @@ local uv_symlink = a.wrap(uv.fs_symlink, 4)
|
|||
--- @type fun(path: string): string?
|
||||
local uv_unlink = a.wrap(uv.fs_unlink, 2)
|
||||
|
||||
local M = {}
|
||||
|
||||
local max_jobs = 10
|
||||
|
||||
local iswin = uv.os_uname().sysname == 'Windows_NT'
|
||||
local ismac = uv.os_uname().sysname == 'Darwin'
|
||||
|
||||
--- @diagnostic disable-next-line:missing-parameter
|
||||
M.compilers = { 'cc', 'gcc', 'clang', 'cl', 'zig' }
|
||||
if uv.os_getenv('CC') then
|
||||
table.insert(M.compilers, 1, uv.os_getenv('CC'))
|
||||
end
|
||||
|
||||
local function system(cmd, opts)
|
||||
log.trace('running job: (cwd=%s) %s', opts.cwd, table.concat(cmd, ' '))
|
||||
local r = a.wrap(vim.system, 3)(cmd, opts) --[[@as vim.SystemCompleted]]
|
||||
|
|
@ -50,6 +39,10 @@ local function system(cmd, opts)
|
|||
return r
|
||||
end
|
||||
|
||||
local iswin = uv.os_uname().sysname == 'Windows_NT'
|
||||
|
||||
local M = {}
|
||||
|
||||
---
|
||||
--- PARSER INFO
|
||||
---
|
||||
|
|
@ -99,18 +92,6 @@ end
|
|||
--- PARSER MANAGEMENT FUNCTIONS
|
||||
---
|
||||
|
||||
local function istring(c)
|
||||
return type(c) == 'string'
|
||||
end
|
||||
|
||||
local function cc_err()
|
||||
log.error(
|
||||
'No C compiler found! "'
|
||||
.. table.concat(vim.tbl_filter(istring, M.compilers), '", "')
|
||||
.. '" are not executable.'
|
||||
)
|
||||
end
|
||||
|
||||
--- @param x string
|
||||
--- @return boolean
|
||||
local function executable(x)
|
||||
|
|
@ -122,10 +103,6 @@ end
|
|||
--- @param compile_location string
|
||||
--- @return string? err
|
||||
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
|
||||
|
||||
logger:info(
|
||||
string.format(
|
||||
'Generating parser.c from %s...',
|
||||
|
|
@ -134,7 +111,7 @@ local function do_generate(logger, repo, compile_location)
|
|||
)
|
||||
|
||||
local r = system({
|
||||
fn.exepath('tree-sitter'),
|
||||
'tree-sitter',
|
||||
'generate',
|
||||
'--no-bindings',
|
||||
'--abi',
|
||||
|
|
@ -232,10 +209,6 @@ 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({
|
||||
|
|
@ -266,86 +239,6 @@ local function do_download_git(logger, repo, project_name, cache_dir, revision,
|
|||
end
|
||||
end
|
||||
|
||||
--- @type table<string,table<string,boolean>>
|
||||
local cc_args_cache = vim.defaulttable()
|
||||
|
||||
--- @param cc string
|
||||
--- @param arg string
|
||||
--- @return boolean
|
||||
local function test_cc_arg(cc, arg)
|
||||
if cc_args_cache[cc][arg] == nil then
|
||||
cc_args_cache[cc][arg] = system({ cc, '-xc', '-', arg }, {
|
||||
stdin = 'int main(void) { return 0; }',
|
||||
}).code == 0
|
||||
end
|
||||
return cc_args_cache[cc][arg]
|
||||
end
|
||||
|
||||
---@param executables string[]
|
||||
---@return string?
|
||||
function M.select_executable(executables)
|
||||
return vim.tbl_filter(executable, executables)[1]
|
||||
end
|
||||
|
||||
-- Returns the compiler arguments based on the compiler and OS
|
||||
---@param repo InstallInfo
|
||||
---@param compiler string
|
||||
---@return string[]
|
||||
local function 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',
|
||||
}
|
||||
end
|
||||
|
||||
if compiler:find('zig$') or compiler:find('zig.exe$') then
|
||||
return {
|
||||
'cc',
|
||||
'-o',
|
||||
'parser.so',
|
||||
repo.files,
|
||||
'-lc',
|
||||
'-Isrc',
|
||||
'-shared',
|
||||
'-Os',
|
||||
}
|
||||
end
|
||||
|
||||
local args = {
|
||||
'-o',
|
||||
'parser.so',
|
||||
'-I./src',
|
||||
repo.files,
|
||||
'-Os',
|
||||
ismac and '-bundle' or '-shared',
|
||||
}
|
||||
|
||||
--- @param arg string
|
||||
local function add_cc_arg(arg)
|
||||
if test_cc_arg(compiler, arg) then
|
||||
args[#args + 1] = arg
|
||||
end
|
||||
end
|
||||
|
||||
if not iswin then
|
||||
add_cc_arg('-Wall')
|
||||
add_cc_arg('-Wextra')
|
||||
add_cc_arg('-fPIC')
|
||||
|
||||
-- Make sure we don't compile in any unresolved symbols, otherwise nvim will
|
||||
-- just exit (not even crash)
|
||||
add_cc_arg('-Werror=implicit-function-declaration')
|
||||
end
|
||||
|
||||
return args
|
||||
end
|
||||
|
||||
---@param repo InstallInfo
|
||||
---@return boolean
|
||||
local function can_download_tar(repo)
|
||||
|
|
@ -355,21 +248,40 @@ local function can_download_tar(repo)
|
|||
return can_use_tar and (is_github or is_gitlab) and not iswin
|
||||
end
|
||||
|
||||
-- Returns the compile command based on the OS and user options
|
||||
---@param logger Logger
|
||||
---@param repo InstallInfo
|
||||
---@param cc string
|
||||
---@param compile_location string
|
||||
---@return string? err
|
||||
local function do_compile(logger, repo, cc, compile_location)
|
||||
local args = vim.iter(select_compiler_args(repo, cc)):flatten():totable()
|
||||
local cmd = vim.list_extend({ cc }, args)
|
||||
local function do_compile(logger, compile_location)
|
||||
logger:info(string.format('Compiling parser'))
|
||||
|
||||
logger:info('Compiling parser')
|
||||
|
||||
local r = system(cmd, { cwd = compile_location })
|
||||
local r = system({
|
||||
'tree-sitter',
|
||||
'build',
|
||||
'-o',
|
||||
'parser.so',
|
||||
}, { cwd = compile_location })
|
||||
if r.code > 0 then
|
||||
return logger:error('Error during compilation: %s', r.stderr)
|
||||
return logger:error('Error during "tree-sitter build": %s', r.stderr)
|
||||
end
|
||||
end
|
||||
|
||||
---@param logger Logger
|
||||
---@param compile_location string
|
||||
---@param target_location string
|
||||
---@return string? err
|
||||
local function do_install(logger, compile_location, target_location)
|
||||
logger:info(string.format('Installing parser'))
|
||||
|
||||
if iswin then -- why can't you just be normal?!
|
||||
local tempfile = target_location .. tostring(uv.hrtime())
|
||||
uv_rename(target_location, tempfile) -- parser may be in use: rename...
|
||||
uv_unlink(tempfile) -- ...and mark for garbage collection
|
||||
end
|
||||
|
||||
local err = uv_copyfile(compile_location, target_location)
|
||||
a.main()
|
||||
if err then
|
||||
return logger:error('Error during parser installation: %s', err)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -383,12 +295,6 @@ local function install_lang0(lang, cache_dir, install_dir, generate)
|
|||
|
||||
local repo = get_parser_install_info(lang)
|
||||
if repo then
|
||||
local cc = M.select_executable(M.compilers)
|
||||
if not cc then
|
||||
cc_err()
|
||||
return
|
||||
end
|
||||
|
||||
local project_name = 'tree-sitter-' .. lang
|
||||
|
||||
local revision = repo.revision
|
||||
|
|
@ -414,7 +320,7 @@ local function install_lang0(lang, cache_dir, install_dir, generate)
|
|||
compile_location = fs.joinpath(compile_location, repo.location)
|
||||
end
|
||||
|
||||
do
|
||||
do -- generate parser from grammar
|
||||
if repo.generate or generate then
|
||||
local err = do_generate(logger, repo, compile_location)
|
||||
if err then
|
||||
|
|
@ -423,24 +329,25 @@ local function install_lang0(lang, cache_dir, install_dir, generate)
|
|||
end
|
||||
end
|
||||
|
||||
do
|
||||
local err = do_compile(logger, repo, cc, compile_location)
|
||||
do -- compile parser
|
||||
local err = do_compile(logger, compile_location)
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
end
|
||||
|
||||
local parser_lib_name = fs.joinpath(install_dir, lang) .. '.so'
|
||||
do -- install parser
|
||||
local parser_lib_name = fs.joinpath(compile_location, 'parser.so')
|
||||
local install_location = fs.joinpath(install_dir, lang) .. '.so'
|
||||
local err = do_install(logger, parser_lib_name, install_location)
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
|
||||
local err = uv_copyfile(fs.joinpath(compile_location, 'parser.so'), parser_lib_name)
|
||||
a.main()
|
||||
if err then
|
||||
return logger:error(err)
|
||||
local revfile = fs.joinpath(config.get_install_dir('parser-info') or '', lang .. '.revision')
|
||||
util.write_file(revfile, revision or '')
|
||||
end
|
||||
|
||||
local revfile = fs.joinpath(config.get_install_dir('parser-info') or '', lang .. '.revision')
|
||||
util.write_file(revfile, revision or '')
|
||||
|
||||
if not repo.path then
|
||||
util.delete(fs.joinpath(cache_dir, project_name))
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue