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 - name: Run Luacheck
run: sudo ./scripts/style-check.sh 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 ## Style Checks and Tests
We haven't implemented any functional tests yet. Feel free to contribute. 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 Please install luacheck and activate our `pre-push` hook to automatically check style before
every push: every push:
```bash ```bash
luarocks install luacheck luarocks install luacheck
cargo install stylua
ln -s ../../scripts/pre-push .git/hooks/pre-push ln -s ../../scripts/pre-push .git/hooks/pre-push
``` ```

View file

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

View file

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

View file

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

View file

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

View file

@ -1,75 +1,92 @@
local api = vim.api local api = vim.api
local fn = vim.fn local fn = vim.fn
local queries = require'nvim-treesitter.query' local queries = require "nvim-treesitter.query"
local info = require'nvim-treesitter.info' local info = require "nvim-treesitter.info"
local shell = require'nvim-treesitter.shell_command_selectors' local shell = require "nvim-treesitter.shell_command_selectors"
local install = require'nvim-treesitter.install' local install = require "nvim-treesitter.install"
local health_start = vim.fn["health#report_start"] local health_start = vim.fn["health#report_start"]
local health_ok = vim.fn['health#report_ok'] local health_ok = vim.fn["health#report_ok"]
local health_error = vim.fn['health#report_error'] local health_error = vim.fn["health#report_error"]
local health_warn = vim.fn['health#report_warn'] local health_warn = vim.fn["health#report_warn"]
local M = {} local M = {}
local NVIM_TREESITTER_MINIMUM_ABI = 13 local NVIM_TREESITTER_MINIMUM_ABI = 13
local function install_health() local function install_health()
health_start('Installation') health_start "Installation"
if fn.executable('tree-sitter') == 0 then if fn.executable "tree-sitter" == 0 then
health_warn('`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar,'.. health_warn(
' not required for :TSInstall)') "`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar,"
.. " not required for :TSInstall)"
)
else else
local handle = io.popen('tree-sitter -V') local handle = io.popen "tree-sitter -V"
local result = handle:read("*a") local result = handle:read "*a"
handle:close() handle:close()
local version = vim.split(result,'\n')[1]:match('[^tree%psitter].*') local version = vim.split(result, "\n")[1]:match "[^tree%psitter].*"
health_ok( health_ok(
"`tree-sitter` found " .. "`tree-sitter` found "
(version or "(unknown version)") .. " (parser generator, only needed for :TSInstallFromGrammar)" .. (version or "(unknown version)")
.. " (parser generator, only needed for :TSInstallFromGrammar)"
) )
end end
if fn.executable('node') == 0 then if fn.executable "node" == 0 then
health_warn('`node` executable not found (only needed for :TSInstallFromGrammar,'.. health_warn(
' not required for :TSInstall)') "`node` executable not found (only needed for :TSInstallFromGrammar," .. " not required for :TSInstall)"
)
else else
local handle = io.popen('node --version') local handle = io.popen "node --version"
local result = handle:read("*a") local result = handle:read "*a"
handle:close() handle:close()
local version = vim.split(result,'\n')[1] local version = vim.split(result, "\n")[1]
health_ok('`node` found '..version..' (only needed for :TSInstallFromGrammar)') health_ok("`node` found " .. version .. " (only needed for :TSInstallFromGrammar)")
end end
if fn.executable('git') == 0 then if fn.executable "git" == 0 then
health_error('`git` executable not found.', { health_error("`git` executable not found.", {
'Install it with your package manager.', "Install it with your package manager.",
'Check that your `$PATH` is set correctly.' "Check that your `$PATH` is set correctly.",
}) })
else else
health_ok('`git` executable found.') health_ok "`git` executable found."
end end
local cc = shell.select_executable(install.compilers) local cc = shell.select_executable(install.compilers)
if not cc then if not cc then
health_error('`cc` executable not found.', { health_error("`cc` executable not found.", {
'Check that any of '..vim.inspect(install.compilers)..' is in your $PATH' "Check that any of "
..' or set the environment variable CC or `require"nvim-treesitter.install".compilers` explicitly!' .. vim.inspect(install.compilers)
.. " is in your $PATH"
.. ' or set the environment variable CC or `require"nvim-treesitter.install".compilers` explicitly!',
}) })
else else
health_ok('`'..cc..'` executable found. Selected from '..vim.inspect(install.compilers)) health_ok("`" .. cc .. "` executable found. Selected from " .. vim.inspect(install.compilers))
end end
if vim.treesitter.language_version then if vim.treesitter.language_version then
if vim.treesitter.language_version >= NVIM_TREESITTER_MINIMUM_ABI 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 health_ok(
..' (required >='..NVIM_TREESITTER_MINIMUM_ABI..'). Parsers must be compatible with runtime ABI.') "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 else
health_error('Neovim was compiled with tree-sitter runtime ABI version '..vim.treesitter.language_version..'.\n' health_error(
..'nvim-treesitter expects at least ABI version '..NVIM_TREESITTER_MINIMUM_ABI..'\n' "Neovim was compiled with tree-sitter runtime ABI version "
..'Please make sure that Neovim is linked against are recent tree-sitter runtime when building' .. vim.treesitter.language_version
..' or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI.') .. ".\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 end
end end
@ -90,35 +107,35 @@ function M.checkhealth()
-- Installation dependency checks -- Installation dependency checks
install_health() install_health()
queries.invalidate_query_cache() queries.invalidate_query_cache()
health_start("Parser/Features H L F I") health_start "Parser/Features H L F I"
-- Parser installation checks -- Parser installation checks
for _, parser_name in pairs(info.installed_parsers()) do 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 -- Only print informations about installed parsers
if installed >= 1 then if installed >= 1 then
local multiple_parsers = installed > 1 and "+" or "" 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 for _, query_group in pairs(queries.built_in_query_groups) do
local status, err = query_status(parser_name, query_group) local status, err = query_status(parser_name, query_group)
out = out..status.." " out = out .. status .. " "
if err then if err then
table.insert(error_collection, {parser_name, query_group, err}) table.insert(error_collection, { parser_name, query_group, err })
end end
end end
print(out) print(out)
end end
end end
print([[ print [[
Legend: H[ighlight], L[ocals], F[olds], I[ndents] Legend: H[ighlight], L[ocals], F[olds], I[ndents]
+) multiple parsers found, only one will be used +) 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 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 for _, p in ipairs(error_collection) do
local lang, type, err = unpack(p) local lang, type, err = unpack(p)
health_error(lang..'('..type..'): '..err) health_error(lang .. "(" .. type .. "): " .. err)
end end
end end
end end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,25 +2,25 @@
-- Locals are a generalization of definition and scopes -- Locals are a generalization of definition and scopes
-- its the way nvim-treesitter uses to "understand" the code -- its the way nvim-treesitter uses to "understand" the code
local queries = require'nvim-treesitter.query' local queries = require "nvim-treesitter.query"
local ts_utils = require'nvim-treesitter.ts_utils' local ts_utils = require "nvim-treesitter.ts_utils"
local api = vim.api local api = vim.api
local M = {} local M = {}
function M.collect_locals(bufnr) function M.collect_locals(bufnr)
return queries.collect_group_results(bufnr, 'locals') return queries.collect_group_results(bufnr, "locals")
end end
-- Iterates matches from a locals query file. -- Iterates matches from a locals query file.
-- @param bufnr the buffer -- @param bufnr the buffer
-- @param root the root node -- @param root the root node
function M.iter_locals(bufnr, root) function M.iter_locals(bufnr, root)
return queries.iter_group_results(bufnr, 'locals', root) return queries.iter_group_results(bufnr, "locals", root)
end end
function M.get_locals(bufnr) function M.get_locals(bufnr)
return queries.get_matches(bufnr, 'locals') return queries.get_matches(bufnr, "locals")
end end
--- Creates unique id for a node based on text and range --- Creates unique id for a node based on text and range
@ -30,7 +30,7 @@ end
-- @returns a string id -- @returns a string id
function M.get_definition_id(scope, node_text) function M.get_definition_id(scope, node_text)
-- Add a vaild starting character in case node text doesn't start with a valid one. -- 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 end
function M.get_definitions(bufnr) 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) accumulator(local_def, local_def.node, full_match, last_match)
else else
for match_key, def in pairs(local_def) do for match_key, def in pairs(local_def) do
M.recurse_local_nodes( M.recurse_local_nodes(def, accumulator, full_match and (full_match .. "." .. match_key) or match_key, match_key)
def,
accumulator,
full_match and (full_match..'.'..match_key) or match_key,
match_key)
end end
end end
end end
@ -188,10 +184,10 @@ function M.get_definition_scopes(node, bufnr, scope_type)
-- Definition is valid for the containing scope -- Definition is valid for the containing scope
-- and the containing scope of that scope -- and the containing scope of that scope
if scope_type == 'parent' then if scope_type == "parent" then
scope_count = 2 scope_count = 2
-- Definition is valid in all parent scopes -- Definition is valid in all parent scopes
elseif scope_type == 'global' then elseif scope_type == "global" then
scope_count = nil scope_count = nil
end end
@ -200,7 +196,9 @@ function M.get_definition_scopes(node, bufnr, scope_type)
table.insert(scopes, scope) table.insert(scopes, scope)
i = i + 1 i = i + 1
if scope_count and i >= scope_count then break end if scope_count and i >= scope_count then
break
end
end end
return scopes return scopes
@ -231,13 +229,16 @@ function M.find_usages(node, scope_node, bufnr)
local bufnr = bufnr or api.nvim_get_current_buf() local bufnr = bufnr or api.nvim_get_current_buf()
local node_text = ts_utils.get_node_text(node, bufnr)[1] 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 scope_node = scope_node or ts_utils.get_root_for_node(node)
local usages = {} local usages = {}
for match in M.iter_locals(bufnr, scope_node) do for match in M.iter_locals(bufnr, scope_node) do
if match.reference if
match.reference
and match.reference.node and match.reference.node
and ts_utils.get_node_text(match.reference.node, bufnr)[1] == node_text and ts_utils.get_node_text(match.reference.node, bufnr)[1] == node_text
then then
@ -257,7 +258,9 @@ function M.containing_scope(node, bufnr, allow_scope)
local allow_scope = allow_scope == nil or allow_scope == true local allow_scope = allow_scope == nil or allow_scope == true
local scopes = M.get_scopes(bufnr) 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 local iter_node = node
@ -272,7 +275,9 @@ function M.nested_scope(node, cursor_pos)
local bufnr = api.nvim_get_current_buf() local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr) 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 row = cursor_pos.row
local col = cursor_pos.col 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 for _, child in ipairs(ts_utils.get_named_children(scope)) do
local row_, col_ = child:start() 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 return child
end end
end end
@ -290,12 +295,16 @@ function M.next_scope(node)
local bufnr = api.nvim_get_current_buf() local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr) 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 scope = M.containing_scope(node)
local parent = scope:parent() local parent = scope:parent()
if not parent then return end if not parent then
return
end
local is_prev = true local is_prev = true
for _, child in ipairs(ts_utils.get_named_children(parent)) do 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 bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr) 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 scope = M.containing_scope(node)
local parent = scope:parent() local parent = scope:parent()
if not parent then return end if not parent then
return
end
local is_prev = true local is_prev = true
local children = ts_utils.get_named_children(parent) 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 if children[i] == scope then
is_prev = false is_prev = false
elseif not is_prev and vim.tbl_contains(scopes, children[i]) then 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 ft_to_parsername = {}
local function update_ft_to_parsername(name, parser) 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 for _, ft in pairs(parser.used_by) do
ft_to_parsername[ft] = name ft_to_parsername[ft] = name
end end
@ -14,19 +14,22 @@ end
local list = setmetatable({}, { local list = setmetatable({}, {
__newindex = function(table, parsername, parserconfig) __newindex = function(table, parsername, parserconfig)
rawset(
rawset(table, parsername, setmetatable(parserconfig, { table,
__newindex = function(parserconfigtable, key, value) parsername,
if key == "used_by" then setmetatable(parserconfig, {
ft_to_parsername[value] = parsername __newindex = function(parserconfigtable, key, value)
else if key == "used_by" then
rawset(parserconfigtable, key, value) ft_to_parsername[value] = parsername
end else
end rawset(parserconfigtable, key, value)
})) end
end,
})
)
update_ft_to_parsername(parsername, parserconfig) update_ft_to_parsername(parsername, parserconfig)
end end,
}) })
list.javascript = { list.javascript = {
@ -34,16 +37,16 @@ list.javascript = {
url = "https://github.com/tree-sitter/tree-sitter-javascript", url = "https://github.com/tree-sitter/tree-sitter-javascript",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
used_by = { 'javascriptreact' }, used_by = { "javascriptreact" },
maintainers = {"@steelsojka"}, maintainers = { "@steelsojka" },
} }
list.c = { list.c = {
install_info = { install_info = {
url = "https://github.com/tree-sitter/tree-sitter-c", url = "https://github.com/tree-sitter/tree-sitter-c",
files = { "src/parser.c" } files = { "src/parser.c" },
}, },
maintainers = {"@vigoux"}, maintainers = { "@vigoux" },
} }
list.clojure = { list.clojure = {
@ -51,7 +54,7 @@ list.clojure = {
url = "https://github.com/sogaiu/tree-sitter-clojure", url = "https://github.com/sogaiu/tree-sitter-clojure",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@sogaiu"}, maintainers = { "@sogaiu" },
} }
list.commonlisp = { list.commonlisp = {
@ -60,8 +63,8 @@ list.commonlisp = {
files = { "src/parser.c" }, files = { "src/parser.c" },
generate_requires_npm = true, generate_requires_npm = true,
}, },
filetype = 'lisp', filetype = "lisp",
maintainers = {"@theHamsta"}, maintainers = { "@theHamsta" },
} }
list.cpp = { list.cpp = {
@ -70,16 +73,16 @@ list.cpp = {
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
generate_requires_npm = true, generate_requires_npm = true,
}, },
maintainers = {"@theHamsta"}, maintainers = { "@theHamsta" },
} }
list.cuda = { list.cuda = {
install_info = { install_info = {
url = "https://github.com/theHamsta/tree-sitter-cuda", 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, generate_requires_npm = true,
}, },
maintainers = {"@theHamsta"}, maintainers = { "@theHamsta" },
} }
list.dockerfile = { list.dockerfile = {
@ -88,7 +91,7 @@ list.dockerfile = {
branch = "main", branch = "main",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@camdencheek"}, maintainers = { "@camdencheek" },
} }
list.rust = { list.rust = {
@ -96,7 +99,7 @@ list.rust = {
url = "https://github.com/tree-sitter/tree-sitter-rust", url = "https://github.com/tree-sitter/tree-sitter-rust",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@vigoux"}, maintainers = { "@vigoux" },
} }
list.ledger = { list.ledger = {
@ -104,15 +107,15 @@ list.ledger = {
url = "https://github.com/cbarrete/tree-sitter-ledger", url = "https://github.com/cbarrete/tree-sitter-ledger",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@cbarrete"}, maintainers = { "@cbarrete" },
} }
list.lua = { list.lua = {
install_info = { install_info = {
url = "https://github.com/nvim-treesitter/tree-sitter-lua", 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 = { list.python = {
@ -120,7 +123,7 @@ list.python = {
url = "https://github.com/tree-sitter/tree-sitter-python", url = "https://github.com/tree-sitter/tree-sitter-python",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = {'@stsewd', "@theHamsta"}, maintainers = { "@stsewd", "@theHamsta" },
} }
list.go = { list.go = {
@ -128,7 +131,7 @@ list.go = {
url = "https://github.com/tree-sitter/tree-sitter-go", url = "https://github.com/tree-sitter/tree-sitter-go",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@theHamsta", "@WinWisely268"}, maintainers = { "@theHamsta", "@WinWisely268" },
} }
list.gomod = { list.gomod = {
@ -137,7 +140,7 @@ list.gomod = {
branch = "main", branch = "main",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@camdencheek"}, maintainers = { "@camdencheek" },
filetype = "gomod", filetype = "gomod",
} }
@ -146,7 +149,7 @@ list.graphql = {
url = "https://github.com/bkegley/tree-sitter-graphql", url = "https://github.com/bkegley/tree-sitter-graphql",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@bkegley"}, maintainers = { "@bkegley" },
} }
list.ruby = { list.ruby = {
@ -154,7 +157,7 @@ list.ruby = {
url = "https://github.com/tree-sitter/tree-sitter-ruby", url = "https://github.com/tree-sitter/tree-sitter-ruby",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = {'@TravonteD'}, maintainers = { "@TravonteD" },
} }
list.bash = { list.bash = {
@ -163,8 +166,8 @@ list.bash = {
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
used_by = { "zsh", "PKGBUILD" }, used_by = { "zsh", "PKGBUILD" },
filetype = 'sh', filetype = "sh",
maintainers = {"@TravonteD"}, maintainers = { "@TravonteD" },
} }
list.fish = { list.fish = {
@ -172,7 +175,7 @@ list.fish = {
url = "https://github.com/krnik/tree-sitter-fish", url = "https://github.com/krnik/tree-sitter-fish",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@krnik", "@ram02z"}, maintainers = { "@krnik", "@ram02z" },
} }
list.php = { list.php = {
@ -180,7 +183,7 @@ list.php = {
url = "https://github.com/tree-sitter/tree-sitter-php", url = "https://github.com/tree-sitter/tree-sitter-php",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = {"@tk-shirasaka"}, maintainers = { "@tk-shirasaka" },
} }
list.java = { list.java = {
@ -188,7 +191,7 @@ list.java = {
url = "https://github.com/tree-sitter/tree-sitter-java", url = "https://github.com/tree-sitter/tree-sitter-java",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@p00f"}, maintainers = { "@p00f" },
} }
list.kotlin = { list.kotlin = {
@ -196,7 +199,7 @@ list.kotlin = {
url = "https://github.com/tormodatt/tree-sitter-kotlin", url = "https://github.com/tormodatt/tree-sitter-kotlin",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@tormodatt"}, maintainers = { "@tormodatt" },
} }
list.html = { list.html = {
@ -204,7 +207,7 @@ list.html = {
url = "https://github.com/tree-sitter/tree-sitter-html", url = "https://github.com/tree-sitter/tree-sitter-html",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = {"@TravonteD"}, maintainers = { "@TravonteD" },
} }
list.julia = { list.julia = {
@ -212,7 +215,7 @@ list.julia = {
url = "https://github.com/tree-sitter/tree-sitter-julia", url = "https://github.com/tree-sitter/tree-sitter-julia",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@mroavi", "@theHamsta"}, maintainers = { "@mroavi", "@theHamsta" },
} }
list.json = { list.json = {
@ -220,7 +223,7 @@ list.json = {
url = "https://github.com/tree-sitter/tree-sitter-json", url = "https://github.com/tree-sitter/tree-sitter-json",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@steelsojka"}, maintainers = { "@steelsojka" },
} }
list.css = { list.css = {
@ -228,15 +231,15 @@ list.css = {
url = "https://github.com/tree-sitter/tree-sitter-css", url = "https://github.com/tree-sitter/tree-sitter-css",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@TravonteD"}, maintainers = { "@TravonteD" },
} }
list.scss = { list.scss = {
install_info = { install_info = {
url = "https://github.com/serenadeai/tree-sitter-scss", 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 = { list.erlang = {
@ -245,16 +248,16 @@ list.erlang = {
files = { "src/parser.c" }, files = { "src/parser.c" },
branch = "main", branch = "main",
}, },
maintainers = { '@ostera' }, maintainers = { "@ostera" },
} }
list.elixir = { list.elixir = {
install_info = { install_info = {
url = "https://github.com/ananthakumaran/tree-sitter-elixir", url = "https://github.com/ananthakumaran/tree-sitter-elixir",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true, requires_generate_from_grammar = true,
}, },
maintainers = { '@nifoc' }, maintainers = { "@nifoc" },
} }
list.ocaml = { list.ocaml = {
@ -263,7 +266,7 @@ list.ocaml = {
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
location = "tree-sitter-ocaml/ocaml", location = "tree-sitter-ocaml/ocaml",
}, },
maintainers = {'@undu'}, maintainers = { "@undu" },
} }
list.ocaml_interface = { list.ocaml_interface = {
@ -272,25 +275,25 @@ list.ocaml_interface = {
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
location = "tree-sitter-ocaml_interface/interface", location = "tree-sitter-ocaml_interface/interface",
}, },
maintainers = {'@undu'}, maintainers = { "@undu" },
filetype = 'ocamlinterface' filetype = "ocamlinterface",
} }
list.ocamllex = { list.ocamllex = {
install_info = { install_info = {
url = "https://github.com/atom-ocaml/tree-sitter-ocamllex", url = "https://github.com/atom-ocaml/tree-sitter-ocamllex",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true, requires_generate_from_grammar = true,
}, },
maintainers = {'@undu'}, maintainers = { "@undu" },
} }
list.swift = { list.swift = {
install_info = { install_info = {
url = "https://github.com/tree-sitter/tree-sitter-swift", url = "https://github.com/tree-sitter/tree-sitter-swift",
files = { "src/parser.c" }, files = { "src/parser.c" },
requires_generate_from_grammar = true, requires_generate_from_grammar = true,
} },
} }
list.c_sharp = { list.c_sharp = {
@ -298,8 +301,8 @@ list.c_sharp = {
url = "https://github.com/tree-sitter/tree-sitter-c-sharp", url = "https://github.com/tree-sitter/tree-sitter-c-sharp",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
filetype = 'cs', filetype = "cs",
maintainers = {'@Luxed'}, maintainers = { "@Luxed" },
} }
list.typescript = { list.typescript = {
@ -309,7 +312,7 @@ list.typescript = {
location = "tree-sitter-typescript/typescript", location = "tree-sitter-typescript/typescript",
generate_requires_npm = true, generate_requires_npm = true,
}, },
maintainers = {"@steelsojka"}, maintainers = { "@steelsojka" },
} }
list.tsx = { list.tsx = {
@ -320,24 +323,24 @@ list.tsx = {
generate_requires_npm = true, generate_requires_npm = true,
}, },
used_by = { "typescript.tsx" }, used_by = { "typescript.tsx" },
filetype = 'typescriptreact', filetype = "typescriptreact",
maintainers = {'@steelsojka'} maintainers = { "@steelsojka" },
} }
list.scala = { list.scala = {
install_info = { install_info = {
url = "https://github.com/tree-sitter/tree-sitter-scala", url = "https://github.com/tree-sitter/tree-sitter-scala",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
} },
} }
list.supercollider = { list.supercollider = {
install_info = { install_info = {
url = "https://github.com/madskjeldgaard/tree-sitter-supercollider", url = "https://github.com/madskjeldgaard/tree-sitter-supercollider",
files = {"src/parser.c", "src/scanner.c"}, files = { "src/parser.c", "src/scanner.c" },
branch = "main", branch = "main",
}, },
maintainers = {"@madskjeldgaard"}, maintainers = { "@madskjeldgaard" },
filetype = "supercollider", filetype = "supercollider",
} }
@ -345,16 +348,16 @@ list.haskell = {
install_info = { install_info = {
url = "https://github.com/tree-sitter/tree-sitter-haskell", url = "https://github.com/tree-sitter/tree-sitter-haskell",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
} },
} }
list.hcl = { list.hcl = {
install_info = { install_info = {
url = "https://github.com/MichaHoffmann/tree-sitter-hcl", url = "https://github.com/MichaHoffmann/tree-sitter-hcl",
files = {"src/parser.c", "src/scanner.cc"}, files = { "src/parser.c", "src/scanner.cc" },
branch = "main" branch = "main",
}, },
maintainers = {"@MichaHoffmann"}, maintainers = { "@MichaHoffmann" },
filetype = "hcl", filetype = "hcl",
used_by = { "terraform", "packer", "nomad" }, used_by = { "terraform", "packer", "nomad" },
} }
@ -373,18 +376,18 @@ list.toml = {
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
generate_requires_npm = true, generate_requires_npm = true,
}, },
maintainers = {"@tk-shirasaka"}, maintainers = { "@tk-shirasaka" },
} }
list.glimmer = { list.glimmer = {
install_info = { install_info = {
url = "https://github.com/alexlafroscia/tree-sitter-glimmer", url = "https://github.com/alexlafroscia/tree-sitter-glimmer",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
branch = 'main', branch = "main",
}, },
readme_name = "Glimmer and Ember", readme_name = "Glimmer and Ember",
maintainers = { "@alexlafroscia" }, maintainers = { "@alexlafroscia" },
filetype = "handlebars" filetype = "handlebars",
} }
list.vue = { list.vue = {
@ -392,7 +395,7 @@ list.vue = {
url = "https://github.com/ikatyang/tree-sitter-vue", url = "https://github.com/ikatyang/tree-sitter-vue",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = {"@WhyNotHugo"}, maintainers = { "@WhyNotHugo" },
} }
list.jsonc = { list.jsonc = {
@ -402,14 +405,14 @@ list.jsonc = {
generate_requires_npm = true, generate_requires_npm = true,
}, },
readme_name = "JSON with comments", readme_name = "JSON with comments",
maintainers = {"@WhyNotHugo"}, maintainers = { "@WhyNotHugo" },
} }
list.elm = { list.elm = {
install_info = { install_info = {
url = "https://github.com/elm-tooling/tree-sitter-elm", url = "https://github.com/elm-tooling/tree-sitter-elm",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
} },
} }
list.yaml = { list.yaml = {
@ -417,7 +420,7 @@ list.yaml = {
url = "https://github.com/ikatyang/tree-sitter-yaml", url = "https://github.com/ikatyang/tree-sitter-yaml",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = {"@stsewd"}, maintainers = { "@stsewd" },
} }
list.nix = { list.nix = {
@ -425,7 +428,7 @@ list.nix = {
url = "https://github.com/cstrahan/tree-sitter-nix", url = "https://github.com/cstrahan/tree-sitter-nix",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@leo60228"}, maintainers = { "@leo60228" },
} }
list.dart = { list.dart = {
@ -433,7 +436,7 @@ list.dart = {
url = "https://github.com/UserNobody14/tree-sitter-dart", url = "https://github.com/UserNobody14/tree-sitter-dart",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@Akin909"}, maintainers = { "@Akin909" },
} }
list.rst = { list.rst = {
@ -441,7 +444,7 @@ list.rst = {
url = "https://github.com/stsewd/tree-sitter-rst", url = "https://github.com/stsewd/tree-sitter-rst",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@stsewd"}, maintainers = { "@stsewd" },
} }
list.fennel = { list.fennel = {
@ -449,7 +452,7 @@ list.fennel = {
url = "https://github.com/travonted/tree-sitter-fennel", url = "https://github.com/travonted/tree-sitter-fennel",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {'@TravonteD'}, maintainers = { "@TravonteD" },
} }
list.teal = { list.teal = {
@ -457,7 +460,7 @@ list.teal = {
url = "https://github.com/euclidianAce/tree-sitter-teal", url = "https://github.com/euclidianAce/tree-sitter-teal",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {'@euclidianAce'}, maintainers = { "@euclidianAce" },
} }
list.ql = { list.ql = {
@ -465,7 +468,7 @@ list.ql = {
url = "https://github.com/tree-sitter/tree-sitter-ql", url = "https://github.com/tree-sitter/tree-sitter-ql",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {'@pwntester'}, maintainers = { "@pwntester" },
} }
list.verilog = { list.verilog = {
@ -482,9 +485,9 @@ list.verilog = {
list.regex = { list.regex = {
install_info = { install_info = {
url = "https://github.com/tree-sitter/tree-sitter-regex", url = "https://github.com/tree-sitter/tree-sitter-regex",
files = { "src/parser.c" } files = { "src/parser.c" },
}, },
maintainers = {"@theHamsta"}, maintainers = { "@theHamsta" },
} }
list.comment = { list.comment = {
@ -492,7 +495,7 @@ list.comment = {
url = "https://github.com/stsewd/tree-sitter-comment", url = "https://github.com/stsewd/tree-sitter-comment",
files = { "src/parser.c", "src/scanner.c" }, files = { "src/parser.c", "src/scanner.c" },
}, },
maintainers = {"@stsewd"}, maintainers = { "@stsewd" },
} }
list.jsdoc = { list.jsdoc = {
@ -500,16 +503,16 @@ list.jsdoc = {
url = "https://github.com/tree-sitter/tree-sitter-jsdoc", url = "https://github.com/tree-sitter/tree-sitter-jsdoc",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
maintainers = {"@steelsojka"}, maintainers = { "@steelsojka" },
} }
list.query = { list.query = {
install_info = { install_info = {
url = "https://github.com/nvim-treesitter/tree-sitter-query", url = "https://github.com/nvim-treesitter/tree-sitter-query",
files = { "src/parser.c" } files = { "src/parser.c" },
}, },
readme_name = "Tree-sitter query language", readme_name = "Tree-sitter query language",
maintainers = {"@steelsojka"}, maintainers = { "@steelsojka" },
} }
list.sparql = { list.sparql = {
@ -525,10 +528,10 @@ list.gdscript = {
install_info = { install_info = {
url = "https://github.com/PrestonKnopp/tree-sitter-gdscript", url = "https://github.com/PrestonKnopp/tree-sitter-gdscript",
files = { "src/parser.c", "src/scanner.cc" }, files = { "src/parser.c", "src/scanner.cc" },
requires_generate_from_grammar = true, requires_generate_from_grammar = true,
}, },
readme_name = "Godot (gdscript)", readme_name = "Godot (gdscript)",
maintainers = {"@Shatur95"}, maintainers = { "@Shatur95" },
} }
list.turtle = { list.turtle = {
@ -545,9 +548,9 @@ list.devicetree = {
url = "https://github.com/joelspadin/tree-sitter-devicetree", url = "https://github.com/joelspadin/tree-sitter-devicetree",
files = { "src/parser.c" }, files = { "src/parser.c" },
branch = "main", branch = "main",
requires_generate_from_grammar = true, requires_generate_from_grammar = true,
}, },
filetype = 'dts', filetype = "dts",
maintainers = { "@jedrzejboczar" }, maintainers = { "@jedrzejboczar" },
} }
@ -563,7 +566,7 @@ list.svelte = {
list.r = { list.r = {
install_info = { install_info = {
url = "https://github.com/r-lib/tree-sitter-r", url = "https://github.com/r-lib/tree-sitter-r",
files = { "src/parser.c" } files = { "src/parser.c" },
}, },
maintainers = { "@jimhester" }, maintainers = { "@jimhester" },
} }
@ -582,8 +585,8 @@ list.latex = {
url = "https://github.com/latex-lsp/tree-sitter-latex", url = "https://github.com/latex-lsp/tree-sitter-latex",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
filetype = 'tex', filetype = "tex",
used_by = {'cls', 'sty'}, used_by = { "cls", "sty" },
maintainers = { "@theHamsta by asking @clason" }, maintainers = { "@theHamsta by asking @clason" },
} }
@ -592,36 +595,36 @@ list.bibtex = {
url = "https://github.com/latex-lsp/tree-sitter-bibtex", url = "https://github.com/latex-lsp/tree-sitter-bibtex",
files = { "src/parser.c" }, files = { "src/parser.c" },
}, },
filetype = 'bib', filetype = "bib",
maintainers = { "@theHamsta by asking @clason" }, maintainers = { "@theHamsta by asking @clason" },
} }
list.zig = { list.zig = {
install_info = { install_info = {
url = "https://github.com/Himujjal/tree-sitter-zig", url = "https://github.com/Himujjal/tree-sitter-zig",
files = { "src/parser.c" } files = { "src/parser.c" },
}, },
filetype = "zig", filetype = "zig",
maintainers = { "@Himujjal" } maintainers = { "@Himujjal" },
} }
list.fortran = { list.fortran = {
install_info = { install_info = {
url = "https://github.com/stadelmanma/tree-sitter-fortran", url = "https://github.com/stadelmanma/tree-sitter-fortran",
files = { "src/parser.c", "src/scanner.cc", }, files = { "src/parser.c", "src/scanner.cc" },
}, },
} }
list.cmake = { list.cmake = {
install_info = { install_info = {
url = "https://github.com/uyha/tree-sitter-cmake", url = "https://github.com/uyha/tree-sitter-cmake",
files = { "src/parser.c", "src/scanner.cc"}, files = { "src/parser.c", "src/scanner.cc" },
}, },
maintainers = { "@uyha" }, maintainers = { "@uyha" },
} }
local M = { local M = {
list = list list = list,
} }
function M.ft_to_lang(ft) function M.ft_to_lang(ft)
@ -629,20 +632,23 @@ function M.ft_to_lang(ft)
end end
function M.available_parsers() 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) return vim.tbl_keys(M.list)
else else
return vim.tbl_filter(function(p) return not M.list[p].install_info.requires_generate_from_grammar end, return vim.tbl_filter(function(p)
vim.tbl_keys(M.list)) return not M.list[p].install_info.requires_generate_from_grammar
end, vim.tbl_keys(
M.list
))
end end
end end
function M.maintained_parsers() 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 vim.tbl_filter(function(lang)
return M.list[lang].maintainers return M.list[lang].maintainers
and (has_tree_sitter_cli or not M.list[lang].install_info.requires_generate_from_grammar) end, and (has_tree_sitter_cli or not M.list[lang].install_info.requires_generate_from_grammar)
M.available_parsers()) end, M.available_parsers())
end end
function M.get_parser_configs() function M.get_parser_configs()
@ -654,9 +660,9 @@ local parser_files
function M.reset_cache() function M.reset_cache()
parser_files = setmetatable({}, { parser_files = setmetatable({}, {
__index = function(tbl, key) __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) return rawget(tbl, key)
end end,
}) })
end end
@ -665,9 +671,13 @@ M.reset_cache()
function M.has_parser(lang) function M.has_parser(lang)
local lang = lang or M.get_buf_lang(api.nvim_get_current_buf()) 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 -- 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 return #parser_files[lang] > 0
end end

View file

@ -1,15 +1,15 @@
local api = vim.api local api = vim.api
local tsq = require'vim.treesitter.query' local tsq = require "vim.treesitter.query"
local tsrange = require'nvim-treesitter.tsrange' local tsrange = require "nvim-treesitter.tsrange"
local utils = require'nvim-treesitter.utils' local utils = require "nvim-treesitter.utils"
local parsers = require'nvim-treesitter.parsers' local parsers = require "nvim-treesitter.parsers"
local caching = require'nvim-treesitter.caching' local caching = require "nvim-treesitter.caching"
local M = {} local M = {}
local EMPTY_ITER = function() end 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 -- Creates a function that checks whether a given query exists
-- for a specific language. -- for a specific language.
@ -24,10 +24,10 @@ for _, query in ipairs(M.built_in_query_groups) do
end end
function M.available_query_groups() 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 = {} local groups = {}
for _, f in ipairs(query_files) do for _, f in ipairs(query_files) do
groups[vim.fn.fnamemodify(f, ':t:r')] = true groups[vim.fn.fnamemodify(f, ":t:r")] = true
end end
local list = {} local list = {}
for k, _ in pairs(groups) do for k, _ in pairs(groups) do
@ -42,7 +42,7 @@ do
local function update_cached_matches(bufnr, changed_tick, query_group) local function update_cached_matches(bufnr, changed_tick, query_group)
query_cache.set(query_group, bufnr, { query_cache.set(query_group, bufnr, {
tick = changed_tick, tick = changed_tick,
cache= M.collect_group_results(bufnr, query_group) or {} cache = M.collect_group_results(bufnr, query_group) or {},
}) })
end end
@ -50,7 +50,7 @@ do
bufnr = bufnr or api.nvim_get_current_buf() bufnr = bufnr or api.nvim_get_current_buf()
local cached_local = query_cache.get(query_group, bufnr) local cached_local = query_cache.get(query_group, bufnr)
if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then 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 end
return query_cache.get(query_group, bufnr).cache return query_cache.get(query_group, bufnr).cache
@ -58,7 +58,7 @@ do
end end
local function runtime_queries(lang, query_name) 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 end
local query_files_cache = {} local query_files_cache = {}
@ -66,11 +66,11 @@ function M.has_query_files(lang, query_name)
if not query_files_cache[lang] then if not query_files_cache[lang] then
query_files_cache[lang] = {} query_files_cache[lang] = {}
end end
if query_files_cache[lang][query_name] == nil then if query_files_cache[lang][query_name] == nil then
local files = runtime_queries(lang, query_name) local files = runtime_queries(lang, query_name)
query_files_cache[lang][query_name] = files and #files > 0 query_files_cache[lang][query_name] = files and #files > 0
end end
return query_files_cache[lang][query_name] return query_files_cache[lang][query_name]
end end
do do
@ -117,7 +117,7 @@ do
end end
end end
else else
error("Cannot have query_name by itself!") error "Cannot have query_name by itself!"
end end
end 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. --- 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) function M.invalidate_query_file(fname)
local fnamemodify = vim.fn.fnamemodify 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 end
function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) 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 function insert_to_path(object, path, value)
local curr_obj = object local curr_obj = object
for index=1,(#path -1) do for index = 1, (#path - 1) do
if curr_obj[path[index]] == nil then if curr_obj[path[index]] == nil then
curr_obj[path[index]] = {} curr_obj[path[index]] = {}
end end
@ -164,7 +164,7 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
for id, node in pairs(match) do for id, node in pairs(match) do
local name = query.captures[id] -- name of the capture in the query local name = query.captures[id] -- name of the capture in the query
if name ~= nil then if name ~= nil then
local path = split(name..'.node') local path = split(name .. ".node")
insert_to_path(prepared_match, path, node) insert_to_path(prepared_match, path, node)
end end
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]) insert_to_path(prepared_match, split(pred[2]), pred[3])
end end
if pred[1] == "make-range!" and type(pred[2]) == "string" and #pred == 4 then if pred[1] == "make-range!" and type(pred[2]) == "string" and #pred == 4 then
insert_to_path(prepared_match, split(pred[2]..'.node'), insert_to_path(
tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]])) prepared_match,
split(pred[2] .. ".node"),
tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]])
)
end end
end end
end end
@ -194,8 +197,8 @@ end
-- Works like M.get_references or M.get_scopes except you can choose the capture -- 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 -- 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) function M.get_capture_matches(bufnr, capture_string, query_group, root, lang)
if not string.sub(capture_string, 1, 1) == '@' then if not string.sub(capture_string, 1, 1) == "@" then
print('capture_string must start with "@"') print 'capture_string must start with "@"'
return return
end end
@ -214,7 +217,7 @@ function M.get_capture_matches(bufnr, capture_string, query_group, root, lang)
end end
function M.find_best_match(bufnr, capture_string, query_group, filter_predicate, scoring_function, root) 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 "@" --remove leading "@"
capture_string = string.sub(capture_string, 2) capture_string = string.sub(capture_string, 2)
end end
@ -248,10 +251,14 @@ end
function M.iter_group_results(bufnr, query_group, root, root_lang) function M.iter_group_results(bufnr, query_group, root, root_lang)
local buf_lang = parsers.get_buf_lang(bufnr) 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) 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 if not root then
local first_tree = parser:trees()[1] local first_tree = parser:trees()[1]
@ -261,9 +268,11 @@ function M.iter_group_results(bufnr, query_group, root, root_lang)
end end
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 if not root_lang then
local lang_tree = parser:language_for_range(range) 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
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) 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. -- 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) 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 -- @param query_type The query to get the capture from. This is ignore if a function is provided
-- for the captuer argument. -- for the captuer argument.
function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type) function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
local type_fn = type(capture_or_fn) == 'function' local type_fn = type(capture_or_fn) == "function" and capture_or_fn
and capture_or_fn
or function() or function()
return capture_or_fn, query_type return capture_or_fn, query_type
end end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,41 +1,49 @@
-- Execute as `nvim --headless -c "luafile ./scripts/update-readme.lua"` -- 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 = {} local sorted_parsers = {}
for k, v in pairs(parsers) do for k, v in pairs(parsers) do
table.insert(sorted_parsers, {name = k, parser = v}) table.insert(sorted_parsers, { name = k, parser = v })
end 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 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 if v.parser.maintainers then
generated_text = generated_text.. generated_text = generated_text
'- [x] '..link..' (maintained by '..table.concat(v.parser.maintainers, ', ')..')\n' .. "- [x] "
.. link
.. " (maintained by "
.. table.concat(v.parser.maintainers, ", ")
.. ")\n"
else else
generated_text = generated_text.. generated_text = generated_text .. "- [ ] " .. link .. "\n"
'- [ ] '..link..'\n'
end end
end end
print(generated_text) 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%-%->", local new_readme_text = string.gsub(
"<!--parserinfo-->\n"..generated_text.."<!--parserinfo-->") readme_text,
vim.fn.writefile(vim.fn.split(new_readme_text, '\n'), "README.md") "<!%-%-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 if string.find(readme_text, generated_text, 1, "plain") then
print("README.md is up-to-date!") print "README.md is up-to-date!"
vim.cmd('q') vim.cmd "q"
else 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%-%->"))) print(string.sub(readme_text, string.find(readme_text, "<!%-%-parserinfo%-%->.*<!%-%-parserinfo%-%->")))
vim.cmd('cq') vim.cmd "cq"
end end

View file

@ -1,10 +1,10 @@
-- Execute as `nvim --headless -c "luafile ./scripts/write-lockfile.lua"` -- 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 if skip_langs == vim.NIL then
skip_langs = {} skip_langs = {}
else else
skip_langs = vim.fn.split(skip_langs, ',') skip_langs = vim.fn.split(skip_langs, ",")
end end
print("Skipping languages: "..vim.inspect(skip_langs)) print("Skipping languages: " .. vim.inspect(skip_langs))
require 'nvim-treesitter.install'.write_lockfile('verbose', skip_langs) require("nvim-treesitter.install").write_lockfile("verbose", skip_langs)
vim.cmd('q') 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, tabstop = 4,
shiftwidth = 4, shiftwidth = 4,
softtabstop = 0, softtabstop = 0,
expandtab = true, expandtab = true,
}) })
describe('indent C:', function() describe("indent C:", function()
describe('whole file:', function() describe("whole file:", function()
runner:whole_file('.') runner:whole_file "."
end) end)
describe('new line:', function() describe("new line:", function()
runner:new_line('array.c', { on_line = 2, text = '0,', indent = 4 }) 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 = 3, text = "x++;", indent = 8 })
runner:new_line('cond.c', { on_line = 8, 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("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("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("label.c", { on_line = 3, text = "normal:", indent = 0 })
runner:new_line('loop.c', { on_line = 3, text = 'x++;', indent = 8 }) 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_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("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 = 1, text = "brave new \\", indent = 0 })
runner:new_line('string.c', { on_line = 4, text = '"brave new "', indent = 4 }) 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("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("switch.c", { on_line = 3, text = "x++;", indent = 12 })
runner:new_line('ternary.c', { on_line = 4, text = ': (x == 0) : 0', indent = 8 }) 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 -- 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 = 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 = 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 = 10, text = "x++;", indent = 8 })
end) end)
end) end)

View file

@ -1,9 +1,9 @@
local M = {} local M = {}
local assert = require('luassert') local assert = require "luassert"
local say = require('say') local say = require "say"
local scan_dir = require('plenary.scandir').scan_dir local scan_dir = require("plenary.scandir").scan_dir
local Path = require('plenary.path') local Path = require "plenary.path"
local function same_indent(state, arguments) local function same_indent(state, arguments)
local before = arguments[1] local before = arguments[1]
@ -11,11 +11,11 @@ local function same_indent(state, arguments)
local ok = true local ok = true
local errors = { before = {}, after = {} } local errors = { before = {}, after = {} }
for line = 1,#before do for line = 1, #before do
if before[line] ~= after[line] then if before[line] ~= after[line] then
-- store the actual indentation length for each line -- store the actual indentation length for each line
errors.before[line] = #string.match(before[line], '^%s*') errors.before[line] = #string.match(before[line], "^%s*")
errors.after[line] = #string.match(after[line], '^%s*') errors.after[line] = #string.match(after[line], "^%s*")
ok = false ok = false
end end
end end
@ -35,28 +35,33 @@ local function format_indent(arg, fmtargs)
end end
width = width + 3 width = width + 3
local header_fmt = '%8s %2s%-' .. tostring(width + 1) .. 's %s' local header_fmt = "%8s %2s%-" .. tostring(width + 1) .. "s %s"
local fmt = '%8s %2s |%-' .. tostring(width) .. '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 for i, line in ipairs(arg) do
if fmtargs.errors.before[i] then if fmtargs.errors.before[i] then
local indents = string.format('%d vs %d', fmtargs.errors.after[i], fmtargs.errors.before[i]) 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)) table.insert(output, fmt:format(indents, "=>", fmtargs.other[i], line))
else else
table.insert(output, fmt:format('', '', fmtargs.other[i], line)) table.insert(output, fmt:format("", "", fmtargs.other[i], line))
end end
end end
return table.concat(output, '\n') return table.concat(output, "\n")
end end
say:set_namespace('en') say:set_namespace "en"
say:set('assertion.same_indent.positive', 'Incorrect indentation\n%s') say:set("assertion.same_indent.positive", "Incorrect indentation\n%s")
say:set('assertion.same_indent.negative', 'Incorrect indentation\n%s') say:set("assertion.same_indent.negative", "Incorrect indentation\n%s")
assert:register('assertion', 'same_indent', same_indent, assert:register(
'assertion.same_indent.positive', 'assert.same_indent.negative') "assertion",
"same_indent",
same_indent,
"assertion.same_indent.positive",
"assert.same_indent.negative"
)
-- Custom assertion better suited for indentation diffs -- Custom assertion better suited for indentation diffs
local function compare_indent(before, after) local function compare_indent(before, after)
@ -66,7 +71,7 @@ local function compare_indent(before, after)
end end
local function set_buf_indent_opts(opts) 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 for _, opt in ipairs(optnames) do
if opts[opt] ~= nil then if opts[opt] ~= nil then
vim.bo[opt] = opts[opt] 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)) assert.are.same(1, vim.fn.filereadable(file), string.format('File "%s" not readable', file))
-- load reference 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) 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) set_buf_indent_opts(opts)
-- perform the test -- 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) 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)' -- clear any changes to avoid 'No write since last change (add ! to override)'
vim.cmd 'edit!' vim.cmd "edit!"
return before, after return before, after
end end
function M.indent_whole_file(file, opts) function M.indent_whole_file(file, opts)
local before, after = M.run_indent_test(file, function() local before, after = M.run_indent_test(file, function()
vim.cmd 'silent normal gg=G' vim.cmd "silent normal gg=G"
end, opts) end, opts)
compare_indent(before, after) compare_indent(before, after)
@ -114,11 +119,11 @@ end
function M.indent_new_line(file, spec, opts) function M.indent_new_line(file, spec, opts)
local before, after = M.run_indent_test(file, function() local before, after = M.run_indent_test(file, function()
-- move to the line and input the new one -- move to the line and input the new one
vim.cmd(string.format('normal! %dG', spec.on_line)) vim.cmd(string.format("normal! %dG", spec.on_line))
vim.cmd(string.format('normal! o%s', spec.text)) vim.cmd(string.format("normal! o%s", spec.text))
end, opts) 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) table.insert(before, spec.on_line + 1, indent .. spec.text)
compare_indent(before, after) compare_indent(before, after)
@ -140,7 +145,7 @@ function Runner:new(it, base_dir, buf_opts)
end end
function Runner:whole_file(dirs) 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) dirs = vim.tbl_map(function(dir)
dir = self.base_dir / Path:new(dir) dir = self.base_dir / Path:new(dir)
assert.is.same(1, vim.fn.isdirectory(dir.filename)) assert.is.same(1, vim.fn.isdirectory(dir.filename))
@ -157,7 +162,7 @@ end
function Runner:new_line(file, spec, title) function Runner:new_line(file, spec, title)
title = title and title or tostring(spec.on_line) 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 local path = self.base_dir / file
M.indent_new_line(path.filename, spec, self.buf_opts) M.indent_new_line(path.filename, spec, self.buf_opts)
end) 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/ -- will use both c/ and cpp/
local run = Runner:new(it, 'tests/indent', { local run = Runner:new(it, "tests/indent", {
tabstop = 4, tabstop = 4,
shiftwidth = 4, shiftwidth = 4,
softtabstop = 0, softtabstop = 0,
expandtab = true, expandtab = true,
filetype = 'cpp', filetype = "cpp",
}) })
describe('indent C++:', function() describe("indent C++:", function()
describe('whole file:', function() describe("whole file:", function()
run:whole_file({'c/', 'cpp/'}) run:whole_file { "c/", "cpp/" }
end) end)
describe('new line:', function() describe("new line:", function()
run:new_line('cpp/access.cpp', { on_line = 3, text = 'protected:', indent = 0 }) 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/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 }) 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 -- 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/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 = 3, text = "x++;", indent = 8 })
run:new_line('c/cond.c', { on_line = 8, 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/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/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/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/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_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/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 = 1, text = "brave new \\", indent = 0 })
run:new_line('c/string.c', { on_line = 4, text = '"brave new "', indent = 4 }) 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/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/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/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 -- 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 = 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 = 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 = 10, text = "x++;", indent = 8 })
end) end)
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, tabstop = 2,
shiftwidth = 2, shiftwidth = 2,
softtabstop = 0, softtabstop = 0,
expandtab = true, expandtab = true,
}) })
describe("indent Lua:", function()
describe('indent Lua:', function() describe("whole file:", function()
describe('whole file:', function() run:whole_file "."
run:whole_file('.')
end) end)
describe('new line:', function() describe("new line:", function()
run:new_line('comment.lua', { on_line = 1, text = 'line', indent = '-- ' }) 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("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 = 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 = 2, text = "y = y + 1", indent = 4 })
run:new_line('func.lua', { on_line = 5, text = '3,', 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 = 1, text = "x", indent = 0 })
run:new_line('string.lua', { on_line = 2, 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 = 3, text = "x", indent = 2 })
run:new_line('string.lua', { on_line = 4, text = 'x', indent = 4 }) 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 = 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 = 5, text = "4,", indent = 4 })
run:new_line('table.lua', { on_line = 7, 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("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 = 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 = 7, text = "x = x + 1", indent = 2 })
run:new_line('cond.lua', { on_line = 8, text = 'x = x + 1', indent = 4 }) run:new_line("cond.lua", { on_line = 8, text = "x = x + 1", indent = 4 })
end) end)
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, tabstop = 4,
shiftwidth = 4, shiftwidth = 4,
softtabstop = 0, softtabstop = 0,
expandtab = true, expandtab = true,
}) })
describe('indent Python:', function() describe("indent Python:", function()
describe('whole file:', function() describe("whole file:", function()
run:whole_file('.') run:whole_file "."
end) end)
describe('new line:', function() describe("new line:", function()
run:new_line('aligned_indent.py', { on_line = 1, text = 'arg3,', indent = 19 }) 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 = 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 = 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 = 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 = 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_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("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("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("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 = 1, text = "arg0,", indent = 8 })
run:new_line('hanging_indent.py', { on_line = 5, text = '0,', indent = 4 }) 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 = 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 = 4, text = "+ 1 \\", indent = 4 })
run:new_line('join_lines.py', { on_line = 7, 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 = 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 = 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 = 29, text = "[1, 2],", indent = 12 })
run:new_line('nested_collections.py', { on_line = 39, text = '0,', indent = 5 }) 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 = 14, text = "x", indent = 4 })
run:new_line('strings.py', { on_line = 15, text = 'x', indent = 0 }) run:new_line("strings.py", { on_line = 15, text = "x", indent = 0 })
run:new_line('strings.py', { on_line = 16, text = 'x', indent = 8 }) run:new_line("strings.py", { on_line = 16, text = "x", indent = 8 })
end) end)
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, tabstop = 4,
shiftwidth = 4, shiftwidth = 4,
softtabstop = 0, softtabstop = 0,
expandtab = true, expandtab = true,
}) })
describe('indent Rust:', function() describe("indent Rust:", function()
describe('whole file:', function() describe("whole file:", function()
run:whole_file('.') run:whole_file "."
end) end)
describe('new line:', function() describe("new line:", function()
run:new_line('array.rs', { on_line = 2, text = '0,', indent = 4 }) 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("array.rs", { on_line = 8, text = "0,", indent = 8 })
run:new_line('comment.rs', { on_line = 3, text = 'a', indent = '/// ' }) 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 = 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 = 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 = 4, text = "x += 1;", indent = 8 })
run:new_line('cond.rs', { on_line = 6, 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 = 2, text = "Q,", indent = 4 })
run:new_line('enum.rs', { on_line = 4, text = 'i32,', indent = 8 }) 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("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 = 1, text = "let _x = 1;", indent = 4 })
run:new_line('func.rs', { on_line = 6, text = 'z: i32,', 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 = 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("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 = 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 = 2, text = "x += 1;", indent = 8 })
run:new_line('loop.rs', { on_line = 6, 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 = 1, text = "() => {},", indent = 4 })
run:new_line('macro.rs', { on_line = 12, text = 'B C', 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("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 = 2, text = "-1 => -1,", indent = 8 })
run:new_line('match.rs', { on_line = 7, text = 'let y = 1;', indent = 12 }) 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 = 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 = 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("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 = 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 = 5, text = "brave new \\", indent = 8 })
run:new_line('string.rs', { on_line = 9, 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 = 1, text = "z: i32,", indent = 4 })
run:new_line('struct.rs', { on_line = 2, 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 = 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 = 7, text = "fn baz();", indent = 4 })
run:new_line('trait.rs', { on_line = 8, text = '()', indent = 8 }) 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 = 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 = 2, text = "T: Debug,", indent = 4 })
run:new_line('where.rs', { on_line = 9, text = 'T: Debug,', indent = 4 }) run:new_line("where.rs", { on_line = 9, text = "T: Debug,", indent = 4 })
end) end)
end) end)