aboutsummaryrefslogtreecommitdiffstats
path: root/plugin
diff options
context:
space:
mode:
authorChristian Clason <c.clason@uni-graz.at>2023-06-12 09:54:30 -0600
committerChristian Clason <c.clason@uni-graz.at>2025-05-12 18:43:40 +0200
commit692b051b09935653befdb8f7ba8afdb640adf17b (patch)
tree167162b6b129ae04f68c5735078521a72917c742 /plugin
parentfeat(c-family): inherit injections (diff)
downloadnvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.tar
nvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.tar.gz
nvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.tar.bz2
nvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.tar.lz
nvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.tar.xz
nvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.tar.zst
nvim-treesitter-692b051b09935653befdb8f7ba8afdb640adf17b.zip
feat!: drop modules, general refactor and cleanup
Diffstat (limited to 'plugin')
-rw-r--r--plugin/filetypes.lua66
-rw-r--r--plugin/nvim-treesitter.lua102
-rw-r--r--plugin/query_predicates.lua141
3 files changed, 284 insertions, 25 deletions
diff --git a/plugin/filetypes.lua b/plugin/filetypes.lua
new file mode 100644
index 000000000..a4c236ec3
--- /dev/null
+++ b/plugin/filetypes.lua
@@ -0,0 +1,66 @@
+local filetypes = {
+ angular = { 'htmlangular' },
+ bash = { 'sh' },
+ bibtex = { 'bib' },
+ c_sharp = { 'cs', 'csharp', 'c-sharp' },
+ commonlisp = { 'lisp' },
+ cooklang = { 'cook' },
+ devicetree = { 'dts' },
+ diff = { 'gitdiff' },
+ eex = { 'eelixir' },
+ elixir = { 'ex' },
+ embedded_template = { 'eruby' },
+ erlang = { 'erl' },
+ facility = { 'fsd' },
+ faust = { 'dsp' },
+ gdshader = { 'gdshaderinc' },
+ git_config = { 'gitconfig' },
+ git_rebase = { 'gitrebase' },
+ glimmer = { 'handlebars', 'html.handlebars' },
+ godot_resource = { 'gdresource' },
+ haskell = { 'hs' },
+ haskell_persistent = { 'haskellpersistent' },
+ idris = { 'idris2' },
+ janet_simple = { 'janet' },
+ javascript = { 'javascriptreact', 'ecma', 'jsx', 'js' },
+ javascript_glimmer = { 'javascript.glimmer' },
+ linkerscript = { 'ld' },
+ latex = { 'tex' },
+ m68k = { 'asm68k' },
+ make = { 'automake' },
+ markdown = { 'pandoc', 'quarto', 'rmd' },
+ muttrc = { 'neomuttrc' },
+ ocaml_interface = { 'ocamlinterface' },
+ perl = { 'pl' },
+ poe_filter = { 'poefilter' },
+ properties = { 'jproperties' },
+ python = { 'py', 'gyp' },
+ qmljs = { 'qml' },
+ runescript = { 'clientscript' },
+ scala = { 'sbt' },
+ slang = { 'shaderslang' },
+ sqp = { 'mysqp' },
+ ssh_config = { 'sshconfig' },
+ starlark = { 'bzl' },
+ surface = { 'sface' },
+ t32 = { 'trace32' },
+ tcl = { 'expect' },
+ terraform = { 'terraform-vars' },
+ textproto = { 'pbtxt' },
+ tlaplus = { 'tla' },
+ tsx = { 'typescriptreact', 'typescript.tsx' },
+ typescript = { 'ts' },
+ typescript_glimmer = { 'typescript.glimmer' },
+ typst = { 'typ' },
+ udev = { 'udevrules' },
+ uxntal = { 'tal', 'uxn' },
+ v = { 'vlang' },
+ verilog = { 'systemverilog' },
+ vhs = { 'tape' },
+ xml = { 'xsd', 'xslt', 'svg' },
+ xresources = { 'xdefaults' },
+}
+
+for lang, ft in pairs(filetypes) do
+ vim.treesitter.language.register(lang, ft)
+end
diff --git a/plugin/nvim-treesitter.lua b/plugin/nvim-treesitter.lua
index 4ea3925fd..3ab264d41 100644
--- a/plugin/nvim-treesitter.lua
+++ b/plugin/nvim-treesitter.lua
@@ -1,34 +1,86 @@
--- Last Change: 2022 Apr 16
-
if vim.g.loaded_nvim_treesitter then
return
end
vim.g.loaded_nvim_treesitter = true
--- setup modules
-require("nvim-treesitter").setup()
-
local api = vim.api
--- define autocommands
-local augroup = api.nvim_create_augroup("NvimTreesitter", {})
+local function complete_available_parsers(arglead)
+ return vim.iter.filter(function(v)
+ return v:find(arglead)
+ end, require('nvim-treesitter.parsers').get_available())
+end
+
+local function complete_installed_parsers(arglead)
+ return vim.iter.filter(function(v)
+ return v:find(arglead)
+ end, require('nvim-treesitter.config').installed_parsers())
+end
+
+-- create user commands
+api.nvim_create_user_command('TSInstallInfo', function()
+ require('nvim-treesitter.install').info()
+end, { nargs = 0, desc = 'List available treesitter parsers' })
+
+api.nvim_create_user_command('TSInstall', function(args)
+ require('nvim-treesitter.install').install(args.fargs, { force = args.bang })
+end, {
+ nargs = '+',
+ bang = true,
+ bar = true,
+ complete = complete_available_parsers,
+ desc = 'Install treesitter parsers',
+})
+
+api.nvim_create_user_command('TSInstallFromGrammar', function(args)
+ require('nvim-treesitter.install').install(args.fargs, {
+ generate_from_grammar = true,
+ force = args.bang,
+ })
+end, {
+ nargs = '+',
+ bang = true,
+ bar = true,
+ complete = complete_available_parsers,
+ desc = 'Install treesitter parsers from grammar',
+})
+
+api.nvim_create_user_command('TSInstallSync', function(args)
+ require('nvim-treesitter.install').install(args.fargs, {
+ with_sync = true,
+ force = args.bang,
+ })
+end, {
+ nargs = '+',
+ bang = true,
+ bar = true,
+ complete = complete_available_parsers,
+ desc = 'Install treesitter parsers synchronously',
+})
+
+api.nvim_create_user_command('TSUpdate', function(args)
+ require('nvim-treesitter.install').update(args.fargs)
+end, {
+ nargs = '*',
+ bar = true,
+ complete = complete_installed_parsers,
+ desc = 'Update installed treesitter parsers',
+})
+
+api.nvim_create_user_command('TSUpdateSync', function(args)
+ require('nvim-treesitter.install').update(args.fargs, { with_sync = true })
+end, {
+ nargs = '*',
+ bar = true,
+ complete = complete_installed_parsers,
+ desc = 'Update installed treesitter parsers synchronously',
+})
-api.nvim_create_autocmd("Filetype", {
- pattern = "query",
- group = augroup,
- callback = function()
- api.nvim_clear_autocmds {
- group = augroup,
- event = "BufWritePost",
- }
- api.nvim_create_autocmd("BufWritePost", {
- group = augroup,
- buffer = 0,
- callback = function(opts)
- require("nvim-treesitter.query").invalidate_query_file(opts.file)
- end,
- desc = "Invalidate query file",
- })
- end,
- desc = "Reload query",
+api.nvim_create_user_command('TSUninstall', function(args)
+ require('nvim-treesitter.install').uninstall(args.fargs)
+end, {
+ nargs = '+',
+ bar = true,
+ complete = complete_installed_parsers,
+ desc = 'Uninstall treesitter parsers',
})
diff --git a/plugin/query_predicates.lua b/plugin/query_predicates.lua
new file mode 100644
index 000000000..abffea2f0
--- /dev/null
+++ b/plugin/query_predicates.lua
@@ -0,0 +1,141 @@
+local query = vim.treesitter.query
+
+-- register custom predicates
+
+---@param match (TSNode|nil)[]
+---@param pred string[]
+---@return boolean|nil
+query.add_predicate('kind-eq?', function(match, _, _, pred)
+ local node = match[pred[2]]
+ if not node then
+ return true
+ end
+
+ local types = { unpack(pred, 3) }
+ return vim.list_contains(types, node:type())
+end)
+
+-- register custom directives
+
+local mimetype_aliases = {
+ ['importmap'] = 'json',
+ ['module'] = 'javascript',
+ ['application/ecmascript'] = 'javascript',
+ ['text/ecmascript'] = 'javascript',
+}
+
+---@param match (TSNode|nil)[]
+---@param _ string
+---@param bufnr integer
+---@param pred string[]
+---@return boolean|nil
+query.add_directive('set-lang-from-mimetype!', function(match, _, bufnr, pred, metadata)
+ local capture_id = pred[2]
+ local node = match[capture_id]
+ if not node then
+ return
+ end
+ local type_attr_value = vim.treesitter.get_node_text(node, bufnr)
+ local configured = mimetype_aliases[type_attr_value]
+ if configured then
+ metadata['injection.language'] = configured
+ else
+ local parts = vim.split(type_attr_value, '/', {})
+ metadata['injection.language'] = parts[#parts]
+ end
+end)
+
+local injection_aliases = {
+ ex = 'elixir',
+ pl = 'perl',
+ sh = 'bash',
+ uxn = 'uxntal',
+ ts = 'typescript',
+}
+
+---@param match (TSNode|nil)[]
+---@param _ string
+---@param bufnr integer
+---@param pred string[]
+---@return boolean|nil
+query.add_directive('set-lang-from-info-string!', function(match, _, bufnr, pred, metadata)
+ local capture_id = pred[2]
+ local node = match[capture_id]
+ if not node then
+ return
+ end
+
+ local injection_alias = vim.treesitter.get_node_text(node, bufnr)
+ local filetype = vim.filetype.match({ filename = 'a.' .. injection_alias })
+ metadata['injection.language'] = filetype or injection_aliases[injection_alias] or injection_alias
+end)
+
+query.add_directive('downcase!', function(match, _, bufnr, pred, metadata)
+ local text, key, value ---@type string|string[], string, string|integer
+
+ if #pred == 3 then
+ -- (#downcase! @capture "key")
+ key = pred[3]
+ value = metadata[pred[2]][key]
+ else
+ -- (#downcase! "key")
+ key = pred[2]
+ value = metadata[key]
+ end
+
+ if type(value) == 'string' then
+ text = value
+ else
+ local node = match[value]
+ text = vim.treesitter.get_node_text(node, bufnr) or ''
+ end
+
+ if #pred == 3 then
+ metadata[pred[2]][key] = string.lower(text)
+ else
+ metadata[key] = string.lower(text)
+ end
+end)
+
+-- Trim blank lines from end of the region
+-- Arguments are the captures to trim.
+---@param match (TSNode|nil)[]
+---@param _ string
+---@param bufnr integer
+---@param pred string[]
+---@param metadata table
+---TODO(clason): upstream
+query.add_directive('trim!', function(match, _, bufnr, pred, metadata)
+ for _, id in ipairs({ select(2, unpack(pred)) }) do
+ local node = match[id]
+ if not node then
+ return
+ end
+
+ local start_row, start_col, end_row, end_col = node:range()
+
+ -- Don't trim if region ends in middle of a line
+ if end_col ~= 0 then
+ return
+ end
+
+ while true do
+ -- As we only care when end_col == 0, always inspect one line above end_row.
+ local end_line = vim.api.nvim_buf_get_lines(bufnr, end_row - 1, end_row, true)[1]
+
+ if end_line ~= '' then
+ break
+ end
+
+ end_row = end_row - 1
+ end
+
+ -- If this produces an invalid range, we just skip it.
+ if start_row < end_row or (start_row == end_row and start_col <= end_col) then
+ if not metadata[id] then
+ metadata[id] = {}
+ end
+ metadata[id].range = { start_row, start_col, end_row, end_col }
+ end
+ end
+end)