Use stylua for autoformat code (#1480)

This commit is contained in:
Santos Gallegos 2021-07-04 16:12:17 -05:00 committed by GitHub
parent 90f15d9bf7
commit be8f656087
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1181 additions and 979 deletions

View file

@ -18,3 +18,14 @@ jobs:
- name: Run Luacheck
run: sudo ./scripts/style-check.sh
stylua:
name: StyLua
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Lint with stylua
uses: JohnnyMorganz/stylua-action@1.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --check .

3
.stylua.toml Normal file
View file

@ -0,0 +1,3 @@
indent_type = "Spaces"
indent_width = 2
no_call_parentheses = true

1
.styluaignore Normal file
View file

@ -0,0 +1 @@
tests/indent/lua/

View file

@ -15,12 +15,13 @@ Depending on which part of the plugin you want to contribute to, please read the
## Style Checks and Tests
We haven't implemented any functional tests yet. Feel free to contribute.
However, we check code style with `luacheck`!
However, we check code style with `luacheck` and `stylua`!
Please install luacheck and activate our `pre-push` hook to automatically check style before
every push:
```bash
luarocks install luacheck
cargo install stylua
ln -s ../../scripts/pre-push .git/hooks/pre-push
```

View file

@ -1,24 +1,23 @@
if not pcall(require,"vim.treesitter.languagetree") then
error("nvim-treesitter requires a more recent Neovim nightly version!")
if not pcall(require, "vim.treesitter.languagetree") then
error "nvim-treesitter requires a more recent Neovim nightly version!"
end
local install = require'nvim-treesitter.install'
local utils = require'nvim-treesitter.utils'
local ts_utils = require'nvim-treesitter.ts_utils'
local info = require'nvim-treesitter.info'
local configs = require'nvim-treesitter.configs'
local parsers = require'nvim-treesitter.parsers'
local install = require "nvim-treesitter.install"
local utils = require "nvim-treesitter.utils"
local ts_utils = require "nvim-treesitter.ts_utils"
local info = require "nvim-treesitter.info"
local configs = require "nvim-treesitter.configs"
local parsers = require "nvim-treesitter.parsers"
-- Registers all query predicates
require"nvim-treesitter.query_predicates"
require "nvim-treesitter.query_predicates"
local M = {}
function M.setup()
utils.setup_commands('install', install.commands)
utils.setup_commands('info', info.commands)
utils.setup_commands('configs', configs.commands)
utils.setup_commands("install", install.commands)
utils.setup_commands("info", info.commands)
utils.setup_commands("configs", configs.commands)
configs.init()
end
@ -35,37 +34,43 @@ local get_line_for_node = function(node, type_patterns, transform_fn)
break
end
end
if not is_valid then return '' end
local line = transform_fn(vim.trim(ts_utils.get_node_text(node)[1] or ''))
if not is_valid then
return ""
end
local line = transform_fn(vim.trim(ts_utils.get_node_text(node)[1] or ""))
-- Escape % to avoid statusline to evaluate content as expression
return line:gsub('%%', '%%%%')
return line:gsub("%%", "%%%%")
end
-- Trim spaces and opening brackets from end
local transform_line = function(line)
return line:gsub('%s*[%[%(%{]*%s*$', '')
return line:gsub("%s*[%[%(%{]*%s*$", "")
end
function M.statusline(opts)
if not parsers.has_parser() then return end
if not parsers.has_parser() then
return
end
local options = opts or {}
if type(opts) == 'number' then
options = {indicator_size = opts}
if type(opts) == "number" then
options = { indicator_size = opts }
end
local indicator_size = options.indicator_size or 100
local type_patterns = options.type_patterns or {'class', 'function', 'method'}
local type_patterns = options.type_patterns or { "class", "function", "method" }
local transform_fn = options.transform_fn or transform_line
local separator = options.separator or ' -> '
local separator = options.separator or " -> "
local current_node = ts_utils.get_node_at_cursor()
if not current_node then return "" end
if not current_node then
return ""
end
local lines = {}
local expr = current_node
while expr do
local line = get_line_for_node(expr, type_patterns, transform_fn)
if line ~= '' and not vim.tbl_contains(lines, line) then
if line ~= "" and not vim.tbl_contains(lines, line) then
table.insert(lines, 1, line)
end
expr = expr:parent()
@ -74,7 +79,7 @@ function M.statusline(opts)
local text = table.concat(lines, separator)
local text_len = #text
if text_len > indicator_size then
return '...'..text:sub(text_len - indicator_size, text_len)
return "..." .. text:sub(text_len - indicator_size, text_len)
end
return text

View file

@ -12,7 +12,7 @@ function M.create_buffer_cache()
__index = function(tbl, key)
rawset(tbl, key, {})
return rawget(tbl, key)
end
end,
})
function cache.set(type_name, bufnr, value)
@ -23,7 +23,7 @@ function M.create_buffer_cache()
on_detach = function()
cache.remove(type_name, bufnr)
return true
end
end,
})
end

View file

@ -1,10 +1,10 @@
local api = vim.api
local queries = require'nvim-treesitter.query'
local ts_query = require'vim.treesitter.query'
local parsers = require'nvim-treesitter.parsers'
local utils = require'nvim-treesitter.utils'
local caching = require'nvim-treesitter.caching'
local queries = require "nvim-treesitter.query"
local ts_query = require "vim.treesitter.query"
local parsers = require "nvim-treesitter.parsers"
local utils = require "nvim-treesitter.utils"
local caching = require "nvim-treesitter.caching"
local M = {}
@ -12,7 +12,7 @@ local config = {
modules = {},
ensure_installed = {},
ignore_install = {},
update_strategy = 'lockfile',
update_strategy = "lockfile",
}
-- List of modules that need to be setup on initialization.
local queued_modules_defs = {}
@ -20,31 +20,33 @@ local queued_modules_defs = {}
local is_initialized = false
local builtin_modules = {
highlight = {
module_path = 'nvim-treesitter.highlight',
module_path = "nvim-treesitter.highlight",
enable = false,
disable = {'markdown'}, -- FIXME(vigoux): markdown highlighting breaks everything for now
disable = { "markdown" }, -- FIXME(vigoux): markdown highlighting breaks everything for now
custom_captures = {},
is_supported = queries.has_highlights,
additional_vim_regex_highlighting = false,
},
incremental_selection = {
module_path = 'nvim-treesitter.incremental_selection',
module_path = "nvim-treesitter.incremental_selection",
enable = false,
disable = {},
keymaps = {
init_selection="gnn",
node_incremental="grn",
scope_incremental="grc",
node_decremental="grm"
init_selection = "gnn",
node_incremental = "grn",
scope_incremental = "grc",
node_decremental = "grm",
},
is_supported = function() return true end
is_supported = function()
return true
end,
},
indent = {
module_path = 'nvim-treesitter.indent',
module_path = "nvim-treesitter.indent",
enable = false,
disable = {},
is_supported = queries.has_indents
}
is_supported = queries.has_indents,
},
}
local attached_buffers_by_module = caching.create_buffer_cache()
@ -53,11 +55,13 @@ local attached_buffers_by_module = caching.create_buffer_cache()
local function resolve_module(mod_name)
local config_mod = M.get_module(mod_name)
if not config_mod then return end
if not config_mod then
return
end
if type(config_mod.attach) == 'function' and type(config_mod.detach) == 'function' then
if type(config_mod.attach) == "function" and type(config_mod.detach) == "function" then
return config_mod
elseif type(config_mod.module_path) == 'string' then
elseif type(config_mod.module_path) == "string" then
return require(config_mod.module_path)
end
end
@ -92,7 +96,9 @@ end
-- @param mod path to module
local function enable_all(mod)
local config_mod = M.get_module(mod)
if not config_mod then return end
if not config_mod then
return
end
for _, bufnr in pairs(api.nvim_list_bufs()) do
enable_module(mod, bufnr)
@ -120,7 +126,7 @@ local function disable_mod_conf_autocmd(mod)
end
-- TODO(kyazdani): detach the correct autocmd... doesn't work when using %s, cmd.
-- This will remove all autocomands!
api.nvim_command("autocmd! NvimTreesitter FileType *")
api.nvim_command "autocmd! NvimTreesitter FileType *"
config_mod.loaded = false
end
@ -129,7 +135,9 @@ end
-- @param mod path to module
local function disable_all(mod)
local config_mod = M.get_module(mod)
if not config_mod or not config_mod.enable then return end
if not config_mod or not config_mod.enable then
return
end
for _, bufnr in pairs(api.nvim_list_bufs()) do
disable_module(mod, bufnr)
@ -158,7 +166,9 @@ end
-- @param mod path to module
local function toggle_all(mod)
local config_mod = M.get_module(mod)
if not config_mod then return end
if not config_mod then
return
end
if config_mod.enable then
disable_all(mod)
@ -175,11 +185,11 @@ local function recurse_modules(accumulator, root, path)
local root = root or config.modules
for name, module in pairs(root) do
local new_path = path and (path..'.'..name) or name
local new_path = path and (path .. "." .. name) or name
if M.is_module(module) then
accumulator(name, module, new_path, root)
elseif type(module) == 'table' then
elseif type(module) == "table" then
recurse_modules(accumulator, module, new_path)
end
end
@ -189,53 +199,56 @@ end
-- @param process_function function used as the `process` parameter
-- for vim.inspect (https://github.com/kikito/inspect.lua#optionsprocess)
local function config_info(process_function)
process_function = process_function or function(item, path)
if path[#path] == vim.inspect.METATABLE then return end
if path[#path] == "is_supported" then return end
return item
end
print(vim.inspect(config, {process = process_function}))
process_function = process_function
or function(item, path)
if path[#path] == vim.inspect.METATABLE then
return
end
if path[#path] == "is_supported" then
return
end
return item
end
print(vim.inspect(config, { process = process_function }))
end
function M.edit_query_file(query_group, lang)
lang = lang or parsers.get_buf_lang()
local files = ts_query.get_query_files(lang, query_group, true)
if #files == 0 then
vim.notify('No query file found! Creating a new one!')
vim.notify "No query file found! Creating a new one!"
M.edit_query_file_user_after(query_group, lang)
elseif #files == 1 then
vim.cmd(':edit '..files[1])
vim.cmd(":edit " .. files[1])
else
local counter = 0
local choices = {
'Select a file:',
"Select a file:",
unpack(vim.tbl_map(function(f)
counter = counter + 1
return counter..'. '..f
end,
files
))
counter = counter + 1
return counter .. ". " .. f
end, files)),
}
local choice = vim.fn.inputlist(choices)
if choice > 0 and choice <= #files then
vim.cmd(':edit '..files[choice])
vim.cmd(":edit " .. files[choice])
end
end
end
function M.edit_query_file_user_after(query_group, lang)
lang = lang or parsers.get_buf_lang()
local folder = utils.join_path(vim.fn.stdpath('config'), 'after', 'queries', lang)
local file = utils.join_path(folder, query_group..'.scm')
local folder = utils.join_path(vim.fn.stdpath "config", "after", "queries", lang)
local file = utils.join_path(folder, query_group .. ".scm")
if vim.fn.isdirectory(folder) ~= 1 then
local choice = vim.fn.inputlist({'"'..folder.." does not exist. Create it?", "1. Yes", "2. No"})
local choice = vim.fn.inputlist { '"' .. folder .. " does not exist. Create it?", "1. Yes", "2. No" }
if choice == 1 then
vim.fn.mkdir(folder, "p", "0755")
else
return
end
end
vim.cmd(':edit '..file)
vim.cmd(":edit " .. file)
end
M.commands = {
@ -311,14 +324,18 @@ function M.is_enabled(mod, lang)
end
local module_config = M.get_module(mod)
if not module_config then return false end
if not module_config then
return false
end
if not module_config.enable or not module_config.is_supported(lang) then
return false
end
for _, parser in pairs(module_config.disable) do
if lang == parser then return false end
if lang == parser then
return false
end
end
return true
@ -327,12 +344,12 @@ end
-- Setup call for users to override module configurations.
-- @param user_data module overrides
function M.setup(user_data)
config.modules = vim.tbl_deep_extend('force', config.modules, user_data)
config.modules = vim.tbl_deep_extend("force", config.modules, user_data)
config.ignore_install = user_data.ignore_install or {}
local ensure_installed = user_data.ensure_installed or {}
if #ensure_installed > 0 then
require'nvim-treesitter.install'.ensure_installed(ensure_installed)
require("nvim-treesitter.install").ensure_installed(ensure_installed)
end
config.modules.ensure_installed = nil
@ -381,7 +398,9 @@ function M.define_modules(mod_defs)
group[key] = vim.tbl_extend("keep", mod, {
enable = false,
disable = {},
is_supported = function() return true end
is_supported = function()
return true
end,
})
end, mod_defs)
@ -404,9 +423,7 @@ function M.attach_module(mod_name, bufnr, lang)
local lang = lang or parsers.get_buf_lang(bufnr)
local resolved_mod = resolve_module(mod_name)
if resolved_mod
and not attached_buffers_by_module.has(mod_name, bufnr)
and M.is_enabled(mod_name, lang) then
if resolved_mod and not attached_buffers_by_module.has(mod_name, bufnr) and M.is_enabled(mod_name, lang) then
attached_buffers_by_module.set(mod_name, bufnr, true)
resolved_mod.attach(bufnr, lang)
end
@ -450,9 +467,9 @@ end
-- A module should contain an attach and detach function.
-- @param mod the module table
function M.is_module(mod)
return type(mod) == 'table'
and ((type(mod.attach) == 'function' and type(mod.detach) == 'function')
or type(mod.module_path) == 'string')
return type(mod) == "table" and ((type(mod.attach) == "function" and type(mod.detach) == "function") or type(
mod.module_path
) == "string")
end
-- Initializes built-in modules and any queued modules

View file

@ -1,17 +1,19 @@
local api = vim.api
local tsutils = require'nvim-treesitter.ts_utils'
local query = require'nvim-treesitter.query'
local parsers = require'nvim-treesitter.parsers'
local tsutils = require "nvim-treesitter.ts_utils"
local query = require "nvim-treesitter.query"
local parsers = require "nvim-treesitter.parsers"
local M = {}
-- This is cached on buf tick to avoid computing that multiple times
-- Especially not for every line in the file when `zx` is hit
local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local max_fold_level = api.nvim_win_get_option(0, 'foldnestmax')
local max_fold_level = api.nvim_win_get_option(0, "foldnestmax")
local parser = parsers.get_parser(bufnr)
if not parser then return {} end
if not parser then
return {}
end
local matches = query.get_capture_matches_recursively(bufnr, function(lang)
if query.has_folds(lang) then
@ -44,13 +46,13 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local current_level = 0
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start
for lnum=0, api.nvim_buf_line_count(bufnr) do
local prefix = ''
for lnum = 0, api.nvim_buf_line_count(bufnr) do
local prefix = ""
local shift = levels_tmp[lnum] or 0
-- Determine if it's the start of a fold
if levels_tmp[lnum] and shift >= 0 then
prefix = '>'
prefix = ">"
end
current_level = current_level + shift
@ -67,13 +69,15 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
end)
function M.get_fold_indic(lnum)
if not parsers.has_parser() or not lnum then return '0' end
if not parsers.has_parser() or not lnum then
return "0"
end
local buf = api.nvim_get_current_buf()
local levels = folds_levels(buf) or {}
return levels[lnum] or '0'
return levels[lnum] or "0"
end
return M

View file

@ -1,75 +1,92 @@
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 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 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')
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)')
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")
local handle = io.popen "tree-sitter -V"
local result = handle:read "*a"
handle:close()
local version = vim.split(result,'\n')[1]:match('[^tree%psitter].*')
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)"
"`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)')
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")
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)')
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.'
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.')
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!'
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))
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.')
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.')
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
@ -90,35 +107,35 @@ function M.checkhealth()
-- Installation dependency checks
install_health()
queries.invalidate_query_cache()
health_start("Parser/Features H L F I")
health_start "Parser/Features H L F I"
-- Parser installation checks
for _, parser_name in pairs(info.installed_parsers()) do
local installed = #api.nvim_get_runtime_file('parser/'..parser_name..'.so', false)
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))
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.." "
out = out .. status .. " "
if err then
table.insert(error_collection, {parser_name, query_group, err})
table.insert(error_collection, { parser_name, query_group, err })
end
end
print(out)
end
end
print([[
print [[
Legend: H[ighlight], L[ocals], F[olds], I[ndents]
+) multiple parsers found, only one will be used
x) errors found in the query, try to run :TSUpdate {lang}]])
x) errors found in the query, try to run :TSUpdate {lang}]]
if #error_collection > 0 then
print('\nThe following errors have been detected:')
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)
health_error(lang .. "(" .. type .. "): " .. err)
end
end
end

View file

@ -1,11 +1,10 @@
local api = vim.api
local ts = vim.treesitter
local parsers = require'nvim-treesitter.parsers'
local configs = require'nvim-treesitter.configs'
local parsers = require "nvim-treesitter.parsers"
local configs = require "nvim-treesitter.configs"
local M = {
}
local M = {}
local hlmap = vim.treesitter.highlighter.hl_map
@ -104,7 +103,7 @@ hlmap["variable.builtin"] = "TSVariableBuiltin"
function M.attach(bufnr, lang)
local parser = parsers.get_parser(bufnr, lang)
local config = configs.get_module('highlight')
local config = configs.get_module "highlight"
for k, v in pairs(config.custom_captures) do
hlmap[k] = v
@ -112,9 +111,9 @@ function M.attach(bufnr, lang)
ts.highlighter.new(parser, {})
local is_table = type(config.additional_vim_regex_highlighting) == 'table'
local is_table = type(config.additional_vim_regex_highlighting) == "table"
if config.additional_vim_regex_highlighting and (not is_table or config.additional_vim_regex_highlighting[lang]) then
api.nvim_buf_set_option(bufnr, 'syntax', 'ON')
api.nvim_buf_set_option(bufnr, "syntax", "ON")
end
end
@ -122,7 +121,7 @@ function M.detach(bufnr)
if ts.highlighter.active[bufnr] then
ts.highlighter.active[bufnr]:destroy()
end
api.nvim_buf_set_option(bufnr, 'syntax', 'ON')
api.nvim_buf_set_option(bufnr, "syntax", "ON")
end
return M

View file

@ -1,10 +1,10 @@
local api = vim.api
local configs = require'nvim-treesitter.configs'
local ts_utils = require'nvim-treesitter.ts_utils'
local locals = require'nvim-treesitter.locals'
local parsers = require'nvim-treesitter.parsers'
local queries = require'nvim-treesitter.query'
local configs = require "nvim-treesitter.configs"
local ts_utils = require "nvim-treesitter.ts_utils"
local locals = require "nvim-treesitter.locals"
local parsers = require "nvim-treesitter.parsers"
local queries = require "nvim-treesitter.query"
local M = {}
@ -21,8 +21,8 @@ end
--
-- The range of ts nodes start with 0 and the ending range is exclusive.
local function visual_selection_range()
local _, csrow, cscol, _ = unpack(vim.fn.getpos("'<"))
local _, cerow, cecol, _ = unpack(vim.fn.getpos("'>"))
local _, csrow, cscol, _ = unpack(vim.fn.getpos "'<")
local _, cerow, cecol, _ = unpack(vim.fn.getpos "'>")
local start_row, start_col, end_row, end_col
@ -39,8 +39,8 @@ local function visual_selection_range()
end
-- The last char in ts is equivalent to the EOF in another line.
local last_row = vim.fn.line("$")
local last_col = vim.fn.col({last_row, "$"})
local last_row = vim.fn.line "$"
local last_col = vim.fn.col { last_row, "$" }
last_row = last_row - 1
last_col = last_col - 1
if end_row == last_row and end_col == last_col then
@ -92,12 +92,7 @@ local function select_incremental(get_parent)
end
node = parent
local srow, scol, erow, ecol = node:range()
local same_range = (
srow == csrow
and scol == cscol
and erow == cerow
and ecol == cecol
)
local same_range = (srow == csrow and scol == cscol and erow == cerow and ecol == cecol)
if not same_range then
table.insert(selections[buf], node)
if node ~= nodes[#nodes] then
@ -126,7 +121,9 @@ end)
function M.node_decremental()
local buf = api.nvim_get_current_buf()
local nodes = selections[buf]
if not nodes or #nodes < 2 then return end
if not nodes or #nodes < 2 then
return
end
table.remove(selections[buf])
local node = nodes[#nodes]
@ -134,13 +131,13 @@ function M.node_decremental()
end
function M.attach(bufnr)
local config = configs.get_module('incremental_selection')
local config = configs.get_module "incremental_selection"
for funcname, mapping in pairs(config.keymaps) do
local mode
if funcname == "init_selection" then
mode = 'n'
mode = "n"
else
mode = 'x'
mode = "x"
end
local cmd = string.format(":lua require'nvim-treesitter.incremental_selection'.%s()<CR>", funcname)
api.nvim_buf_set_keymap(bufnr, mode, mapping, cmd, { silent = true, noremap = true })
@ -148,12 +145,12 @@ function M.attach(bufnr)
end
function M.detach(bufnr)
local config = configs.get_module('incremental_selection')
local config = configs.get_module "incremental_selection"
for f, mapping in pairs(config.keymaps) do
if f == "init_selection" then
api.nvim_buf_del_keymap(bufnr, 'n', mapping)
api.nvim_buf_del_keymap(bufnr, "n", mapping)
else
api.nvim_buf_del_keymap(bufnr, 'x', mapping)
api.nvim_buf_del_keymap(bufnr, "x", mapping)
end
end
end

View file

@ -1,6 +1,6 @@
local parsers = require'nvim-treesitter.parsers'
local queries = require'nvim-treesitter.query'
local tsutils = require'nvim-treesitter.ts_utils'
local parsers = require "nvim-treesitter.parsers"
local queries = require "nvim-treesitter.query"
local tsutils = require "nvim-treesitter.ts_utils"
local M = {}
@ -8,7 +8,9 @@ local M = {}
local function get_node_at_line(root, lnum)
for node in root:iter_children() do
local srow, _, erow = node:range()
if srow == lnum then return node end
if srow == lnum then
return node
end
if node:child_count() > 0 and srow < lnum and lnum <= erow then
return get_node_at_line(node, lnum)
@ -17,13 +19,15 @@ local function get_node_at_line(root, lnum)
end
local function node_fmt(node)
if not node then return nil end
if not node then
return nil
end
return tostring(node)
end
local get_indents = tsutils.memoize_by_buf_tick(function(bufnr, root, lang)
local get_map = function(capture)
local matches = queries.get_capture_matches(bufnr, capture, 'indents', root, lang) or {}
local matches = queries.get_capture_matches(bufnr, capture, "indents", root, lang) or {}
local map = {}
for _, node in ipairs(matches) do
map[tostring(node)] = true
@ -32,29 +36,33 @@ local get_indents = tsutils.memoize_by_buf_tick(function(bufnr, root, lang)
end
return {
indents = get_map('@indent.node'),
branches = get_map('@branch.node'),
returns = get_map('@return.node'),
ignores = get_map('@ignore.node'),
indents = get_map "@indent.node",
branches = get_map "@branch.node",
returns = get_map "@return.node",
ignores = get_map "@ignore.node",
}
end, {
-- Memoize by bufnr and lang together.
key = function(bufnr, _, lang)
return tostring(bufnr) .. '_' .. lang
end
return tostring(bufnr) .. "_" .. lang
end,
})
function M.get_indent(lnum)
local parser = parsers.get_parser()
if not parser or not lnum then return -1 end
if not parser or not lnum then
return -1
end
local root, _, lang_tree = tsutils.get_root_for_position(lnum, 0, parser)
-- Not likely, but just in case...
if not root then return 0 end
if not root then
return 0
end
local q = get_indents(vim.api.nvim_get_current_buf(), root, lang_tree:lang())
local node = get_node_at_line(root, lnum-1)
local node = get_node_at_line(root, lnum - 1)
local indent = 0
local indent_size = vim.fn.shiftwidth()
@ -65,11 +73,11 @@ function M.get_indent(lnum)
if not node then
local prevnonblank = vim.fn.prevnonblank(lnum)
if prevnonblank ~= lnum then
local prev_node = get_node_at_line(root, prevnonblank-1)
local prev_node = get_node_at_line(root, prevnonblank - 1)
-- get previous node in any case to avoid erroring
while not prev_node and prevnonblank-1 > 0 do
prevnonblank = vim.fn.prevnonblank(prevnonblank-1)
prev_node = get_node_at_line(root, prevnonblank-1)
while not prev_node and prevnonblank - 1 > 0 do
prevnonblank = vim.fn.prevnonblank(prevnonblank - 1)
prev_node = get_node_at_line(root, prevnonblank - 1)
end
-- nodes can be marked @return to prevent using them
@ -91,7 +99,7 @@ function M.get_indent(lnum)
-- if the prevnonblank fails (prev_node wraps our line) we need to fall back to taking
-- the first child of the node that wraps the current line, or the wrapper itself
if not node then
local wrapper = root:descendant_for_range(lnum-1, 0, lnum-1, -1)
local wrapper = root:descendant_for_range(lnum - 1, 0, lnum - 1, -1)
node = wrapper:child(0) or wrapper
if q.indents[node_fmt(wrapper)] ~= nil and wrapper ~= root then
indent = indent_size
@ -107,7 +115,7 @@ function M.get_indent(lnum)
while node do
-- do not indent if we are inside an @ignore block
if q.ignores[node_fmt(node)] and node:start() < lnum-1 and node:end_() > lnum-1 then
if q.ignores[node_fmt(node)] and node:start() < lnum - 1 and node:end_() > lnum - 1 then
return -1
end
@ -129,8 +137,8 @@ local indent_funcs = {}
function M.attach(bufnr)
indent_funcs[bufnr] = vim.bo.indentexpr
vim.bo.indentexpr = 'nvim_treesitter#indent()'
vim.api.nvim_command("au Filetype "..vim.bo.filetype.." setlocal indentexpr=nvim_treesitter#indent()")
vim.bo.indentexpr = "nvim_treesitter#indent()"
vim.api.nvim_command("au Filetype " .. vim.bo.filetype .. " setlocal indentexpr=nvim_treesitter#indent()")
end
function M.detach(bufnr)

View file

@ -1,24 +1,26 @@
local api = vim.api
local configs = require'nvim-treesitter.configs'
local parsers = require'nvim-treesitter.parsers'
local configs = require "nvim-treesitter.configs"
local parsers = require "nvim-treesitter.parsers"
local M = {}
local function install_info()
local max_len = 0
for _, ft in pairs(parsers.available_parsers()) do
if #ft > max_len then max_len = #ft end
if #ft > max_len then
max_len = #ft
end
end
local parser_list = parsers.available_parsers()
table.sort(parser_list)
for _, ft in pairs(parser_list) do
local is_installed = #api.nvim_get_runtime_file('parser/'..ft..'.so', false) > 0
api.nvim_out_write(ft..string.rep(' ', max_len - #ft + 1))
local is_installed = #api.nvim_get_runtime_file("parser/" .. ft .. ".so", false) > 0
api.nvim_out_write(ft .. string.rep(" ", max_len - #ft + 1))
if is_installed then
api.nvim_out_write("[✓] installed\n")
api.nvim_out_write "[✓] installed\n"
else
api.nvim_out_write("[✗] not installed\n")
api.nvim_out_write "[✗] not installed\n"
end
end
end
@ -30,8 +32,8 @@ end
local function namespace_modules(modulelist)
local modules = {}
for _, module in ipairs(modulelist) do
if module:find('%.') then
local namespace, submodule = module:match('^(.*)%.(.*)$')
if module:find "%." then
local namespace, submodule = module:match "^(.*)%.(.*)$"
if not modules[namespace] then
modules[namespace] = {}
end
@ -61,46 +63,48 @@ local function append_module_table(curbuf, parserlist, namespace, modulelist)
table.sort(modulelist)
-- header
local header = '>> ' .. namespace .. string.rep(' ', maxlen_parser - #namespace - 1)
local header = ">> " .. namespace .. string.rep(" ", maxlen_parser - #namespace - 1)
for _, module in pairs(modulelist) do
header = header .. module .. ' '
header = header .. module .. " "
end
api.nvim_buf_set_lines(curbuf, -1, -1, true, {header})
api.nvim_buf_set_lines(curbuf, -1, -1, true, { header })
-- actual table
for _, parser in ipairs(parserlist) do
local padding = string.rep(' ', maxlen_parser - #parser + 2)
local line = parser .. padding
local namespace_prefix = (namespace == 'default') and '' or namespace .. '.'
local padding = string.rep(" ", maxlen_parser - #parser + 2)
local line = parser .. padding
local namespace_prefix = (namespace == "default") and "" or namespace .. "."
for _, module in pairs(modulelist) do
local modlen = #module
module = namespace_prefix .. module
if configs.is_enabled(module, parser) then
line = line .. ''
line = line .. ""
else
line = line .. ''
line = line .. ""
end
line = line .. string.rep(' ', modlen + 1)
line = line .. string.rep(" ", modlen + 1)
end
api.nvim_buf_set_lines(curbuf, -1, -1, true, {line})
api.nvim_buf_set_lines(curbuf, -1, -1, true, { line })
end
api.nvim_buf_set_lines(curbuf, -1, -1, true, {''})
api.nvim_buf_set_lines(curbuf, -1, -1, true, { "" })
end
local function print_info_modules(parserlist, module)
api.nvim_command('enew')
api.nvim_command "enew"
local curbuf = api.nvim_get_current_buf()
local modules
if module then
modules = namespace_modules({module})
modules = namespace_modules { module }
else
modules = namespace_modules(configs.available_modules())
end
local namespaces = {}
for k, _ in pairs(modules) do table.insert(namespaces, k) end
for k, _ in pairs(modules) do
table.insert(namespaces, k)
end
table.sort(namespaces)
table.sort(parserlist)
@ -108,9 +112,10 @@ local function print_info_modules(parserlist, module)
append_module_table(curbuf, parserlist, namespace, modules[namespace])
end
api.nvim_buf_set_option(curbuf, 'modified', false)
api.nvim_buf_set_option(curbuf, 'buftype', 'nofile')
api.nvim_exec([[
api.nvim_buf_set_option(curbuf, "modified", false)
api.nvim_buf_set_option(curbuf, "buftype", "nofile")
api.nvim_exec(
[[
syntax match TSModuleInfoGood //
syntax match TSModuleInfoBad //
syntax match TSModuleInfoHeader /^>>.*$/ contains=TSModuleInfoNamespace
@ -121,11 +126,15 @@ local function print_info_modules(parserlist, module)
highlight default link TSModuleInfoHeader Type
highlight default link TSModuleInfoNamespace Statement
highlight default link TSModuleInfoParser Identifier
]], false)
]],
false
)
end
local function module_info(module)
if module and not configs.get_module(module) then return end
if module and not configs.get_module(module) then
return
end
local parserlist = parsers.available_parsers()
if module then

View file

@ -2,16 +2,16 @@ local api = vim.api
local fn = vim.fn
local luv = vim.loop
local utils = require'nvim-treesitter.utils'
local parsers = require'nvim-treesitter.parsers'
local info = require'nvim-treesitter.info'
local configs = require'nvim-treesitter.configs'
local shell = require'nvim-treesitter.shell_command_selectors'
local utils = require "nvim-treesitter.utils"
local parsers = require "nvim-treesitter.parsers"
local info = require "nvim-treesitter.info"
local configs = require "nvim-treesitter.configs"
local shell = require "nvim-treesitter.shell_command_selectors"
local M = {}
local lockfile = {}
M.compilers = { vim.fn.getenv('CC'), "cc", "gcc", "clang", "cl" }
M.compilers = { vim.fn.getenv "CC", "cc", "gcc", "clang", "cl" }
local started_commands = 0
local finished_commands = 0
@ -31,27 +31,31 @@ local function reset_progress_counter()
end
local function get_job_status()
return "[nvim-treesitter] ["..finished_commands.."/"..started_commands
..(failed_commands > 0 and ", failed: "..failed_commands or "").."]"
return "[nvim-treesitter] ["
.. finished_commands
.. "/"
.. started_commands
.. (failed_commands > 0 and ", failed: " .. failed_commands or "")
.. "]"
end
local function get_revision(lang)
if #lockfile == 0 then
local filename = utils.join_path(utils.get_package_path(), 'lockfile.json')
local filename = utils.join_path(utils.get_package_path(), "lockfile.json")
lockfile = vim.fn.filereadable(filename) == 1 and vim.fn.json_decode(vim.fn.readfile(filename)) or {}
end
return (lockfile[lang] and lockfile[lang].revision)
end
local function get_installed_revision(lang)
local lang_file = utils.join_path(utils.get_parser_info_dir(), lang..'.revision')
local lang_file = utils.join_path(utils.get_parser_info_dir(), lang .. ".revision")
if vim.fn.filereadable(lang_file) == 1 then
return vim.fn.readfile(lang_file)[1]
end
end
local function is_installed(lang)
return #api.nvim_get_runtime_file('parser/'..lang..'.so', false) > 0
return #api.nvim_get_runtime_file("parser/" .. lang .. ".so", false) > 0
end
local function needs_update(lang)
@ -61,17 +65,16 @@ end
local function outdated_parsers()
return vim.tbl_filter(function(lang)
return needs_update(lang)
end,
info.installed_parsers())
end, info.installed_parsers())
end
local function onread(handle, is_stderr)
return function(err, data)
if data then
if is_stderr then
complete_error_output[handle] = (complete_error_output[handle] or '')..data
complete_error_output[handle] = (complete_error_output[handle] or "") .. data
else
complete_std_output[handle] = (complete_std_output[handle] or '')..data
complete_std_output[handle] = (complete_std_output[handle] or "") .. data
end
end
end
@ -83,52 +86,62 @@ function M.iter_cmd(cmd_list, i, lang, success_message)
end
if i == #cmd_list + 1 then
finished_commands = finished_commands + 1
return print(get_job_status().." "..success_message)
return print(get_job_status() .. " " .. success_message)
end
local attr = cmd_list[i]
if attr.info then print(get_job_status().." "..attr.info) end
if attr.info then
print(get_job_status() .. " " .. attr.info)
end
if type(attr.cmd) == 'function' then
if type(attr.cmd) == "function" then
local ok, err = pcall(attr.cmd)
if ok then
M.iter_cmd(cmd_list, i + 1, lang, success_message)
else
failed_commands = failed_commands + 1
finished_commands = finished_commands + 1
return api.nvim_err_writeln((attr.err or ("Failed to execute the following command:\n"..vim.inspect(attr)))
..'\n'..vim.inspect(err))
return api.nvim_err_writeln(
(attr.err or ("Failed to execute the following command:\n" .. vim.inspect(attr))) .. "\n" .. vim.inspect(err)
)
end
else
local handle
local stdout = luv.new_pipe(false)
local stderr = luv.new_pipe(false)
attr.opts.stdio = {nil, stdout, stderr}
handle = luv.spawn(attr.cmd, attr.opts, vim.schedule_wrap(function(code)
if code ~= 0 then
stdout:read_stop()
stderr:read_stop()
end
stdout:close()
stderr:close()
handle:close()
if code ~= 0 then
failed_commands = failed_commands + 1
finished_commands = finished_commands + 1
if complete_std_output[handle] and complete_std_output[handle] ~= '' then
print(complete_std_output[handle])
attr.opts.stdio = { nil, stdout, stderr }
handle = luv.spawn(
attr.cmd,
attr.opts,
vim.schedule_wrap(function(code)
if code ~= 0 then
stdout:read_stop()
stderr:read_stop()
end
stdout:close()
stderr:close()
handle:close()
if code ~= 0 then
failed_commands = failed_commands + 1
finished_commands = finished_commands + 1
if complete_std_output[handle] and complete_std_output[handle] ~= "" then
print(complete_std_output[handle])
end
local err_msg = complete_error_output[handle] or ''
api.nvim_err_writeln(
'nvim-treesitter['..lang..']: '
..(attr.err or ("Failed to execute the following command:\n"..vim.inspect(attr)))
..'\n'
..err_msg)
return
end
M.iter_cmd(cmd_list, i + 1, lang, success_message)
end))
local err_msg = complete_error_output[handle] or ""
api.nvim_err_writeln(
"nvim-treesitter["
.. lang
.. "]: "
.. (attr.err or ("Failed to execute the following command:\n" .. vim.inspect(attr)))
.. "\n"
.. err_msg
)
return
end
M.iter_cmd(cmd_list, i + 1, lang, success_message)
end)
)
luv.read_start(stdout, onread(handle, false))
luv.read_start(stderr, onread(handle, true))
end
@ -142,7 +155,7 @@ local function get_command(cmd)
end
end
local final = string.format('%s %s', cmd.cmd, options)
local final = string.format("%s %s", cmd.cmd, options)
if cmd.opts and cmd.opts.cwd then
final = shell.make_directory_change_for_command(cmd.opts.cwd, final)
end
@ -155,19 +168,18 @@ local function iter_cmd_sync(cmd_list)
print(cmd.info)
end
if type(cmd.cmd) == 'function' then
if type(cmd.cmd) == "function" then
cmd.cmd()
else
local ret = vim.fn.system(get_command(cmd))
if vim.v.shell_error ~= 0 then
print(ret)
api.nvim_err_writeln((cmd.err and cmd.err..'\n' or '')
.."Failed to execute the following command:\n"
..vim.inspect(cmd))
api.nvim_err_writeln(
(cmd.err and cmd.err .. "\n" or "") .. "Failed to execute the following command:\n" .. vim.inspect(cmd)
)
return false
end
end
end
return true
@ -178,7 +190,7 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
local path_sep = utils.get_path_sep()
local project_name = 'tree-sitter-'..lang
local project_name = "tree-sitter-" .. lang
local maybe_local_path = vim.fn.expand(repo.url)
local from_local_path = vim.fn.isdirectory(maybe_local_path) == 1
if from_local_path then
@ -190,33 +202,40 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
if from_local_path then
compile_location = repo.url
else
local repo_location = string.gsub(repo.location or project_name, '/', path_sep)
compile_location = cache_folder..path_sep..repo_location
local repo_location = string.gsub(repo.location or project_name, "/", path_sep)
compile_location = cache_folder .. path_sep .. repo_location
end
local parser_lib_name = install_folder..path_sep..lang..".so"
local parser_lib_name = install_folder .. path_sep .. lang .. ".so"
generate_from_grammar = repo.requires_generate_from_grammar or generate_from_grammar
if generate_from_grammar and vim.fn.executable('tree-sitter') ~= 1 then
api.nvim_err_writeln('tree-sitter CLI not found: `tree-sitter` is not executable!')
if generate_from_grammar and vim.fn.executable "tree-sitter" ~= 1 then
api.nvim_err_writeln "tree-sitter CLI not found: `tree-sitter` is not executable!"
if repo.requires_generate_from_grammar then
api.nvim_err_writeln('tree-sitter CLI is needed because `'..lang..'` is marked that it needs '
..'to be generated from the grammar definitions to be compatible with nvim!')
api.nvim_err_writeln(
"tree-sitter CLI is needed because `"
.. lang
.. "` is marked that it needs "
.. "to be generated from the grammar definitions to be compatible with nvim!"
)
end
return
end
if generate_from_grammar and vim.fn.executable('node') ~= 1 then
api.nvim_err_writeln('Node JS not found: `node` is not executable!')
if generate_from_grammar and vim.fn.executable "node" ~= 1 then
api.nvim_err_writeln "Node JS not found: `node` is not executable!"
return
end
local cc = shell.select_executable(M.compilers)
if not cc then
api.nvim_err_writeln('No C compiler found! "'
..table.concat(vim.tbl_filter(function(c) return type(c) == 'string' end, M.compilers), '", "')
..'" are not executable.')
api.nvim_err_writeln('No C compiler found! "' .. table.concat(
vim.tbl_filter(function(c)
return type(c) == "string"
end, M.compilers),
'", "'
) .. '" are not executable.')
return
end
local revision = configs.get_update_strategy() == 'lockfile' and get_revision(lang)
local revision = configs.get_update_strategy() == "lockfile" and get_revision(lang)
local command_list = {}
if not from_local_path then
@ -225,83 +244,86 @@ local function run_install(cache_folder, install_folder, lang, repo, with_sync,
end
if generate_from_grammar then
if repo.generate_requires_npm then
if vim.fn.executable('npm') ~= 1 then
api.nvim_err_writeln('`'..lang..'` requires NPM to be installed from grammar.js')
if vim.fn.executable "npm" ~= 1 then
api.nvim_err_writeln("`" .. lang .. "` requires NPM to be installed from grammar.js")
return
end
vim.list_extend(command_list, {
{
cmd = 'npm',
info = 'Installing NPM dependencies of '..lang..' parser',
err = 'Error during `npm install` (required for parser generation of '..lang..' with npm dependencies)',
cmd = "npm",
info = "Installing NPM dependencies of " .. lang .. " parser",
err = "Error during `npm install` (required for parser generation of " .. lang .. " with npm dependencies)",
opts = {
args = {'install'},
cwd = compile_location
}
}
args = { "install" },
cwd = compile_location,
},
},
})
end
vim.list_extend(command_list, {
{
cmd = vim.fn.exepath('tree-sitter'),
info = 'Generating source files from grammar.js...',
cmd = vim.fn.exepath "tree-sitter",
info = "Generating source files from grammar.js...",
err = 'Error during "tree-sitter generate"',
opts = {
args = {'generate'},
cwd = compile_location
}
}
args = { "generate" },
cwd = compile_location,
},
},
})
end
vim.list_extend(command_list, {
{
cmd = cc,
info = 'Compiling...',
err = 'Error during compilation',
info = "Compiling...",
err = "Error during compilation",
opts = {
args = vim.tbl_flatten(shell.select_compiler_args(repo, cc)),
cwd = compile_location
}
cwd = compile_location,
},
},
shell.select_mv_cmd('parser.so', parser_lib_name, compile_location),
shell.select_mv_cmd("parser.so", parser_lib_name, compile_location),
{
cmd = function()
vim.fn.writefile({revision or ''}, utils.join_path(utils.get_parser_info_dir(), lang..'.revision'))
end
}
vim.fn.writefile({ revision or "" }, utils.join_path(utils.get_parser_info_dir(), lang .. ".revision"))
end,
},
})
if not from_local_path then
vim.list_extend(command_list, {shell.select_install_rm_cmd(cache_folder, project_name)})
vim.list_extend(command_list, { shell.select_install_rm_cmd(cache_folder, project_name) })
end
if with_sync then
if iter_cmd_sync(command_list) == true then
print('Treesitter parser for '..lang..' has been installed')
print("Treesitter parser for " .. lang .. " has been installed")
end
else
M.iter_cmd(command_list, 1, lang, 'Treesitter parser for '..lang..' has been installed')
M.iter_cmd(command_list, 1, lang, "Treesitter parser for " .. lang .. " has been installed")
end
end
local function install_lang(lang, ask_reinstall, cache_folder, install_folder, with_sync, generate_from_grammar)
if is_installed(lang) and ask_reinstall ~= "force" then
if not ask_reinstall then
return
end
if is_installed(lang) and ask_reinstall ~= 'force' then
if not ask_reinstall then return end
local yesno = fn.input(lang .. ' parser already available: would you like to reinstall ? y/n: ')
print('\n ') -- mandatory to avoid messing up command line
if not string.match(yesno, '^y.*') then return end
local yesno = fn.input(lang .. " parser already available: would you like to reinstall ? y/n: ")
print "\n "
if not string.match(yesno, "^y.*") then
return
end
end
local parser_config = parsers.get_parser_configs()[lang]
if not parser_config then
return api.nvim_err_writeln('Parser not available for language '..lang)
return api.nvim_err_writeln("Parser not available for language " .. lang)
end
local install_info = parser_config.install_info
vim.validate {
url={ install_info.url, 'string' },
files={ install_info.files, 'table' }
url = { install_info.url, "string" },
files = { install_info.files, "table" },
}
run_install(cache_folder, install_folder, lang, install_info, with_sync, generate_from_grammar)
@ -314,27 +336,31 @@ local function install(options)
local generate_from_grammar = options.generate_from_grammar
local exclude_configured_parsers = options.exclude_configured_parsers
return function (...)
if fn.executable('git') == 0 then
return api.nvim_err_writeln('Git is required on your system to run this command')
return function(...)
if fn.executable "git" == 0 then
return api.nvim_err_writeln "Git is required on your system to run this command"
end
local cache_folder, err = utils.get_cache_dir()
if err then return api.nvim_err_writeln(err) end
if err then
return api.nvim_err_writeln(err)
end
local install_folder, err = utils.get_parser_install_dir()
if err then return api.nvim_err_writeln(err) end
if err then
return api.nvim_err_writeln(err)
end
local languages
local ask
if ... == 'all' then
if ... == "all" then
languages = parsers.available_parsers()
ask = false
elseif ... == 'maintained' then
elseif ... == "maintained" then
languages = parsers.maintained_parsers()
ask = false
else
languages = vim.tbl_flatten({...})
languages = vim.tbl_flatten { ... }
ask = ask_reinstall
end
@ -354,69 +380,73 @@ end
function M.update(options)
options = options or {}
return function (...)
return function(...)
M.lockfile = {}
reset_progress_counter()
if ... and ... ~= 'all' then
local languages = vim.tbl_flatten({...})
if ... and ... ~= "all" then
local languages = vim.tbl_flatten { ... }
local installed = 0
for _, lang in ipairs(languages) do
if (not is_installed(lang)) or (needs_update(lang)) then
installed = installed + 1
install({
ask_reinstall = 'force',
with_sync = options.with_sync })(lang)
end
if (not is_installed(lang)) or (needs_update(lang)) then
installed = installed + 1
install {
ask_reinstall = "force",
with_sync = options.with_sync,
}(lang)
end
end
if installed == 0 then
print('Parsers are up-to-date!')
print "Parsers are up-to-date!"
end
else
local parsers_to_update = configs.get_update_strategy() == 'lockfile'
and outdated_parsers()
local parsers_to_update = configs.get_update_strategy() == "lockfile" and outdated_parsers()
or info.installed_parsers()
if #parsers_to_update == 0 then
print('All parsers are up-to-date!')
print "All parsers are up-to-date!"
end
for _, lang in pairs(parsers_to_update) do
install({
ask_reinstall = 'force',
install {
ask_reinstall = "force",
exclude_configured_parsers = true,
with_sync = options.with_sync
})(lang)
with_sync = options.with_sync,
}(lang)
end
end
end
end
function M.uninstall(...)
local path_sep = '/'
if fn.has('win32') == 1 then
path_sep = '\\'
local path_sep = "/"
if fn.has "win32" == 1 then
path_sep = "\\"
end
if vim.tbl_contains({'all', 'maintained'}, ...) then
if vim.tbl_contains({ "all", "maintained" }, ...) then
reset_progress_counter()
local installed = info.installed_parsers()
if ... == "maintained" then
local maintained = parsers.maintained_parsers()
installed = vim.tbl_filter(function(l) return vim.tbl_contains(maintained, l) end, installed)
installed = vim.tbl_filter(function(l)
return vim.tbl_contains(maintained, l)
end, installed)
end
for _, langitem in pairs(installed) do
M.uninstall(langitem)
end
elseif ... then
local languages = vim.tbl_flatten({...})
local languages = vim.tbl_flatten { ... }
for _, lang in ipairs(languages) do
local install_dir, err = utils.get_parser_install_dir()
if err then return api.nvim_err_writeln(err) end
if err then
return api.nvim_err_writeln(err)
end
local parser_lib = install_dir..path_sep..lang..".so"
local parser_lib = install_dir .. path_sep .. lang .. ".so"
local command_list = {
shell.select_rm_file_cmd(parser_lib, "Uninstalling parser for "..lang)
shell.select_rm_file_cmd(parser_lib, "Uninstalling parser for " .. lang),
}
M.iter_cmd(command_list, 1, lang, 'Treesitter parser for '..lang..' has been uninstalled')
M.iter_cmd(command_list, 1, lang, "Treesitter parser for " .. lang .. " has been uninstalled")
end
end
end
@ -428,38 +458,41 @@ function M.write_lockfile(verbose, skip_langs)
skip_langs = skip_langs or {}
for k, v in pairs(parsers.get_parser_configs()) do
table.insert(sorted_parsers, {name = k, parser = v})
table.insert(sorted_parsers, { name = k, parser = v })
end
table.sort(sorted_parsers, function(a, b) return a.name < b.name end)
table.sort(sorted_parsers, function(a, b)
return a.name < b.name
end)
for _, v in ipairs(sorted_parsers) do
if not vim.tbl_contains(skip_langs, v.name) then
-- I'm sure this can be done in aync way with iter_cmd
local sha = vim.split(vim.fn.systemlist('git ls-remote '..v.parser.install_info.url)[1], '\t')[1]
local sha = vim.split(vim.fn.systemlist("git ls-remote " .. v.parser.install_info.url)[1], "\t")[1]
lockfile[v.name] = { revision = sha }
if verbose then
print(v.name..': '..sha)
print(v.name .. ": " .. sha)
end
else
print('Skipping '..v.name)
print("Skipping " .. v.name)
end
end
if verbose then
print(vim.inspect(lockfile))
end
vim.fn.writefile(vim.fn.split(vim.fn.json_encode(lockfile), '\n'),
utils.join_path(utils.get_package_path(), "lockfile.json"))
vim.fn.writefile(
vim.fn.split(vim.fn.json_encode(lockfile), "\n"),
utils.join_path(utils.get_package_path(), "lockfile.json")
)
end
M.ensure_installed = install({ exclude_configured_parsers = true })
M.ensure_installed = install { exclude_configured_parsers = true }
M.commands = {
TSInstall = {
run = install({ ask_reinstall = true }),
['run!'] = install({ ask_reinstall = 'force' }),
run = install { ask_reinstall = true },
["run!"] = install { ask_reinstall = "force" },
args = {
"-nargs=+",
"-bang",
@ -467,8 +500,8 @@ M.commands = {
},
},
TSInstallFromGrammar = {
run = install({ generate_from_grammar = true, ask_reinstall = true }),
['run!'] = install({ generate_from_grammar = true, ask_reinstall = 'force' }),
run = install { generate_from_grammar = true, ask_reinstall = true },
["run!"] = install { generate_from_grammar = true, ask_reinstall = "force" },
args = {
"-nargs=+",
"-bang",
@ -476,8 +509,8 @@ M.commands = {
},
},
TSInstallSync = {
run = install( { with_sync = true, ask_reinstall = true }),
['run!'] = install( { with_sync = true, ask_reinstall = 'force' }),
run = install { with_sync = true, ask_reinstall = true },
["run!"] = install { with_sync = true, ask_reinstall = "force" },
args = {
"-nargs=+",
"-bang",
@ -485,14 +518,14 @@ M.commands = {
},
},
TSUpdate = {
run = M.update({}),
run = M.update {},
args = {
"-nargs=*",
"-complete=custom,nvim_treesitter#installed_parsers",
},
},
TSUpdateSync = {
run = M.update({ with_sync = true }),
run = M.update { with_sync = true },
args = {
"-nargs=*",
"-complete=custom,nvim_treesitter#installed_parsers",

View file

@ -2,25 +2,25 @@
-- Locals are a generalization of definition and scopes
-- its the way nvim-treesitter uses to "understand" the code
local queries = require'nvim-treesitter.query'
local ts_utils = require'nvim-treesitter.ts_utils'
local queries = require "nvim-treesitter.query"
local ts_utils = require "nvim-treesitter.ts_utils"
local api = vim.api
local M = {}
function M.collect_locals(bufnr)
return queries.collect_group_results(bufnr, 'locals')
return queries.collect_group_results(bufnr, "locals")
end
-- Iterates matches from a locals query file.
-- @param bufnr the buffer
-- @param root the root node
function M.iter_locals(bufnr, root)
return queries.iter_group_results(bufnr, 'locals', root)
return queries.iter_group_results(bufnr, "locals", root)
end
function M.get_locals(bufnr)
return queries.get_matches(bufnr, 'locals')
return queries.get_matches(bufnr, "locals")
end
--- Creates unique id for a node based on text and range
@ -30,7 +30,7 @@ end
-- @returns a string id
function M.get_definition_id(scope, node_text)
-- Add a vaild starting character in case node text doesn't start with a valid one.
return table.concat({ 'k', node_text or '', scope:range() }, '_')
return table.concat({ "k", node_text or "", scope:range() }, "_")
end
function M.get_definitions(bufnr)
@ -131,11 +131,7 @@ function M.recurse_local_nodes(local_def, accumulator, full_match, last_match)
accumulator(local_def, local_def.node, full_match, last_match)
else
for match_key, def in pairs(local_def) do
M.recurse_local_nodes(
def,
accumulator,
full_match and (full_match..'.'..match_key) or match_key,
match_key)
M.recurse_local_nodes(def, accumulator, full_match and (full_match .. "." .. match_key) or match_key, match_key)
end
end
end
@ -188,10 +184,10 @@ function M.get_definition_scopes(node, bufnr, scope_type)
-- Definition is valid for the containing scope
-- and the containing scope of that scope
if scope_type == 'parent' then
if scope_type == "parent" then
scope_count = 2
-- Definition is valid in all parent scopes
elseif scope_type == 'global' then
elseif scope_type == "global" then
scope_count = nil
end
@ -200,7 +196,9 @@ function M.get_definition_scopes(node, bufnr, scope_type)
table.insert(scopes, scope)
i = i + 1
if scope_count and i >= scope_count then break end
if scope_count and i >= scope_count then
break
end
end
return scopes
@ -231,13 +229,16 @@ function M.find_usages(node, scope_node, bufnr)
local bufnr = bufnr or api.nvim_get_current_buf()
local node_text = ts_utils.get_node_text(node, bufnr)[1]
if not node_text or #node_text < 1 then return {} end
if not node_text or #node_text < 1 then
return {}
end
local scope_node = scope_node or ts_utils.get_root_for_node(node)
local usages = {}
for match in M.iter_locals(bufnr, scope_node) do
if match.reference
if
match.reference
and match.reference.node
and ts_utils.get_node_text(match.reference.node, bufnr)[1] == node_text
then
@ -257,7 +258,9 @@ function M.containing_scope(node, bufnr, allow_scope)
local allow_scope = allow_scope == nil or allow_scope == true
local scopes = M.get_scopes(bufnr)
if not node or not scopes then return end
if not node or not scopes then
return
end
local iter_node = node
@ -272,7 +275,9 @@ function M.nested_scope(node, cursor_pos)
local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr)
if not node or not scopes then return end
if not node or not scopes then
return
end
local row = cursor_pos.row
local col = cursor_pos.col
@ -280,7 +285,7 @@ function M.nested_scope(node, cursor_pos)
for _, child in ipairs(ts_utils.get_named_children(scope)) do
local row_, col_ = child:start()
if vim.tbl_contains(scopes, child) and ((row_+1 == row and col_ > col) or row_+1 > row) then
if vim.tbl_contains(scopes, child) and ((row_ + 1 == row and col_ > col) or row_ + 1 > row) then
return child
end
end
@ -290,12 +295,16 @@ function M.next_scope(node)
local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr)
if not node or not scopes then return end
if not node or not scopes then
return
end
local scope = M.containing_scope(node)
local parent = scope:parent()
if not parent then return end
if not parent then
return
end
local is_prev = true
for _, child in ipairs(ts_utils.get_named_children(parent)) do
@ -311,16 +320,20 @@ function M.previous_scope(node)
local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr)
if not node or not scopes then return end
if not node or not scopes then
return
end
local scope = M.containing_scope(node)
local parent = scope:parent()
if not parent then return end
if not parent then
return
end
local is_prev = true
local children = ts_utils.get_named_children(parent)
for i=#children,1,-1 do
for i = #children, 1, -1 do
if children[i] == scope then
is_prev = false
elseif not is_prev and vim.tbl_contains(scopes, children[i]) then

View file

@ -4,7 +4,7 @@ local ts = vim.treesitter
local ft_to_parsername = {}
local function update_ft_to_parsername(name, parser)
if type(parser.used_by) == 'table' then
if type(parser.used_by) == "table" then
for _, ft in pairs(parser.used_by) do
ft_to_parsername[ft] = name
end
@ -14,19 +14,22 @@ end
local list = setmetatable({}, {
__newindex = function(table, parsername, parserconfig)
rawset(table, parsername, setmetatable(parserconfig, {
__newindex = function(parserconfigtable, key, value)
if key == "used_by" then
ft_to_parsername[value] = parsername
else
rawset(parserconfigtable, key, value)
end
end
}))
rawset(
table,
parsername,
setmetatable(parserconfig, {
__newindex = function(parserconfigtable, key, value)
if key == "used_by" then
ft_to_parsername[value] = parsername
else
rawset(parserconfigtable, key, value)
end
end,
})
)
update_ft_to_parsername(parsername, parserconfig)
end
end,
})
list.javascript = {
@ -34,16 +37,16 @@ list.javascript = {
url = "https://github.com/tree-sitter/tree-sitter-javascript",
files = { "src/parser.c", "src/scanner.c" },
},
used_by = { 'javascriptreact' },
maintainers = {"@steelsojka"},
used_by = { "javascriptreact" },
maintainers = { "@steelsojka" },
}
list.c = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-c",
files = { "src/parser.c" }
files = { "src/parser.c" },
},
maintainers = {"@vigoux"},
maintainers = { "@vigoux" },
}
list.clojure = {
@ -51,7 +54,7 @@ list.clojure = {
url = "https://github.com/sogaiu/tree-sitter-clojure",
files = { "src/parser.c" },
},
maintainers = {"@sogaiu"},
maintainers = { "@sogaiu" },
}
list.commonlisp = {
@ -60,8 +63,8 @@ list.commonlisp = {
files = { "src/parser.c" },
generate_requires_npm = true,
},
filetype = 'lisp',
maintainers = {"@theHamsta"},
filetype = "lisp",
maintainers = { "@theHamsta" },
}
list.cpp = {
@ -70,16 +73,16 @@ list.cpp = {
files = { "src/parser.c", "src/scanner.cc" },
generate_requires_npm = true,
},
maintainers = {"@theHamsta"},
maintainers = { "@theHamsta" },
}
list.cuda = {
install_info = {
url = "https://github.com/theHamsta/tree-sitter-cuda",
files = {"src/parser.c", "src/scanner.cc"},
files = { "src/parser.c", "src/scanner.cc" },
generate_requires_npm = true,
},
maintainers = {"@theHamsta"},
maintainers = { "@theHamsta" },
}
list.dockerfile = {
@ -88,7 +91,7 @@ list.dockerfile = {
branch = "main",
files = { "src/parser.c" },
},
maintainers = {"@camdencheek"},
maintainers = { "@camdencheek" },
}
list.rust = {
@ -96,7 +99,7 @@ list.rust = {
url = "https://github.com/tree-sitter/tree-sitter-rust",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@vigoux"},
maintainers = { "@vigoux" },
}
list.ledger = {
@ -104,15 +107,15 @@ list.ledger = {
url = "https://github.com/cbarrete/tree-sitter-ledger",
files = { "src/parser.c" },
},
maintainers = {"@cbarrete"},
maintainers = { "@cbarrete" },
}
list.lua = {
install_info = {
url = "https://github.com/nvim-treesitter/tree-sitter-lua",
files = { "src/parser.c", "src/scanner.cc" }
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {"@vigoux"},
maintainers = { "@vigoux" },
}
list.python = {
@ -120,7 +123,7 @@ list.python = {
url = "https://github.com/tree-sitter/tree-sitter-python",
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {'@stsewd', "@theHamsta"},
maintainers = { "@stsewd", "@theHamsta" },
}
list.go = {
@ -128,7 +131,7 @@ list.go = {
url = "https://github.com/tree-sitter/tree-sitter-go",
files = { "src/parser.c" },
},
maintainers = {"@theHamsta", "@WinWisely268"},
maintainers = { "@theHamsta", "@WinWisely268" },
}
list.gomod = {
@ -137,7 +140,7 @@ list.gomod = {
branch = "main",
files = { "src/parser.c" },
},
maintainers = {"@camdencheek"},
maintainers = { "@camdencheek" },
filetype = "gomod",
}
@ -146,7 +149,7 @@ list.graphql = {
url = "https://github.com/bkegley/tree-sitter-graphql",
files = { "src/parser.c" },
},
maintainers = {"@bkegley"},
maintainers = { "@bkegley" },
}
list.ruby = {
@ -154,7 +157,7 @@ list.ruby = {
url = "https://github.com/tree-sitter/tree-sitter-ruby",
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {'@TravonteD'},
maintainers = { "@TravonteD" },
}
list.bash = {
@ -163,8 +166,8 @@ list.bash = {
files = { "src/parser.c", "src/scanner.cc" },
},
used_by = { "zsh", "PKGBUILD" },
filetype = 'sh',
maintainers = {"@TravonteD"},
filetype = "sh",
maintainers = { "@TravonteD" },
}
list.fish = {
@ -172,7 +175,7 @@ list.fish = {
url = "https://github.com/krnik/tree-sitter-fish",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@krnik", "@ram02z"},
maintainers = { "@krnik", "@ram02z" },
}
list.php = {
@ -180,7 +183,7 @@ list.php = {
url = "https://github.com/tree-sitter/tree-sitter-php",
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {"@tk-shirasaka"},
maintainers = { "@tk-shirasaka" },
}
list.java = {
@ -188,7 +191,7 @@ list.java = {
url = "https://github.com/tree-sitter/tree-sitter-java",
files = { "src/parser.c" },
},
maintainers = {"@p00f"},
maintainers = { "@p00f" },
}
list.kotlin = {
@ -196,7 +199,7 @@ list.kotlin = {
url = "https://github.com/tormodatt/tree-sitter-kotlin",
files = { "src/parser.c" },
},
maintainers = {"@tormodatt"},
maintainers = { "@tormodatt" },
}
list.html = {
@ -204,7 +207,7 @@ list.html = {
url = "https://github.com/tree-sitter/tree-sitter-html",
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {"@TravonteD"},
maintainers = { "@TravonteD" },
}
list.julia = {
@ -212,7 +215,7 @@ list.julia = {
url = "https://github.com/tree-sitter/tree-sitter-julia",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@mroavi", "@theHamsta"},
maintainers = { "@mroavi", "@theHamsta" },
}
list.json = {
@ -220,7 +223,7 @@ list.json = {
url = "https://github.com/tree-sitter/tree-sitter-json",
files = { "src/parser.c" },
},
maintainers = {"@steelsojka"},
maintainers = { "@steelsojka" },
}
list.css = {
@ -228,15 +231,15 @@ list.css = {
url = "https://github.com/tree-sitter/tree-sitter-css",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@TravonteD"},
maintainers = { "@TravonteD" },
}
list.scss = {
install_info = {
url = "https://github.com/serenadeai/tree-sitter-scss",
files = { "src/parser.c", "src/scanner.c" }
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@elianiva"},
maintainers = { "@elianiva" },
}
list.erlang = {
@ -245,16 +248,16 @@ list.erlang = {
files = { "src/parser.c" },
branch = "main",
},
maintainers = { '@ostera' },
maintainers = { "@ostera" },
}
list.elixir = {
install_info = {
url = "https://github.com/ananthakumaran/tree-sitter-elixir",
files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true,
files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true,
},
maintainers = { '@nifoc' },
maintainers = { "@nifoc" },
}
list.ocaml = {
@ -263,7 +266,7 @@ list.ocaml = {
files = { "src/parser.c", "src/scanner.cc" },
location = "tree-sitter-ocaml/ocaml",
},
maintainers = {'@undu'},
maintainers = { "@undu" },
}
list.ocaml_interface = {
@ -272,25 +275,25 @@ list.ocaml_interface = {
files = { "src/parser.c", "src/scanner.cc" },
location = "tree-sitter-ocaml_interface/interface",
},
maintainers = {'@undu'},
filetype = 'ocamlinterface'
maintainers = { "@undu" },
filetype = "ocamlinterface",
}
list.ocamllex = {
install_info = {
url = "https://github.com/atom-ocaml/tree-sitter-ocamllex",
files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true,
requires_generate_from_grammar = true,
},
maintainers = {'@undu'},
maintainers = { "@undu" },
}
list.swift = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-swift",
files = { "src/parser.c" },
requires_generate_from_grammar = true,
}
requires_generate_from_grammar = true,
},
}
list.c_sharp = {
@ -298,8 +301,8 @@ list.c_sharp = {
url = "https://github.com/tree-sitter/tree-sitter-c-sharp",
files = { "src/parser.c", "src/scanner.c" },
},
filetype = 'cs',
maintainers = {'@Luxed'},
filetype = "cs",
maintainers = { "@Luxed" },
}
list.typescript = {
@ -309,7 +312,7 @@ list.typescript = {
location = "tree-sitter-typescript/typescript",
generate_requires_npm = true,
},
maintainers = {"@steelsojka"},
maintainers = { "@steelsojka" },
}
list.tsx = {
@ -320,24 +323,24 @@ list.tsx = {
generate_requires_npm = true,
},
used_by = { "typescript.tsx" },
filetype = 'typescriptreact',
maintainers = {'@steelsojka'}
filetype = "typescriptreact",
maintainers = { "@steelsojka" },
}
list.scala = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-scala",
files = { "src/parser.c", "src/scanner.c" },
}
},
}
list.supercollider = {
install_info = {
url = "https://github.com/madskjeldgaard/tree-sitter-supercollider",
files = {"src/parser.c", "src/scanner.c"},
files = { "src/parser.c", "src/scanner.c" },
branch = "main",
},
maintainers = {"@madskjeldgaard"},
maintainers = { "@madskjeldgaard" },
filetype = "supercollider",
}
@ -345,16 +348,16 @@ list.haskell = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-haskell",
files = { "src/parser.c", "src/scanner.cc" },
}
},
}
list.hcl = {
install_info = {
url = "https://github.com/MichaHoffmann/tree-sitter-hcl",
files = {"src/parser.c", "src/scanner.cc"},
branch = "main"
files = { "src/parser.c", "src/scanner.cc" },
branch = "main",
},
maintainers = {"@MichaHoffmann"},
maintainers = { "@MichaHoffmann" },
filetype = "hcl",
used_by = { "terraform", "packer", "nomad" },
}
@ -373,18 +376,18 @@ list.toml = {
files = { "src/parser.c", "src/scanner.c" },
generate_requires_npm = true,
},
maintainers = {"@tk-shirasaka"},
maintainers = { "@tk-shirasaka" },
}
list.glimmer = {
install_info = {
url = "https://github.com/alexlafroscia/tree-sitter-glimmer",
files = { "src/parser.c", "src/scanner.c" },
branch = 'main',
branch = "main",
},
readme_name = "Glimmer and Ember",
maintainers = { "@alexlafroscia" },
filetype = "handlebars"
filetype = "handlebars",
}
list.vue = {
@ -392,7 +395,7 @@ list.vue = {
url = "https://github.com/ikatyang/tree-sitter-vue",
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {"@WhyNotHugo"},
maintainers = { "@WhyNotHugo" },
}
list.jsonc = {
@ -402,14 +405,14 @@ list.jsonc = {
generate_requires_npm = true,
},
readme_name = "JSON with comments",
maintainers = {"@WhyNotHugo"},
maintainers = { "@WhyNotHugo" },
}
list.elm = {
install_info = {
url = "https://github.com/elm-tooling/tree-sitter-elm",
files = { "src/parser.c", "src/scanner.cc" },
}
},
}
list.yaml = {
@ -417,7 +420,7 @@ list.yaml = {
url = "https://github.com/ikatyang/tree-sitter-yaml",
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = {"@stsewd"},
maintainers = { "@stsewd" },
}
list.nix = {
@ -425,7 +428,7 @@ list.nix = {
url = "https://github.com/cstrahan/tree-sitter-nix",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@leo60228"},
maintainers = { "@leo60228" },
}
list.dart = {
@ -433,7 +436,7 @@ list.dart = {
url = "https://github.com/UserNobody14/tree-sitter-dart",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@Akin909"},
maintainers = { "@Akin909" },
}
list.rst = {
@ -441,7 +444,7 @@ list.rst = {
url = "https://github.com/stsewd/tree-sitter-rst",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@stsewd"},
maintainers = { "@stsewd" },
}
list.fennel = {
@ -449,7 +452,7 @@ list.fennel = {
url = "https://github.com/travonted/tree-sitter-fennel",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {'@TravonteD'},
maintainers = { "@TravonteD" },
}
list.teal = {
@ -457,7 +460,7 @@ list.teal = {
url = "https://github.com/euclidianAce/tree-sitter-teal",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {'@euclidianAce'},
maintainers = { "@euclidianAce" },
}
list.ql = {
@ -465,7 +468,7 @@ list.ql = {
url = "https://github.com/tree-sitter/tree-sitter-ql",
files = { "src/parser.c" },
},
maintainers = {'@pwntester'},
maintainers = { "@pwntester" },
}
list.verilog = {
@ -482,9 +485,9 @@ list.verilog = {
list.regex = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-regex",
files = { "src/parser.c" }
files = { "src/parser.c" },
},
maintainers = {"@theHamsta"},
maintainers = { "@theHamsta" },
}
list.comment = {
@ -492,7 +495,7 @@ list.comment = {
url = "https://github.com/stsewd/tree-sitter-comment",
files = { "src/parser.c", "src/scanner.c" },
},
maintainers = {"@stsewd"},
maintainers = { "@stsewd" },
}
list.jsdoc = {
@ -500,16 +503,16 @@ list.jsdoc = {
url = "https://github.com/tree-sitter/tree-sitter-jsdoc",
files = { "src/parser.c" },
},
maintainers = {"@steelsojka"},
maintainers = { "@steelsojka" },
}
list.query = {
install_info = {
url = "https://github.com/nvim-treesitter/tree-sitter-query",
files = { "src/parser.c" }
files = { "src/parser.c" },
},
readme_name = "Tree-sitter query language",
maintainers = {"@steelsojka"},
maintainers = { "@steelsojka" },
}
list.sparql = {
@ -525,10 +528,10 @@ list.gdscript = {
install_info = {
url = "https://github.com/PrestonKnopp/tree-sitter-gdscript",
files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true,
requires_generate_from_grammar = true,
},
readme_name = "Godot (gdscript)",
maintainers = {"@Shatur95"},
maintainers = { "@Shatur95" },
}
list.turtle = {
@ -545,9 +548,9 @@ list.devicetree = {
url = "https://github.com/joelspadin/tree-sitter-devicetree",
files = { "src/parser.c" },
branch = "main",
requires_generate_from_grammar = true,
requires_generate_from_grammar = true,
},
filetype = 'dts',
filetype = "dts",
maintainers = { "@jedrzejboczar" },
}
@ -563,7 +566,7 @@ list.svelte = {
list.r = {
install_info = {
url = "https://github.com/r-lib/tree-sitter-r",
files = { "src/parser.c" }
files = { "src/parser.c" },
},
maintainers = { "@jimhester" },
}
@ -582,8 +585,8 @@ list.latex = {
url = "https://github.com/latex-lsp/tree-sitter-latex",
files = { "src/parser.c" },
},
filetype = 'tex',
used_by = {'cls', 'sty'},
filetype = "tex",
used_by = { "cls", "sty" },
maintainers = { "@theHamsta by asking @clason" },
}
@ -592,36 +595,36 @@ list.bibtex = {
url = "https://github.com/latex-lsp/tree-sitter-bibtex",
files = { "src/parser.c" },
},
filetype = 'bib',
filetype = "bib",
maintainers = { "@theHamsta by asking @clason" },
}
list.zig = {
install_info = {
url = "https://github.com/Himujjal/tree-sitter-zig",
files = { "src/parser.c" }
files = { "src/parser.c" },
},
filetype = "zig",
maintainers = { "@Himujjal" }
maintainers = { "@Himujjal" },
}
list.fortran = {
install_info = {
url = "https://github.com/stadelmanma/tree-sitter-fortran",
files = { "src/parser.c", "src/scanner.cc", },
files = { "src/parser.c", "src/scanner.cc" },
},
}
list.cmake = {
install_info = {
url = "https://github.com/uyha/tree-sitter-cmake",
files = { "src/parser.c", "src/scanner.cc"},
files = { "src/parser.c", "src/scanner.cc" },
},
maintainers = { "@uyha" },
}
local M = {
list = list
list = list,
}
function M.ft_to_lang(ft)
@ -629,20 +632,23 @@ function M.ft_to_lang(ft)
end
function M.available_parsers()
if vim.fn.executable('tree-sitter') == 1 and vim.fn.executable('node') == 1 then
if vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1 then
return vim.tbl_keys(M.list)
else
return vim.tbl_filter(function(p) return not M.list[p].install_info.requires_generate_from_grammar end,
vim.tbl_keys(M.list))
return vim.tbl_filter(function(p)
return not M.list[p].install_info.requires_generate_from_grammar
end, vim.tbl_keys(
M.list
))
end
end
function M.maintained_parsers()
local has_tree_sitter_cli = vim.fn.executable('tree-sitter') == 1 and vim.fn.executable('node') == 1
local has_tree_sitter_cli = vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1
return vim.tbl_filter(function(lang)
return M.list[lang].maintainers
and (has_tree_sitter_cli or not M.list[lang].install_info.requires_generate_from_grammar) end,
M.available_parsers())
and (has_tree_sitter_cli or not M.list[lang].install_info.requires_generate_from_grammar)
end, M.available_parsers())
end
function M.get_parser_configs()
@ -654,9 +660,9 @@ local parser_files
function M.reset_cache()
parser_files = setmetatable({}, {
__index = function(tbl, key)
rawset(tbl, key, api.nvim_get_runtime_file('parser/' .. key .. '.*', false))
rawset(tbl, key, api.nvim_get_runtime_file("parser/" .. key .. ".*", false))
return rawget(tbl, key)
end
end,
})
end
@ -665,9 +671,13 @@ M.reset_cache()
function M.has_parser(lang)
local lang = lang or M.get_buf_lang(api.nvim_get_current_buf())
if not lang or #lang == 0 then return false end
if not lang or #lang == 0 then
return false
end
-- HACK: nvim internal API
if vim._ts_has_language(lang) then return true end
if vim._ts_has_language(lang) then
return true
end
return #parser_files[lang] > 0
end

View file

@ -1,15 +1,15 @@
local api = vim.api
local tsq = require'vim.treesitter.query'
local tsrange = require'nvim-treesitter.tsrange'
local utils = require'nvim-treesitter.utils'
local parsers = require'nvim-treesitter.parsers'
local caching = require'nvim-treesitter.caching'
local tsq = require "vim.treesitter.query"
local tsrange = require "nvim-treesitter.tsrange"
local utils = require "nvim-treesitter.utils"
local parsers = require "nvim-treesitter.parsers"
local caching = require "nvim-treesitter.caching"
local M = {}
local EMPTY_ITER = function() end
M.built_in_query_groups = {'highlights', 'locals', 'folds', 'indents', 'injections'}
M.built_in_query_groups = { "highlights", "locals", "folds", "indents", "injections" }
-- Creates a function that checks whether a given query exists
-- for a specific language.
@ -24,10 +24,10 @@ for _, query in ipairs(M.built_in_query_groups) do
end
function M.available_query_groups()
local query_files = api.nvim_get_runtime_file('queries/*/*.scm', true)
local query_files = api.nvim_get_runtime_file("queries/*/*.scm", true)
local groups = {}
for _, f in ipairs(query_files) do
groups[vim.fn.fnamemodify(f, ':t:r')] = true
groups[vim.fn.fnamemodify(f, ":t:r")] = true
end
local list = {}
for k, _ in pairs(groups) do
@ -42,7 +42,7 @@ do
local function update_cached_matches(bufnr, changed_tick, query_group)
query_cache.set(query_group, bufnr, {
tick = changed_tick,
cache= M.collect_group_results(bufnr, query_group) or {}
cache = M.collect_group_results(bufnr, query_group) or {},
})
end
@ -50,7 +50,7 @@ do
bufnr = bufnr or api.nvim_get_current_buf()
local cached_local = query_cache.get(query_group, bufnr)
if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then
update_cached_matches(bufnr,api.nvim_buf_get_changedtick(bufnr), query_group)
update_cached_matches(bufnr, api.nvim_buf_get_changedtick(bufnr), query_group)
end
return query_cache.get(query_group, bufnr).cache
@ -58,7 +58,7 @@ do
end
local function runtime_queries(lang, query_name)
return api.nvim_get_runtime_file(string.format('queries/%s/%s.scm', lang, query_name), true) or {}
return api.nvim_get_runtime_file(string.format("queries/%s/%s.scm", lang, query_name), true) or {}
end
local query_files_cache = {}
@ -66,11 +66,11 @@ function M.has_query_files(lang, query_name)
if not query_files_cache[lang] then
query_files_cache[lang] = {}
end
if query_files_cache[lang][query_name] == nil then
local files = runtime_queries(lang, query_name)
query_files_cache[lang][query_name] = files and #files > 0
end
return query_files_cache[lang][query_name]
if query_files_cache[lang][query_name] == nil then
local files = runtime_queries(lang, query_name)
query_files_cache[lang][query_name] = files and #files > 0
end
return query_files_cache[lang][query_name]
end
do
@ -117,7 +117,7 @@ do
end
end
else
error("Cannot have query_name by itself!")
error "Cannot have query_name by itself!"
end
end
end
@ -125,7 +125,7 @@ end
--- This function is meant for an autocommand and not to be used. Only use if file is a query file.
function M.invalidate_query_file(fname)
local fnamemodify = vim.fn.fnamemodify
M.invalidate_query_cache(fnamemodify(fname, ':p:h:t'), fnamemodify(fname, ':t:r'))
M.invalidate_query_cache(fnamemodify(fname, ":p:h:t"), fnamemodify(fname, ":t:r"))
end
function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
@ -142,7 +142,7 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
local function insert_to_path(object, path, value)
local curr_obj = object
for index=1,(#path -1) do
for index = 1, (#path - 1) do
if curr_obj[path[index]] == nil then
curr_obj[path[index]] = {}
end
@ -164,7 +164,7 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
for id, node in pairs(match) do
local name = query.captures[id] -- name of the capture in the query
if name ~= nil then
local path = split(name..'.node')
local path = split(name .. ".node")
insert_to_path(prepared_match, path, node)
end
end
@ -178,8 +178,11 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
insert_to_path(prepared_match, split(pred[2]), pred[3])
end
if pred[1] == "make-range!" and type(pred[2]) == "string" and #pred == 4 then
insert_to_path(prepared_match, split(pred[2]..'.node'),
tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]]))
insert_to_path(
prepared_match,
split(pred[2] .. ".node"),
tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]])
)
end
end
end
@ -194,8 +197,8 @@ end
-- Works like M.get_references or M.get_scopes except you can choose the capture
-- Can also be a nested capture like @definition.function to get all nodes defining a function
function M.get_capture_matches(bufnr, capture_string, query_group, root, lang)
if not string.sub(capture_string, 1, 1) == '@' then
print('capture_string must start with "@"')
if not string.sub(capture_string, 1, 1) == "@" then
print 'capture_string must start with "@"'
return
end
@ -214,7 +217,7 @@ function M.get_capture_matches(bufnr, capture_string, query_group, root, lang)
end
function M.find_best_match(bufnr, capture_string, query_group, filter_predicate, scoring_function, root)
if string.sub(capture_string, 1, 1) == '@' then
if string.sub(capture_string, 1, 1) == "@" then
--remove leading "@"
capture_string = string.sub(capture_string, 2)
end
@ -248,10 +251,14 @@ end
function M.iter_group_results(bufnr, query_group, root, root_lang)
local buf_lang = parsers.get_buf_lang(bufnr)
if not buf_lang then return EMPTY_ITER end
if not buf_lang then
return EMPTY_ITER
end
local parser = parsers.get_parser(bufnr, buf_lang)
if not parser then return EMPTY_ITER end
if not parser then
return EMPTY_ITER
end
if not root then
local first_tree = parser:trees()[1]
@ -261,9 +268,11 @@ function M.iter_group_results(bufnr, query_group, root, root_lang)
end
end
if not root then return EMPTY_ITER end
if not root then
return EMPTY_ITER
end
local range = {root:range()}
local range = { root:range() }
if not root_lang then
local lang_tree = parser:language_for_range(range)
@ -273,10 +282,14 @@ function M.iter_group_results(bufnr, query_group, root, root_lang)
end
end
if not root_lang then return EMPTY_ITER end
if not root_lang then
return EMPTY_ITER
end
local query = M.get_query(root_lang, query_group)
if not query then return EMPTY_ITER end
if not query then
return EMPTY_ITER
end
-- The end row is exclusive so we need to add 1 to it.
return M.iter_prepared_matches(query, root, bufnr, range[1], range[3] + 1)
@ -300,8 +313,7 @@ end
-- @param query_type The query to get the capture from. This is ignore if a function is provided
-- for the captuer argument.
function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
local type_fn = type(capture_or_fn) == 'function'
and capture_or_fn
local type_fn = type(capture_or_fn) == "function" and capture_or_fn
or function()
return capture_or_fn, query_type
end

View file

@ -1,4 +1,4 @@
local query = require"vim.treesitter.query"
local query = require "vim.treesitter.query"
local function error(str)
vim.api.nvim_err_writeln(str)
@ -21,7 +21,9 @@ local function valid_args(name, pred, count, strict_count)
end
query.add_predicate("nth?", function(match, pattern, bufnr, pred)
if not valid_args("nth?", pred, 2, true) then return end
if not valid_args("nth?", pred, 2, true) then
return
end
local node = match[pred[2]]
local n = pred[3]
@ -33,13 +35,17 @@ query.add_predicate("nth?", function(match, pattern, bufnr, pred)
end)
local function has_ancestor(match, pattern, bufnr, pred)
if not valid_args(pred[1], pred, 2) then return end
if not valid_args(pred[1], pred, 2) then
return
end
local node = match[pred[2]]
local ancestor_types = {unpack(pred, 3)}
if not node then return true end
local ancestor_types = { unpack(pred, 3) }
if not node then
return true
end
local just_direct_parent = pred[1]:find('has-parent', 1, true)
local just_direct_parent = pred[1]:find("has-parent", 1, true)
node = node:parent()
while node do
@ -55,40 +61,48 @@ local function has_ancestor(match, pattern, bufnr, pred)
return false
end
query.add_predicate('has-ancestor?', has_ancestor)
query.add_predicate("has-ancestor?", has_ancestor)
query.add_predicate('has-parent?', has_ancestor)
query.add_predicate("has-parent?", has_ancestor)
query.add_predicate('is?', function(match, pattern, bufnr, pred)
if not valid_args("is?", pred, 2) then return end
query.add_predicate("is?", function(match, pattern, bufnr, pred)
if not valid_args("is?", pred, 2) then
return
end
-- Avoid circular dependencies
local locals = require"nvim-treesitter.locals"
local locals = require "nvim-treesitter.locals"
local node = match[pred[2]]
local types = {unpack(pred, 3)}
local types = { unpack(pred, 3) }
if not node then return true end
if not node then
return true
end
local _, _, kind = locals.find_definition(node, bufnr)
return vim.tbl_contains(types, kind)
end)
query.add_predicate('has-type?', function(match, pattern, bufnr, pred)
if not valid_args(pred[1], pred, 2) then return end
query.add_predicate("has-type?", function(match, pattern, bufnr, pred)
if not valid_args(pred[1], pred, 2) then
return
end
local node = match[pred[2]]
local types = {unpack(pred, 3)}
local types = { unpack(pred, 3) }
if not node then return true end
if not node then
return true
end
return vim.tbl_contains(types, node:type())
end)
-- Just avoid some anoying warnings for this directive
query.add_directive('make-range!', function() end)
query.add_directive("make-range!", function() end)
query.add_directive('downcase!', function(match, _, bufnr, pred, metadata)
query.add_directive("downcase!", function(match, _, bufnr, pred, metadata)
local text, key, value
if #pred == 3 then

View file

@ -1,116 +1,118 @@
local fn = vim.fn
local utils = require'nvim-treesitter.utils'
local utils = require "nvim-treesitter.utils"
local M = {}
function M.select_mkdir_cmd(directory, cwd, info_msg)
if fn.has('win32') == 1 then
if fn.has "win32" == 1 then
return {
cmd = 'cmd',
cmd = "cmd",
opts = {
args = { '/C', 'mkdir', directory},
args = { "/C", "mkdir", directory },
cwd = cwd,
},
info = info_msg,
err = "Could not create "..directory,
err = "Could not create " .. directory,
}
else
return {
cmd = 'mkdir',
cmd = "mkdir",
opts = {
args = { directory },
cwd = cwd,
},
info = info_msg,
err = "Could not create "..directory,
err = "Could not create " .. directory,
}
end
end
function M.select_rm_file_cmd(file, info_msg)
if fn.has('win32') == 1 then
if fn.has "win32" == 1 then
return {
cmd = 'cmd',
cmd = "cmd",
opts = {
args = { '/C', 'if', 'exist', file, 'del', file },
args = { "/C", "if", "exist", file, "del", file },
},
info = info_msg,
err = "Could not delete "..file,
err = "Could not delete " .. file,
}
else
return {
cmd = 'rm',
cmd = "rm",
opts = {
args = { file },
},
info = info_msg,
err = "Could not delete "..file,
err = "Could not delete " .. file,
}
end
end
function M.select_executable(executables)
return vim.tbl_filter(function(c) return c ~= vim.NIL and fn.executable(c) == 1 end, executables)[1]
return vim.tbl_filter(function(c)
return c ~= vim.NIL and fn.executable(c) == 1
end, executables)[1]
end
function M.select_compiler_args(repo, compiler)
if (string.match(compiler, 'cl$') or string.match(compiler, 'cl.exe$')) then
if string.match(compiler, "cl$") or string.match(compiler, "cl.exe$") then
return {
'/Fe:',
'parser.so',
'/Isrc',
"/Fe:",
"parser.so",
"/Isrc",
repo.files,
'-Os',
'/LD',
"-Os",
"/LD",
}
else
local args = {
'-o',
'parser.so',
'-I./src',
"-o",
"parser.so",
"-I./src",
repo.files,
'-shared',
'-Os',
'-lstdc++',
"-shared",
"-Os",
"-lstdc++",
}
if fn.has('win32') == 0 then
table.insert(args, '-fPIC')
if fn.has "win32" == 0 then
table.insert(args, "-fPIC")
end
return args
end
end
function M.select_install_rm_cmd(cache_folder, project_name)
if fn.has('win32') == 1 then
local dir = cache_folder ..'\\'.. project_name
if fn.has "win32" == 1 then
local dir = cache_folder .. "\\" .. project_name
return {
cmd = 'cmd',
cmd = "cmd",
opts = {
args = { '/C', 'if', 'exist', dir, 'rmdir', '/s', '/q', dir },
}
args = { "/C", "if", "exist", dir, "rmdir", "/s", "/q", dir },
},
}
else
return {
cmd = 'rm',
cmd = "rm",
opts = {
args = { '-rf', cache_folder..'/'..project_name },
}
args = { "-rf", cache_folder .. "/" .. project_name },
},
}
end
end
function M.select_mv_cmd(from, to, cwd)
if fn.has('win32') == 1 then
if fn.has "win32" == 1 then
return {
cmd = 'cmd',
cmd = "cmd",
opts = {
args = { '/C', 'move', '/Y', from, to },
args = { "/C", "move", "/Y", from, to },
cwd = cwd,
}
},
}
else
return {
cmd = 'mv',
cmd = "mv",
opts = {
args = { from, to },
cwd = cwd,
@ -120,93 +122,94 @@ function M.select_mv_cmd(from, to, cwd)
end
function M.select_download_commands(repo, project_name, cache_folder, revision)
local can_use_tar = vim.fn.executable('tar') == 1 and vim.fn.executable('curl') == 1
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 is_windows = fn.has('win32') == 1
local is_windows = fn.has "win32" == 1
revision = revision or repo.branch or "master"
if can_use_tar and (is_github or is_gitlab) and not is_windows then
local path_sep = utils.get_path_sep()
local url = repo.url:gsub('.git$', '')
local url = repo.url:gsub(".git$", "")
return {
M.select_install_rm_cmd(cache_folder, project_name..'-tmp'),
M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"),
{
cmd = 'curl',
info = 'Downloading...',
err = 'Error during download, please verify your internet connection',
cmd = "curl",
info = "Downloading...",
err = "Error during download, please verify your internet connection",
opts = {
args = {
'-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"
"-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_folder,
},
},
M.select_mkdir_cmd(project_name..'-tmp', cache_folder, 'Creating temporary directory'),
M.select_mkdir_cmd(project_name .. "-tmp", cache_folder, "Creating temporary directory"),
{
cmd = 'tar',
info = 'Extracting...',
err = 'Error during tarball extraction.',
cmd = "tar",
info = "Extracting...",
err = "Error during tarball extraction.",
opts = {
args = {
'-xvf',
project_name..".tar.gz",
'-C',
project_name..'-tmp',
"-xvf",
project_name .. ".tar.gz",
"-C",
project_name .. "-tmp",
},
cwd = cache_folder,
},
},
M.select_rm_file_cmd(cache_folder..path_sep..project_name..".tar.gz"),
M.select_mv_cmd(utils.join_path(project_name..'-tmp', url:match('[^/]-$')..'-'..revision),
M.select_rm_file_cmd(cache_folder .. path_sep .. project_name .. ".tar.gz"),
M.select_mv_cmd(
utils.join_path(project_name .. "-tmp", url:match "[^/]-$" .. "-" .. revision),
project_name,
cache_folder),
M.select_install_rm_cmd(cache_folder, project_name..'-tmp')
cache_folder
),
M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"),
}
else
local git_folder = utils.join_path(cache_folder, project_name)
local clone_error = 'Error during download, please verify your internet connection'
local clone_error = "Error during download, please verify your internet connection"
return {
{
cmd = 'git',
info = 'Downloading...',
cmd = "git",
info = "Downloading...",
err = clone_error,
opts = {
args = {
'clone',
"clone",
repo.url,
project_name
project_name,
},
cwd = cache_folder,
},
},
{
cmd = 'git',
info = 'Checking out locked revision',
err = 'Error while checking out revision',
cmd = "git",
info = "Checking out locked revision",
err = "Error while checking out revision",
opts = {
args = {
'checkout', revision,
"checkout",
revision,
},
cwd = git_folder
}
}
cwd = git_folder,
},
},
}
end
end
function M.make_directory_change_for_command(dir, command)
if fn.has('win32') == 1 then
if fn.has "win32" == 1 then
return string.format("pushd %s & %s & popd", dir, command)
else
return string.format("cd %s;\n %s", dir, command)

View file

@ -1,7 +1,7 @@
local api = vim.api
local parsers = require'nvim-treesitter.parsers'
local utils = require'nvim-treesitter.utils'
local parsers = require "nvim-treesitter.parsers"
local utils = require "nvim-treesitter.utils"
local M = {}
@ -11,20 +11,22 @@ local M = {}
-- @return list of lines of text of the node
function M.get_node_text(node, bufnr)
local bufnr = bufnr or api.nvim_get_current_buf()
if not node then return {} end
if not node then
return {}
end
-- We have to remember that end_col is end-exclusive
local start_row, start_col, end_row, end_col = M.get_node_range(node)
if start_row ~= end_row then
local lines = api.nvim_buf_get_lines(bufnr, start_row, end_row+1, false)
lines[1] = string.sub(lines[1], start_col+1)
local lines = api.nvim_buf_get_lines(bufnr, start_row, end_row + 1, false)
lines[1] = string.sub(lines[1], start_col + 1)
lines[#lines] = string.sub(lines[#lines], 1, end_col)
return lines
else
local line = api.nvim_buf_get_lines(bufnr, start_row, start_row+1, false)[1]
local line = api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1]
-- If line is nil then the line is empty
return line and { string.sub(line, start_col+1, end_col) } or {}
return line and { string.sub(line, start_col + 1, end_col) } or {}
end
end
@ -32,7 +34,9 @@ end
-- @param dest the possible parent
-- @param source the possible child node
function M.is_parent(dest, source)
if not (dest and source) then return false end
if not (dest and source) then
return false
end
local current = source
while current ~= nil do
@ -54,9 +58,11 @@ function M.get_next_node(node, allow_switch_parents, allow_next_parent)
local destination_node
local parent = node:parent()
if not parent then return end
if not parent then
return
end
local found_pos = 0
for i = 0,parent:named_child_count()-1,1 do
for i = 0, parent:named_child_count() - 1, 1 do
if parent:named_child(i) == node then
found_pos = i
break
@ -83,10 +89,12 @@ end
function M.get_previous_node(node, allow_switch_parents, allow_previous_parent)
local destination_node
local parent = node:parent()
if not parent then return end
if not parent then
return
end
local found_pos = 0
for i = 0,parent:named_child_count()-1,1 do
for i = 0, parent:named_child_count() - 1, 1 do
if parent:named_child(i) == node then
found_pos = i
break
@ -107,8 +115,8 @@ end
function M.get_named_children(node)
local nodes = {}
for i=0,node:named_child_count() - 1,1 do
nodes[i+1] = node:named_child(i)
for i = 0, node:named_child_count() - 1, 1 do
nodes[i + 1] = node:named_child(i)
end
return nodes
end
@ -118,19 +126,23 @@ function M.get_node_at_cursor(winnr)
local cursor_range = { cursor[1] - 1, cursor[2] }
local root = M.get_root_for_position(unpack(cursor_range))
if not root then return end
if not root then
return
end
return root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2])
end
function M.get_root_for_position(line, col, root_lang_tree)
if not root_lang_tree then
if not parsers.has_parser() then return end
if not parsers.has_parser() then
return
end
root_lang_tree = parsers.get_parser()
end
local lang_tree = root_lang_tree:language_for_range({ line, col, line, col })
local lang_tree = root_lang_tree:language_for_range { line, col, line, col }
for _, tree in ipairs(lang_tree:trees()) do
local root = tree:root()
@ -157,13 +169,15 @@ function M.get_root_for_node(node)
end
function M.highlight_node(node, buf, hl_namespace, hl_group)
if not node then return end
M.highlight_range({node:range()}, buf, hl_namespace, hl_group)
if not node then
return
end
M.highlight_range({ node:range() }, buf, hl_namespace, hl_group)
end
function M.highlight_range(range, buf, hl_namespace, hl_group)
local start_row, start_col, end_row, end_col = unpack(range)
vim.highlight.range(buf, hl_namespace, hl_group, {start_row, start_col}, {end_row, end_col})
vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col })
end
-- Set visual selection to node
@ -173,8 +187,8 @@ function M.update_selection(buf, node, selection_mode)
selection_mode = selection_mode or "charwise"
local start_row, start_col, end_row, end_col = M.get_node_range(node)
if end_row == vim.fn.line('$') then
end_col = #vim.fn.getline('$')
if end_row == vim.fn.line "$" then
end_col = #vim.fn.getline "$"
end
-- Convert to 1-based indices
@ -186,12 +200,10 @@ function M.update_selection(buf, node, selection_mode)
vim.fn.setpos(".", { buf, start_row, start_col, 0 })
-- Start visual selection in appropriate mode
local v_table = {charwise = "v", linewise = "V", blockwise = "<C-v>"}
local v_table = { charwise = "v", linewise = "V", blockwise = "<C-v>" }
---- Call to `nvim_replace_termcodes()` is needed for sending appropriate
---- command to enter blockwise mode
local mode_string = vim.api.nvim_replace_termcodes(
v_table[selection_mode] or selection_mode, true, true, true
)
local mode_string = vim.api.nvim_replace_termcodes(v_table[selection_mode] or selection_mode, true, true, true)
vim.cmd("normal! " .. mode_string)
-- Convert exclusive end position to inclusive
@ -231,7 +243,7 @@ function M.is_in_node_range(node, line, col)
end
function M.get_node_range(node_or_range)
if type(node_or_range) == 'table' then
if type(node_or_range) == "table" then
return unpack(node_or_range)
else
return node_or_range:range()
@ -242,7 +254,7 @@ function M.node_to_lsp_range(node)
local start_line, start_col, end_line, end_col = M.get_node_range(node)
local rtn = {}
rtn.start = { line = start_line, character = start_col }
rtn['end'] = { line = end_line, character = end_col }
rtn["end"] = { line = end_line, character = end_col }
return rtn
end
@ -277,13 +289,13 @@ function M.memoize_by_buf_tick(fn, options)
-- Clean up logic only!
api.nvim_buf_attach(bufnr, false, {
on_detach = detach_handler,
on_reload = detach_handler
on_reload = detach_handler,
})
end
cache[key] = {
result = fn(...),
last_tick = tick
last_tick = tick,
}
return cache[key].result
@ -291,24 +303,28 @@ function M.memoize_by_buf_tick(fn, options)
end
function M.swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second)
if not node_or_range1 or not node_or_range2 then return end
if not node_or_range1 or not node_or_range2 then
return
end
local range1 = M.node_to_lsp_range(node_or_range1)
local range2 = M.node_to_lsp_range(node_or_range2)
local text1 = M.get_node_text(node_or_range1)
local text2 = M.get_node_text(node_or_range2)
local edit1 = { range = range1, newText = table.concat(text2, '\n') }
local edit2 = { range = range2, newText = table.concat(text1, '\n') }
vim.lsp.util.apply_text_edits({edit1, edit2}, bufnr)
local edit1 = { range = range1, newText = table.concat(text2, "\n") }
local edit2 = { range = range2, newText = table.concat(text1, "\n") }
vim.lsp.util.apply_text_edits({ edit1, edit2 }, bufnr)
if cursor_to_second then
utils.set_jump()
local char_delta = 0
local line_delta = 0
if range1["end"].line < range2.start.line
or (range1["end"].line == range2.start.line and range1["end"].character < range2.start.character) then
if
range1["end"].line < range2.start.line
or (range1["end"].line == range2.start.line and range1["end"].character < range2.start.character)
then
line_delta = #text2 - #text1
end
@ -320,29 +336,32 @@ function M.swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second)
--space_between_ranges = range2.start.character - range1["end"].character
--char_delta = correction_after_line_change + text_now_before_range2 + space_between_ranges
--- Equivalent to:
char_delta = #(text2[#text2]) - range1["end"].character
char_delta = #text2[#text2] - range1["end"].character
-- add range1.start.character if last line of range1 (now text2) does not start at 0
if range1.start.line == range2.start.line + line_delta then
char_delta = char_delta + range1.start.character
end
else
char_delta = #(text2[#text2]) - #(text1[#text1])
char_delta = #text2[#text2] - #text1[#text1]
end
end
api.nvim_win_set_cursor(api.nvim_get_current_win(),
{range2.start.line + 1 + line_delta,
range2.start.character + char_delta})
api.nvim_win_set_cursor(
api.nvim_get_current_win(),
{ range2.start.line + 1 + line_delta, range2.start.character + char_delta }
)
end
end
function M.goto_node(node, goto_end, avoid_set_jump)
if not node then return end
if not node then
return
end
if not avoid_set_jump then
utils.set_jump()
end
local range = {node:range()}
local range = { node:range() }
local position
if not goto_end then
position = { range[1], range[2] }

View file

@ -3,75 +3,72 @@ local TSRange = {}
TSRange.__index = TSRange
local api = vim.api
local ts_utils = require'nvim-treesitter.ts_utils'
local ts_utils = require "nvim-treesitter.ts_utils"
local function get_byte_offset(buf, row, col)
return api.nvim_buf_get_offset(buf, row)
+ vim.fn.byteidx(api.nvim_buf_get_lines(buf, row, row + 1, false), col)
return api.nvim_buf_get_offset(buf, row) + vim.fn.byteidx(api.nvim_buf_get_lines(buf, row, row + 1, false), col)
end
function TSRange.new(buf, start_row, start_col, end_row, end_col)
return setmetatable(
{
start_pos = {start_row, start_col, get_byte_offset(buf, start_row, start_col)},
end_pos = {end_row, end_col, get_byte_offset(buf, end_row, end_col)},
buf = buf,
[1] = start_row,
[2] = start_col,
[3] = end_row,
[4] = end_col,
},
TSRange)
return setmetatable({
start_pos = { start_row, start_col, get_byte_offset(buf, start_row, start_col) },
end_pos = { end_row, end_col, get_byte_offset(buf, end_row, end_col) },
buf = buf,
[1] = start_row,
[2] = start_col,
[3] = end_row,
[4] = end_col,
}, TSRange)
end
function TSRange.from_nodes(buf, start_node, end_node)
TSRange.__index = TSRange
local start_pos = start_node and {start_node:start()} or {end_node:start()}
local end_pos = end_node and {end_node:end_()} or {start_node:end_()}
return setmetatable(
{
start_pos = {start_pos[1], start_pos[2], start_pos[3]},
end_pos = {end_pos[1], end_pos[2], end_pos[3]},
buf = buf,
[1] = start_pos[1],
[2] = start_pos[2],
[3] = end_pos[1],
[4] = end_pos[2],
},
TSRange)
local start_pos = start_node and { start_node:start() } or { end_node:start() }
local end_pos = end_node and { end_node:end_() } or { start_node:end_() }
return setmetatable({
start_pos = { start_pos[1], start_pos[2], start_pos[3] },
end_pos = { end_pos[1], end_pos[2], end_pos[3] },
buf = buf,
[1] = start_pos[1],
[2] = start_pos[2],
[3] = end_pos[1],
[4] = end_pos[2],
}, TSRange)
end
function TSRange.from_table(buf, range)
return setmetatable(
{
start_pos = {range[1], range[2], get_byte_offset(buf, range[1], range[2])},
end_pos = {range[3], range[4], get_byte_offset(buf, range[3], range[4])},
buf = buf,
[1] = range[1],
[2] = range[2],
[3] = range[3],
[4] = range[4],
},
TSRange)
return setmetatable({
start_pos = { range[1], range[2], get_byte_offset(buf, range[1], range[2]) },
end_pos = { range[3], range[4], get_byte_offset(buf, range[3], range[4]) },
buf = buf,
[1] = range[1],
[2] = range[2],
[3] = range[3],
[4] = range[4],
}, TSRange)
end
function TSRange:parent()
local root = ts_utils.get_root_for_position(self[1], self[2])
return root
and root:named_descendant_for_range(self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2])
or nil
return root and root:named_descendant_for_range(
self.start_pos[1],
self.start_pos[2],
self.end_pos[1],
self.end_pos[2]
) or nil
end
function TSRange:field()
end
function TSRange:field() end
function TSRange:child_count()
return #self:collect_children()
end
function TSRange:named_child_count()
return #self:collect_children(function(c) return c:named() end)
return #self:collect_children(function(c)
return c:named()
end)
end
function TSRange:iter_children()
@ -79,7 +76,9 @@ function TSRange:iter_children()
return function()
while true do
local node = raw_iterator()
if not node then return end
if not node then
return
end
local _, _, start_byte = node:start()
local _, _, end_byte = node:end_()
if start_byte >= self.start_pos[3] and end_byte <= self.end_pos[3] then
@ -104,7 +103,9 @@ function TSRange:child(index)
end
function TSRange:named_child(index)
return self:collect_children(function(c) return c.named() end)[index + 1]
return self:collect_children(function(c)
return c.named()
end)[index + 1]
end
function TSRange:start()
@ -120,7 +121,7 @@ function TSRange:range()
end
function TSRange:type()
return 'nvim-treesitter-range'
return "nvim-treesitter-range"
end
function TSRange:symbol()
@ -136,11 +137,18 @@ function TSRange:missing()
end
function TSRange:has_error()
return #self:collect_children(function(c) return c:has_error() end) > 0 and true or false
return #self:collect_children(function(c)
return c:has_error()
end) > 0 and true or false
end
function TSRange:sexpr()
return table.concat(vim.tbl_map(function(c) return c:sexpr() end, self:collect_children()), ' ')
return table.concat(
vim.tbl_map(function(c)
return c:sexpr()
end, self:collect_children()),
" "
)
end
M.TSRange = TSRange

View file

@ -6,20 +6,23 @@ local M = {}
function M.setup_commands(mod, commands)
for command_name, def in pairs(commands) do
local call_fn = string.format("lua require'nvim-treesitter.%s'.commands.%s['run<bang>'](<f-args>)",
mod, command_name)
local parts = vim.tbl_flatten({
local call_fn = string.format(
"lua require'nvim-treesitter.%s'.commands.%s['run<bang>'](<f-args>)",
mod,
command_name
)
local parts = vim.tbl_flatten {
"command!",
def.args,
command_name,
call_fn,
})
}
api.nvim_command(table.concat(parts, " "))
end
end
function M.get_path_sep()
return fn.has('win32') == 1 and '\\' or '/'
return fn.has "win32" == 1 and "\\" or "/"
end
-- Returns a function that joins the given arguments with separator. Arguments
@ -29,40 +32,40 @@ print(M.generate_join(" ")("foo", "bar"))
--]]
-- prints "foo bar"
function M.generate_join(separator)
return function (...)
return table.concat({...}, separator)
return function(...)
return table.concat({ ... }, separator)
end
end
M.join_path = M.generate_join(M.get_path_sep())
local join_space = M.generate_join(" ")
local join_space = M.generate_join " "
function M.get_package_path()
-- Path to this source file, removing the leading '@'
local source = string.sub(debug.getinfo(1, 'S').source, 2)
local source = string.sub(debug.getinfo(1, "S").source, 2)
-- Path to the package root
return fn.fnamemodify(source, ":p:h:h:h")
end
function M.get_cache_dir()
local cache_dir = fn.stdpath('data')
local cache_dir = fn.stdpath "data"
if luv.fs_access(cache_dir, 'RW') then
if luv.fs_access(cache_dir, "RW") then
return cache_dir
elseif luv.fs_access('/tmp', 'RW') then
return '/tmp'
elseif luv.fs_access("/tmp", "RW") then
return "/tmp"
end
return nil, join_space('Invalid cache rights,', fn.stdpath('data'), 'or /tmp should be read/write')
return nil, join_space("Invalid cache rights,", fn.stdpath "data", "or /tmp should be read/write")
end
-- Returns $XDG_DATA_HOME/nvim/site, but could use any directory that is in
-- runtimepath
function M.get_site_dir()
local path_sep = M.get_path_sep()
return M.join_path(fn.stdpath('data'), path_sep, 'site')
return M.join_path(fn.stdpath "data", path_sep, "site")
end
-- Try the package dir of the nvim-treesitter plugin first, followed by the
@ -75,7 +78,7 @@ function M.get_parser_install_dir(folder_name)
local package_path_parser_dir = M.join_path(package_path, folder_name)
-- If package_path is read/write, use that
if luv.fs_access(package_path_parser_dir, 'RW') then
if luv.fs_access(package_path_parser_dir, "RW") then
return package_path_parser_dir
end
@ -87,24 +90,24 @@ function M.get_parser_install_dir(folder_name)
if not luv.fs_stat(parser_dir) then
local ok, error = pcall(vim.fn.mkdir, parser_dir, "p", "0755")
if not ok then
return nil, join_space('Couldn\'t create parser dir', parser_dir, ':', error)
return nil, join_space("Couldn't create parser dir", parser_dir, ":", error)
end
return parser_dir
end
-- parser_dir exists, use it if it's read/write
if luv.fs_access(parser_dir, 'RW') then
if luv.fs_access(parser_dir, "RW") then
return parser_dir
end
-- package_path isn't read/write, parser_dir exists but isn't read/write
-- either, give up
return nil, join_space('Invalid cache rights,', package_path, 'or', parser_dir, 'should be read/write')
return nil, join_space("Invalid cache rights,", package_path, "or", parser_dir, "should be read/write")
end
function M.get_parser_info_dir()
return M.get_parser_install_dir('parser-info')
return M.get_parser_install_dir "parser-info"
end
-- Gets a property at path
@ -112,12 +115,14 @@ end
-- @param path the '.' separated path
-- @returns the value at path or nil
function M.get_at_path(tbl, path)
if path == '' then return tbl end
local segments = vim.split(path, '.', true)
if path == "" then
return tbl
end
local segments = vim.split(path, ".", true)
local result = tbl
for _, segment in ipairs(segments) do
if type(result) == 'table' then
if type(result) == "table" then
result = result[segment]
end
end
@ -173,11 +178,13 @@ function M.identity(a)
end
function M.constant(a)
return function() return a end
return function()
return a
end
end
function M.to_func(a)
return type(a) == 'function' and a or M.constant(a)
return type(a) == "function" and a or M.constant(a)
end
return M

View file

@ -1,7 +1,7 @@
-- Execute as `nvim --headless -c "luafile ./scripts/check-queries.lua"`
local function extract_captures()
local lines = vim.fn.readfile("CONTRIBUTING.md")
local lines = vim.fn.readfile "CONTRIBUTING.md"
local captures = {}
local current_query
@ -18,17 +18,17 @@ local function extract_captures()
end
-- Complete captures for injections.
local parsers = require 'nvim-treesitter.info'.installed_parsers()
local parsers = require("nvim-treesitter.info").installed_parsers()
for _, lang in pairs(parsers) do
table.insert(captures['injections'], lang)
table.insert(captures["injections"], lang)
end
return captures
end
local function do_check()
local parsers = require 'nvim-treesitter.info'.installed_parsers()
local queries = require 'nvim-treesitter.query'
local parsers = require("nvim-treesitter.info").installed_parsers()
local queries = require "nvim-treesitter.query"
local query_types = queries.built_in_query_groups
local captures = extract_captures()
@ -36,7 +36,7 @@ local function do_check()
for _, lang in pairs(parsers) do
for _, query_type in pairs(query_types) do
print('Checking '..lang..' '..query_type)
print("Checking " .. lang .. " " .. query_type)
local ok, query = pcall(queries.get_query, lang, query_type)
if not ok then
vim.api.nvim_err_writeln(query)
@ -45,9 +45,9 @@ local function do_check()
if query then
for _, capture in ipairs(query.captures) do
local is_valid = (
vim.startswith(capture, "_") -- Helpers.
or vim.tbl_contains(captures[query_type], capture)
)
vim.startswith(capture, "_") -- Helpers.
or vim.tbl_contains(captures[query_type], capture)
)
if not is_valid then
local error = string.format("(x) Invalid capture @%s in %s for %s.", capture, query_type, lang)
print(error)
@ -60,36 +60,36 @@ local function do_check()
end
if last_error then
print()
print("Last error: ")
print "Last error: "
error(last_error)
end
end
local ok, err = pcall(do_check)
local allowed_to_fail = vim.split(vim.env.ALLOWED_INSTALLATION_FAILURES or '', ",", true)
local allowed_to_fail = vim.split(vim.env.ALLOWED_INSTALLATION_FAILURES or "", ",", true)
for k, v in pairs(require 'nvim-treesitter.parsers'.get_parser_configs()) do
if not require 'nvim-treesitter.parsers'.has_parser(k) then
for k, v in pairs(require("nvim-treesitter.parsers").get_parser_configs()) do
if not require("nvim-treesitter.parsers").has_parser(k) then
-- On CI all parsers that can be installed from C files should be installed
if vim.env.CI
if
vim.env.CI
and not v.install_info.requires_generate_from_grammar
and not vim.tbl_contains(allowed_to_fail, k) then
print('Error: parser for '..k..' is not installed')
vim.cmd('cq')
and not vim.tbl_contains(allowed_to_fail, k)
then
print("Error: parser for " .. k .. " is not installed")
vim.cmd "cq"
else
print('Warning: parser for '..k..' is not installed')
print("Warning: parser for " .. k .. " is not installed")
end
end
end
if ok then
print('Check successful!\n')
vim.cmd('q')
print "Check successful!\n"
vim.cmd "q"
else
print('Check failed:')
print "Check failed:"
print(err)
print('\n')
vim.cmd('cq')
print "\n"
vim.cmd "cq"
end

View file

@ -5,7 +5,7 @@ vim.cmd [[runtime! plugin/nvim-treesitter.vim]]
vim.o.swapfile = false
vim.bo.swapfile = false
require('nvim-treesitter.configs').setup {
ensure_installed = 'maintained',
indent = { enable = true },
require("nvim-treesitter.configs").setup {
ensure_installed = "maintained",
indent = { enable = true },
}

View file

@ -1,41 +1,49 @@
-- Execute as `nvim --headless -c "luafile ./scripts/update-readme.lua"`
local parsers = require 'nvim-treesitter.parsers'.get_parser_configs()
local parsers = require("nvim-treesitter.parsers").get_parser_configs()
local sorted_parsers = {}
for k, v in pairs(parsers) do
table.insert(sorted_parsers, {name = k, parser = v})
table.insert(sorted_parsers, { name = k, parser = v })
end
table.sort(sorted_parsers, function(a, b) return a.name < b.name end)
table.sort(sorted_parsers, function(a, b)
return a.name < b.name
end)
local generated_text = ''
local generated_text = ""
for _, v in ipairs(sorted_parsers) do
local link = '['..(v.parser.readme_name or v.name)..']('..v.parser.install_info.url..')'
local link = "[" .. (v.parser.readme_name or v.name) .. "](" .. v.parser.install_info.url .. ")"
if v.parser.maintainers then
generated_text = generated_text..
'- [x] '..link..' (maintained by '..table.concat(v.parser.maintainers, ', ')..')\n'
generated_text = generated_text
.. "- [x] "
.. link
.. " (maintained by "
.. table.concat(v.parser.maintainers, ", ")
.. ")\n"
else
generated_text = generated_text..
'- [ ] '..link..'\n'
generated_text = generated_text .. "- [ ] " .. link .. "\n"
end
end
print(generated_text)
print("\n")
print "\n"
local readme_text = table.concat(vim.fn.readfile('README.md'), '\n')
local readme_text = table.concat(vim.fn.readfile "README.md", "\n")
local new_readme_text = string.gsub(readme_text, "<!%-%-parserinfo%-%->.*<!%-%-parserinfo%-%->",
"<!--parserinfo-->\n"..generated_text.."<!--parserinfo-->")
vim.fn.writefile(vim.fn.split(new_readme_text, '\n'), "README.md")
local new_readme_text = string.gsub(
readme_text,
"<!%-%-parserinfo%-%->.*<!%-%-parserinfo%-%->",
"<!--parserinfo-->\n" .. generated_text .. "<!--parserinfo-->"
)
vim.fn.writefile(vim.fn.split(new_readme_text, "\n"), "README.md")
if string.find(readme_text, generated_text, 1, 'plain') then
print("README.md is up-to-date!")
vim.cmd('q')
if string.find(readme_text, generated_text, 1, "plain") then
print "README.md is up-to-date!"
vim.cmd "q"
else
print("New README.md was written. Please commit that change! Old text was: ")
print "New README.md was written. Please commit that change! Old text was: "
print(string.sub(readme_text, string.find(readme_text, "<!%-%-parserinfo%-%->.*<!%-%-parserinfo%-%->")))
vim.cmd('cq')
vim.cmd "cq"
end

View file

@ -1,10 +1,10 @@
-- Execute as `nvim --headless -c "luafile ./scripts/write-lockfile.lua"`
local skip_langs = vim.fn.getenv('SKIP_LOCKFILE_UPDATE_FOR_LANGS')
local skip_langs = vim.fn.getenv "SKIP_LOCKFILE_UPDATE_FOR_LANGS"
if skip_langs == vim.NIL then
skip_langs = {}
else
skip_langs = vim.fn.split(skip_langs, ',')
skip_langs = vim.fn.split(skip_langs, ",")
end
print("Skipping languages: "..vim.inspect(skip_langs))
require 'nvim-treesitter.install'.write_lockfile('verbose', skip_langs)
vim.cmd('q')
print("Skipping languages: " .. vim.inspect(skip_langs))
require("nvim-treesitter.install").write_lockfile("verbose", skip_langs)
vim.cmd "q"

View file

@ -1,35 +1,35 @@
local Runner = require('tests.indent.common').Runner
local Runner = require("tests.indent.common").Runner
local runner = Runner:new(it, 'tests/indent/c', {
local runner = Runner:new(it, "tests/indent/c", {
tabstop = 4,
shiftwidth = 4,
softtabstop = 0,
expandtab = true,
})
describe('indent C:', function()
describe('whole file:', function()
runner:whole_file('.')
describe("indent C:", function()
describe("whole file:", function()
runner:whole_file "."
end)
describe('new line:', function()
runner:new_line('array.c', { on_line = 2, text = '0,', indent = 4 })
runner:new_line('cond.c', { on_line = 3, text = 'x++;', indent = 8 })
runner:new_line('cond.c', { on_line = 8, text = 'x++;', indent = 8 })
runner:new_line('expr.c', { on_line = 10, text = '2 *', indent = 8 })
runner:new_line('func.c', { on_line = 17, text = 'int z,', indent = 4 })
runner:new_line('label.c', { on_line = 3, text = 'normal:', indent = 0 })
runner:new_line('loop.c', { on_line = 3, text = 'x++;', indent = 8 })
runner:new_line('preproc_cond.c', { on_line = 5, text = 'x++;', indent = 4 })
runner:new_line('preproc_func.c', { on_line = 3, text = 'x++; \\', indent = 8 })
runner:new_line('string.c', { on_line = 1, text = 'brave new \\', indent = 0 })
runner:new_line('string.c', { on_line = 4, text = '"brave new "', indent = 4 })
runner:new_line('struct.c', { on_line = 4, text = 'int y;', indent = 8 })
runner:new_line('switch.c', { on_line = 3, text = 'x++;', indent = 12 })
runner:new_line('ternary.c', { on_line = 4, text = ': (x == 0) : 0', indent = 8 })
describe("new line:", function()
runner:new_line("array.c", { on_line = 2, text = "0,", indent = 4 })
runner:new_line("cond.c", { on_line = 3, text = "x++;", indent = 8 })
runner:new_line("cond.c", { on_line = 8, text = "x++;", indent = 8 })
runner:new_line("expr.c", { on_line = 10, text = "2 *", indent = 8 })
runner:new_line("func.c", { on_line = 17, text = "int z,", indent = 4 })
runner:new_line("label.c", { on_line = 3, text = "normal:", indent = 0 })
runner:new_line("loop.c", { on_line = 3, text = "x++;", indent = 8 })
runner:new_line("preproc_cond.c", { on_line = 5, text = "x++;", indent = 4 })
runner:new_line("preproc_func.c", { on_line = 3, text = "x++; \\", indent = 8 })
runner:new_line("string.c", { on_line = 1, text = "brave new \\", indent = 0 })
runner:new_line("string.c", { on_line = 4, text = '"brave new "', indent = 4 })
runner:new_line("struct.c", { on_line = 4, text = "int y;", indent = 8 })
runner:new_line("switch.c", { on_line = 3, text = "x++;", indent = 12 })
runner:new_line("ternary.c", { on_line = 4, text = ": (x == 0) : 0", indent = 8 })
-- the line after inserted one will be left with wrong indent but we only care about the inserted one
runner:new_line('no_braces.c', { on_line = 4, text = 'x++;', indent = 8 })
runner:new_line('no_braces.c', { on_line = 7, text = 'x++;', indent = 8 })
runner:new_line('no_braces.c', { on_line = 10, text = 'x++;', indent = 8 })
runner:new_line("no_braces.c", { on_line = 4, text = "x++;", indent = 8 })
runner:new_line("no_braces.c", { on_line = 7, text = "x++;", indent = 8 })
runner:new_line("no_braces.c", { on_line = 10, text = "x++;", indent = 8 })
end)
end)

View file

@ -1,9 +1,9 @@
local M = {}
local assert = require('luassert')
local say = require('say')
local scan_dir = require('plenary.scandir').scan_dir
local Path = require('plenary.path')
local assert = require "luassert"
local say = require "say"
local scan_dir = require("plenary.scandir").scan_dir
local Path = require "plenary.path"
local function same_indent(state, arguments)
local before = arguments[1]
@ -11,11 +11,11 @@ local function same_indent(state, arguments)
local ok = true
local errors = { before = {}, after = {} }
for line = 1,#before do
for line = 1, #before do
if before[line] ~= after[line] then
-- store the actual indentation length for each line
errors.before[line] = #string.match(before[line], '^%s*')
errors.after[line] = #string.match(after[line], '^%s*')
errors.before[line] = #string.match(before[line], "^%s*")
errors.after[line] = #string.match(after[line], "^%s*")
ok = false
end
end
@ -35,28 +35,33 @@ local function format_indent(arg, fmtargs)
end
width = width + 3
local header_fmt = '%8s %2s%-' .. tostring(width + 1) .. 's %s'
local fmt = '%8s %2s |%-' .. tostring(width) .. 's |%s'
local header_fmt = "%8s %2s%-" .. tostring(width + 1) .. "s %s"
local fmt = "%8s %2s |%-" .. tostring(width) .. "s |%s"
local output = {header_fmt:format('', '', 'Found:', 'Expected:')}
local output = { header_fmt:format("", "", "Found:", "Expected:") }
for i, line in ipairs(arg) do
if fmtargs.errors.before[i] then
local indents = string.format('%d vs %d', fmtargs.errors.after[i], fmtargs.errors.before[i])
table.insert(output, fmt:format(indents, '=>', fmtargs.other[i], line))
local indents = string.format("%d vs %d", fmtargs.errors.after[i], fmtargs.errors.before[i])
table.insert(output, fmt:format(indents, "=>", fmtargs.other[i], line))
else
table.insert(output, fmt:format('', '', fmtargs.other[i], line))
table.insert(output, fmt:format("", "", fmtargs.other[i], line))
end
end
return table.concat(output, '\n')
return table.concat(output, "\n")
end
say:set_namespace('en')
say:set('assertion.same_indent.positive', 'Incorrect indentation\n%s')
say:set('assertion.same_indent.negative', 'Incorrect indentation\n%s')
assert:register('assertion', 'same_indent', same_indent,
'assertion.same_indent.positive', 'assert.same_indent.negative')
say:set_namespace "en"
say:set("assertion.same_indent.positive", "Incorrect indentation\n%s")
say:set("assertion.same_indent.negative", "Incorrect indentation\n%s")
assert:register(
"assertion",
"same_indent",
same_indent,
"assertion.same_indent.positive",
"assert.same_indent.negative"
)
-- Custom assertion better suited for indentation diffs
local function compare_indent(before, after)
@ -66,7 +71,7 @@ local function compare_indent(before, after)
end
local function set_buf_indent_opts(opts)
local optnames = {'tabstop', 'shiftwidth', 'softtabstop', 'expandtab', 'filetype'}
local optnames = { "tabstop", "shiftwidth", "softtabstop", "expandtab", "filetype" }
for _, opt in ipairs(optnames) do
if opts[opt] ~= nil then
vim.bo[opt] = opts[opt]
@ -78,10 +83,10 @@ function M.run_indent_test(file, runner, opts)
assert.are.same(1, vim.fn.filereadable(file), string.format('File "%s" not readable', file))
-- load reference file
vim.cmd(string.format('edit %s', file))
vim.cmd(string.format("edit %s", file))
local before = vim.api.nvim_buf_get_lines(0, 0, -1, true)
assert.are.same('nvim_treesitter#indent()', vim.bo.indentexpr)
assert.are.same("nvim_treesitter#indent()", vim.bo.indentexpr)
set_buf_indent_opts(opts)
-- perform the test
@ -91,14 +96,14 @@ function M.run_indent_test(file, runner, opts)
local after = vim.api.nvim_buf_get_lines(0, 0, -1, true)
-- clear any changes to avoid 'No write since last change (add ! to override)'
vim.cmd 'edit!'
vim.cmd "edit!"
return before, after
end
function M.indent_whole_file(file, opts)
local before, after = M.run_indent_test(file, function()
vim.cmd 'silent normal gg=G'
vim.cmd "silent normal gg=G"
end, opts)
compare_indent(before, after)
@ -114,11 +119,11 @@ end
function M.indent_new_line(file, spec, opts)
local before, after = M.run_indent_test(file, function()
-- move to the line and input the new one
vim.cmd(string.format('normal! %dG', spec.on_line))
vim.cmd(string.format('normal! o%s', spec.text))
vim.cmd(string.format("normal! %dG", spec.on_line))
vim.cmd(string.format("normal! o%s", spec.text))
end, opts)
local indent = type(spec.indent) == 'string' and spec.indent or string.rep(' ', spec.indent)
local indent = type(spec.indent) == "string" and spec.indent or string.rep(" ", spec.indent)
table.insert(before, spec.on_line + 1, indent .. spec.text)
compare_indent(before, after)
@ -140,7 +145,7 @@ function Runner:new(it, base_dir, buf_opts)
end
function Runner:whole_file(dirs)
dirs = type(dirs) == "table" and dirs or {dirs}
dirs = type(dirs) == "table" and dirs or { dirs }
dirs = vim.tbl_map(function(dir)
dir = self.base_dir / Path:new(dir)
assert.is.same(1, vim.fn.isdirectory(dir.filename))
@ -157,7 +162,7 @@ end
function Runner:new_line(file, spec, title)
title = title and title or tostring(spec.on_line)
self.it(string.format('%s[%s]', file, title), function()
self.it(string.format("%s[%s]", file, title), function()
local path = self.base_dir / file
M.indent_new_line(path.filename, spec, self.buf_opts)
end)

View file

@ -1,42 +1,42 @@
local Runner = require('tests.indent.common').Runner
local Runner = require("tests.indent.common").Runner
-- will use both c/ and cpp/
local run = Runner:new(it, 'tests/indent', {
local run = Runner:new(it, "tests/indent", {
tabstop = 4,
shiftwidth = 4,
softtabstop = 0,
expandtab = true,
filetype = 'cpp',
filetype = "cpp",
})
describe('indent C++:', function()
describe('whole file:', function()
run:whole_file({'c/', 'cpp/'})
describe("indent C++:", function()
describe("whole file:", function()
run:whole_file { "c/", "cpp/" }
end)
describe('new line:', function()
run:new_line('cpp/access.cpp', { on_line = 3, text = 'protected:', indent = 0 })
run:new_line('cpp/class.cpp', { on_line = 2, text = 'using T = int;', indent = 4 })
run:new_line('cpp/stream.cpp', { on_line = 5, text = '<< x + 3', indent = 8 })
describe("new line:", function()
run:new_line("cpp/access.cpp", { on_line = 3, text = "protected:", indent = 0 })
run:new_line("cpp/class.cpp", { on_line = 2, text = "using T = int;", indent = 4 })
run:new_line("cpp/stream.cpp", { on_line = 5, text = "<< x + 3", indent = 8 })
-- TODO: find a clean way to import these from c_spec.lua
run:new_line('c/array.c', { on_line = 2, text = '0,', indent = 4 })
run:new_line('c/cond.c', { on_line = 3, text = 'x++;', indent = 8 })
run:new_line('c/cond.c', { on_line = 8, text = 'x++;', indent = 8 })
run:new_line('c/expr.c', { on_line = 10, text = '2 *', indent = 8 })
run:new_line('c/func.c', { on_line = 17, text = 'int z,', indent = 4 })
run:new_line('c/label.c', { on_line = 3, text = 'normal:', indent = 0 })
run:new_line('c/loop.c', { on_line = 3, text = 'x++;', indent = 8 })
run:new_line('c/preproc_cond.c', { on_line = 5, text = 'x++;', indent = 4 })
run:new_line('c/preproc_func.c', { on_line = 3, text = 'x++; \\', indent = 8 })
run:new_line('c/string.c', { on_line = 1, text = 'brave new \\', indent = 0 })
run:new_line('c/string.c', { on_line = 4, text = '"brave new "', indent = 4 })
run:new_line('c/struct.c', { on_line = 4, text = 'int y;', indent = 8 })
run:new_line('c/switch.c', { on_line = 3, text = 'x++;', indent = 12 })
run:new_line('c/ternary.c', { on_line = 4, text = ': (x == 0) : 0', indent = 8 })
run:new_line("c/array.c", { on_line = 2, text = "0,", indent = 4 })
run:new_line("c/cond.c", { on_line = 3, text = "x++;", indent = 8 })
run:new_line("c/cond.c", { on_line = 8, text = "x++;", indent = 8 })
run:new_line("c/expr.c", { on_line = 10, text = "2 *", indent = 8 })
run:new_line("c/func.c", { on_line = 17, text = "int z,", indent = 4 })
run:new_line("c/label.c", { on_line = 3, text = "normal:", indent = 0 })
run:new_line("c/loop.c", { on_line = 3, text = "x++;", indent = 8 })
run:new_line("c/preproc_cond.c", { on_line = 5, text = "x++;", indent = 4 })
run:new_line("c/preproc_func.c", { on_line = 3, text = "x++; \\", indent = 8 })
run:new_line("c/string.c", { on_line = 1, text = "brave new \\", indent = 0 })
run:new_line("c/string.c", { on_line = 4, text = '"brave new "', indent = 4 })
run:new_line("c/struct.c", { on_line = 4, text = "int y;", indent = 8 })
run:new_line("c/switch.c", { on_line = 3, text = "x++;", indent = 12 })
run:new_line("c/ternary.c", { on_line = 4, text = ": (x == 0) : 0", indent = 8 })
-- the line after inserted one will be left with wrong indent but we only care about the inserted one
run:new_line('c/no_braces.c', { on_line = 4, text = 'x++;', indent = 8 })
run:new_line('c/no_braces.c', { on_line = 7, text = 'x++;', indent = 8 })
run:new_line('c/no_braces.c', { on_line = 10, text = 'x++;', indent = 8 })
run:new_line("c/no_braces.c", { on_line = 4, text = "x++;", indent = 8 })
run:new_line("c/no_braces.c", { on_line = 7, text = "x++;", indent = 8 })
run:new_line("c/no_braces.c", { on_line = 10, text = "x++;", indent = 8 })
end)
end)

View file

@ -1,35 +1,33 @@
local Runner = require('tests.indent.common').Runner
local Runner = require("tests.indent.common").Runner
local run = Runner:new(it, 'tests/indent/lua', {
local run = Runner:new(it, "tests/indent/lua", {
tabstop = 2,
shiftwidth = 2,
softtabstop = 0,
expandtab = true,
})
describe('indent Lua:', function()
describe('whole file:', function()
run:whole_file('.')
describe("indent Lua:", function()
describe("whole file:", function()
run:whole_file "."
end)
describe('new line:', function()
run:new_line('comment.lua', { on_line = 1, text = 'line', indent = '-- ' })
run:new_line('comment.lua', { on_line = 5, text = 'multiline', indent = ' ' })
run:new_line('func.lua', { on_line = 1, text = 'x = x + 1', indent = 2 })
run:new_line('func.lua', { on_line = 2, text = 'y = y + 1', indent = 4 })
run:new_line('func.lua', { on_line = 5, text = '3,', indent = 4 })
run:new_line('string.lua', { on_line = 1, text = 'x', indent = 0 })
run:new_line('string.lua', { on_line = 2, text = 'x', indent = 0 })
run:new_line('string.lua', { on_line = 3, text = 'x', indent = 2 })
run:new_line('string.lua', { on_line = 4, text = 'x', indent = 4 })
run:new_line('table.lua', { on_line = 1, text = 'b = 0,', indent = 2 })
run:new_line('table.lua', { on_line = 5, text = '4,', indent = 4 })
run:new_line('table.lua', { on_line = 7, text = '4,', indent = 4 })
run:new_line('loop.lua', { on_line = 4, text = 'x = x + 1', indent = 2 })
run:new_line('cond.lua', { on_line = 5, text = 'x = x + 1', indent = 2 })
run:new_line('cond.lua', { on_line = 7, text = 'x = x + 1', indent = 2 })
run:new_line('cond.lua', { on_line = 8, text = 'x = x + 1', indent = 4 })
describe("new line:", function()
run:new_line("comment.lua", { on_line = 1, text = "line", indent = "-- " })
run:new_line("comment.lua", { on_line = 5, text = "multiline", indent = " " })
run:new_line("func.lua", { on_line = 1, text = "x = x + 1", indent = 2 })
run:new_line("func.lua", { on_line = 2, text = "y = y + 1", indent = 4 })
run:new_line("func.lua", { on_line = 5, text = "3,", indent = 4 })
run:new_line("string.lua", { on_line = 1, text = "x", indent = 0 })
run:new_line("string.lua", { on_line = 2, text = "x", indent = 0 })
run:new_line("string.lua", { on_line = 3, text = "x", indent = 2 })
run:new_line("string.lua", { on_line = 4, text = "x", indent = 4 })
run:new_line("table.lua", { on_line = 1, text = "b = 0,", indent = 2 })
run:new_line("table.lua", { on_line = 5, text = "4,", indent = 4 })
run:new_line("table.lua", { on_line = 7, text = "4,", indent = 4 })
run:new_line("loop.lua", { on_line = 4, text = "x = x + 1", indent = 2 })
run:new_line("cond.lua", { on_line = 5, text = "x = x + 1", indent = 2 })
run:new_line("cond.lua", { on_line = 7, text = "x = x + 1", indent = 2 })
run:new_line("cond.lua", { on_line = 8, text = "x = x + 1", indent = 4 })
end)
end)

View file

@ -1,38 +1,38 @@
local Runner = require('tests.indent.common').Runner
local Runner = require("tests.indent.common").Runner
local run = Runner:new(it, 'tests/indent/python', {
local run = Runner:new(it, "tests/indent/python", {
tabstop = 4,
shiftwidth = 4,
softtabstop = 0,
expandtab = true,
})
describe('indent Python:', function()
describe('whole file:', function()
run:whole_file('.')
describe("indent Python:", function()
describe("whole file:", function()
run:whole_file "."
end)
describe('new line:', function()
run:new_line('aligned_indent.py', { on_line = 1, text = 'arg3,', indent = 19 })
run:new_line('basic_blocks.py', { on_line = 1, text = 'wait,', indent = 4 })
run:new_line('basic_blocks.py', { on_line = 6, text = 'x += 1', indent = 4 })
run:new_line('basic_blocks.py', { on_line = 10, text = 'x += 1', indent = 8 })
run:new_line('basic_blocks.py', { on_line = 7, text = 'x += 1', indent = 4 }, '7, after last line of a block')
run:new_line('basic_blocks.py', { on_line = 11, text = 'x += 1', indent = 8 }, '11, after last line of a block')
run:new_line('basic_collections.py', { on_line = 3, text = '4,', indent = 4 })
run:new_line('comprehensions.py', { on_line = 8, text = 'if x != 2', indent = 4 })
run:new_line('control_flow.py', { on_line = 23, text = 'x = 4', indent = 4 })
run:new_line('hanging_indent.py', { on_line = 1, text = 'arg0,', indent = 8 })
run:new_line('hanging_indent.py', { on_line = 5, text = '0,', indent = 4 })
run:new_line('join_lines.py', { on_line = 1, text = '+ 1 \\', indent = 4 })
run:new_line('join_lines.py', { on_line = 4, text = '+ 1 \\', indent = 4 })
run:new_line('join_lines.py', { on_line = 7, text = '+ 1 \\', indent = 4 })
run:new_line('nested_collections.py', { on_line = 5, text = '0,', indent = 12 })
run:new_line('nested_collections.py', { on_line = 6, text = ',0', indent = 12 })
run:new_line('nested_collections.py', { on_line = 29, text = '[1, 2],', indent = 12 })
run:new_line('nested_collections.py', { on_line = 39, text = '0,', indent = 5 })
run:new_line('strings.py', { on_line = 14, text = 'x', indent = 4 })
run:new_line('strings.py', { on_line = 15, text = 'x', indent = 0 })
run:new_line('strings.py', { on_line = 16, text = 'x', indent = 8 })
describe("new line:", function()
run:new_line("aligned_indent.py", { on_line = 1, text = "arg3,", indent = 19 })
run:new_line("basic_blocks.py", { on_line = 1, text = "wait,", indent = 4 })
run:new_line("basic_blocks.py", { on_line = 6, text = "x += 1", indent = 4 })
run:new_line("basic_blocks.py", { on_line = 10, text = "x += 1", indent = 8 })
run:new_line("basic_blocks.py", { on_line = 7, text = "x += 1", indent = 4 }, "7, after last line of a block")
run:new_line("basic_blocks.py", { on_line = 11, text = "x += 1", indent = 8 }, "11, after last line of a block")
run:new_line("basic_collections.py", { on_line = 3, text = "4,", indent = 4 })
run:new_line("comprehensions.py", { on_line = 8, text = "if x != 2", indent = 4 })
run:new_line("control_flow.py", { on_line = 23, text = "x = 4", indent = 4 })
run:new_line("hanging_indent.py", { on_line = 1, text = "arg0,", indent = 8 })
run:new_line("hanging_indent.py", { on_line = 5, text = "0,", indent = 4 })
run:new_line("join_lines.py", { on_line = 1, text = "+ 1 \\", indent = 4 })
run:new_line("join_lines.py", { on_line = 4, text = "+ 1 \\", indent = 4 })
run:new_line("join_lines.py", { on_line = 7, text = "+ 1 \\", indent = 4 })
run:new_line("nested_collections.py", { on_line = 5, text = "0,", indent = 12 })
run:new_line("nested_collections.py", { on_line = 6, text = ",0", indent = 12 })
run:new_line("nested_collections.py", { on_line = 29, text = "[1, 2],", indent = 12 })
run:new_line("nested_collections.py", { on_line = 39, text = "0,", indent = 5 })
run:new_line("strings.py", { on_line = 14, text = "x", indent = 4 })
run:new_line("strings.py", { on_line = 15, text = "x", indent = 0 })
run:new_line("strings.py", { on_line = 16, text = "x", indent = 8 })
end)
end)

View file

@ -1,53 +1,53 @@
local Runner = require('tests.indent.common').Runner
local Runner = require("tests.indent.common").Runner
local run = Runner:new(it, 'tests/indent/rust', {
local run = Runner:new(it, "tests/indent/rust", {
tabstop = 4,
shiftwidth = 4,
softtabstop = 0,
expandtab = true,
})
describe('indent Rust:', function()
describe('whole file:', function()
run:whole_file('.')
describe("indent Rust:", function()
describe("whole file:", function()
run:whole_file "."
end)
describe('new line:', function()
run:new_line('array.rs', { on_line = 2, text = '0,', indent = 4 })
run:new_line('array.rs', { on_line = 8, text = '0,', indent = 8 })
run:new_line('comment.rs', { on_line = 3, text = 'a', indent = '/// ' })
run:new_line('cond.rs', { on_line = 11, text = 'x += 1;', indent = 12 })
run:new_line('cond.rs', { on_line = 2, text = 'x += 1;', indent = 8 })
run:new_line('cond.rs', { on_line = 4, text = 'x += 1;', indent = 8 })
run:new_line('cond.rs', { on_line = 6, text = 'x += 1;', indent = 8 })
run:new_line('enum.rs', { on_line = 2, text = 'Q,', indent = 4 })
run:new_line('enum.rs', { on_line = 4, text = 'i32,', indent = 8 })
run:new_line('enum.rs', { on_line = 8, text = 'z: u32,', indent = 8 })
run:new_line('func.rs', { on_line = 1, text = 'let _x = 1;', indent = 4 })
run:new_line('func.rs', { on_line = 6, text = 'z: i32,', indent = 4 })
run:new_line('impl.rs', { on_line = 3, text = 'const FOO: u32 = 1;', indent = 4 })
run:new_line('impl.rs', { on_line = 4, text = 'let _x = 1;', indent = 8 })
run:new_line('loop.rs', { on_line = 10, text = 'x += 1;', indent = 8 })
run:new_line('loop.rs', { on_line = 2, text = 'x += 1;', indent = 8 })
run:new_line('loop.rs', { on_line = 6, text = 'x += 1;', indent = 8 })
run:new_line('macro.rs', { on_line = 1, text = '() => {},', indent = 4 })
run:new_line('macro.rs', { on_line = 12, text = 'B C', indent = 4 })
run:new_line('macro.rs', { on_line = 2, text = 'struct $c;', indent = 8 })
run:new_line('match.rs', { on_line = 2, text = '-1 => -1,', indent = 8 })
run:new_line('match.rs', { on_line = 7, text = 'let y = 1;', indent = 12 })
run:new_line('mod.rs', { on_line = 1, text = 'const Z: i32 = 1;', indent = 4 })
run:new_line('mod.rs', { on_line = 2, text = 'const Z: i32 = 1;', indent = 4 })
run:new_line('mod.rs', { on_line = 6, text = 'const Z: i32 = 1;', indent = 8 })
run:new_line('string.rs', { on_line = 2, text = 'brave new', indent = 0 })
run:new_line('string.rs', { on_line = 5, text = 'brave new \\', indent = 8 })
run:new_line('string.rs', { on_line = 9, text = 'brave new \\', indent = 8 })
run:new_line('struct.rs', { on_line = 1, text = 'z: i32,', indent = 4 })
run:new_line('struct.rs', { on_line = 2, text = 'z: i32,', indent = 4 })
run:new_line('trait.rs', { on_line = 4, text = 'fn baz();', indent = 4 })
run:new_line('trait.rs', { on_line = 7, text = 'fn baz();', indent = 4 })
run:new_line('trait.rs', { on_line = 8, text = '()', indent = 8 })
run:new_line('where.rs', { on_line = 17, text = 'T: Debug,', indent = 4 })
run:new_line('where.rs', { on_line = 2, text = 'T: Debug,', indent = 4 })
run:new_line('where.rs', { on_line = 9, text = 'T: Debug,', indent = 4 })
describe("new line:", function()
run:new_line("array.rs", { on_line = 2, text = "0,", indent = 4 })
run:new_line("array.rs", { on_line = 8, text = "0,", indent = 8 })
run:new_line("comment.rs", { on_line = 3, text = "a", indent = "/// " })
run:new_line("cond.rs", { on_line = 11, text = "x += 1;", indent = 12 })
run:new_line("cond.rs", { on_line = 2, text = "x += 1;", indent = 8 })
run:new_line("cond.rs", { on_line = 4, text = "x += 1;", indent = 8 })
run:new_line("cond.rs", { on_line = 6, text = "x += 1;", indent = 8 })
run:new_line("enum.rs", { on_line = 2, text = "Q,", indent = 4 })
run:new_line("enum.rs", { on_line = 4, text = "i32,", indent = 8 })
run:new_line("enum.rs", { on_line = 8, text = "z: u32,", indent = 8 })
run:new_line("func.rs", { on_line = 1, text = "let _x = 1;", indent = 4 })
run:new_line("func.rs", { on_line = 6, text = "z: i32,", indent = 4 })
run:new_line("impl.rs", { on_line = 3, text = "const FOO: u32 = 1;", indent = 4 })
run:new_line("impl.rs", { on_line = 4, text = "let _x = 1;", indent = 8 })
run:new_line("loop.rs", { on_line = 10, text = "x += 1;", indent = 8 })
run:new_line("loop.rs", { on_line = 2, text = "x += 1;", indent = 8 })
run:new_line("loop.rs", { on_line = 6, text = "x += 1;", indent = 8 })
run:new_line("macro.rs", { on_line = 1, text = "() => {},", indent = 4 })
run:new_line("macro.rs", { on_line = 12, text = "B C", indent = 4 })
run:new_line("macro.rs", { on_line = 2, text = "struct $c;", indent = 8 })
run:new_line("match.rs", { on_line = 2, text = "-1 => -1,", indent = 8 })
run:new_line("match.rs", { on_line = 7, text = "let y = 1;", indent = 12 })
run:new_line("mod.rs", { on_line = 1, text = "const Z: i32 = 1;", indent = 4 })
run:new_line("mod.rs", { on_line = 2, text = "const Z: i32 = 1;", indent = 4 })
run:new_line("mod.rs", { on_line = 6, text = "const Z: i32 = 1;", indent = 8 })
run:new_line("string.rs", { on_line = 2, text = "brave new", indent = 0 })
run:new_line("string.rs", { on_line = 5, text = "brave new \\", indent = 8 })
run:new_line("string.rs", { on_line = 9, text = "brave new \\", indent = 8 })
run:new_line("struct.rs", { on_line = 1, text = "z: i32,", indent = 4 })
run:new_line("struct.rs", { on_line = 2, text = "z: i32,", indent = 4 })
run:new_line("trait.rs", { on_line = 4, text = "fn baz();", indent = 4 })
run:new_line("trait.rs", { on_line = 7, text = "fn baz();", indent = 4 })
run:new_line("trait.rs", { on_line = 8, text = "()", indent = 8 })
run:new_line("where.rs", { on_line = 17, text = "T: Debug,", indent = 4 })
run:new_line("where.rs", { on_line = 2, text = "T: Debug,", indent = 4 })
run:new_line("where.rs", { on_line = 9, text = "T: Debug,", indent = 4 })
end)
end)