需求来源

在使用 Neovim 一年多以后,发现之前配置的 Neovim 中的很多功能用不上,显得 Neovim 中的配置十分地臃肿,因此打算重新写一份 Neovim 的配置指南,便于后面重新构建 Neovim,也给需要从零开始构建的朋友们一个参考。

现在配置的 Neovim 具有以下功能:

  • 能够运行 $\LaTeX$ 并且支持实时预览,一键清理 $\LaTeX$ 的附属文件,支持正向搜索和反向搜索
  • 能够方便地切换文件夹中和文件进行编辑,提供类似 VS Code 的文件浏览侧边栏
  • 能够支持 $\LaTeX$,C++/C 和 Python 代码的高亮和自动补全
  • 支持 C++/C 和 Python 代码的编译和运行
  • 好看的主题和类 VS Code 的界面 UI
  • 支持 Git 查看新增和修改的代码段,优化 Git 提交显示
  • 支持彩虹配对括号和特殊注释高亮
  • 自动高亮和当前光标下相对应的单词
  • 显示不同缩进参考线
  • 支持快速查询快捷键和 Git 记录查询
  • 自动切换中英输入法
  • 美观的状态栏以及丰富的图标支持
  • 支持模糊搜索
  • 支持给指定文本快速添加配对符号如括号、引号等
  • 集成 Copilot AI 辅助代码和文本写作
  • 支持快捷注释和取消注释代码块
  • 提供缓冲区标签栏,支持快速切换缓冲区和鼠标操作
  • 支持插件管理界面和懒加载
  • 支持自定义代码片段替换和插入

如果想要开箱即用,我个人的 Neovim 配置的仓库地址:[neovim-config](https://github.com/chen-huaneng/neovim-config)

版本信息

我使用的系统是 Windows 10 22H2,我的 Neovim 版本信息如下:

1NVIM v0.11.3
2Build type: Release
3LuaJIT 2.1.1741730670
4
5   system vimrc file: "$VIM/sysinit.vim"
6  fall-back for $VIM: "C:/Program Files (x86)/nvim/share/nvim"
7
8Run :checkhealth for more info

Neovim 配置基础知识

Lua 语言

在配置 Neovim 的时候,尽量使用 Lua,因为这是 Neovim 而不是 Vim,如果对 Lua 不了解,可以快速了解一下基本的语法和语义: Learn Lua in Y Minutes

配置文件路径

在 Windows 10 系统中,Neovim 的配置文件路径一般在 C:\Users\<UserName>\AppData\Local\nvim\。默认会读取该文件夹下的 init.lua 或者 init.vim 文件,这也是配置文件的主入口,理论上来说可以将所有的配置都写到这个文件里面,但是这不是一个好做法,因此划分成不同的文件和目录来管理不同功能的配置会更好。

本篇教程配置 Neovim 之后的目录结构应该是下面的样子:

 1.
 2│   im-select.exe
 3│   init.lua
 4│   lazy-lock.json
 5 6├───lua
 7│   │   bootstrap.lua
 8│   │   
 9│   ├───core
10│   │       autocmds.lua
11│   │       functions.lua
12│   │       init.lua
13│   │       keymaps.lua
14│   │       options.lua
15│   │       
16│   └───plugins
17│       │   autopairs.lua
18│       │   bufferline.lua
19│       │   colorscheme.lua
20│       │   comment.lua
21│       │   copilot.lua
22│       │   gitsigns.lua
23│       │   im-select.lua
24│       │   indent-blankline.lua
25│       │   local-highlight.lua
26│       │   lualine.lua
27│       │   luasnip.lua
28│       │   nvim-tree.lua
29│       │   nvim-web-devicons.lua
30│       │   rainbow-delimiters.lua
31│       │   surround.lua
32│       │   telescope.lua
33│       │   todo-comments.lua
34│       │   treesitter.lua
35│       │   vimtex.lua
36│       │   which-key.lua
37│       │   
38│       └───lsp
39│               lspconfig.lua
40│               mason.lua
41│               nvim-cmp.lua
42│               vimtex-cmp.lua
4344└───snippets
45        tex.lua

解释如下:

  • init.lua 为 Neovim 配置的主入口,用于导入其他 *.lua 文件。
  • lua 目录,当我们在 Lua 中调用 require 加载模块(文件)的时候,它会自动在 lua 文件夹里进行搜索
    • 将路径分隔符从 / 替换为 .,然后去掉 .lua 后缀就得到了 require 的参数格式
  • core 目录,用于管理核心配置和 Neovim 自带的配置
  • plugins 目录,用于管理插件
  • snippets 目录,用于管理自定义代码片段

选项配置

主要用到的就是 vim.gvim.optvim.cmd

按键配置

在 Neovim 中进行按键绑定的语法如下:

1vim.keymap.set(<mode>, <key>, <action>, <opts>)

从零开始配置 Neovim

在配置 Neovim 的时候弄清楚每一个选项的意思是很有必要的,因此会尽量在本文中说明每个选项的含义,同时在配置中会有相应的注释,如果没有说明则该选项的意义在注释中可以找到,尽量让配置文件是 self-contained 而且可读性强。

安装 Neovim

我使用的是 Scoop,因此安装 Neovim 只需要在命令行中运行下面的指令就可以:

1scoop install main/neovim

安装完成之后如果不存在前面说的配置文件夹和相应的 init.lua 文件,直接创建目录并新建 init.lua 文件即可。每次修改配置文件后,将配置文件编辑保存,重启 Neovim 就能看到相应的效果。接下来会按照 Neovim 启动执行文件的顺序介绍各个模块。

init.lua 入口文件

Neovim 启动时首先加载的就是 init.lua 文件:

  • require("core") 加载 lua/core/init.lua,初始化所有核心编辑器设置
  • require("bootstrap") 加载 lua/boostrap.lua,启动并配置 lazy.nvim 插件管理器

init.lua 文件配置:

1require("core")
2require("bootstrap")

`lazy-lock.json` 文件由 `lazy.nvim` 自动生成和管理,用于锁定所有插件的 commit hash,确保在不同设备上或重装时能恢复到完全相同的插件版本,保证了配置的稳定性。

lua/core 核心配置

core/init.lua 核心模块的入口

作为 core 模块的入口,按顺序加载所有核心配置文件:

1require("core.keymaps")
2require("core.options")
3require("core.autocmds")
4require("core.functions")

core/keymaps.lua 定义全局快捷键

定义全局的快捷键和一些插件的快捷键:

  1---------------------
  2-- Basic name norm --
  3---------------------
  4
  5--[[
  6----------------------keymap---------------------------
  7  <C-z> which means Ctrl-z, <C-p> for Ctrl-p, and so on
  8  <CR> which means <Enter>
  9  <S-m> which means Shift-m
 10  <A-Left> which means Alt-Left arrow key
 11  <BS> which means Backspace key
 12------------------------mode---------------------------
 13  'n': normal mode
 14  'x': visual mode
 15the difference between 'x', 'v' and 's' see: https://vi.stackexchange.com/questions/38859/what-does-mode-x-mean-in-neovim
 16--]]
 17
 18---------------------------
 19-- Define common options --
 20---------------------------
 21
 22local opts = {
 23  noremap = true, -- non-recursive
 24  silent = true, -- do not show message
 25}
 26
 27-- Shorten function name
 28local keymap = vim.api.nvim_set_keymap
 29
 30--Remap space as leader key
 31vim.g.mapleader = " "
 32
 33----------------------
 34-- Built-in mapping --
 35----------------------
 36
 37-- Unmappings <C-z> and set to no actions (<nop>) which used to disable these shortcut keys
 38keymap("n", "<C-z>", "<nop>", opts)
 39
 40-- Press <Enter> to clear search highlights results
 41keymap("n", "<CR>", "<cmd>noh<CR>", opts)
 42
 43-- Press <Shift-m> to open the help documentation for the word at the cursor
 44keymap("n", "<S-m>", ':execute "help " . expand("<cword>")<cr>', opts)
 45
 46-- The 'Y' key is remapped to copy to the end of the line, and the 'E' key is mapped to jump to the end of the previous word
 47keymap("n", "Y", "y$", opts)
 48keymap("n", "E", "ge", opts)
 49keymap("v", "Y", "y$", opts)
 50keymap("v", "E", "ge", opts) -- causes errors with luasnip autocmp
 51
 52-- <S-h> and <S-l> are used to jump to the beginning and end of a row respectively
 53keymap("v", "<S-h>", "g^", opts)
 54keymap("v", "<S-l>", "g$", opts)
 55keymap("n", "<S-h>", "g^", opts)
 56keymap("n", "<S-l>", "g$", opts)
 57
 58-- Use <C-h>, <C-j>, <C-k>, and <C-l> to navigate quickly between windows
 59keymap("n", "<C-h>", "<C-w>h", opts)
 60keymap("n", "<C-j>", "<C-w>j", opts)
 61keymap("n", "<C-k>", "<C-w>k", opts)
 62keymap("n", "<C-l>", "<C-w>l", opts)
 63
 64-- Resize windows width and height with arrows
 65-- delta: 2 lines
 66keymap("n", "<C-Up>", ":resize -2<CR>", opts)
 67keymap("n", "<C-Down>", ":resize +2<CR>", opts)
 68keymap("n", "<C-Left>", ":vertical resize -2<CR>", opts)
 69keymap("n", "<C-Right>", ":vertical resize +2<CR>", opts)
 70
 71-- Navigate between buffers through <TAB> and <S-TAB>
 72keymap("n", "<TAB>", ":bnext<CR>", opts)
 73keymap("n", "<S-TAB>", ":bprevious<CR>", opts)
 74
 75-- Can continuously use <Tab> or <S-Tab> to change the indentation in selection mode
 76keymap("v", ">", ">gv", opts)
 77keymap("v", "<", "<gv", opts)
 78
 79--------------------
 80-- Telescope.nvim --
 81--------------------
 82
 83-- Start the find_files function in the Telescope plugin to search for project files
 84vim.keymap.set("n", "<C-p>", "<cmd>Telescope find_files<CR>", { remap = true })
 85
 86------------------
 87-- Comment.nvim --
 88------------------
 89
 90-- Toggle comments <Ctrl-/> line comments used to switch between the current line and the selected area
 91keymap('n', '<C-_>', '<Plug>(comment_toggle_linewise_current)', opts)
 92keymap('x', '<C-_>', '<Plug>(comment_toggle_linewise_visual)', opts)
 93
 94-----------------
 95-- Copilot.vim --
 96-----------------
 97
 98-- Change the shortcut key for accepting Copilot suggestions
 99vim.keymap.set('i', '<C-R>', 'copilot#Accept("\\<CR>")', {
100  expr = true,
101  replace_keycodes = false
102})
103vim.g.copilot_no_tab_map = true

core/options.lua 全局选项配置

定义 Neovim 的全局选项配置:

 1local options = {
 2
 3  -- GENERAL
 4  timeoutlen = 500,               -- time to wait for a mapped sequence to complete (in milliseconds), keyboard shortcut waiting time
 5  updatetime = 300,               -- faster completion (4000ms default), update the inspection interval time
 6  swapfile = false,               -- creates a swap file
 7  undofile = true,                -- enable persistent undo
 8  writebackup = false,            -- if a file is being edited by another program, it is not allowed to be edited
 9  backup = false,           -- backup file creation
10  confirm = true,           -- a confirmation pops up when there is no save or the file is read-only
11
12  -- APPEARANCE
13  fileencoding = "UTF-8",         -- the encoding written to a file
14  encoding = "UTF-8",             -- UTF-8 encoding is used when processing text
15  guifont = "monospace:h17",      -- the font used in graphical neovim applications
16  background = "dark",            -- colorschemes that can be light or dark will be made dark
17  termguicolors = true,           -- set term gui colors (most terminals support this)
18  conceallevel = 0,               -- so that `` is visible in markdown files
19  number = true,                  -- show numbered lines
20  relativenumber = true,          -- set relative numbered lines
21  numberwidth = 2,                -- set number column width to 2 {default 4}
22  signcolumn = "yes",             -- always show the sign column, otherwise it would shift the text each time
23  cursorline = true,              -- highlight the current line
24  wrap = true,                    -- display lines as one long line, enable line breaks
25  showbreak = "↪ ",               -- set indent of wrapped lines
26  cmdheight = 1,                  -- space in the neovim command line for displaying messages, command line height
27  pumheight = 10,                 -- pop up menu height, the height of the completed menu
28  wildmenu = true,                -- display the completion menu
29  splitbelow = true,              -- force all horizontal splits to go below current window
30  splitright = true,              -- force all vertical splits to go to the right of current window
31  scrolloff = 999,                  -- minimal number of screen lines to keep above and below the cursor, achieve an effect similar to that of a Typora typewriter
32
33  -- INDENT
34  tabstop = 4,                    -- show 4 spaces for a tab
35  shiftwidth = 4,                 -- the number of spaces inserted for each indentation
36  softtabstop = 4,                -- insert 4 spaces for a tab
37  expandtab = true,               -- convert tabs to spaces
38  breakindent = true,             -- tab wrapped lines
39  linebreak = true,               -- companion to wrap, don't split words
40  backspace = "indent,eol,start", -- allow backspace on indent, end of line or insert mode start position
41  smarttab = true,                -- automatically adjust the indentation length of the new line based on the indentation of the current line
42  shiftround = true,              -- align to multiples of shiftwidth when moving with >> and <<
43  autoindent = true,              -- indentation of the new line is aligned to the current line
44  smartindent = true,             -- enable universal intelligent indentation
45
46  -- EDIT
47  spell = false,                   -- turns on spellchecker
48  clipboard = "unnamedplus",      -- allows neovim to access the system clipboard
49  mouse = "a",                    -- allow the mouse to be used in neovim
50  ignorecase = true,              -- ignore case in search patterns
51  smartcase = true,               -- when searching for capital letters, it automatically distinguishes between upper and lower case
52  hlsearch = true,                -- search highlighting
53  incsearch = true,               -- when entering the search mode, each character input automatically jumps to the first matching result
54  showmatch = true,               -- highlight the matching parentheses
55  virtualedit = "block",          -- vitualblock mode doesn't get stuck at the end of line
56  inccommand = "split",           -- shows all inline replacements in split
57  autoread = true,                -- external file modifications are automatically loaded
58  whichwrap = "<,>,[,]",          -- when the cursor is moved to the beginning or end of a line, it can be moved across lines
59  list = false,                   -- do not display invisible characters
60  listchars = "space:·,tab:>-",   -- display methods of spaces and tabs
61}
62
63-- turns on all values in options table above
64for k, v in pairs(options) do
65  vim.opt[k] = v
66end

core/autocmds.lua 自动命令配置

设置自动命令,用于在特定事件发生时执行操作:

 1local api = vim.api
 2
 3-- close help, man, qf, lspinfo with 'q'
 4api.nvim_create_autocmd(
 5  "FileType",
 6  {
 7    pattern = { "man", "help", "qf", "lspinfo" }, -- "startuptime",
 8    command = "nnoremap <buffer><silent> q :close<CR>",
 9  }
10)
11
12-- Terminal mappings 
13--[[
14  The set_terminal_keymaps function is defined. In terminal mode, the shortcut key <esc> is mapped to <C-c>, which can be used to quickly exit terminal mode.
15  Navigate between different Windows with <C-h>, <C-j>, <C-k>, and <C-l>. When the terminal is opened (TermOpen), set_terminal_keymaps() is automatically called.
16  Press <C-w> to exit from Terminal mode to Normal mode.
17--]]
18function _G.set_terminal_keymaps()
19  local opts = { buffer = 0 }
20  vim.keymap.set('t', '<esc>', [[<C-c>]], opts)
21  vim.keymap.set('t', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
22  vim.keymap.set('t', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
23  vim.keymap.set('t', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
24  vim.keymap.set('t', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
25  vim.keymap.set('t', '<C-w>', [[<C-\><C-n><C-w>]], opts)
26end
27
28vim.api.nvim_create_autocmd({ "TermOpen" }, {
29  pattern = { "term://*" }, -- use term://*toggleterm#* for only ToggleTerm
30  command = "lua set_terminal_keymaps()",
31})

core/functions.lus 自定义函数

存放可被复用的自定义 Lua 函数:

1-- Used to find the word under the cursor
2function SearchWordUnderCursor()
3    local word = vim.fn.expand('<cword>') -- get the word under the cursor
4    require('telescope.builtin').live_grep({ default_text = word }) -- invoke the live_grep function of the Telescope plugin
5end

lua/bootstrap.lua 插件管理器

负责 lazy.nvim 插件管理器的安装和配置,主要功能:

  • 自动检查 lazy.nvim 是否安装,如果未安装则从 Github 下载
  • 调用 require("lazy").setup(),并从 lua/pluginslua/plugins/lsp 目录导入所有插件配置
  • 自定义 lazy.nvim 的界面图标

文件配置:

 1-- Bootstrap lazy.nvim
 2local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
 3-- Check if lazy.nvim is installed (check if the path exists)
 4if not (vim.uv or vim.loop).fs_stat(lazypath) then
 5  -- Define the remote repository address of lazy.nvim
 6  local lazyrepo = "https://github.com/folke/lazy.nvim.git"
 7  -- Clone the path from the repository to the local area
 8  local out = vim.fn.system({
 9    "git", 
10    "clone", 
11    "--filter=blob:none",  -- Optimize cloning speed and only download necessary files
12    "--branch=stable",     -- Use the stable branch
13    lazyrepo, 
14    lazypath
15  })
16  -- If the clone fails (git returns a non-zero error code)
17  if vim.v.shell_error ~= 0 then
18    -- Display error messages and debug output
19    vim.api.nvim_echo({
20      { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
21      { out, "WarningMsg" },
22      { "\nPress any key to exit..." },
23    }, true, {})
24    -- Wait for the user to press the button and exit
25    vim.fn.getchar()
26    os.exit(1)
27  end
28end
29
30-- Add the path of the lazy.nvim plugin manager to the runtime path (rtp) of Neovim
31vim.opt.rtp:prepend(lazypath)
32
33-- Initialize the lazy.nvim plugin manager
34require("lazy").setup({
35  -- Plugin configuration module
36  { import = "plugins" },       -- main plugin directory (lua/plugins directory)
37  { import = "plugins.lsp" }    -- LSP plugin directory (lua/plugins/lsp directory)
38}, {
39  -- Configuration options of the plugin manager
40  install = {
41    colorscheme = { "gruvbox" },  -- Automatically install the gruvbox color theme during installation
42  },
43  checker = {
44    enabled = true,               -- Enables plugins version checking (check for updates)
45    notify = false,               -- Does not pop up notifications when an update is detected
46  },
47  change_detection = {
48    notify = false,               -- No notification pops up when the plugin file is changed
49  },
50  ui = {
51    icons = {
52      -- Custom UI icons
53      cmd = "⌘",            -- command
54      config = "🛠",        -- configuration
55      event = "📅",         -- event
56      ft = "📂",            -- file type
57      init = "⚙",          -- initialization shell
58      keys = "🗝",          -- keys binding
59      plugin = "🔌",        -- plugins
60      runtime = "💻",       -- running
61      require = "🌙",       -- require invocation
62      source = "📄",        -- source file
63      start = "🚀",         -- start plugins
64      task = "📌",          -- task
65      lazy = "💤 ",         -- lazy plugins
66    },
67  },
68})

lua/plugins 插件配置

plugins/lsp 代码分析与补全

lsp/ 目录用于存放所有与 LSP(Language Server Protocol)、代码补全和语法分析相关的插件。

lspconfig.lua 主配置文件

用于连接 mason 安装的 LSP 服务器到 Neovim 的 LSP 客户端。

 1return {
 2  "neovim/nvim-lspconfig",
 3  event = { "BufReadPre", "BufNewFile" }, -- Load when opening/creating a new file
 4  dependencies = {
 5    { "hrsh7th/cmp-nvim-lsp" }, -- Provide LSP completion capability for auto-completion plugins (such as nvim-cmp)
 6    { "antosha417/nvim-lsp-file-operations", config = true }, -- Automatically handle file operations (such as synchronizing file structures when renaming)
 7  },
 8  config = function()
 9    -- import lspconfig plugin
10    local lspconfig = require("lspconfig")
11
12    -- import cmp-nvim-lsp plugin
13    local cmp_nvim_lsp = require("cmp_nvim_lsp")
14
15    -- used to enable autocompletion (assign to every lsp server config)
16    local default = cmp_nvim_lsp.default_capabilities()
17
18    -- change the diagnostic symbols in the sign column (gutter)
19    vim.diagnostic.config({
20      signs = {
21        text = {
22          [vim.diagnostic.severity.ERROR] = "", -- error
23          [vim.diagnostic.severity.WARN] = "",  -- warning
24          [vim.diagnostic.severity.INFO] = "",  -- information
25          [vim.diagnostic.severity.HINT] = "󰠠",  -- hint
26        }
27      },
28      update_in_insert = true,  -- real-time update diagnosis in insertion mode
29      underline = true,  -- display error line
30    })
31
32    -- configure python server
33    lspconfig["pyright"].setup({
34      capabilities = default, -- enable default capabilities (including completion)
35      filetypes = { "python" },  -- only useful to .py file type
36    })
37
38    -- configure cpp server
39    lspconfig["clangd"].setup({
40      capabilities = default, -- enable default capabilities (including completion)
41      filetypes = { "h", "c", "cpp", "cc", "objc", "objcpp"}, -- supported file type
42      single_file_support = true, -- enable single-file mode (applicable to large-scale projects)
43    })
44  end,
45}

mason.lua LSP 管理

核心的 LSP 管理工具,用于安装和管理 LSP 服务器、代码格式化工具(Formatter)和代码检查工具(Linter)。

 1return {
 2  "williamboman/mason.nvim",
 3  ft ={ "py", "cpp", "c", "tex", "bib", "h", "cc", "objc", "objcpp" }, -- Specify the supported file types
 4  dependencies = {
 5    "williamboman/mason-lspconfig.nvim", -- Used for managing the installation and configuration of LSP servers
 6    "WhoIsSethDaniel/mason-tool-installer.nvim", -- Used for managing the installation of development tools (such as formatters, linters)
 7  },
 8
 9  config = function()
10    -- import mason
11    local mason = require("mason")
12
13    -- import mason-lspconfig
14    local mason_lspconfig = require("mason-lspconfig")
15
16    -- import mason-tool-installer
17    local mason_tool_installer = require("mason-tool-installer")
18
19    -- enable mason and configure icons
20    mason.setup({
21      ui = {
22        icons = {
23          package_installed = "✓",   -- installed packages
24          package_pending = "➜",     -- the package being installed
25          package_uninstalled = "✗", -- uninstalled package
26        },
27      },
28    })
29
30    mason_lspconfig.setup({
31      -- list of servers for mason to install
32      ensure_installed = {
33        "pyright", -- python LSP
34        "clangd",  -- cpp LSP
35      },
36      -- auto-install configured servers (with lspconfig)
37      automatic_installation = true, -- not the same as ensure_installed
38    })
39
40    mason_tool_installer.setup({
41      ensure_installed = {
42        "clang-format", -- cpp formatter
43        "black",    -- python formatter
44        "pylint",   -- python linter
45        "flake8",     -- Python static analysis
46        "bandit",     -- Python security check
47        "cpplint",    -- cpp linter
48      },
49    })
50  end,
51}

nvim-cmp.lua 自动补全

核心的自动补全引擎插件:

  1return {
  2  "hrsh7th/nvim-cmp",
  3  event = { "InsertEnter", "CmdlineEnter" }, -- Load the plugin when entering in insert mode or command-line mode
  4  dependencies = {
  5    "hrsh7th/cmp-buffer", -- source for text in buffer
  6    "hrsh7th/cmp-path", -- source for file system paths
  7    "L3MON4D3/LuaSnip", -- snippet engine
  8    "saadparwaiz1/cmp_luasnip", -- for autocompletion
  9    -- "onsails/lspkind.nvim", -- vs-code like pictograms
 10    "hrsh7th/cmp-cmdline", -- command-line mode completion
 11    "petertriho/cmp-git", -- git command completion
 12    "f3fora/cmp-spell", -- spelling check completion
 13    "micangl/cmp-vimtex", -- LaTeX completion (VimTeX Plugin)
 14  },
 15  config = function()
 16
 17    local cmp = require("cmp")
 18
 19    local luasnip = require("luasnip")
 20
 21------------------------
 22-- Icon configuration --
 23------------------------
 24
 25    local kind_icons = {
 26      article = "󰧮", -- article type (LaTeX)
 27      book = "", -- book type (LaTeX)
 28      incollection = "󱓷", -- collection type (LaTeX)
 29      Function = "󰊕", -- function
 30      Constructor = "", -- constructor
 31      Text = "󰦨", -- plain text
 32      Method = "", -- method
 33      Field = "󰅪", -- field/attribute
 34      Variable = "󱃮", -- variable
 35      Class = "", -- class
 36      Interface = "", -- interface
 37      Module = "", -- module
 38      Property = "", -- property
 39      Unit = "", -- unit 
 40      Value = "󰚯", -- value
 41      Enum = "", -- enumeration
 42      Keyword = "", -- keyword
 43      Snippet = "", -- code snippet
 44      -- Color = "󰌁", -- color
 45      Color = "", -- color
 46      File = "", -- file
 47      Reference = "", -- reference
 48      Folder = "", -- folder
 49      EnumMember = "", --enumeration member
 50      spell = "",
 51      -- EnumMember = "",
 52      Constant = "󰀫", -- constant
 53      Struct = "",
 54      -- Struct = "",
 55      Event = "", -- event
 56      Operator = "󰘧", -- operator
 57      TypeParameter = "", -- type parameter
 58    }
 59    -- find more here: https://www.nerdfonts.com/cheat-sheet
 60
 61----------------------
 62-- Completion logic --
 63----------------------
 64
 65    cmp.setup({
 66      completion = {
 67        completeopt = "menu,noselect", -- Complete menu behavior (not automatically selected)
 68        keyword_length = 1, -- At least one character is entered to trigger completion
 69      },
 70      snippet = { -- configure how nvim-cmp interacts with snippet engine
 71        expand = function(args)
 72          luasnip.lsp_expand(args.body) -- Extend the snippet using LuaSnip
 73        end,
 74      },
 75
 76-----------------
 77-- Key mapping --
 78-----------------
 79
 80      mapping = cmp.mapping.preset.insert({
 81        ["<CR>"] = cmp.mapping.confirm({ select = true }), -- Press Enter to confirm completion (no forced selection)
 82
 83        -- supertab
 84        ["<Tab>"] = cmp.mapping(function(fallback)
 85          if cmp.visible() then
 86            cmp.select_next_item()
 87          elseif luasnip.locally_jumpable(1) then
 88            luasnip.jump(1)
 89          elseif luasnip.expandable() then
 90            luasnip.expand()
 91          else
 92            fallback()
 93          end
 94        end, { "i", "s" }),
 95        ["<S-Tab>"] = cmp.mapping(function()
 96          if cmp.visible() then
 97            cmp.select_prev_item()
 98          elseif luasnip.locally_jumpable(-1) then
 99            luasnip.jump(-1)
100          else
101            -- fallback()
102          end
103        end, { "i", "s" }),
104      }),
105
106-----------------------------------
107-- Formatting for autocompletion --
108-----------------------------------
109
110      formatting = {
111        fields = { "kind", "abbr", "menu" }, -- Completed item display fields (type, abbreviation, source)
112        format = function(entry, vim_item)
113          vim_item.kind = string.format("%s", kind_icons[vim_item.kind]) -- Kind icons
114          vim_item.menu = ({
115            vimtex = vim_item.menu,
116            luasnip = "[Snippet]",
117            nvim_lsp = "[LSP]",
118            buffer = "[Buffer]",
119            spell = "[Spell]",
120            cmdline = "[CMD]",
121            path = "[Path]",
122          })[entry.source.name]
123          return vim_item
124        end,
125      },
126
127--------------------------------
128-- Sources for autocompletion --
129--------------------------------
130
131      sources = cmp.config.sources({
132        { name = "nvim_lsp" },
133        { name = "luasnip" }, -- snippets
134        { name = "vimtex" },
135        { name = "buffer", keyword_length = 3 }, -- text within current buffer
136        { name = "spell",
137          keyword_length = 4,
138          option = {
139              keep_all_entries = false,
140              enable_in_context = function()
141                  return true -- Always enable spell check
142              end
143          },
144        },
145        { name = "path" },
146      }),
147
148-------------------------
149-- Other configuration --
150-------------------------
151
152      confirm_opts = {
153        behavior = cmp.ConfirmBehavior.Replace, -- Replace the current cursor content
154        select = false,
155      },
156      view = {
157        entries = 'custom', -- Customize the display method of completion items
158      },
159      window = {
160        completion = cmp.config.window.bordered(), -- Complete the window with a border
161        documentation = cmp.config.window.bordered(), -- Documentation window with a border
162      },
163      performance = {
164         trigger_debounce_time = 500,
165         throttle = 550,
166         fetching_timeout = 80,
167      },
168    })
169
170    -- `/` cmdline setup.
171    cmp.setup.cmdline('/', {
172      mapping = cmp.mapping.preset.cmdline(),
173      sources = {
174        {name = 'buffer'}
175      }
176    })
177
178    -- `:` cmdline setup.
179    cmp.setup.cmdline(':', {
180      mapping = cmp.mapping.preset.cmdline(),
181      sources = {
182        {name = 'path'},
183        {name = 'cmdline'}
184      }
185    })
186
187  end,
188}

vimtex-cmp.lua $\LaTeX$ 支持

通过显示额外信息、符号和 BibTeX 解析,提升 LaTeX 编辑效率:

 1return {
 2  "micangl/cmp-vimtex",
 3  ft = { "tex", "bib", "cls" }, -- Only loaded when .tex .bib .cls files are opened
 4  config = function()
 5    require('cmp_vimtex').setup({
 6      additional_information = {
 7        info_in_menu = true,
 8        info_in_window = true,
 9        info_max_length = 60,
10        match_against_info = true,
11        symbols_in_menu = true,
12      },
13      bibtex_parser = {
14        enabled = true,
15      },
16    })
17  end,
18}

plugins/autopairs.lua 自动补全括号

自动补全括号、引号等成对符号:

 1return {
 2  "windwp/nvim-autopairs",
 3  event = { "InsertEnter" },
 4  dependencies = {
 5    "hrsh7th/nvim-cmp",
 6  },
 7  config = function()
 8    -- import nvim-autopairs
 9    local autopairs = require("nvim-autopairs")
10
11    -- configure autopairs
12    autopairs.setup({
13      check_ts = true,                      -- enable treesitter
14      disable_filetype = { "TelescopePrompt", "spectre_panel" },
15      disable_in_macro = true,
16      disable_in_replace_mode = true,
17      enable_moveright = true,
18      ignored_next_char = "",
19      enable_check_bracket_line = true, --- check bracket in same line
20    })
21
22    local Rule = require 'nvim-autopairs.rule'
23
24    local cond = require 'nvim-autopairs.conds'
25
26    autopairs.add_rules({
27      Rule("`", "'", "tex"),
28      Rule("$", "$", "tex"),
29      Rule(' ', ' ')
30          :with_pair(function(opts)
31            local pair = opts.line:sub(opts.col, opts.col + 1)
32            return vim.tbl_contains({ '$$', '()', '{}', '[]', '<>' }, pair)
33          end)
34          :with_move(cond.none())
35          :with_cr(cond.none())
36          :with_del(function(opts)
37            local col = vim.api.nvim_win_get_cursor(0)[2]
38            local context = opts.line:sub(col - 1, col + 2)
39            return vim.tbl_contains({ '$  $', '(  )', '{  }', '[  ]', '<  >' }, context)
40          end),
41      Rule("$ ", " ", "tex")
42          :with_pair(cond.not_after_regex(" "))
43          :with_del(cond.none()),
44      Rule("[ ", " ", "tex")
45          :with_pair(cond.not_after_regex(" "))
46          :with_del(cond.none()),
47      Rule("{ ", " ", "tex")
48          :with_pair(cond.not_after_regex(" "))
49          :with_del(cond.none()),
50      Rule("( ", " ", "tex")
51          :with_pair(cond.not_after_regex(" "))
52          :with_del(cond.none()),
53      Rule("< ", " ", "tex")
54          :with_pair(cond.not_after_regex(" "))
55          :with_del(cond.none()),
56    })
57
58    autopairs.get_rule('$'):with_move(function(opts)
59      return opts.char == opts.next_char:sub(1, 1)
60    end)
61
62    -- import nvim-cmp plugin (completions plugin)
63    local cmp = require("cmp")
64
65    -- import nvim-autopairs completion functionality
66    local cmp_autopairs = require("nvim-autopairs.completion.cmp")
67
68    -- make autopairs and completion work together
69    cmp.event:on(
70      'confirm_done',
71      cmp_autopairs.on_confirm_done({
72        filetypes = {
73          tex = false -- Disable for tex
74        }
75      })
76    )
77  end,
78}

bufferline.lua 缓冲区标签栏

在顶部显示一个类似 VSCode 的标签栏,用于展示和切换打开的缓冲区:

 1return {
 2  "akinsho/bufferline.nvim",
 3  dependencies = { "nvim-tree/nvim-web-devicons" },
 4  version = "*",
 5  config = function()
 6    local bufferline = require('bufferline')
 7    bufferline.setup({
 8      options = {
 9        mode = "buffers",
10        separator_style = "slant",
11        close_command = "bdelete! %d", -- Use the Lua API to close the buffer
12        diagnostics = false,           -- OR: | "nvim_lsp" 
13        diagnostics_update_in_insert = false,
14        show_tab_indicators = false,
15        show_close_icon = false,
16        -- numbers = "ordinal", -- Display buffer numbers as ordinal numbers
17        sort_by = 'insert_after_current', -- OR: 'insert_at_end' | 'tabs' | 'extension' | 'relative_directory' | 'directory' | 'id' |
18        offsets = {
19          {
20            filetype = "NvimTree",
21            -- text = "Explorer",
22            text = function()
23              return vim.fn.getcwd()
24            end,
25            highlight = "Directory",
26            separator = "", -- use a "true" to enable the default, or set your own character
27            -- padding = 1
28          }
29        },
30        hover = {
31          enabled = true,
32          delay = 30,
33          reveal = { 'close' }
34        },
35        vim.api.nvim_create_autocmd("User", {
36          pattern = "AlphaReady",
37          desc = "disable tabline for alpha",
38          callback = function()
39            vim.opt.showtabline = 0
40          end,
41        }),
42        vim.api.nvim_create_autocmd("BufUnload", {
43          buffer = 0,
44          desc = "enable tabline after alpha",
45          callback = function()
46            vim.opt.showtabline = 2
47          end,
48        })
49      },
50    })
51  end,
52}

colorscheme.lua 颜色主题

设置 gruvbox 为主颜色主题,并覆盖了一些高亮组以优化显示效果:

 1-- GRUVBOX
 2return {
 3  "ellisonleao/gruvbox.nvim",
 4  priority = 1000, -- make sure to load this before all the other start plugins
 5  config = function()
 6    require("gruvbox").setup({
 7      overrides = {
 8        SignColumn = { bg = "#282828" },
 9        NvimTreeCutHL = { fg = "#fb4934", bg = "#282828" },
10        NvimTreeCopiedHL = { fg = "#b8bb26", bg = "#282828" },
11        DiagnosticSignError = { fg = "#fb4934", bg = "#282828" },
12        DiagnosticSignWarn = { fg = "#fabd2f", bg = "#282828" },
13        DiagnosticSignHint = { fg = "#8ec07c", bg = "#282828" },
14        DiagnosticSignInfo = { fg = "#d3869b", bg = "#282828" },
15      }
16    })
17    vim.cmd("colorscheme gruvbox")
18  end,
19}

comment.lua 注释插件

强大的注释插件,通过 <C-/> 智能切换注释:

 1return {
 2  "numToStr/Comment.nvim",
 3  event = { "BufReadPre", "BufNewFile" },
 4  dependencies = {
 5    "JoosepAlviste/nvim-ts-context-commentstring",
 6  },
 7  config = function()
 8    -- import comment plugin safely
 9    local comment = require("Comment")
10
11    local ts_context_commentstring = require("ts_context_commentstring.integrations.comment_nvim")
12
13    -- enable comment
14    comment.setup({
15      --Add a space b/w comment and the line
16      padding = true,
17      ---Whether the cursor should stay at its position
18      sticky = true,
19      ---Lines to be ignored while (un)comment
20      ignore = nil,
21      ---Function to call before (un)comment
22      pre_hook = ts_context_commentstring.create_pre_hook(), -- for commenting tsx and jsx files
23      mappings = {
24        ---Operator-pending mapping; `gcc` `gbc` `gc[count]{motion}` `gb[count]{motion}`
25        basic = false,
26        ---Extra mapping; `gco`, `gcO`, `gcA`
27        extra = false,
28      },
29    })
30  end,
31}

copilot.lua 集成 AI

集成 GitHub Copilot,提供 AI 代码建议:

1return {
2  "github/copilot.vim",
3  init = function()
4    vim.g.copilot_enabled = false -- Set Copilot to be disabled by default
5  end,
6}

gitsigns.lua Git 状态集成

在行号列显示 Git 状态(新增、修改、删除):

 1return {
 2  "lewis6991/gitsigns.nvim",
 3  event = { "BufReadPre", "BufNewFile" },
 4  config = function()
 5    require("gitsigns").setup({
 6      signs = {
 7        add = { text = "▎" },
 8        change = { text = "▎" },
 9        delete = { text = "▎" },
10        topdelete = { text = "▎" },
11        changedelete = { text = "▎" },
12        untracked    = { text = "┆" },
13      },
14      signcolumn = true, -- Toggle with `:Gitsigns toggle_signs`
15      numhl = false, -- Toggle with `:Gitsigns toggle_numhl`
16      linehl = false, -- Toggle with `:Gitsigns toggle_linehl`
17      word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff`
18      watch_gitdir = {
19        interval = 1000,
20        follow_files = true,
21      },
22      attach_to_untracked = true,
23      current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame`
24      current_line_blame_opts = {
25        virt_text = true,
26        virt_text_pos = "eol", -- 'eol' | 'overlay' | 'right_align'
27        delay = 1000,
28        ignore_whitespace = false,
29      },
30      sign_priority = 6,
31      update_debounce = 100,
32      status_formatter = nil, -- Use default
33      max_file_length = 40000,
34      preview_config = {
35        -- Options passed to nvim_open_win
36        border = "single",
37        style = "minimal",
38        relative = "cursor",
39        row = 0,
40        col = 1,
41      },
42    })
43  end
44}

im-select.lua 自动切换输入法

自动切换中英输入法:

1return {
2    "keaising/im-select.nvim",
3    config = function()
4        require("im_select").setup({})
5    end,
6}

indent-blankline.lua 显示缩进参考线

显示缩进参考线,使代码结构更清晰:

 1return {
 2  "lukas-reineke/indent-blankline.nvim",
 3  version = "*",
 4  event = { "BufReadPre", "BufNewFile" },
 5  config = function()
 6    require("ibl").setup({
 7      indent = {
 8        char = "│",
 9        tab_char = "│",
10        highlight = "IblIndent",
11        smart_indent_cap = true,
12        priority = 1,
13        repeat_linebreak = true,
14      },
15      scope = {
16        enabled = true,
17        char = nil,
18        show_start = false,
19        show_end = false,
20        show_exact_scope = false,
21        injected_languages = true,
22        highlight = "IblScope",
23        priority = 1024,
24        include = {
25          node_type = { ["*"] = { "*" } }, -- makes lines show on all blocks
26        },
27      },
28      exclude = {
29        filetypes = {
30          "help",
31          "alpha",
32          "dashboard",
33          "NvimTree",
34          "Trouble",
35          "trouble",
36          "lazy",
37          "mason",
38          "notify",
39          "toggleterm",
40          "lspinfo",
41          "checkhealth",
42          "man",
43          "gitcommit",
44          "TelescopePrompt",
45          "TelescopeResults",
46          "",
47        },
48        buftypes = {
49          "terminal",
50          "nofile",
51          "quickfix",
52          "prompt",
53        },
54      },
55    })
56  end

local-highlight.lua 自动高亮

自动高亮光标下的所有相同单词:

 1return {
 2  'tzachar/local-highlight.nvim',
 3  config = function()
 4    require('local-highlight').setup({
 5      -- file_types = {'python', 'cpp'}, -- If this is given only attach to this
 6      -- OR attach to every filetype except:
 7      disable_file_types = {},
 8      hlgroup = 'Pmenu', -- change highlight color to value given in table found by running :highlight
 9      cw_hlgroup = nil,
10      insert_mode = false,
11      animate = {
12        enabled = false,
13      },
14    })
15  end
16}

lualine.lua 丰富状态栏

配置一个功能丰富的状态栏,显示模式、Git 分支、诊断信息、文件名等:

 1return {
 2  "nvim-lualine/lualine.nvim",
 3  dependencies = { "nvim-tree/nvim-web-devicons" },
 4  config = function()
 5    require('lualine').setup({
 6      options = {
 7        icons_enabled = true,
 8        theme = 'gruvbox',
 9        component_separators = { left = '', right = ''},
10        section_separators = { left = '', right = ''},
11        disabled_filetypes = {
12          statusline = {},
13          winbar = {},
14        },
15        ignore_focus = {},
16        always_divide_middle = true,
17        globalstatus = false,
18        refresh = {
19          statusline = 1000,
20          tabline = 1000,
21          winbar = 1000,
22        }
23      },
24      sections = {
25        lualine_a = {'mode'},
26        lualine_b = {'branch', 'diff', 'diagnostics'},
27        lualine_c = {'filename'},
28        lualine_x = {'encoding', 'fileformat', 'filetype'},
29        lualine_y = {'progress'},
30        lualine_z = {'location'}
31      },
32      inactive_sections = {
33        lualine_a = {},
34        lualine_b = {},
35        lualine_c = {'filename'},
36        lualine_x = {'location'},
37        lualine_y = {},
38      lualine_z = {}
39      },
40      tabline = {},
41      winbar = {},
42      inactive_winbar = {},
43      extensions = {}
44    })
45  end,
46}

luasnip.lua 代码段引擎

一个支持自定义代码段和引入网络代码段的引擎:

 1return {
 2  "L3MON4D3/LuaSnip",
 3  -- follow latest release
 4  version = "v2.*", -- Replace <CurrentMajor> by the latest released major (first number of latest release)
 5  config = function()
 6    local ls = require("luasnip")
 7
 8    ls.config.set_config({ -- Setting LuaSnip config
 9      enable_autosnippets = true, -- Enable autotriggered snippets
10      store_selection_keys = "<Tab>", -- Use Tab (or some other key if you prefer) to trigger visual selection
11      update_events = "TextChanged, TextChangedI", -- Update text when type
12    })
13
14    local nvim_config_path = vim.fn.stdpath("config") -- get neovim configuration path
15    -- Lazy-load snippets, i.e. only load when required, e.g. for a given filetype
16    require("luasnip.loaders.from_lua").lazy_load({
17      paths = nvim_config_path .. "/snippets"
18    })
19
20    -- vim.keymap.set({"i"}, "<C-E>", function() ls.expand() end, {silent = true})
21    vim.keymap.set({"i", "s"}, "<Tab>", function() ls.jump( 1) end, {silent = true})
22    vim.keymap.set({"i", "s"}, "<S-Tab>", function() ls.jump(-1) end, {silent = true})
23
24    -- vim.keymap.set({"i", "s"}, "<C-W>", function()
25    --   if ls.choice_active() then
26    --     ls.change_choice(1)
27    --   end
28    -- end, {silent = true})
29  end,
30}

nvim-tree.lua 文件浏览侧边栏

一个高性能的文件浏览器侧边栏,替代了默认的 netrw

  1return {
  2  "nvim-tree/nvim-tree.lua",
  3  cmd = {"NvimTreeToggle", "NvimTreeFocus"},
  4  dependencies = { "nvim-tree/nvim-web-devicons" },
  5  config = function()
  6    local nvimtree = require("nvim-tree")
  7
  8    -- recommended settings from nvim-tree documentation
  9    vim.g.loaded_netrw = 1
 10    vim.g.loaded_netrwPlugin = 1
 11
 12    local function on_attach(bufnr)
 13      local api = require('nvim-tree.api')
 14
 15      local function opts(desc)
 16        return { desc = 'nvim-tree: ' .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
 17      end
 18
 19      -- custom mappings
 20      local keymap = vim.keymap -- for conciseness
 21      keymap.set('n', '<CR>', api.node.open.tab, opts('Open'))
 22      keymap.set('n', '<S-M>', api.node.show_info_popup, opts('Info'))
 23      keymap.set('n', 'h', api.node.navigate.parent_close, opts('Close Directory'))
 24      keymap.set('n', 'l', api.node.open.edit, opts('Open'))
 25      keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling'))
 26      keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling'))
 27      keymap.set('n', '-', api.tree.change_root_to_parent, opts('Up'))
 28      keymap.set('n', 'a', api.fs.create, opts('Create'))
 29      keymap.set('n', 'y', api.fs.copy.node, opts('Copy'))
 30      keymap.set('n', 'd', api.fs.remove, opts('Delete'))
 31      keymap.set('n', 'D', api.fs.trash, opts('Trash'))
 32      keymap.set('n', '?', api.tree.toggle_help, opts('Help'))
 33      keymap.set('n', 'H', api.tree.toggle_hidden_filter, opts('Toggle Dotfiles'))
 34      keymap.set('n', 'p', api.fs.paste, opts('Paste'))
 35      keymap.set('n', 'O', api.node.navigate.parent, opts('Parent Directory'))
 36      keymap.set('n', 'q', api.tree.close, opts('Close'))
 37      keymap.set('n', 'r', api.fs.rename, opts('Rename'))
 38      keymap.set('n', 'R', api.tree.reload, opts('Refresh'))
 39      keymap.set('n', 'o', api.node.run.system, opts('System Open'))
 40      keymap.set('n', 's', api.tree.search_node, opts('Search'))
 41      keymap.set('n', 'v', api.node.open.vertical, opts('Vertical Split'))
 42      keymap.set('n', 'x', api.fs.cut, opts('Cut'))
 43      keymap.set('n', '<2-LeftMouse>', api.node.open.edit, opts('Open'))
 44    end
 45
 46    -- configure nvim-tree
 47    nvimtree.setup({
 48      on_attach = on_attach,
 49      actions = {
 50        open_file = {
 51          quit_on_open = true,
 52          eject = true,
 53          resize_window = true,
 54          window_picker = {
 55            enable = true,
 56            picker = "default",
 57            chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
 58            exclude = {
 59              filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" },
 60              buftype = { "nofile", "terminal", "help" },
 61            },
 62          },
 63        },
 64        change_dir = {
 65          enable = false,
 66          global = false,
 67          restrict_above_cwd = false,
 68        },
 69        use_system_clipboard = true,
 70        expand_all = {
 71          max_folder_discovery = 300,
 72          exclude = {},
 73        },
 74        file_popup = {
 75          open_win_config = {
 76            col = 1,
 77            row = 1,
 78            relative = "cursor",
 79            border = "shadow",
 80            style = "minimal",
 81          },
 82        },
 83        remove_file = {
 84          close_window = true,
 85        },
 86      },
 87      git = {
 88        enable = true,
 89        show_on_dirs = true,
 90        -- show_on_open_dirs = true,
 91        disable_for_dirs = {},
 92        timeout = 500,
 93        cygwin_support = false,
 94      },
 95      filters = {
 96        git_ignored = false,
 97        dotfiles = false,
 98        git_clean = false,
 99        no_buffer = false,
100        no_bookmark = false,
101        -- custom = { ".git" },
102        -- custom = { ".DS_Store" },
103        exclude = {},
104      },
105      update_focused_file = {
106        enable = true,
107        update_root = true,
108        ignore_list = {},
109        update_cwd = true,
110      },
111      renderer = {
112        add_trailing = false,
113        group_empty = false,
114        full_name = false,
115        root_folder_label = ":t",
116        indent_width = 2,
117        special_files = {},
118        symlink_destination = true,
119        highlight_git = false,
120        highlight_diagnostics = false,
121        highlight_opened_files = "none",
122        highlight_modified = "none",
123        highlight_bookmarks = "none",
124        highlight_clipboard = "name",
125        indent_markers = {
126          enable = false,
127          inline_arrows = true,
128          icons = {
129            corner = "└",
130            edge = "│",
131            item = "│",
132            bottom = "─",
133            none = " ",
134          },
135        },
136        icons = {
137          web_devicons = {
138            file = {
139              enable = true,
140              color = true,
141            },
142            folder = {
143              enable = false,
144              color = true,
145            },
146          },
147          git_placement = "before",
148          modified_placement = "after",
149          diagnostics_placement = "signcolumn",
150          bookmarks_placement = "signcolumn",
151          padding = " ",
152          symlink_arrow = " ➛ ",
153          show = {
154            file = true,
155            folder = true,
156            folder_arrow = true,
157            git = true,
158            modified = true,
159            diagnostics = true,
160            bookmarks = false,
161          },
162          glyphs = {
163            default = "",
164            -- toml = "󰰤", -- Change this to the desired icon for TOML files
165            symlink = "",
166            bookmark = "󰆤",
167            modified = "●",
168            folder = {
169              arrow_closed = "",
170              arrow_open = "",
171              default = "",
172              open = "",
173              empty = "",
174              empty_open = "",
175              symlink = "",
176              symlink_open = "",
177            },
178            git = {
179              unstaged = "➜",
180              staged = "✓",
181              unmerged = "",
182              renamed = "➜",
183              untracked = "★",
184              deleted = "✗",
185              -- deleted = "",
186              ignored = "◌",
187            },
188          },
189        },
190      },
191      diagnostics = {
192        enable = true,
193        show_on_dirs = true,
194        show_on_open_dirs = true,
195        debounce_delay = 50,
196        severity = {
197          min = vim.diagnostic.severity.HINT,
198          max = vim.diagnostic.severity.ERROR,
199        },
200        icons = {
201          hint = "",
202          info = "",
203          warning = "",
204          error = "",
205        },
206      },
207      hijack_cursor = false,
208      auto_reload_on_write = true,
209      disable_netrw = false,
210      hijack_netrw = true,
211      hijack_unnamed_buffer_when_opening = false,
212      root_dirs = {},
213      prefer_startup_root = false,
214      sync_root_with_cwd = false,
215      reload_on_bufenter = false,
216      respect_buf_cwd = false,
217      select_prompts = false,
218      sort = {
219        sorter = "name",
220        folders_first = true,
221        files_first = false,
222      },
223      view = {
224        centralize_selection = false,
225        cursorline = true,
226        debounce_delay = 15,
227        side = "left",
228        preserve_window_proportions = false,
229        number = false,
230        relativenumber = false,
231        signcolumn = "yes",
232        width = 30,
233        float = {
234          enable = false,
235          quit_on_focus_loss = true,
236          open_win_config = {
237            relative = "editor",
238            border = "rounded",
239            width = 30,
240            height = 30,
241            row = 1,
242            col = 1,
243          },
244        },
245      },
246      hijack_directories = {
247        enable = true,
248        auto_open = true,
249      },
250      system_open = {
251        cmd = "",
252        args = {},
253      },
254      modified = {
255        enable = false,
256        show_on_dirs = true,
257        show_on_open_dirs = true,
258      },
259      live_filter = {
260        prefix = "[FILTER]: ",
261        always_show_folders = true,
262      },
263      filesystem_watchers = {
264        enable = true,
265        debounce_delay = 50,
266        ignore_dirs = {},
267      },
268      trash = {
269        cmd = "gio trash",
270      },
271      tab = {
272        sync = {
273          open = false,
274          close = false,
275          ignore = {},
276        },
277      },
278      notify = {
279        threshold = vim.log.levels.ERROR,
280        absolute_path = true,
281      },
282      help = {
283        sort_by = "key",
284      },
285      ui = {
286        confirm = {
287          remove = true,
288          trash = true,
289          default_yes = true,
290        },
291      },
292      experimental = {},
293      log = {
294        enable = false,
295        truncate = false,
296        types = {
297          all = false,
298          config = false,
299          copy_paste = false,
300          dev = false,
301          diagnostics = false,
302          git = false,
303          profile = false,
304          watcher = false,
305        },
306      },
307    })
308  end
309}

nvim-web-devicons.lua UI 组件

为各种 UI 组件(如 nvim-tree, lualine)提供文件类型图标:

 1return {
 2  "nvim-tree/nvim-web-devicons",
 3  config = function()
 4    require("nvim-web-devicons").set_icon({
 5      gql = {
 6        icon = "",
 7        color = "#e535ab",
 8        cterm_color = "199",
 9        name = "GraphQL",
10      },
11    })
12  end,
13}

rainbow-delimiters.lua 彩虹符号

为配对的符号(比如 ()[]{})的不同层级添加不同的颜色,方便区分:

1return {
2    "hiphish/rainbow-delimiters.nvim",
3}

surround.lua 环绕符号增强

方便地添加、修改和删除环绕符号,例如将 hello 变为 "hello"

 1return {
 2  "kylechui/nvim-surround",
 3  event = { "BufReadPre", "BufNewFile" },
 4  version = "*", -- Use for stability; omit to use `main` branch for the latest features
 5  config = function()
 6    require("nvim-surround").setup({
 7      keymaps = {
 8        insert = false,
 9        insert_line = false,
10        normal = false,
11        normal_cur = false,
12        normal_line = false,
13        normal_cur_line = false,
14        visual = "<S-s>", -- Press <S-s> and surround sign, like ( < " ' { [
15        visual_line = false,
16        delete = false,
17        change = false,
18      },
19      aliases = {
20        ["a"] = false,
21        ["b"] = false,
22        ["B"] = false,
23        ["r"] = false,
24        ["q"] = false,
25        ["s"] = false,
26      },
27    })
28  end
29}

telescope.lua 模糊搜索

一个高度可扩展的模糊搜索工具,用于快速查找文件、缓冲区、Git 提交、帮助文档等:

  1return {
  2  "nvim-telescope/telescope.nvim",
  3  branch = "0.1.x",
  4  dependencies = {
  5    "nvim-lua/plenary.nvim",
  6    "debugloop/telescope-undo.nvim",
  7    {
  8      "nvim-telescope/telescope-fzf-native.nvim",
  9      build = "make",
 10    },
 11    "nvim-tree/nvim-web-devicons",
 12  },
 13  config = function()
 14    local telescope = require("telescope")
 15    local actions = require("telescope.actions")
 16
 17    telescope.setup({
 18      defaults = {
 19        path_display = { "truncate " },
 20        mappings = {
 21          i = {
 22            -- ["<C-n>"] = actions.cycle_history_next,
 23            -- ["<C-p>"] = actions.cycle_history_prev,
 24
 25            ["<C-j>"] = actions.move_selection_next,
 26            ["<C-k>"] = actions.move_selection_previous,
 27
 28            ["<C-c>"] = actions.close,
 29
 30            ["<Down>"] = actions.move_selection_next,
 31            ["<Up>"] = actions.move_selection_previous,
 32
 33            ["<CR>"] = actions.select_default,
 34            -- ["<C-x>"] = actions.select_horizontal,
 35            -- ["<C-v>"] = actions.select_vertical,
 36            -- ["<C-t>"] = actions.select_tab,
 37
 38            ["<C-u>"] = actions.preview_scrolling_up,
 39            ["<C-d>"] = actions.preview_scrolling_down,
 40
 41            ["<PageUp>"] = actions.results_scrolling_up,
 42            ["<PageDown>"] = actions.results_scrolling_down,
 43
 44            ["<Tab>"] = actions.toggle_selection + actions.move_selection_worse,
 45            ["<S-Tab>"] = actions.toggle_selection + actions.move_selection_better,
 46            ["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
 47            ["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
 48            -- ["<C-l>"] = actions.complete_tag,
 49            -- ["<C-_>"] = actions.which_key, -- keys from pressing <C-/>
 50          },
 51          n = {
 52            ["<esc>"] = actions.close,
 53            ["<CR>"] = actions.select_default,
 54            -- ["<C-x>"] = actions.select_horizontal,
 55            -- ["<C-v>"] = actions.select_vertical,
 56            -- ["<C-t>"] = actions.select_tab,
 57
 58            ["<Tab>"] = actions.toggle_selection + actions.move_selection_worse,
 59            ["<S-Tab>"] = actions.toggle_selection + actions.move_selection_better,
 60            ["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
 61            ["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
 62
 63            ["j"] = actions.move_selection_next,
 64            ["k"] = actions.move_selection_previous,
 65            ["K"] = actions.move_to_top,
 66            -- ["M"] = actions.move_to_middle,
 67            ["J"] = actions.move_to_bottom,
 68
 69            ["<Down>"] = actions.move_selection_next,
 70            ["<Up>"] = actions.move_selection_previous,
 71            ["gg"] = actions.move_to_top,
 72            ["G"] = actions.move_to_bottom,
 73
 74            ["<C-u>"] = actions.preview_scrolling_up,
 75            ["<C-d>"] = actions.preview_scrolling_down,
 76
 77            ["<PageUp>"] = actions.results_scrolling_up,
 78            ["<PageDown>"] = actions.results_scrolling_down,
 79
 80            ["?"] = actions.which_key,
 81          },
 82        },
 83      },
 84      load_extension = {
 85        "fzf",
 86        "yank_history",
 87      },
 88      extensions = {
 89        undo = {
 90          mappings = {
 91            i = {
 92              ["<C-a>"] = require("telescope-undo.actions").yank_additions,
 93              ["<C-d>"] = require("telescope-undo.actions").yank_deletions,
 94              ["<C-u>"] = require("telescope-undo.actions").restore,
 95              -- ["<C-Y>"] = require("telescope-undo.actions").yank_deletions,
 96              -- ["<C-cr>"] = require("telescope-undo.actions").restore,
 97              -- alternative defaults, for users whose terminals do questionable things with modified <cr>
 98            },
 99            n = {
100              ["y"] = require("telescope-undo.actions").yank_additions,
101              ["Y"] = require("telescope-undo.actions").yank_deletions,
102              ["u"] = require("telescope-undo.actions").restore,
103            },
104          },
105        },
106      },
107    })
108  end,
109}

todo-comments.lua 高亮代码注释

高亮代码中的 TODOWARNINGNOTEHACKPERFFIX 等特殊注释:

1return {
2    "folke/todo-comments.nvim",
3    dependencies = { "nvim-lua/plenary.nvim" },
4    opts = {
5    }
6}

treesitter.lua 语法高亮

提供更快速、更精确的语法高亮和代码结构分析:

 1return {
 2  "nvim-treesitter/nvim-treesitter",
 3  event = { "BufReadPre", "BufNewFile" },
 4  build = ":TSUpdate",
 5  dependencies = {
 6    "JoosepAlviste/nvim-ts-context-commentstring",
 7    "windwp/nvim-ts-autotag",
 8  },
 9  config = function()
10    require("nvim-treesitter.configs").setup({
11      -- enable syntax highlighting
12      highlight = {
13        enable = true,
14        disable = { "css", "latex", "markdown", "cls" }, -- list of language that will be disabled
15      },
16      -- enable indentation
17      indent = { enable = true },
18      -- enable autotagging (w/ nvim-ts-autotag plugin)
19      autotag = {
20        enable = false,
21      },
22      -- ensure these language parsers are installed
23      ensure_installed = {
24        "bash",
25        "lua",
26        "vim",
27        "gitignore",
28        "python",
29        "c",
30        "cpp",
31        "bibtex",
32        "vimdoc",
33        -- "latex",
34      },
35      auto_install = true,
36      ignore_install = { "latex" }, -- List of parsers to ignore installing
37      autopairs = {
38        enable = true,
39      },
40      -- indent = { enable = false, disable = { "latex", "python", "css" } },
41      incremental_selection = {
42        enable = true,
43        keymaps = {
44          init_selection = "<C-n>",
45          node_incremental = "<C-n>",
46          scope_incremental = false,
47          node_decremental = "<C-p>",
48        },
49      },
50    })
51
52    -- enable nvim-ts-context-commentstring plugin for commenting tsx and jsx
53    require("ts_context_commentstring").setup({})
54  end,
55}

vimtex.lua $\LaTeX$ 集成

为 LaTeX 提供了强大的支持,包括编译、预览、目录、语法高亮等:

 1return {
 2  "lervag/vimtex",
 3  ft = { "tex", "bib", "cls" }, -- 只在打开 .tex, .bib, .cls 文件时加载
 4  init = function()
 5    -- Indentation settings
 6    vim.g.vimtex_indent_enabled = false            -- Disable auto-indent from Vimtex
 7    vim.g.tex_indent_items = false                 -- Disable indent for enumerate
 8    vim.g.tex_indent_brace = false                 -- Disable brace indent
 9
10    -- Suppression settings
11    vim.g.vimtex_quickfix_mode = 0                 -- Suppress quickfix on save/build
12
13    -- Other settings
14    vim.g.vimtex_mappings_enabled = false          -- Disable default mappings
15    vim.g.tex_flavor = 'latex'                     -- Set file type for TeX files
16  end,
17}

which-key.lua 编辑体验增强

当按下 <leader> 键后,弹窗提示所有可用的后续快捷键,同时定义了大量围绕文件、编译、Git 和 Telescope 的快捷键:

  1return {
  2  "folke/which-key.nvim",
  3  commit = '*',
  4  event = "VeryLazy",
  5  init = function()
  6    vim.o.timeout = true
  7    vim.o.timeoutlen = 200
  8  end,
  9  opts = {
 10    setup = {
 11      show_help = true,
 12      plugins = {
 13        presets = {
 14          operators = false,    -- adds help for operators like d, y, ... and registers them for motion / text object completion
 15          motions = false,      -- adds help for motions
 16          text_objects = false, -- help for text objects triggered after entering an operator
 17          windows = false,      -- default bindings on <c-w>
 18          nav = false,          -- misc bindings to work with windows
 19          z = false,            -- bindings for folds, spelling and others prefixed with z
 20          g = false,            -- bindings for prefixed with g
 21          marks = false,        -- shows a list of your marks on ' and `
 22          registers = false,    -- shows your registers on " in NORMAL or <C-r> in INSERT mode
 23          spelling = {
 24            enabled = false,    -- enabling this will show WhichKey when pressing z= to select spelling suggestions
 25            suggestions = 10,   -- how many suggestions should be shown in the list?
 26          },
 27          -- the presets plugin, adds help for a bunch of default keybindings in Neovim
 28          -- No actual key bindings are created
 29        },
 30      },
 31      key_labels = {
 32        -- override the label used to display some keys. It doesn't effect WK in any other way.
 33        -- For example:
 34        -- ["<space>"] = "SPC",
 35        -- ["<CR>"] = "RET",
 36        -- ["<tab>"] = "TAB",
 37      },
 38      -- triggers = "auto", -- automatically setup triggers
 39      triggers = { "<leader>" }, -- or specify a list manually
 40      -- add operators that will trigger motion and text object completion
 41      -- to enable native operators, set the preset / operators plugin above
 42      -- operators = { gc = "Comments" },
 43      icons = {
 44        breadcrumb = "»", -- symbol used in the command line area that shows your active key combo
 45        separator = "➜", -- symbol used between a key and it's label
 46        group = "+",      -- symbol prepended to a group
 47      },
 48      popup_mappings = {
 49        scroll_down = "<c-d>", -- binding to scroll down inside the popup
 50        scroll_up = "<c-u>",   -- binding to scroll up inside the popup
 51      },
 52      window = {
 53        border = "rounded",       -- none, single, double, shadow
 54        position = "bottom",      -- bottom, top
 55        margin = { 1, 0, 1, 0 },  -- extra window margin [top, right, bottom, left]
 56        padding = { 2, 2, 2, 2 }, -- extra window padding [top, right, bottom, left]
 57        winblend = 0,
 58        zindex = 1000,            -- positive value to position WhichKey above other floating windows.
 59      },
 60      layout = {
 61        height = { min = 4, max = 25 },                                             -- min and max height of the columns
 62        width = { min = 20, max = 50 },                                             -- min and max width of the columns
 63        spacing = 3,                                                                -- spacing between columns
 64        align = "left",                                                             -- align columns left, center or right
 65      },
 66      ignore_missing = true,                                                        -- enable this to hide mappings for which you didn't specify a label
 67      hidden = { "<silent>", "<cmd>", "<Cmd>", "<CR>", "call", "lua", "^:", "^ " }, -- hide mapping boilerplate
 68      triggers_nowait = {
 69      },
 70      triggers_blacklist = {
 71        -- list of mode / prefixes that should never be hooked by WhichKey
 72        -- this is mostly relevant for key maps that start with a native binding
 73        -- most people should not need to change this
 74        i = { "j", "k" },
 75        v = { "j", "k" },
 76      },
 77      -- disable the WhichKey popup for certain buf types and file types.
 78      -- Disabled by default for Telescope
 79      disable = {
 80        buftypes = {},
 81        filetypes = {},
 82      },
 83    },
 84    defaults = {
 85      buffer = nil,   -- Global mappings. Specify a buffer number for buffer local mappings
 86      silent = true,  -- use `silent` when creating keymaps
 87      noremap = true, -- use `noremap` when creating keymaps
 88      nowait = true,  -- use `nowait` when creating keymaps
 89      prefix = "<leader>",
 90      mode = { "n", "v" },
 91      d = { "<cmd>update! | bdelete!<CR>", "delete buffer" },
 92      e = { "<cmd>NvimTreeToggle<CR>", "explorer" },
 93      i = { "<cmd>VimtexTocOpen<CR>", "index" },
 94      k = {
 95        function()
 96          -- Initialize variables
 97          local filename = vim.fn.expand("%:p")       -- Complete file path
 98          local basename = vim.fn.expand("%:t:r")     -- File names without extensions
 99          local filetype = vim.bo.filetype            -- Current file type
100          local deleted_files = {}
101          local messages = {}
102
103          -- Clean up the compiled products (c/cpp)
104          if filetype == "c" or filetype == "cpp" then
105            local targets = { ".exe", ".o" }
106            for _, ext in ipairs(targets) do
107              local file = basename .. ext
108              local full_path = vim.fn.fnamemodify(filename, ":h") .. "\\" .. file
109              if vim.fn.filereadable(full_path) == 1 then
110                os.remove(full_path)
111                table.insert(deleted_files, file)
112              end
113            end
114          end
115
116          -- Conditional execution of VimtexClean (LaTeX files only)
117          if filetype == "tex" then
118            vim.cmd("VimtexClean")  -- Clean up LaTeX auxiliary files
119            table.insert(messages, "[LaTeX] already clean auxiliary files.")
120          end
121
122          -- Generate feedback information
123          if #deleted_files > 0 then
124            table.insert(messages, 1, "[Code] already clean compile files:\n" .. table.concat(deleted_files, "\n"))
125          end
126          if #messages == 0 then
127            table.insert(messages, "[Code] no auxiliary file need to clean.")
128          end
129
130          -- Show notification
131          vim.notify(table.concat(messages, "\n\n"), "info", {
132            title = "Clean Auxiliary",
133            timeout = 3000
134          })
135        end,
136        "kill aux"
137      },
138      q = { "<cmd>wa! | qa!<CR>", "quit" },
139      r = {
140        function()
141          local filename = vim.fn.expand("%:p")
142          local basename = vim.fn.expand("%:t:r")
143          local filetype = vim.bo.filetype
144          local cmd = ""
145          local quoted_filename = string.format('"%s"', filename) -- Handle paths containing Spaces
146
147          -- Dynamically select operations based on file types
148          if filetype == "tex" then
149            -- LaTeX file: Triggers VimtexCompile compilation
150            vim.cmd("VimtexCompile")
151            return
152          elseif filetype == "python" then
153            cmd = "python " .. quoted_filename
154          elseif filetype == "cpp" then
155            local exe_name = basename .. ".exe"
156            cmd = string.format("g++ %s -o %s && .\\%s", quoted_filename, exe_name, exe_name)
157          elseif filetype == "c" then
158            local exe_name = basename .. ".exe"
159            cmd = string.format("gcc %s -o %s && .\\%s", quoted_filename, exe_name, exe_name)
160          else
161            vim.notify("unsupported file type: " .. filetype, "error", { title = "Run/Compile" })
162            return
163          end
164
165          -- Execute the command and display the output
166          local output = vim.fn.system(cmd)
167          vim.api.nvim_echo({{output, "Normal"}}, false, {})
168        end,
169        "run code"
170      },
171      u = { "<cmd>Telescope undo<CR>", "undo history" },
172      v = { "<cmd>VimtexView<CR>", "view" },
173      w = { "<cmd>wa!<CR>", "write" },
174      a = {
175        name = "ACTIONS",
176        c = { "<cmd>vert sb<CR>", "create split" },
177        h = { "<cmd>LocalHighlightToggle<CR>", "local highlight toggle" },
178        j = { "<cmd>clo<CR>", "drop split" },
179        k = { "<cmd>clo<CR>", "kill split" },
180        m = { "<cmd>on<CR>", "max split" },
181        r = { "<cmd>VimtexErrors<CR>", "report errors" },
182        w = { "<cmd>VimtexCountWords!<CR>", "word count" },
183      },
184      c = {
185        name = "Copilot",
186        d = {
187          function()
188            vim.cmd("Copilot disable")
189            vim.notify("[Copilot] Copilot disabled", vim.log.levels.INFO, { title = "Copilot Status" })
190          end,
191          "disable Copilot"
192        },
193        e = {
194          function()
195            vim.cmd("Copilot enable")
196            vim.notify("[Copilot] Copilot enabled", vim.log.levels.INFO, { title = "Copilot Status" })
197          end,
198          "enable Copilot"
199        },
200      },
201      f = {
202        name = "FIND",
203        b = {
204          "<cmd>lua require('telescope.builtin').buffers(require('telescope.themes').get_dropdown{previewer = false})<CR>",
205          "buffers",
206        },
207        f = { "<cmd>Telescope live_grep theme=ivy<CR>", "project" },
208        g = { "<cmd>Telescope git_commits<CR>", "git history" },
209        h = { "<cmd>Telescope help_tags<CR>", "help" },
210        k = { "<cmd>Telescope keymaps<CR>", "keymaps" },
211        r = { "<cmd>Telescope registers<CR>", "registers" },
212        w = { "<cmd>lua SearchWordUnderCursor()<CR>", "word" },
213        r = { "<cmd>Telescope oldfiles<CR>", "recent" },
214      },
215      g = {
216        name = "GIT",
217        b = { "<cmd>Telescope git_branches<CR>", "checkout branch" },
218        c = { "<cmd>Telescope git_commits<CR>", "commits" },
219        d = { "<cmd>Gitsigns diffthis HEAD<CR>", "diff" },
220        k = { "<cmd>Gitsigns prev_hunk<CR>", "prev hunk" },
221        j = { "<cmd>Gitsigns next_hunk<CR>", "next hunk" },
222        l = { "<cmd>Gitsigns blame_line<CR>", "line blame" },
223        p = { "<cmd>Gitsigns preview_hunk<CR>", "preview hunk" },
224        t = { "<cmd>Gitsigns toggle_current_line_blame<CR>", "toggle blame" },
225      },
226    },
227  },
228  config = function(_, opts)
229    local wk = require("which-key")
230    wk.setup(opts.setup)
231    wk.register(opts.defaults)
232  end,
233}

snippets 文件夹

文件夹中的每一个文件对应于一种文件后缀相应的代码段,比如要配置 .tex 文件相应的 Neovim 加载的代码段,就创建一个 tex.lua 文件,这个文件中相应的代码段只会在 Neovim 打开对应于 .tex 文件时起作用。如果要配置对应于所有的文件类型的文件,就是说如果要配置代码段对所有的文件都生效,则要把相应的代码段放在 all.lua 文件中(如果没有这个文件可以创建一个)。

对应的教程可以参考:

tex.lua $LaTeX$ 配置文件

  1-- Summary: When `LS_SELECT_RAW` is populated with a visual selection, the function
  2-- returns an insert node whose initial text is set to the visual selection.
  3-- When `LS_SELECT_RAW` is empty, the function simply returns an empty insert node.
  4local get_visual = function(args, parent)
  5  if (#parent.snippet.env.LS_SELECT_RAW > 0) then
  6    return sn(nil, i(1, parent.snippet.env.LS_SELECT_RAW))
  7  else  -- If LS_SELECT_RAW is empty, return a blank insert node
  8    return sn(nil, i(1))
  9  end
 10end
 11
 12-- Example: expanding a snippet on a new line only.
 13-- In a snippet file, first require the line_begin condition...
 14-- ...then add `condition=line_begin` to any snippet's context table:
 15local line_begin = require("luasnip.extras.expand_conditions").line_begin
 16
 17-- Include this `in_mathzone` function at the start of a snippets file...
 18-- Then include `condition = in_mathzone` to any snippet you want to
 19-- expand only in math contexts.
 20local in_mathzone = function()
 21  -- The `in_mathzone` function requires the VimTeX plugin
 22  return vim.fn['vimtex#syntax#in_mathzone']() == 1
 23end
 24
 25return {
 26--------------------------------------------------
 27-- Example: use of insert node placeholder text --
 28--------------------------------------------------
 29	s({ trig="hr", dscr="The hyperref package's href{}{} command (for url links)" },
 30	  fmta(
 31	    [[\href{<>}{<>}]],
 32	    {
 33	      i(1, "url"),
 34	      i(2, "display name"),
 35	    }
 36	  )
 37	),
 38--------------------------------------------------------
 39-- Example: italic font implementing visual selection --
 40--------------------------------------------------------
 41	s({ trig="tii", dscr="Expands 'tii' into LaTeX's textit{} command." },
 42	  fmta("\\textit{<>}",
 43	    {
 44	      d(1, get_visual),
 45	    }
 46	  )
 47	),
 48----------------------------------
 49-- A fun zero subscript snippet --
 50----------------------------------
 51	s({ trig='([%a%)%]%}])00', regTrig=true, wordTrig=false, snippetType="autosnippet" },
 52	  fmta(
 53	    "<>_{<>}",
 54	    {
 55	      f( function(_, snip) return snip.captures[1] end ),
 56	      t("0")
 57	    }
 58	  )
 59	),
 60-----------------------------------
 61-- Snippets for only in new line --
 62-----------------------------------
 63	-- HTML-like to insert directory hierarchy
 64	s({ trig="h1", snippetType="autosnippet", condition=line_begin },
 65	  fmta(
 66	    [[\section{<>}]],
 67	    { d(1, get_visual) }
 68	  )
 69	),
 70
 71	s({ trig="h2", snippetType="autosnippet", condition=line_begin },
 72	  fmta(
 73	    [[\subsection{<>}]],
 74	    { d(1, get_visual) }
 75	  )
 76	),
 77
 78	s({ trig="h3", snippetType="autosnippet", condition=line_begin },
 79	  fmta(
 80	    [[\section{<>}]],
 81	    { d(1, get_visual) }
 82	  )
 83	),
 84
 85	-- Begin new environment
 86	s({ trig="env", dscr="A generic new environmennt", condition=line_begin },
 87	  fmta(
 88	    [[
 89	      \begin{<>}
 90	          <>
 91	      \end{<>}
 92	    ]],
 93	    {
 94	      i(1),
 95	      i(2),
 96	      rep(1),
 97	    }
 98	  )
 99	),
100------------------------------------
101-- Snippets for only in math mode --
102------------------------------------
103	-- Fraction
104	s({ trig = "ff", snippetType="autosnippet", condition=in_mathzone },
105	  fmta(
106	    "\\frac{<>}{<>}",
107	    {
108	      i(1),
109	      i(2),
110	    }
111	  )
112	),
113
114	-- Greek letter
115	s({ trig=";a", snippetType="autosnippet", condition=in_mathzone },
116	  {
117	    t("\\alpha"),
118	  }
119	),
120	s({ trig=";b", snippetType="autosnippet", condition=in_mathzone },
121	  {
122	    t("\\beta"),
123	  }
124	),
125	s({ trig=";g", snippetType="autosnippet", condition=in_mathzone },
126	  {
127	    t("\\gamma"),
128	  }
129	),
130}