Hi. I hope you are feeling well. In this post I am going through how I configured nvim-treesitter on its main branch.
Code
Without me explaining my life, here is the code for nvim-treesitter:
Note, don't forget to update Lazy.
return {
{
'nvim-treesitter/nvim-treesitter',
lazy = false,
branch = 'main',
build = ':TSUpdate',
config = function()
local parsers = {
'lua',
'python',
'javascript',
'typescript',
'bash',
'markdown',
'markdown_inline',
'java',
}
require('nvim-treesitter').setup()
vim.defer_fn(function()
require('nvim-treesitter').install(parsers):wait(300000)
end, 0)
vim.api.nvim_create_autocmd('FileType', {
pattern = parsers,
callback = function()
vim.treesitter.start()
end,
})
end,
},
-- vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" Didn't invest time into this.
{
'nvim-treesitter/nvim-treesitter-textobjects',
branch = 'main',
opts = {
select = {
-- Automatically jump forward to textobj, similar to targets.vim
lookahead = true,
-- You can choose the select mode (default is charwise 'v')
--
-- Can also be a function which gets passed a table with the keys
-- * query_string: eg '@function.inner'
-- * method: eg 'v' or 'o'
-- and should return the mode ('v', 'V', or '<c-v>') or a table
-- mapping query_strings to modes.
selection_modes = {
['@parameter.outer'] = 'v', -- charwise
['@function.outer'] = 'V', -- linewise
['@class.outer'] = '<c-v>', -- blockwise
},
-- If you set this to `true` (default is `false`) then any textobject is
-- extended to include preceding or succeeding whitespace. Succeeding
-- whitespace has priority in order to act similarly to eg the built-in
-- `ap`.
--
-- Can also be a function which gets passed a table with the keys
-- * query_string: eg '@function.inner'
-- * selection_mode: eg 'v'
-- and should return true of false
include_surrounding_whitespace = false,
},
move = {
set_jumps = true,
},
},
config = function(_, opts)
-- keymaps
-- You can use the capture groups defined in `textobjects.scm`
vim.keymap.set({ 'x', 'o' }, 'af', function()
require('nvim-treesitter-textobjects.select').select_textobject('@function.outer', 'textobjects')
end)
vim.keymap.set({ 'x', 'o' }, 'if', function()
require('nvim-treesitter-textobjects.select').select_textobject('@function.inner', 'textobjects')
end)
vim.keymap.set({ 'x', 'o' }, 'ac', function()
require('nvim-treesitter-textobjects.select').select_textobject('@class.outer', 'textobjects')
end)
vim.keymap.set({ 'x', 'o' }, 'ic', function()
require('nvim-treesitter-textobjects.select').select_textobject('@class.inner', 'textobjects')
end)
-- You can also use captures from other query groups like `locals.scm`
vim.keymap.set({ 'x', 'o' }, 'as', function()
require('nvim-treesitter-textobjects.select').select_textobject('@local.scope', 'locals')
end)
-- keymaps
-- You can use the capture groups defined in `textobjects.scm`
vim.keymap.set({ 'n', 'x', 'o' }, ']m', function()
require('nvim-treesitter-textobjects.move').goto_next_start('@function.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, ']]', function()
require('nvim-treesitter-textobjects.move').goto_next_start('@class.outer', 'textobjects')
end)
-- You can also pass a list to group multiple queries.
vim.keymap.set({ 'n', 'x', 'o' }, ']o', function()
move.goto_next_start({ '@loop.inner', '@loop.outer' }, 'textobjects')
end)
-- You can also use captures from other query groups like `locals.scm` or `folds.scm`
vim.keymap.set({ 'n', 'x', 'o' }, ']s', function()
require('nvim-treesitter-textobjects.move').goto_next_start('@local.scope', 'locals')
end)
vim.keymap.set({ 'n', 'x', 'o' }, ']z', function()
require('nvim-treesitter-textobjects.move').goto_next_start('@fold', 'folds')
end)
vim.keymap.set({ 'n', 'x', 'o' }, ']M', function()
require('nvim-treesitter-textobjects.move').goto_next_end('@function.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, '][', function()
require('nvim-treesitter-textobjects.move').goto_next_end('@class.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, '[m', function()
require('nvim-treesitter-textobjects.move').goto_previous_start('@function.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, '[[', function()
require('nvim-treesitter-textobjects.move').goto_previous_start('@class.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, '[M', function()
require('nvim-treesitter-textobjects.move').goto_previous_end('@function.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, '[]', function()
require('nvim-treesitter-textobjects.move').goto_previous_end('@class.outer', 'textobjects')
end)
-- Go to either the start or the end, whichever is closer.
-- Use if you want more granular movements
vim.keymap.set({ 'n', 'x', 'o' }, ']d', function()
require('nvim-treesitter-textobjects.move').goto_next('@conditional.outer', 'textobjects')
end)
vim.keymap.set({ 'n', 'x', 'o' }, '[d', function()
require('nvim-treesitter-textobjects.move').goto_previous('@conditional.outer', 'textobjects')
end)
end,
},
{},
}
About the Config
I'm going to go through every part of the configuration to (hopefully) explain to myself (and you) how everything works.
Text Objects
So as you might have noticed, the code above has nvim-treesitter-textobjects (also on main branch). The reason being that text objects, at least for me, are very important, so I felt like I should include that as well.
I won't go through how I set up text objects as I copied everything from the docs.
Installing parsers
So I don't think I need to go through that much. But what you should know is that this function:
vim.defer_fn(function()
require('nvim-treesitter').install(parsers):wait(300000)
end, 0)
Is important because we need to wait for setup()
to finish before we run install. The '0' after end is how much we want the function to wait after setup()
finishes, zero, of course.
install()
checks if the parser is already installed so we don't need to worry about that. It won't reinstall the parser.
What the :wait(300000)
does is it basically sets a timer on the install function. So it will try to install parsers for 5 minutes before it stops. But if it is done earlier it continues as normal.
Autocmd
So after installing our parsers we need to start them. Pretty sure you didn't need to worry about that before but now you need this:
vim.api.nvim_create_autocmd('FileType', {
pattern = parsers,
callback = function()
vim.treesitter.start()
end,
})
It is a copy of the snippet on nvim-treesitters readme. The only change i made was that the pattern was the table of file types i have the parsers for. You could set the pattern to '*'
so that it runs treesitter for everything. The benefit of having the pattern as parsers is that you avoid errors and unnecessary checks for parsers.
Side Note
I am not really sure why neovim configurations like kickstart.nvim don't use the main branch of nvim-treesitter. I understand it is different but I haven't had any problems with it so far.
I will try to update this site if I encounter any issues with nvim-treesitter. If you have any questions you can reach me at my mail. I will try my best to answer.