From 61764573406a80a840a5b96e48707e530c9e7327 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Fri, 1 May 2026 08:52:31 -0400 Subject: [PATCH 1/3] fix(treesitter): migrate to main api --- lazy-lock.json | 2 +- lua/plugins/lsp.lua | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lazy-lock.json b/lazy-lock.json index 6d4ff31..d52c348 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -12,7 +12,7 @@ "mason.nvim": { "branch": "main", "commit": "cb8445f8ce85d957416c106b780efd51c6298f89" }, "nvim-dap": { "branch": "master", "commit": "45a69eba683a2c448dd9ecfc4de89511f0646b5f" }, "nvim-lspconfig": { "branch": "master", "commit": "31026a13eefb20681124706a79fc1df6bf11ab27" }, - "nvim-treesitter": { "branch": "master", "commit": "cf12346a3414fa1b06af75c79faebe7f76df080a" }, + "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, "nvim-web-devicons": { "branch": "master", "commit": "4fc505ac7bd7692824a142e96e5f529c133862f8" }, "oil.nvim": { "branch": "master", "commit": "0fcc83805ad11cf714a949c98c605ed717e0b83e" }, "pi.nvim": { "branch": "main", "commit": "6e86a704ed6ff488fda78b64f4e564d6ee620785" }, diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index 890415b..44d9bc0 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -76,7 +76,8 @@ return { }) end, config = function() - require("nvim-treesitter").setup() + local treesitter = require("nvim-treesitter") + treesitter.setup() local function has_c_compiler() return vim.fn.executable("cc") == 1 @@ -93,7 +94,7 @@ return { return end - require("nvim-treesitter.install").ensure_installed(missing) + treesitter.install(missing) end local function tree_sitter_cli_works() @@ -170,14 +171,14 @@ return { end) end - local installed = require("nvim-treesitter.info").installed_parsers() + local installed = treesitter.get_installed("parsers") local missing = vim.iter(treesitter_parsers) :filter(function(parser) return not vim.tbl_contains(installed, parser) end) :totable() - if #missing == 0 and #vim.api.nvim_list_uis() == 0 then + if #missing == 0 then return end From 34c52305af59a5532a0e7892ddb1be917e24b5bb Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Fri, 1 May 2026 08:59:38 -0400 Subject: [PATCH 2/3] refactor(treesitter): use native neovim APIs --- README.md | 18 ++-- lazy-lock.json | 2 - lua/config/treesitter.lua | 46 +++++++++ lua/plugins/lsp.lua | 175 -------------------------------- lua/plugins/render-markdown.lua | 1 - 5 files changed, 57 insertions(+), 185 deletions(-) create mode 100644 lua/config/treesitter.lua diff --git a/README.md b/README.md index b9bc55a..9ad441a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Neovim Configuration -Portable Neovim configuration using lazy.nvim, Mason-managed tooling, native LSP, Treesitter, Telescope, and DAP (Neovim 0.11+, tested on 0.12.1). +Portable Neovim configuration using lazy.nvim, Mason-managed tooling, native LSP, native Treesitter, Telescope, and DAP (Neovim 0.11+, tested on 0.12.1). ## Installation @@ -19,8 +19,8 @@ git clone --recurse-submodules git@github.com:itme-brain/nixos.git - **Native LSP** (`vim.lsp.config` / `vim.lsp.enable`) - no manual server list needed - **Smart LSP picker** (`css`) - auto-detects installed servers for current filetype - **Neovim 0.12 compatible** - uses built-in `:lsp` commands and keeps legacy `:Lsp*` aliases working -- **Portable** - Mason is the source of truth for LSP servers, debug adapters, and tree-sitter-cli -- **Treesitter** - starts via Neovim's native `vim.treesitter.start` +- **Portable** - Mason is the source of truth for LSP servers and debug adapters +- **Treesitter** - uses Neovim's native `vim.treesitter.*` APIs without `nvim-treesitter` - **Debugging** - lazy-loaded `nvim-dap` stack with Mason-managed adapters ## LSP Setup @@ -43,10 +43,14 @@ On Neovim 0.12+, start/stop/restart uses the built-in `:lsp` commands under the ## Treesitter -Treesitter uses the current `nvim-treesitter` main branch API: -- Parsers are installed with `nvim-treesitter` +Treesitter uses Neovim's native API: - Highlighting starts through `vim.treesitter.start` -- `tree-sitter-cli` is bootstrapped through Mason when needed for parser installs/updates +- Parser/filetype mappings use `vim.treesitter.language.register` +- Parser and query installation is intentionally outside lazy.nvim and Mason + +Neovim loads compiled parser libraries from `parser/` directories on `runtimepath` and query files from `queries//`. +`tree-sitter-cli` is only needed by tools that generate or compile parsers from grammar sources; it is not required at runtime for highlighting. +Prefer providing parsers and queries through Neovim's runtime or a reproducible system/development environment. ## Debugging @@ -94,7 +98,7 @@ Mason installs: - **nvim-lspconfig** - LSP configurations - **nvim-cmp** - completion - **telescope.nvim** - fuzzy finder -- **nvim-treesitter** - syntax highlighting +- **Native Treesitter** - syntax highlighting - **nvim-dap** - debug adapter client - **nvim-dap-ui** - debugging UI panes - **mason-nvim-dap.nvim** - Mason debug adapter integration diff --git a/lazy-lock.json b/lazy-lock.json index d52c348..2f78476 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -12,13 +12,11 @@ "mason.nvim": { "branch": "main", "commit": "cb8445f8ce85d957416c106b780efd51c6298f89" }, "nvim-dap": { "branch": "master", "commit": "45a69eba683a2c448dd9ecfc4de89511f0646b5f" }, "nvim-lspconfig": { "branch": "master", "commit": "31026a13eefb20681124706a79fc1df6bf11ab27" }, - "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, "nvim-web-devicons": { "branch": "master", "commit": "4fc505ac7bd7692824a142e96e5f529c133862f8" }, "oil.nvim": { "branch": "master", "commit": "0fcc83805ad11cf714a949c98c605ed717e0b83e" }, "pi.nvim": { "branch": "main", "commit": "6e86a704ed6ff488fda78b64f4e564d6ee620785" }, "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, "render-markdown.nvim": { "branch": "main", "commit": "3f3eea97b80839f629c951ca660ffd125bfa5b34" }, "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, - "treesitter-parser-registry": { "branch": "main", "commit": "6eb15358bb9fc88f0d3401d8538d56652e9bdf3c" }, "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } } diff --git a/lua/config/treesitter.lua b/lua/config/treesitter.lua new file mode 100644 index 0000000..e57ed5d --- /dev/null +++ b/lua/config/treesitter.lua @@ -0,0 +1,46 @@ +local treesitter_filetypes = { + "lua", + "c", + "cpp", + "python", + "nix", + "rust", + "bash", + "markdown", + "html", + "javascript", + "javascriptreact", + "css", + "vim", + "gitconfig", + "gitrebase", + "gitattributes", + "gitcommit", + "gitignore", +} + +local language_by_filetype = { + gitconfig = "git_config", + gitrebase = "git_rebase", + javascriptreact = "javascript", +} + +for filetype, language in pairs(language_by_filetype) do + vim.treesitter.language.register(language, filetype) +end + +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("config_treesitter", { clear = true }), + pattern = treesitter_filetypes, + callback = function(event) + local language = vim.treesitter.language.get_lang(vim.bo[event.buf].filetype) + if not language then + return + end + + local ok, has_parser = pcall(vim.treesitter.language.add, language) + if ok and has_parser then + pcall(vim.treesitter.start, event.buf, language) + end + end, +}) diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index 44d9bc0..2f10b0a 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -14,182 +14,7 @@ local mason_ensure_installed = { "yamlls", -- YAML } -local treesitter_parsers = { - "lua", - "c", - "cpp", - "python", - "nix", - "rust", - "bash", - "markdown", - "markdown_inline", - "html", - "javascript", - "css", - "vim", - "git_config", - "git_rebase", - "gitattributes", - "gitcommit", - "gitignore", -} - return { - { - "neovim-treesitter/nvim-treesitter", - name = "nvim-treesitter", - dependencies = { - "neovim-treesitter/treesitter-parser-registry", - "williamboman/mason.nvim", - }, - lazy = false, - build = ":TSUpdate", - init = function() - vim.api.nvim_create_autocmd("FileType", { - group = vim.api.nvim_create_augroup("config_treesitter", { clear = true }), - pattern = { - "lua", - "c", - "cpp", - "python", - "nix", - "rust", - "bash", - "markdown", - "html", - "javascript", - "javascriptreact", - "css", - "vim", - "gitconfig", - "gitrebase", - "gitattributes", - "gitcommit", - "gitignore", - }, - callback = function(event) - if pcall(vim.treesitter.start, event.buf) then - vim.bo[event.buf].indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" - end - end, - }) - end, - config = function() - local treesitter = require("nvim-treesitter") - treesitter.setup() - - local function has_c_compiler() - return vim.fn.executable("cc") == 1 - or vim.fn.executable("gcc") == 1 - or vim.fn.executable("clang") == 1 - end - - local function install_missing_parsers(missing) - if not has_c_compiler() then - vim.notify_once( - "A C compiler is required to install or update Treesitter parsers", - vim.log.levels.WARN - ) - return - end - - treesitter.install(missing) - end - - local function tree_sitter_cli_works() - if vim.fn.executable("tree-sitter") == 0 then - return false - end - - local result = vim.system({ "tree-sitter", "--version" }, { text = true }):wait() - if result.code == 0 then - return true - end - - vim.notify_once( - "tree-sitter CLI is installed but cannot run. On NixOS, enable nix-ld so Mason-installed binaries can execute.", - vim.log.levels.WARN - ) - return false - end - - local function ensure_treesitter_cli(callback) - if tree_sitter_cli_works() then - callback() - return - end - - if #vim.api.nvim_list_uis() == 0 then - return - end - - local mason_ok, mason = pcall(require, "mason") - local registry_ok, registry = pcall(require, "mason-registry") - if not mason_ok or not registry_ok then - vim.notify_once( - "tree-sitter CLI is required to install or update parsers; install tree-sitter-cli or enable mason.nvim", - vim.log.levels.WARN - ) - return - end - - mason.setup() - registry.refresh(function() - local package_ok, package = pcall(registry.get_package, "tree-sitter-cli") - if not package_ok then - vim.notify_once( - "Mason registry does not include tree-sitter-cli; install tree-sitter-cli before running :TSUpdate", - vim.log.levels.WARN - ) - return - end - - if package:is_installed() then - if tree_sitter_cli_works() then - callback() - end - return - end - - if package:is_installing() then - vim.notify_once("tree-sitter-cli is already being installed by Mason", vim.log.levels.INFO) - return - end - - vim.notify_once("Installing tree-sitter-cli with Mason for Treesitter parser updates", vim.log.levels.INFO) - package:install({}, function(success, error) - if success and tree_sitter_cli_works() then - callback() - else - vim.notify( - "Failed to install tree-sitter-cli with Mason: " .. tostring(error), - vim.log.levels.WARN - ) - end - end) - end) - end - - local installed = treesitter.get_installed("parsers") - local missing = vim.iter(treesitter_parsers) - :filter(function(parser) - return not vim.tbl_contains(installed, parser) - end) - :totable() - - if #missing == 0 then - return - end - - ensure_treesitter_cli(function() - if #missing > 0 then - install_missing_parsers(missing) - end - end) - end - }, - { "m4xshen/autoclose.nvim", config = function() diff --git a/lua/plugins/render-markdown.lua b/lua/plugins/render-markdown.lua index 76aaf9f..1ef8f95 100644 --- a/lua/plugins/render-markdown.lua +++ b/lua/plugins/render-markdown.lua @@ -3,7 +3,6 @@ return { "MeanderingProgrammer/render-markdown.nvim", ft = { "markdown" }, dependencies = { - "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons", }, opts = { From ef4972deb980915b328958b469cc280fd2bb7a68 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Fri, 1 May 2026 09:16:45 -0400 Subject: [PATCH 3/3] feat(treesitter): use community fork provisioner --- README.md | 9 +-- lazy-lock.json | 2 + lua/config/treesitter.lua | 31 +--------- lua/config/treesitter_languages.lua | 52 +++++++++++++++++ lua/plugins/treesitter.lua | 90 +++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 32 deletions(-) create mode 100644 lua/config/treesitter_languages.lua create mode 100644 lua/plugins/treesitter.lua diff --git a/README.md b/README.md index 9ad441a..501248a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ git clone --recurse-submodules git@github.com:itme-brain/nixos.git - **Smart LSP picker** (`css`) - auto-detects installed servers for current filetype - **Neovim 0.12 compatible** - uses built-in `:lsp` commands and keeps legacy `:Lsp*` aliases working - **Portable** - Mason is the source of truth for LSP servers and debug adapters -- **Treesitter** - uses Neovim's native `vim.treesitter.*` APIs without `nvim-treesitter` +- **Treesitter** - uses native `vim.treesitter.*` APIs with community fork provisioning - **Debugging** - lazy-loaded `nvim-dap` stack with Mason-managed adapters ## LSP Setup @@ -46,11 +46,11 @@ On Neovim 0.12+, start/stop/restart uses the built-in `:lsp` commands under the Treesitter uses Neovim's native API: - Highlighting starts through `vim.treesitter.start` - Parser/filetype mappings use `vim.treesitter.language.register` -- Parser and query installation is intentionally outside lazy.nvim and Mason +- Parsers and queries are provisioned by the community `neovim-treesitter/nvim-treesitter` fork Neovim loads compiled parser libraries from `parser/` directories on `runtimepath` and query files from `queries//`. -`tree-sitter-cli` is only needed by tools that generate or compile parsers from grammar sources; it is not required at runtime for highlighting. -Prefer providing parsers and queries through Neovim's runtime or a reproducible system/development environment. +`tree-sitter-cli` is only needed by the provisioner when installing or updating parsers; it is not required at runtime for highlighting. +Mason bootstraps `tree-sitter-cli` when parser installation is needed. ## Debugging @@ -99,6 +99,7 @@ Mason installs: - **nvim-cmp** - completion - **telescope.nvim** - fuzzy finder - **Native Treesitter** - syntax highlighting +- **neovim-treesitter** - parser and query provisioning - **nvim-dap** - debug adapter client - **nvim-dap-ui** - debugging UI panes - **mason-nvim-dap.nvim** - Mason debug adapter integration diff --git a/lazy-lock.json b/lazy-lock.json index 2f78476..6af47f8 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -10,6 +10,7 @@ "mason-lspconfig.nvim": { "branch": "main", "commit": "0c2823e0418f3d9230ff8b201c976e84de1cb401" }, "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" }, "mason.nvim": { "branch": "main", "commit": "cb8445f8ce85d957416c106b780efd51c6298f89" }, + "neovim-treesitter": { "branch": "main", "commit": "df7489eeea351bece7fd0f9c825be5cb6a1438f0" }, "nvim-dap": { "branch": "master", "commit": "45a69eba683a2c448dd9ecfc4de89511f0646b5f" }, "nvim-lspconfig": { "branch": "master", "commit": "31026a13eefb20681124706a79fc1df6bf11ab27" }, "nvim-web-devicons": { "branch": "master", "commit": "4fc505ac7bd7692824a142e96e5f529c133862f8" }, @@ -18,5 +19,6 @@ "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, "render-markdown.nvim": { "branch": "main", "commit": "3f3eea97b80839f629c951ca660ffd125bfa5b34" }, "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "treesitter-parser-registry": { "branch": "main", "commit": "6eb15358bb9fc88f0d3401d8538d56652e9bdf3c" }, "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } } diff --git a/lua/config/treesitter.lua b/lua/config/treesitter.lua index e57ed5d..98992df 100644 --- a/lua/config/treesitter.lua +++ b/lua/config/treesitter.lua @@ -1,37 +1,12 @@ -local treesitter_filetypes = { - "lua", - "c", - "cpp", - "python", - "nix", - "rust", - "bash", - "markdown", - "html", - "javascript", - "javascriptreact", - "css", - "vim", - "gitconfig", - "gitrebase", - "gitattributes", - "gitcommit", - "gitignore", -} +local treesitter_languages = require("config.treesitter_languages") -local language_by_filetype = { - gitconfig = "git_config", - gitrebase = "git_rebase", - javascriptreact = "javascript", -} - -for filetype, language in pairs(language_by_filetype) do +for filetype, language in pairs(treesitter_languages.language_by_filetype) do vim.treesitter.language.register(language, filetype) end vim.api.nvim_create_autocmd("FileType", { group = vim.api.nvim_create_augroup("config_treesitter", { clear = true }), - pattern = treesitter_filetypes, + pattern = treesitter_languages.filetypes, callback = function(event) local language = vim.treesitter.language.get_lang(vim.bo[event.buf].filetype) if not language then diff --git a/lua/config/treesitter_languages.lua b/lua/config/treesitter_languages.lua new file mode 100644 index 0000000..d4f9601 --- /dev/null +++ b/lua/config/treesitter_languages.lua @@ -0,0 +1,52 @@ +local M = {} + +M.install_parsers = { + "bash", + "cpp", + "css", + "git_config", + "git_rebase", + "gitattributes", + "gitcommit", + "gitignore", + "html", + "javascript", + "json", + "nix", + "python", + "rust", + "toml", + "yaml", +} + +M.filetypes = { + "lua", + "c", + "cpp", + "python", + "nix", + "rust", + "bash", + "markdown", + "html", + "javascript", + "javascriptreact", + "css", + "json", + "toml", + "yaml", + "vim", + "gitconfig", + "gitrebase", + "gitattributes", + "gitcommit", + "gitignore", +} + +M.language_by_filetype = { + gitconfig = "git_config", + gitrebase = "git_rebase", + javascriptreact = "javascript", +} + +return M diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua new file mode 100644 index 0000000..b22762f --- /dev/null +++ b/lua/plugins/treesitter.lua @@ -0,0 +1,90 @@ +local treesitter_languages = require("config.treesitter_languages") + +local function tree_sitter_cli_works() + if vim.fn.executable("tree-sitter") == 0 then + return false + end + + local result = vim.system({ "tree-sitter", "--version" }, { text = true }):wait() + return result.code == 0 +end + +local function ensure_tree_sitter_cli(callback) + if tree_sitter_cli_works() then + callback() + return + end + + if #vim.api.nvim_list_uis() == 0 then + return + end + + local mason_ok, mason = pcall(require, "mason") + local registry_ok, registry = pcall(require, "mason-registry") + if not mason_ok or not registry_ok then + vim.notify_once("tree-sitter CLI is required to install Treesitter parsers", vim.log.levels.WARN) + return + end + + mason.setup() + registry.refresh(function() + local package_ok, package = pcall(registry.get_package, "tree-sitter-cli") + if not package_ok then + vim.notify_once("Mason registry does not include tree-sitter-cli", vim.log.levels.WARN) + return + end + + if package:is_installed() then + if tree_sitter_cli_works() then + callback() + else + vim.notify_once("tree-sitter CLI is installed but cannot run", vim.log.levels.WARN) + end + return + end + + if package:is_installing() then + return + end + + package:install({}, function(success, error) + if success and tree_sitter_cli_works() then + callback() + else + vim.notify("Failed to install tree-sitter-cli with Mason: " .. tostring(error), vim.log.levels.WARN) + end + end) + end) +end + +return { + { + "neovim-treesitter/nvim-treesitter", + name = "neovim-treesitter", + dependencies = { + "neovim-treesitter/treesitter-parser-registry", + "williamboman/mason.nvim", + }, + lazy = false, + build = ":TSUpdate", + config = function() + local treesitter = require("nvim-treesitter") + treesitter.setup() + + local installed = treesitter.get_installed("parsers") + local missing = vim.iter(treesitter_languages.install_parsers) + :filter(function(parser) + return not vim.tbl_contains(installed, parser) + end) + :totable() + + if #missing == 0 then + return + end + + ensure_tree_sitter_cli(function() + treesitter.install(missing) + end) + end, + }, +}