refactor: rewrite installation using jobs and async

Replace sync variants with callback support
This commit is contained in:
Lewis Russell
2023-05-22 14:35:25 +01:00
committed by Christian Clason
parent 5aa2984a02
commit cde679e435
15 changed files with 951 additions and 709 deletions

View File

@@ -59,9 +59,6 @@ require'nvim-treesitter'.setup {
-- List of parsers to ignore installing
ignore_install = { },
-- Install parsers synchronously (only applied to `ensure_install`)
sync_install = false,
-- Automatically install missing parsers when entering buffer
auto_install = false,

View File

@@ -7,7 +7,6 @@ This document lists the planned and finished changes in this rewrite towards [Nv
- [ ] **`query_predicates.lua`:** upstream/remove
- [ ] **`parsers.lua`:** modularize?
- [ ] **`parsers.lua`:** assign tiers
- [ ] **`install.lua`:** fix messages, add sync support (@lewis6991)
- [ ] **`install.lua`:** simplify compilation:
- hardcode one compiler + args per platform
- provide `install.compile_command` for overriding (function that takes files, ...?)
@@ -32,5 +31,6 @@ This document lists the planned and finished changes in this rewrite towards [Nv
- [X] install parsers to standard directory by default
- [X] remove bundled queries from runtimepath; copy on parser install
- [X] general refactor and cleanup
- [X] rewrite installation using async module (drop support for sync; use callback instead)
- [X] switch to upstream injection format
- [X] remove locals from highlighting (cf. https://github.com/nvim-treesitter/nvim-treesitter/issues/3944#issuecomment-1458782497)

View File

@@ -38,16 +38,13 @@ To install supported parsers and queries, put this in your `init.lua` file:
>lua
require'nvim-treesitter.configs'.setup {
-- A directory to install the parsers into.
-- A directory to install the parsers and queries to.
-- Defaults to the `stdpath('data')/site` dir.
install_dir = "/some/path/to/store/parsers",
-- A list of parser names, or "core", "stable", "community", "unstable"
ensure_install = { "core", "rust" },
-- Install parsers synchronously (only applied to `ensure_installed`)
sync_install = false,
-- Automatically install missing parsers when entering buffer
auto_install = false,
@@ -66,10 +63,6 @@ COMMANDS *nvim-treesitter-commands*
Install one or more treesitter parsers.
You can use |:TSInstall| `all` to install all parsers. Use |:TSInstall!| to
force the reinstallation of already installed parsers.
*:TSInstallSync*
:TSInstallSync {language} ... ~
Perform the |:TSInstall| operation synchronously.
*:TSInstallInfo*
:TSInstallInfo ~
@@ -83,11 +76,6 @@ Update the installed parser for one more {language} or all installed parsers
if {language} is omitted. The specified parser is installed if it is not already
installed.
*:TSUpdateSync*
:TSUpdateSync {language} ... ~
Perform the |:TSUpdate| operation synchronously.
*:TSUninstall*
:TSUninstall {language} ... ~

View File

@@ -0,0 +1,110 @@
local co = coroutine
local M = {}
---Executes a future with a callback when it is done
--- @param func function
--- @param callback function
--- @param ... unknown
local function execute(func, callback, ...)
local thread = co.create(func)
local function step(...)
local ret = { co.resume(thread, ...) }
--- @type boolean, any
local stat, nargs_or_err = unpack(ret)
if not stat then
error(
string.format(
'The coroutine failed with this message: %s\n%s',
nargs_or_err,
debug.traceback(thread)
)
)
end
if co.status(thread) == 'dead' then
if callback then
callback(unpack(ret, 3, table.maxn(ret)))
end
return
end
--- @type function, any[]
local fn, args = ret[3], { unpack(ret, 4, table.maxn(ret)) }
args[nargs_or_err] = step
fn(unpack(args, 1, nargs_or_err))
end
step(...)
end
--- Creates an async function with a callback style function.
--- @generic F: function
--- @param func F
--- @param argc integer
--- @return F
function M.wrap(func, argc)
--- @param ... unknown
--- @return unknown
return function(...)
return co.yield(argc, func, ...)
end
end
---Use this to create a function which executes in an async context but
---called from a non-async context. Inherently this cannot return anything
---since it is non-blocking
--- @generic F: function
--- @param func async F
--- @param nargs? integer
--- @return F
function M.sync(func, nargs)
nargs = nargs or 0
return function(...)
local callback = select(nargs + 1, ...)
execute(func, callback, unpack({ ... }, 1, nargs))
end
end
--- @param n integer max number of concurrent jobs
--- @param interrupt_check? function
--- @param thunks function[]
--- @return any
function M.join(n, interrupt_check, thunks)
return co.yield(1, function(finish)
if #thunks == 0 then
return finish()
end
local remaining = { select(n + 1, unpack(thunks)) }
local to_go = #thunks
local ret = {} --- @type any[]
local function cb(...)
ret[#ret + 1] = { ... }
to_go = to_go - 1
if to_go == 0 then
finish(ret)
elseif not interrupt_check or not interrupt_check() then
if #remaining > 0 then
local next_task = table.remove(remaining)
next_task(cb)
end
end
end
for i = 1, math.min(n, #thunks) do
thunks[i](cb)
end
end, 1)
end
---An async function that when called will yield to the Neovim scheduler to be
---able to call the API.
--- @type fun()
M.main = M.wrap(vim.schedule, 1)
return M

View File

@@ -1,7 +1,6 @@
local M = {}
---@class TSConfig
---@field sync_install boolean
---@field auto_install boolean
---@field ensure_install string[]
---@field ignore_install string[]
@@ -9,7 +8,6 @@ local M = {}
---@type TSConfig
local config = {
sync_install = false,
auto_install = false,
ensure_install = {},
ignore_install = {},
@@ -38,7 +36,11 @@ function M.setup(user_data)
and not vim.list_contains(M.installed_parsers(), lang)
and not vim.list_contains(config.ignore_install, lang)
then
require('nvim-treesitter.install').install(lang)
require('nvim-treesitter.install').install(lang, nil, function()
-- Need to pcall since 'FileType' can be triggered multiple times
-- per buffer
pcall(vim.treesitter.start, args.buf, lang)
end)
end
end,
})
@@ -48,9 +50,7 @@ function M.setup(user_data)
local to_install = M.norm_languages(config.ensure_install, { ignored = true, installed = true })
if #to_install > 0 then
require('nvim-treesitter.install').install(to_install, {
with_sync = config.sync_install,
})
require('nvim-treesitter.install').install(to_install)
end
end
end
@@ -63,9 +63,10 @@ function M.get_install_dir(dir_name)
local dir = vim.fs.joinpath(config.install_dir, dir_name)
if not vim.loop.fs_stat(dir) then
local ok, error = pcall(vim.fn.mkdir, dir, 'p', '0755')
local ok, err = pcall(vim.fn.mkdir, dir, 'p', '0755')
if not ok then
vim.notify(error, vim.log.levels.ERROR)
local log = require('nvim-treesitter.log')
log.error(err --[[@as string]])
end
end
return dir
@@ -105,35 +106,37 @@ function M.norm_languages(languages, skip)
end
languages = parsers.get_available()
end
--TODO(clason): skip and warn on unavailable parser
for i, tier in ipairs(parsers.tiers) do
if vim.list_contains(languages, tier) then
languages = vim.iter.filter(function(l)
return l ~= tier
end, languages)
end, languages) --[[@as string[] ]]
vim.list_extend(languages, parsers.get_available(i))
end
end
--TODO(clason): support skipping tiers
if skip and skip.ignored then
local ignored = config.ignore_install
languages = vim.iter.filter(function(v)
return not vim.list_contains(ignored, v)
end, languages)
end, languages) --[[@as string[] ]]
end
if skip and skip.installed then
local installed = M.installed_parsers()
languages = vim.iter.filter(function(v)
return not vim.list_contains(installed, v)
end, languages)
end, languages) --[[@as string[] ]]
end
if skip and skip.missing then
local installed = M.installed_parsers()
languages = vim.iter.filter(function(v)
return vim.list_contains(installed, v)
end, languages)
end, languages) --[[@as string[] ]]
end
return languages

View File

@@ -1,6 +1,6 @@
local shell = require('nvim-treesitter.shell_cmds')
local install = require('nvim-treesitter.install')
local config = require('nvim-treesitter.config')
local util = require('nvim-treesitter.util')
local tsq = vim.treesitter.query
local M = {}
@@ -62,7 +62,7 @@ local function install_health()
vim.health.ok('`git` executable found.')
end
local cc = shell.select_executable(install.compilers)
local cc = install.select_executable(install.compilers)
if not cc then
vim.health.error('`cc` executable not found.', {
'Check that any of '
@@ -118,6 +118,7 @@ local function query_status(lang, query_group)
end
function M.check()
--- @type {[1]: string, [2]: string, [3]: string}[]
local error_collection = {}
-- Installation dependency checks
install_health()
@@ -144,22 +145,19 @@ function M.check()
if #error_collection > 0 then
vim.health.start('The following errors have been detected:')
for _, p in ipairs(error_collection) do
local lang, type, err = unpack(p)
local lang, type, err = p[1], p[2], p[3]
local lines = {}
table.insert(lines, lang .. '(' .. type .. '): ' .. err)
local files = tsq.get_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(tsq.parse, lang, fd:read('*a'))
if ok then
table.insert(lines, '| [OK]:"' .. file .. '"')
else
table.insert(lines, '| [ERR]:"' .. file .. '", failed to load: ' .. file_err)
end
fd:close()
local query = util.read_file(file)
local ok, file_err = pcall(tsq.parse, lang, query)
if ok then
table.insert(lines, '| [OK]:"' .. file .. '"')
else
table.insert(lines, '| [ERR]:"' .. file .. '", failed to load: ' .. file_err)
end
end
end

File diff suppressed because it is too large Load Diff

122
lua/nvim-treesitter/job.lua Normal file
View File

@@ -0,0 +1,122 @@
-- Interface with Neovim job control and provide a simple job sequencing structure
local uv = vim.loop
local a = require('nvim-treesitter.async')
local log = require('nvim-treesitter.log')
local M = { JobResult = {}, Opts = {} }
--- @class JobResult
--- @field exit_code integer
--- @field signal integer | string
--- @field stdout string[]
--- @field stderr string[]
--- @class JobOpts
--- @field cwd string
--- @field timeout integer
--- @field env string[]
--- @field on_stderr fun(_: string)
--- @field on_stdout fun(_: string)
--- Wrapper for vim.loop.spawn. Takes a command, options, and callback just like
--- vim.loop.spawn, but ensures that all output from the command has been
--- flushed before calling the callback.
--- @param cmd string
--- @param options uv.aliases.spawn_options
--- @param callback fun(exit_code: integer, signal: integer|string)
local function spawn(cmd, options, callback)
local handle --- @type uv_process_t?
local timer --- @type uv_timer_t
log.trace('running job: (cwd=%s) %s %s', options.cwd, cmd, table.concat(options.args, ' '))
handle = uv.spawn(cmd, options, function(exit_code, signal)
---@cast handle -nil
handle:close()
if timer then
timer:stop()
timer:close()
end
callback(exit_code, signal)
end)
--- @type integer?
--- @diagnostic disable-next-line:undefined-field
local timeout = options.timeout
if timeout then
timer = assert(uv.new_timer())
timer:start(timeout, 0, function()
timer:stop()
timer:close()
if handle and handle:is_active() then
log.warn('Killing %s due to timeout!', cmd)
handle:kill('sigint')
handle:close()
for _, pipe in
pairs(options.stdio --[[@as uv_pipe_t[] ]])
do
pipe:close()
end
callback(-9999, 'sigint')
end
end)
end
end
--- Main exposed function for the jobs module. Takes a task and options and
--- returns an async function that will run the task with the given opts via
--- vim.loop.spawn
--- @param task string[]
--- @param opts JobOpts
--- @param callback fun(_: JobResult)
--- @type fun(task: string|string[], opts: JobOpts): JobResult
M.run = a.wrap(function(task, opts, callback)
local stdout_data = {}
local stderr_data = {}
local stdout = assert(uv.new_pipe(false))
local stderr = assert(uv.new_pipe(false))
spawn(task[1], {
args = { unpack(task, 2) },
stdio = { nil, stdout, stderr },
cwd = opts.cwd,
timeout = opts.timeout and 1000 * opts.timeout or nil,
env = opts.env,
hide = true,
}, function(exit_code, signal)
callback({
exit_code = exit_code,
signal = signal,
stdout = stdout_data,
stderr = stderr_data,
})
end)
for kind, pipe in pairs({ stdout = stdout, stderr = stderr }) do
pipe:read_start(function(err, data)
if kind == 'stderr' and opts.on_stderr and data then
opts.on_stderr(data)
end
if kind == 'stdout' and opts.on_stdout and data then
opts.on_stdout(data)
end
if data then
log.trace('%s -> %s', kind, data)
end
if err then
log.error(err)
end
if data ~= nil then
local output = kind == 'stdout' and stdout_data or stderr_data
table.insert(output, vim.trim(data))
else
pipe:read_stop()
pipe:close()
end
end)
end
end, 3)
return M

133
lua/nvim-treesitter/log.lua Normal file
View File

@@ -0,0 +1,133 @@
local api = vim.api
-- TODO(lewis6991): write these out to a file
local messages = {} --- @type {[1]: string, [2]: string?, [3]: string}[]
local sev_to_hl = {
trace = 'DiagnosticHint',
debug = 'Normal',
info = 'MoreMsg',
warn = 'WarningMsg',
error = 'ErrorMsg',
}
---@param ctx string?
---@param m string
---@param ... any
local function trace(ctx, m, ...)
messages[#messages + 1] = { 'trace', ctx, string.format(m, ...) }
end
---@param ctx string?
---@param m string
---@param ... any
local function debug(ctx, m, ...)
messages[#messages + 1] = { 'debug', ctx, string.format(m, ...) }
end
---@param ctx string?
---@return string
local function mkpfx(ctx)
return ctx and string.format('[nvim-treesitter/%s]', ctx) or '[nvim-treesitter]'
end
---@param ctx string?
---@param m string
---@param ... any
local function info(ctx, m, ...)
local m1 = string.format(m, ...)
messages[#messages + 1] = { 'info', ctx, m1 }
api.nvim_echo({ { mkpfx(ctx) .. ': ' .. m1, sev_to_hl.info } }, true, {})
end
---@param ctx string?
---@param m string
---@param ... any
local function warn(ctx, m, ...)
local m1 = string.format(m, ...)
messages[#messages + 1] = { 'warn', ctx, m1 }
api.nvim_echo({ { mkpfx(ctx) .. ' warning: ' .. m1, sev_to_hl.warn } }, true, {})
end
---@param ctx string?
---@param m string
---@param ... any
local function lerror(ctx, m, ...)
local m1 = string.format(m, ...)
messages[#messages + 1] = { 'error', ctx, m1 }
error(mkpfx(ctx) .. ' error: ' .. m1)
end
--- @class NTSLogModule
--- @field trace fun(fmt: string, ...: any)
--- @field debug fun(fmt: string, ...: any)
--- @field info fun(fmt: string, ...: any)
--- @field warn fun(fmt: string, ...: any)
--- @field error fun(fmt: string, ...: any)
local M = {}
--- @class Logger
--- @field ctx? string
local Logger = {}
M.Logger = Logger
--- @param ctx? string
--- @return Logger
function M.new(ctx)
return setmetatable({ ctx = ctx }, { __index = Logger })
end
---@param m string
---@param ... any
function Logger:trace(m, ...)
trace(self.ctx, m, ...)
end
---@param m string
---@param ... any
function Logger:debug(m, ...)
debug(self.ctx, m, ...)
end
---@param m string
---@param ... any
function Logger:info(m, ...)
info(self.ctx, m, ...)
end
---@param m string
---@param ... any
function Logger:warn(m, ...)
warn(self.ctx, m, ...)
end
---@param m string
---@param ... any
function Logger:error(m, ...)
lerror(self.ctx, m, ...)
end
local noctx_logger = M.new()
setmetatable(M, {
__index = function(t, k)
--- @diagnostic disable-next-line:no-unknown
t[k] = function(...)
return noctx_logger[k](noctx_logger, ...)
end
return t[k]
end,
})
function M.show()
for _, l in ipairs(messages) do
local sev, ctx, msg = l[1], l[2], l[3]
local hl = sev_to_hl[sev]
local text = ctx and string.format('%s(%s): %s', sev, ctx, msg)
or string.format('%s: %s', sev, msg)
api.nvim_echo({ { text, hl } }, false, {})
end
end
return M

View File

@@ -2818,17 +2818,18 @@ M.configs = {
---@param tier integer? only get parsers of specified tier
---@return string[]
function M.get_available(tier)
--- @type string[]
local parsers = vim.tbl_keys(M.configs)
table.sort(parsers)
if tier then
parsers = vim.iter.filter(function(p)
return M.configs[p].tier == tier
end, parsers)
end, parsers) --[[@as string[] ]]
end
if vim.fn.executable('tree-sitter') == 0 or vim.fn.executable('node') == 0 then
parsers = vim.iter.filter(function(p)
return not M.configs[p].install_info.requires_generate_from_grammar
end, parsers)
end, parsers) --[[@as string[] ]]
end
return parsers
end

View File

@@ -1,258 +0,0 @@
local uv = vim.loop
local iswin = uv.os_uname().sysname == 'Windows_NT'
local M = {}
---@param executables string[]
---@return string|nil
function M.select_executable(executables)
return vim.tbl_filter(function(c) ---@param c string
return c ~= vim.NIL and vim.fn.executable(c) == 1
end, executables)[1]
end
-- Returns the compiler arguments based on the compiler and OS
---@param repo InstallInfo
---@param compiler string
---@return string[]
function M.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',
}
elseif compiler:find('zig$') or compiler:find('zig.exe$') then
return {
'c++',
'-o',
'parser.so',
repo.files,
'-lc',
'-Isrc',
'-shared',
'-Os',
}
else
local args = {
'-o',
'parser.so',
'-I./src',
repo.files,
'-Os',
}
if uv.os_uname().sysname == 'Darwin' then
table.insert(args, '-bundle')
else
table.insert(args, '-shared')
end
if
#vim.tbl_filter(function(file) ---@param file string
local ext = vim.fn.fnamemodify(file, ':e')
return ext == 'cc' or ext == 'cpp' or ext == 'cxx'
end, repo.files) > 0
then
table.insert(args, '-lstdc++')
end
if not iswin then
table.insert(args, '-fPIC')
end
return args
end
end
-- Returns the compile command based on the OS and user options
---@param repo InstallInfo
---@param cc string
---@param compile_location string
---@return Command
function M.select_compile_command(repo, cc, compile_location)
local make = M.select_executable({ 'gmake', 'make' })
if cc:find('cl$') or cc:find('cl.exe$') or not repo.use_makefile or iswin or not make then
return {
cmd = cc,
info = 'Compiling...',
err = 'Error during compilation',
opts = {
args = vim.tbl_flatten(M.select_compiler_args(repo, cc)),
cwd = compile_location,
},
}
else
return {
cmd = make,
info = 'Compiling...',
err = 'Error during compilation',
opts = {
args = {
'--makefile=' .. M.get_package_path('scripts', 'compile_parsers.makefile'),
'CC=' .. cc,
},
cwd = compile_location,
},
}
end
end
---@param repo InstallInfo
---@param project_name string
---@param cache_dir string
---@param revision string|nil
---@param prefer_git boolean
---@return table
function M.select_download_commands(repo, project_name, cache_dir, revision, prefer_git)
local can_use_tar = vim.fn.executable('tar') == 1 and vim.fn.executable('curl') == 1
local is_github = repo.url:find('github.com', 1, true)
local is_gitlab = repo.url:find('gitlab.com', 1, true)
local project_dir = vim.fs.joinpath(cache_dir, project_name)
revision = revision or repo.branch or 'master'
if can_use_tar and (is_github or is_gitlab) and not prefer_git then
local url = repo.url:gsub('.git$', '')
local dir_rev = revision
if is_github and revision:find('^v%d') then
dir_rev = revision:sub(2)
end
local temp_dir = project_dir .. '-tmp'
return {
{
cmd = function()
vim.fn.delete(temp_dir, 'rf')
end,
},
{
cmd = 'curl',
info = 'Downloading ' .. project_name .. '...',
err = 'Error during download, please verify your internet connection',
opts = {
args = {
'--silent',
'-L', -- follow redirects
is_github and url .. '/archive/' .. revision .. '.tar.gz'
or url
.. '/-/archive/'
.. revision
.. '/'
.. project_name
.. '-'
.. revision
.. '.tar.gz',
'--output',
project_name .. '.tar.gz',
},
cwd = cache_dir,
},
},
{
cmd = function()
--TODO(clason): use vim.fn.mkdir(temp_dir, 'p') in case stdpath('cache') is not created
uv.fs_mkdir(temp_dir, 493)
end,
info = 'Creating temporary directory',
err = 'Could not create ' .. project_name .. '-tmp',
},
{
cmd = 'tar',
info = 'Extracting ' .. project_name .. '...',
err = 'Error during tarball extraction.',
opts = {
args = {
'-xvzf',
project_name .. '.tar.gz',
'-C',
project_name .. '-tmp',
},
cwd = cache_dir,
},
},
{
cmd = function()
uv.fs_unlink(project_dir .. '.tar.gz')
end,
},
{
cmd = function()
uv.fs_rename(
vim.fs.joinpath(temp_dir, url:match('[^/]-$') .. '-' .. dir_rev),
project_dir
)
end,
},
{
cmd = function()
vim.fn.delete(temp_dir, 'rf')
end,
},
}
else
local git_dir = project_dir
local clone_error = 'Error during download, please verify your internet connection'
return {
{
cmd = 'git',
info = 'Downloading ' .. project_name .. '...',
err = clone_error,
opts = {
args = {
'clone',
repo.url,
project_name,
},
cwd = cache_dir,
},
},
{
cmd = 'git',
info = 'Checking out locked revision',
err = 'Error while checking out revision',
opts = {
args = {
'checkout',
revision,
},
cwd = git_dir,
},
},
}
end
end
function M.get_package_path(...)
return vim.fs.joinpath(vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':p:h:h:h'), ...)
end
--TODO(clason): only needed for iter_cmd_sync -> replace with uv.spawn?
-- Convert path for cmd.exe on Windows (needed when shellslash is set)
---@param p string
---@return string
local function cmdpath(p)
return vim.o.shellslash and p:gsub('/', '\\') or p
end
---@param dir string
---@param command string
---@return string command
function M.make_directory_change_for_command(dir, command)
if iswin then
if string.find(vim.o.shell, 'cmd') ~= nil then
return string.format('pushd %s & %s & popd', cmdpath(dir), command)
else
return string.format('pushd %s ; %s ; popd', cmdpath(dir), command)
end
else
return string.format('cd %s;\n %s', dir, command)
end
end
return M

View File

@@ -0,0 +1,28 @@
local uv = vim.loop
local M = {}
--- @param filename string
--- @return string
function M.read_file(filename)
local file = assert(io.open(filename, 'r'))
local r = file:read('*a')
file:close()
return r
end
--- @param filename string
--- @param content string
function M.write_file(filename, content)
local file = assert(io.open(filename, 'w'))
file:write(content)
file:close()
end
--- Recursively delete a directory
--- @param name string
function M.delete(name)
vim.fs.rm(name, { recursive = true, force = true })
end
return M

View File

@@ -45,19 +45,6 @@ end, {
desc = 'Install treesitter parsers from grammar',
})
api.nvim_create_user_command('TSInstallSync', function(args)
require('nvim-treesitter.install').install(args.fargs, {
with_sync = true,
force = args.bang,
})
end, {
nargs = '+',
bang = true,
bar = true,
complete = complete_available_parsers,
desc = 'Install treesitter parsers synchronously',
})
api.nvim_create_user_command('TSUpdate', function(args)
require('nvim-treesitter.install').update(args.fargs)
end, {
@@ -67,15 +54,6 @@ end, {
desc = 'Update installed treesitter parsers',
})
api.nvim_create_user_command('TSUpdateSync', function(args)
require('nvim-treesitter.install').update(args.fargs, { with_sync = true })
end, {
nargs = '*',
bar = true,
complete = complete_installed_parsers,
desc = 'Update installed treesitter parsers synchronously',
})
api.nvim_create_user_command('TSUninstall', function(args)
require('nvim-treesitter.install').uninstall(args.fargs)
end, {
@@ -84,3 +62,9 @@ end, {
complete = complete_installed_parsers,
desc = 'Uninstall treesitter parsers',
})
api.nvim_create_user_command('TSLog', function()
require('nvim-treesitter.log').show()
end, {
desc = 'View log messages',
})

View File

@@ -65,9 +65,8 @@ for _, v in ipairs(sorted_parsers) do
end
generated_text = generated_text .. footnotes
local readme = assert(io.open('SUPPORTED_LANGUAGES.md', 'r'))
local readme_text = readme:read('*a')
readme:close()
local readme = 'SUPPORTED_LANGUAGES.md'
local readme_text = require('nvim-treesitter.util').read_file(readme)
local new_readme_text = string.gsub(
readme_text,
@@ -75,12 +74,10 @@ local new_readme_text = string.gsub(
'<!--parserinfo-->\n' .. generated_text .. '<!--parserinfo-->'
)
readme = assert(io.open('SUPPORTED_LANGUAGES.md', 'w'))
readme:write(new_readme_text)
readme:close()
require('nvim-treesitter.util').write_file(readme, new_readme_text)
if string.find(readme_text, generated_text, 1, true) then
print('README.md is up-to-date\n')
print(readme .. ' is up-to-date\n')
else
print('New README.md was written\n')
print('New ' .. readme .. ' was written\n')
end

View File

@@ -2,10 +2,8 @@
vim.opt.runtimepath:append('.')
-- Load previous lockfile
local filename = require('nvim-treesitter.shell_cmds').get_package_path('lockfile.json')
local file = assert(io.open(filename, 'r'))
local lockfile = vim.json.decode(file:read('*a'))
file:close()
local filename = require('nvim-treesitter.install').get_package_path('lockfile.json')
local lockfile = vim.json.decode(require('nvim-treesitter.util').read_file(filename))
---@type string?
local skip_lang_string = os.getenv('SKIP_LOCKFILE_UPDATE_FOR_LANGS')
@@ -47,6 +45,4 @@ end
vim.print(lockfile)
-- write new lockfile
file = assert(io.open(filename, 'w'))
file:write(vim.json.encode(lockfile))
file:close()
require('nvim-treesitter.util').write_file(filename, vim.json.encode(lockfile))