nvim/.config/nvim/lua/treesitter.lua

-- nvim/.config/nvim/lua/treesitter.lua
-- Tree-sitter setup: highlights, indent, text objects, and a small incremental
-- selection keymap. I keep auto_install off so grammars never sneak in when
-- I open an unfamiliar file on a laptop with no compiler.

local ok, ts = pcall(require, "nvim-treesitter.configs")
if not ok then return end

ts.setup({
  ensure_installed = {
    "bash", "c", "caddy", "css", "diff", "dockerfile", "git_config",
    "gitcommit", "gitignore", "go", "gomod", "gosum", "hcl", "html",
    "ini", "json", "lua", "luadoc", "make", "markdown", "markdown_inline",
    "python", "regex", "rust", "sql", "toml", "vim", "vimdoc", "yaml",
  },
  auto_install = false,
  sync_install = false,

  highlight = {
    enable = true,
    additional_vim_regex_highlighting = false,
  },
  indent = {
    enable = true,
    -- yaml indent is still flaky for multi-line strings; use built-in.
    disable = { "yaml" },
  },
  incremental_selection = {
    enable = true,
    keymaps = {
      init_selection    = "<C-Space>",
      node_incremental  = "<C-Space>",
      scope_incremental = "<C-s>",
      node_decremental  = "<C-x>",
    },
  },
  textobjects = {
    select = {
      enable = true,
      lookahead = true,
      keymaps = {
        ["af"] = "@function.outer",
        ["if"] = "@function.inner",
        ["ac"] = "@class.outer",
        ["ic"] = "@class.inner",
        ["aa"] = "@parameter.outer",
        ["ia"] = "@parameter.inner",
      },
    },
    move = {
      enable = true,
      set_jumps = true,
      goto_next_start     = { ["]f"] = "@function.outer", ["]c"] = "@class.outer" },
      goto_previous_start = { ["[f"] = "@function.outer", ["[c"] = "@class.outer" },
    },
  },
})

-- Use the tree-sitter folding expression but start unfolded.
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
vim.opt.foldenable = false