Amos Blog

VimTex and LuaSnip

· by Amos

VimTeX: LaTeX Power Inside NeoVim

My main tool for working with LaTeX in NeoVim is VimTeX — a powerful plugin that brings the full functionality you might expect from an IDE like VSCode, but fully integrated in the NeoVim ecosystem.

Why VimTeX?

With VimTeX, you get many essential features to make LaTeX editing smooth and efficient:

In short: everything you’d expect from a full-fledged LaTeX IDE is achievable within NeoVim using VimTeX.


Setting Up VimTeX

Installation is straightforward once you translate Vimscript configs to Lua (the preferred setup for NeoVim now). Here is my vimtex.lua plugin config file that I pieced together:

 1return {
 2  'lervag/vimtex',
 3  lazy = false, -- lazy-loading will disable inverse search
 4  config = function()
 5    vim.g.vimtex_view_method = 'skim'
 6    vim.g.vimtex_compiler_latexmk = {
 7      aux_dir = './.latexmk/aux',
 8      out_dir = '.',
 9    }
10    -- only open quickfix when there are *errors*
11    vim.g.vimtex_quickfix_open_on_warning = 0
12    vim.g.Tex_DefaultTargetFormat = 'pdf'
13    vim.g.Tex_CompileRule_pdf = 'pdflatex'
14  end,
15  keys = {
16    { '<localLeader>l', '', desc = '+vimtex' },
17    { '<localLeader>lb', ':!pdflatex %:p', desc = 'compile pdf' },
18  },
19}

Additionally, in my init.lua, I configure NeoVim to treat LaTeX files with specific options and enable LuaSnip:

 1-- latex is special
 2vim.api.nvim_create_autocmd({ 'FileType' }, {
 3  pattern = { 'bib', 'tex' },
 4  callback = function()
 5    vim.opt_local.conceallevel = 0
 6    vim.opt_local.wrap = true
 7    vim.bo.shiftwidth = 2
 8    vim.bo.tabstop = 2
 9  end,
10})
11--
12-- Load snippets from ~/.config/nvim/LuaSnip/
13require('luasnip.loaders.from_lua').load { paths = '~/.config/nvim/LuaSnip/' }
14require('luasnip').setup { enable_autosnippets = true }

This setup makes LaTeX editing in NeoVim as fast and intuitive as a modern IDE!


LuaSnip: Snippets Made Easy

A killer feature of VimTeX is its deep integration with the snippets plugin LuaSnip, enabling you to create, edit, and use snippets seamlessly for LaTeX — and any other language you might want to write in (HTML, CSS, Markdown, etc.).

Installing LuaSnip is even simpler than VimTeX. Here’s my working luasnip.lua config after resolving some conflicts:

 1return {
 2  'L3MON4D3/LuaSnip',
 3  version = 'v2.*',
 4  build = 'make install_jsregexp',
 5  event = 'InsertEnter',
 6  config = function()
 7    require('luasnip.loaders.from_lua').load { paths = '~/config/nvim/LuaSnip/' }
 8    local ls = require 'luasnip'
 9    ls.setup {
10      update_events = { 'TextChanged', 'TextChangedI' },
11      enable_autosnippets = true,
12      store_selection_keys = '<Tab>',
13    }
14    -- LuaSnip Keymaps
15    --
16    -- Expand snippets in insert mode with Tab
17    -- Jump forward in through tabstops in insert and visual mode with Control-f
18    --local ls = require 'luasnip'
19    --
20    vim.keymap.set({ 'i' }, '<Tab>', function()
21      ls.expand()
22    end, { silent = true })
23    vim.keymap.set({ 'i', 's' }, '<C-L>', function()
24      ls.jump(1)
25    end, { silent = true })
26    vim.keymap.set({ 'i', 's' }, '<C-J>', function()
27      ls.jump(-1)
28    end, { silent = true })
29
30    vim.keymap.set({ 'i', 's' }, '<C-E>', function()
31      if ls.choice_active() then
32        ls.change_choice(1)
33      end
34    end, { silent = true, desc = 'select autocomplete' })
35  end,
36}

Here my keymap to expand the snippet is set to Tab and I can cycle to the various snippets with the keymaps above.

How LuaSnip Works in Practice

When you start typing, for example, "se" in a LaTeX file, LuaSnip will suggest the snippet for \section{}, and pressing <Tab> expands it to: \section{<cursor here>}

allowing you to immediately type the section title — a huge time saver!

VimTeX itself also adds native shortcuts to speed up LaTeX workflows. For instance, the command cse lets you Change Surrounding Environment. Say you start writing an equation but want to switch to align* — just type cse align* and VimTeX transforms the environment quickly and elegantly, making editing feel fluid and natural.


Writing Custom Snippets with LuaSnip

You can define your own snippets loaded automatically with NeoVim. Here’s the header of my snippet file for LaTeX, giving you handy abbreviations:

 1--- Abbreviations used in this article and the LuaSnip docs
 2local ls = require 'luasnip'
 3local s = ls.snippet
 4local sn = ls.snippet_node
 5local t = ls.text_node
 6local i = ls.insert_node
 7local f = ls.function_node
 8local d = ls.dynamic_node
 9local fmt = require('luasnip.extras.fmt').fmt
10local fmta = require('luasnip.extras.fmt').fmta
11local rep = require('luasnip.extras').rep

From here, defining snippets for common LaTeX commands or environments is straightforward and super productive.


Further Resources

If you want to dive deeper, I highly recommend the fantastic tutorial A guide to supercharged mathematical typesetting by ejmastnak. Although it’s written for Vimscript, it covers all the fundamentals and advanced tips for effective LaTeX editing in Vim/NeoVim.


With VimTeX + LuaSnip, your NeoVim becomes a powerhouse LaTeX IDE — lightweight, fast, and extremely customizable.

#neovim #latex #software