diff options
| -rw-r--r-- | lua/nvim-treesitter.lua | 30 | ||||
| -rw-r--r-- | lua/nvim-treesitter/configs.lua | 337 | ||||
| -rw-r--r-- | lua/nvim-treesitter/health.lua | 6 | ||||
| -rw-r--r-- | lua/nvim-treesitter/highlight.lua | 15 | ||||
| -rw-r--r-- | lua/nvim-treesitter/info.lua | 96 | ||||
| -rw-r--r-- | lua/nvim-treesitter/install.lua | 49 | ||||
| -rw-r--r-- | lua/nvim-treesitter/utils.lua | 13 | ||||
| -rw-r--r-- | plugin/nvim-treesitter.vim | 17 |
8 files changed, 452 insertions, 111 deletions
diff --git a/lua/nvim-treesitter.lua b/lua/nvim-treesitter.lua index b053f39b0..731f55e5d 100644 --- a/lua/nvim-treesitter.lua +++ b/lua/nvim-treesitter.lua @@ -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)) - end -end + utils.setup_commands('install', install.commands) + utils.setup_commands('info', info.commands) + utils.setup_commands('configs', configs.commands) --- This function initialize the plugin --- it is run at startup -M._root = {} -function M._root.setup() - install.setup() + 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 return M diff --git a/lua/nvim-treesitter/configs.lua b/lua/nvim-treesitter/configs.lua index fd3b41d29..c9450ed61 100644 --- a/lua/nvim-treesitter/configs.lua +++ b/lua/nvim-treesitter/configs.lua @@ -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 diff --git a/lua/nvim-treesitter/health.lua b/lua/nvim-treesitter/health.lua index 25da7fe35..563e46a90 100644 --- a/lua/nvim-treesitter/health.lua +++ b/lua/nvim-treesitter/health.lua @@ -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 diff --git a/lua/nvim-treesitter/highlight.lua b/lua/nvim-treesitter/highlight.lua index 110954a6a..65ab48dcb 100644 --- a/lua/nvim-treesitter/highlight.lua +++ b/lua/nvim-treesitter/highlight.lua @@ -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 diff --git a/lua/nvim-treesitter/info.lua b/lua/nvim-treesitter/info.lua new file mode 100644 index 000000000..18b1b611f --- /dev/null +++ b/lua/nvim-treesitter/info.lua @@ -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 diff --git a/lua/nvim-treesitter/install.lua b/lua/nvim-treesitter/install.lua index b00d3d773..be09a3bc1 100644 --- a/lua/nvim-treesitter/install.lua +++ b/lua/nvim-treesitter/install.lua @@ -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 diff --git a/lua/nvim-treesitter/utils.lua b/lua/nvim-treesitter/utils.lua index 8313a46a7..59de5dd57 100644 --- a/lua/nvim-treesitter/utils.lua +++ b/lua/nvim-treesitter/utils.lua @@ -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 diff --git a/plugin/nvim-treesitter.vim b/plugin/nvim-treesitter.vim index 06c760a18..a94f56a96 100644 --- a/plugin/nvim-treesitter.vim +++ b/plugin/nvim-treesitter.vim @@ -4,14 +4,17 @@ if exists('g:loaded_nvim_treesitter') finish endif +augroup NvimTreesitter +augroup END + +let g:loaded_nvim_treesitter = 1 + lua << EOF ts_installable_parsers = function() - return table.concat(require'nvim-treesitter'.available_parsers(), '\n') + return table.concat(require'nvim-treesitter.configs'.available_parsers(), '\n') +end +ts_available_modules = function() + return table.concat(require'nvim-treesitter.configs'.available_modules(), '\n') end -require'nvim-treesitter'._root.setup() +require'nvim-treesitter'.setup() EOF - -let g:loaded_nvim_treesitter = 1 - -augroup NvimTreesitter -augroup END |
