feat/refacto: improve configurations

- You should now get the configs through functions
- Configs for languages are now inside a local object called parsers
- You can get the parser installation configurations with `get_parser_configs`
- A new object has been initialized inside configs to specify module config (called config).
- Provide functions to enable/disable a module on one buffer
- Provide functions to enable/disable a module on all buffers, and if filetype is
  specified, for specific filetype
- Provide function to determine if module is activated for a specified filetype
This commit is contained in:
kiyan42 2020-04-22 11:13:05 +02:00
parent b7fdd6ae38
commit 62786ec7c6
8 changed files with 453 additions and 112 deletions

View file

@ -1,30 +1,28 @@
local api = vim.api
local parsers = require'nvim-treesitter.parsers'
local configs = require 'nvim-treesitter.configs'
local install = require'nvim-treesitter.install'
local locals = require'nvim-treesitter.locals'
local highlight = require'nvim-treesitter.highlight'
local utils = require'nvim-treesitter.utils'
local info = require'nvim-treesitter.info'
local configs = require'nvim-treesitter.configs'
local M = {}
function M.available_parsers()
return vim.tbl_keys(configs.repositories)
end
-- This function sets up everythin needed for a given language
-- this is the main interface through the plugin
function M.setup(lang)
if parsers.has_parser(lang) then
local autocmd = "autocmd NvimTreesitter FileType %s lua require'nvim-treesitter.highlight'.setup()"
api.nvim_command(string.format(autocmd, lang))
utils.setup_commands('install', install.commands)
utils.setup_commands('info', info.commands)
utils.setup_commands('configs', configs.commands)
for _, ft in pairs(configs.available_parsers()) do
for _, mod in pairs(configs.available_modules()) do
if parsers.has_parser(ft) and configs.is_enabled(mod, ft) then
local cmd = string.format("lua require'nvim-treesitter.%s'.attach()", mod)
api.nvim_command(string.format("autocmd FileType %s %s", ft, cmd))
end
end
end
end
-- This function initialize the plugin
-- it is run at startup
M._root = {}
function M._root.setup()
install.setup()
end
return M

View file

@ -1,88 +1,343 @@
local M = {}
local api = vim.api
local queries = require'nvim-treesitter.query'
local parser_utils = require'nvim-treesitter.parsers'
local parsers = {}
M.repositories = {
javascript = {
parsers.javascript = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-javascript",
files = { "src/parser.c", "src/scanner.c" },
},
c = {
}
}
parsers.c = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-c",
files = { "src/parser.c" }
},
cpp = {
}
}
parsers.cpp = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-cpp",
files = { "src/parser.c", "src/scanner.cc" }
},
rust = {
}
}
parsers.rust = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-rust",
files = { "src/parser.c", "src/scanner.c" },
},
lua = {
}
}
parsers.lua = {
install_info = {
url = "https://github.com/nvim-treesitter/tree-sitter-lua",
files = { "src/parser.c", "src/scanner.cc" }
},
python = {
}
}
parsers.python = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-python",
files = { "src/parser.c", "src/scanner.cc" },
},
go = {
}
}
parsers.go = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-go",
files = { "src/parser.c" },
},
ruby = {
}
}
parsers.ruby = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-ruby",
files = { "src/parser.c", "src/scanner.cc" },
},
bash = {
}
}
parsers.bash = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-bash",
files = { "src/parser.c", "src/scanner.cc" },
},
php = {
}
}
parsers.php = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-php",
files = { "src/parser.c", "src/scanner.cc" },
},
java = {
}
}
parsers.java = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-java",
files = { "src/parser.c" },
},
html = {
}
}
parsers.html = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-html",
files = { "src/parser.c", "src/scanner.cc" },
},
julia = {
}
}
parsers.julia = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-julia",
files = { "src/parser.c", "src/scanner.c" },
},
json = {
}
}
parsers.json = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-json",
files = { "src/parser.c" },
},
css = {
}
}
parsers.css = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-css",
files = { "src/parser.c", "src/scanner.c" },
},
ocaml = {
}
}
parsers.ocaml = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-ocaml",
files = { "src/parser.c", "src/scanner.cc" },
},
swift = {
}
}
parsers.swift = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-swift",
files = { "src/parser.c" },
},
csharp = {
}
}
parsers.csharp = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-c-sharp",
files = { "src/parser.c", "src/scanner.c" },
},
typescript = {
}
}
parsers.typescript = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-typescript",
files = { "src/parser.c", "src/scanner.c" },
location = "tree-sitter-typescript/typescript"
},
tsx = {
}
}
parsers.tsx = {
install_info = {
url = "https://github.com/tree-sitter/tree-sitter-typescript",
files = { "src/parser.c", "src/scanner.c" },
location = "tree-sitter-tsx/tsx"
}
}
-- @enable can be true or false
-- @disable is a list of languages, only relevant if enable is true
-- @keymaps list of user mappings for a given module if relevant
-- @is_supported function which, given a ft, will return true if the ft works on the module
local config = {
highlight = {
enable = false,
disable = {},
is_supported = function(ft)
return queries.get_query(ft, 'highlights') ~= nil
end
},
-- selection = {
-- enable = false,
-- disable = {},
-- keymaps = {},
-- is_supported = function() return false end
-- },
-- folding = {
-- enable = false,
-- disable = {},
-- keymaps = {},
-- is_supported = function() return false end
-- }
}
local M = {}
local function enable_module(mod, bufnr, ft)
local bufnr = bufnr or api.nvim_get_current_buf()
local ft = ft or api.nvim_buf_get_option(bufnr, 'ft')
if not parsers[ft] or not config[mod] then
return
end
local loaded_mod = require(string.format("nvim-treesitter.%s", mod))
loaded_mod.attach(bufnr, ft)
end
local function enable_mod_conf_autocmd(mod, ft)
if not config[mod] or M.is_enabled(mod, ft) then return end
local cmd = string.format("lua require'nvim-treesitter.%s'.attach()", mod)
api.nvim_command(string.format("autocmd FileType %s %s", ft, cmd))
for i, parser in pairs(config[mod].disable) do
if parser == ft then
table.remove(config[mod].disable, i)
break
end
end
end
local function enable_all(mod, ft)
if not config[mod] then return end
for _, bufnr in pairs(api.nvim_list_bufs()) do
if not ft or api.nvim_buf_get_option(bufnr, 'ft') == ft then
enable_module(mod, bufnr, ft)
end
end
if ft then
enable_mod_conf_autocmd(mod, ft)
else
for _, ft in pairs(M.available_parsers()) do
if parser_utils.has_parser(ft) then
enable_mod_conf_autocmd(mod, ft)
end
end
end
config[mod].enable = true
end
local function disable_module(mod, bufnr, ft)
local bufnr = bufnr or api.nvim_get_current_buf()
local ft = ft or api.nvim_buf_get_option(bufnr, 'ft')
if not parsers[ft] or not config[mod] then
return
end
local loaded_mod = require(string.format("nvim-treesitter.%s", mod))
loaded_mod.detach(bufnr, ft)
end
local function disable_mod_conf_autocmd(mod, ft)
if not config[mod] or not M.is_enabled(mod, ft) then return end
api.nvim_command(string.format("autocmd! FileType %s", ft))
table.insert(config[mod].disable, ft)
end
local function disable_all(mod, ft)
for _, bufnr in pairs(api.nvim_list_bufs()) do
if not ft or api.nvim_buf_get_option(bufnr, 'ft') == ft then
disable_module(mod, bufnr, ft)
end
end
if ft then
disable_mod_conf_autocmd(mod, ft)
else
for _, ft in pairs(M.available_parsers()) do
if parser_utils.has_parser(ft) then
disable_mod_conf_autocmd(mod, ft)
end
end
config[mod].enable = false
end
end
M.commands = {
TSBufEnable = {
run = enable_module,
args = {
"-nargs=1",
"-complete=custom,v:lua.ts_available_modules"
},
description = '`:TSBufEnable module_name` enable a specified module on the current buffer'
},
TSBufDisable = {
run = disable_module,
args = {
"-nargs=1",
"-complete=custom,v:lua.ts_available_modules"
},
description = '`:TSBufDisable module_name` disable a specified module on the current buffer'
},
TSEnableAll = {
run = enable_all,
args = {
"-nargs=+",
"-complete=custom,v:lua.ts_available_modules"
},
description = '`:TSEnableAll module_name (filetype)` enables a specified module on all buffers. If filetype is specified, enable only for specified filetype'
},
TSDisableAll = {
run = disable_all,
args = {
"-nargs=+",
"-complete=custom,v:lua.ts_available_modules"
},
description = '`:TSDisableAll module_name (filetype)` disables a specified module on all buffers. If filetype is specified, disable only for specified filetype'
},
}
-- @param mod: module (string)
-- @param ft: filetype (string)
function M.is_enabled(mod, ft)
if not M.get_parser_configs()[ft] then return false end
local module_config = M.get_config()[mod]
if not module_config then return false end
if not module_config.enable or not module_config.is_supported(ft) then
return false
end
for _, parser in pairs(module_config.disable) do
if ft == parser then return false end
end
return true
end
function M.setup(user_data)
if not user_data then return end
for mod, data in pairs(user_data) do
if config[mod] then
if type(data.enable) == 'boolean' then
config[mod].enable = data.enable
end
if type(data.disable) == 'table' then
config[mod].disable = data.disable
end
if config[mod].keymaps and type(data.keymaps) == 'table' then
config[mod].keymaps = data.keymaps
end
end
end
end
function M.get_config()
return config
end
function M.get_parser_configs()
return parsers
end
function M.available_parsers()
return vim.tbl_keys(parsers)
end
function M.available_modules()
return vim.tbl_keys(config)
end
return M

View file

@ -13,7 +13,7 @@ local health_error = vim.fn['health#report_error']
local M = {}
local function configs_health()
local function install_health()
if fn.executable('git') == 0 then
health_error('`git` executable not found.', {
'Install it with your package manager.',
@ -38,11 +38,11 @@ end
function M.checkhealth()
-- Installation dependency checks
health_start('Installation')
configs_health()
install_health()
local missing_parsers = {}
-- Parser installation checks
for parser_name in pairs(configs.repositories) do
for _, parser_name in pairs(configs.available_parsers()) do
local installed = #api.nvim_get_runtime_file('parser/'..parser_name..'.so', false)
-- Only print informations about installed parsers

View file

@ -1,12 +1,12 @@
local api = vim.api
local queries = require'nvim-treesitter.query'
local ts = vim.treesitter
local queries = require'nvim-treesitter.query'
local M = {
highlighters={}
highlighters = {}
}
function M.setup(bufnr, ft)
function M.attach(bufnr, ft)
local buf = bufnr or api.nvim_get_current_buf()
local ft = ft or api.nvim_buf_get_option(buf, 'ft')
@ -16,4 +16,13 @@ function M.setup(bufnr, ft)
M.highlighters[buf] = ts.TSHighlighter.new(query, buf, ft)
end
function M.detach(bufnr)
local buf = bufnr or api.nvim_get_current_buf()
if M.highlighters[buf] then
M.highlighters[buf]:set_query("")
M.highlighters[buf] = nil
end
api.nvim_buf_set_option(buf, 'syntax', 'on')
end
return M

View file

@ -0,0 +1,96 @@
local api = vim.api
local configs = require'nvim-treesitter.configs'
local M = {}
local function install_info()
local max_len = 0
for _, ft in pairs(configs.available_parsers()) do
if #ft > max_len then max_len = #ft end
end
for _, ft in pairs(configs.available_parsers()) do
local is_installed = #api.nvim_get_runtime_file('parser/'..ft..'.so', false) > 0
api.nvim_out_write(ft..string.rep(' ', max_len - #ft + 1))
if is_installed then
api.nvim_out_write("[✓] installed\n")
else
api.nvim_out_write("[✗] not installed\n")
end
end
end
local function print_info_module(sorted_filetypes, mod)
local max_str_len = #sorted_filetypes[1]
local header = string.format('%s%s', string.rep(' ', max_str_len + 2), mod)
api.nvim_out_write(header..'\n')
for _, ft in pairs(sorted_filetypes) do
local padding = string.rep(' ', max_str_len - #ft + #mod / 2 + 1)
api.nvim_out_write(ft..":"..padding)
if configs.is_enabled(mod, ft) then
api.nvim_out_write('')
else
api.nvim_out_write('')
end
api.nvim_out_write('\n')
end
end
local function print_info_modules(sorted_filetypes)
local max_str_len = #sorted_filetypes[1]
local header = string.rep(' ', max_str_len + 2)
for _, mod in pairs(configs.available_modules()) do
header = string.format('%s%s ', header, mod)
end
api.nvim_out_write(header..'\n')
for _, ft in pairs(sorted_filetypes) do
local padding = string.rep(' ', max_str_len - #ft)
api.nvim_out_write(ft..":"..padding)
for _, mod in pairs(configs.available_modules()) do
local pad_len = #mod / 2 + 1
api.nvim_out_write(string.rep(' ', pad_len))
if configs.is_enabled(mod, ft) then
api.nvim_out_write('')
else
api.nvim_out_write('')
end
api.nvim_out_write(string.rep(' ', pad_len - 1))
end
api.nvim_out_write('\n')
end
end
local function module_info(mod)
if mod and not configs.get_config()[mod] then return end
local ft_by_len = configs.available_parsers()
table.sort(ft_by_len, function(a, b) return #a > #b end)
if mod then
print_info_module(ft_by_len, mod)
else
print_info_modules(ft_by_len)
end
end
M.commands = {
TSInstallInfo = {
run = install_info,
args = {
"-nargs=0",
},
description = '`:TSInstallInfo` print installation state for every filetype'
},
TSModuleInfo = {
run = module_info,
args = {
"-nargs=?",
"-complete=custom,v:lua.ts_available_modules"
},
description = '`:TSModuleInfo` print module state for every filetype, if module is specified, only for current module'
}
}
return M

View file

@ -1,7 +1,8 @@
local api = vim.api
local fn = vim.fn
local luv = vim.loop
local repositories = require'nvim-treesitter/configs'.repositories
local configs = require'nvim-treesitter/configs'
local parsers = configs.get_parser_configs()
local M = {}
@ -118,14 +119,15 @@ local function install(ft)
if not string.match(yesno, '^y.*') then return end
end
local repository = repositories[ft]
if not repository then
local parser_config = parsers[ft]
if not parser_config then
return api.nvim_err_writeln('Parser not available for language '..ft)
end
local install_info = parser_config.install_info
vim.validate {
url={ repository.url, 'string' },
files={ repository.files, 'table' }
url={ install_info.url, 'string' },
files={ install_info.files, 'table' }
}
if fn.executable('git') == 0 then
@ -138,24 +140,7 @@ local function install(ft)
local cache_folder, err = get_cache_dir()
if err then return api.nvim_err_writeln(err) end
run_install(cache_folder, package_path, ft, repository)
end
local function install_info()
local max_len = 0
for parser_name, _ in pairs(repositories) do
if #parser_name > max_len then max_len = #parser_name end
end
for parser_name, _ in pairs(repositories) do
local is_installed = #api.nvim_get_runtime_file('parser/'..parser_name..'.so', false) > 0
api.nvim_out_write(parser_name..string.rep(' ', max_len - #parser_name + 1))
if is_installed then
api.nvim_out_write("[✓] installed\n")
else
api.nvim_out_write("[✗] not installed\n")
end
end
run_install(cache_folder, package_path, ft, install_info)
end
M.commands = {
@ -166,25 +151,7 @@ M.commands = {
"-complete=custom,v:lua.ts_installable_parsers"
},
description = '`:TSInstall {ft}` installs a parser under nvim-treesitter/parser/{name}.so'
},
TSInstallInfo = {
run = install_info,
args = { "-nargs=0" },
description = '`:TSInstallInfo` print installation state for every filetype'
}
}
function M.setup()
for command_name, def in pairs(M.commands) do
local call_fn = string.format("lua require'nvim-treesitter.install'.commands.%s.run(<f-args>)", command_name)
local parts = vim.tbl_flatten({
"command!",
def.args,
command_name,
call_fn,
})
api.nvim_command(table.concat(parts, " "))
end
end
return M

View file

@ -63,4 +63,17 @@ function M.is_parent(dest, source)
return false
end
function M.setup_commands(mod, commands)
for command_name, def in pairs(commands) do
local call_fn = string.format("lua require'nvim-treesitter.%s'.commands.%s.run(<f-args>)", mod, command_name)
local parts = vim.tbl_flatten({
"command!",
def.args,
command_name,
call_fn,
})
api.nvim_command(table.concat(parts, " "))
end
end
return M