What is Vimtex?

Vimtex is a vim plugin that provides support for writing latex in vim. It can also be used in neovim.

I use the LazyVim distro to base my setups on. Below are the plugins I use for my latex compilation.

Latex Compiler

I use latexmk to compile my documents. Below is my current working configuration of the global .latexmkrc file. I use lualatex because it is the most modern and has the best support for unicode and modern fonts.

.latexmkrc

$pdf_mode = 4; # sets lualatex to default engine.
$dvi_mode = 0;
$postscript_mode = 0;

Vimtex

~/.config/nvim/lua/plugins/vimtex.lua

return {
  "lervag/vimtex",
  lazy = false, -- lazy-loading will disable inverse search
  config = function()
    vim.api.nvim_create_autocmd({ "FileType" }, {
      group = vim.api.nvim_create_augroup("lazyvim_vimtex_conceal", { clear = true }),
      pattern = { "bib", "tex" },
      callback = function()
        vim.wo.conceallevel = 0
      end,
    })
    vim.g.vimtex_mappings_disable = { ["n"] = { "K" } } -- disable `K` as it conflicts with LSP hover
    vim.g.vimtex_quickfix_method = vim.fn.executable("pplatex") == 1 and "pplatex" or "latexlog"

    vim.g.vimtex_view_method = "skim" -- <== macos specific, you can use zathura or sumatra or something else.
    vim.g.vimtex_view_skim_sync = 1
    vim.g.vimtex_view_skim_activate = 1
    vim.g.vimtex_view_skim_reading_bar = 1

    vim.g.vimtex_compiler_latexmk = {
      aux_dir = "./aux",
      out_dir = "./out",
    }

  end,
}

Using this configuration, you can use \l keystroke to bring up the vimtex menu. It supports real-time compilation, meaning that the pdf viewer is automatically updated. I have it set such that it uses skim for the pdf viewer, which is specific to OsX, but you can change it to something else. The auxiliary files and final outputs are saved under aux and out of relative to the .tex file.

Indentation

~/.config/nvim/lua/plugins/conform.lua

return {
  "stevearc/conform.nvim",
  optional = true,
  opts = {
    format = {
      timeout_ms = 3000,
      async = false, -- not recommended to change
      quiet = false, -- not recommended to change
    },
    formatters_by_ft = {
      ["tex"] = { "latexindent" },
      -- can add more here for different languages
    },
  },
}

Synatx Highlighting

~/.config/nvim/lua/plugins/treesitter.lua

return {
  "nvim-treesitter/nvim-treesitter",
  opts = function(_, opts)
    vim.treesitter.language.register("markdown", "mdx")
    -- vim.list_extend(opts.highlight.disable, { "tsx" })
    if type(opts.ensure_installed) == "table" then
      vim.list_extend(opts.ensure_installed, {
        "bibtex",
        "latex",
        -- you can add more here
      })
    end
    if type(opts.highlight.disable) == "table" then
      vim.list_extend(opts.highlight.disable, { "latex", "bibtex" })
    else
      opts.highlight.disable = { "latex", "bibtex" }
    end
  end,
}

Snippets

Custom snippets is one of the most powerful tools you can leverage when writing your latex with vim and vimtex. LuaSnip is the plugin that manages all types of snippets

~/config/nvim/lua/plugins/luasnip.lua

return {
  "L3MON4D3/LuaSnip",
  dependencies = {
    "rafamadriz/friendly-snippets",
  },
  opts = {
    history = true,
    delete_check_events = "TextChanged",
  },
  config = function()
    local luasnip_loader = require("luasnip.loaders.from_vscode")
    luasnip_loader.lazy_load({ paths = { "./snippets" }})
    luasnip_loader.lazy_load()
  end,
}

The config function here ensures that my custom snippets appear first, so that I can override default snippets for common stuff like figure or table.

Note that I am using the relative path. Since everything under lua is loaded by nvim, this ends up pointing to ~/config/nvim/snippets.

Inside that directory, you can create a snippets file that uses vscode style snippets. In order to do this, you need to have a package.json file at the root of the snippets directory. You can also use subdirectories to maintain snippets for different purposes.

~/config/nvim/snippets/package.json

{
  "name": "custom-snippets",
  "contributes": {
    "snippets": [
      {
        "language": [
          "tex"
        ],
        "path": "./latex/tex-snippets.json"
      }
    ]
  }
}

Again, note the use of relative paths. The relative path here starts from the directory that package.json is placed in.

~/config/nvim/snippets/latex/tex-snippets.json

{
  "Minipage": {
    "prefix": "minipage",
    "body": ["\\begin{minipage}[t]{$0\\textwidth}", "\\end{minipage}%"],
    "description": "Add a table"
  },
  "Frame": {
    "prefix": "frame",
    "body": ["\\begin{frame}", "\t\\frametitle{$1}", "\\end{frame}", "$0"],
    "description": "Add a beamer frame"
  },
}