前排提示:我采用的配置是基于 这个配置进行改进的,如果对 Neovim 和 LaTeX 有基本的使用经验可以直接参考给出的链接。

如果对哪些部分不清楚或者对某个部分的具体实现感兴趣,可以私信或者评论,我会针对内容进行更新。

最终效果展示:

为什么有这篇文章

在写这篇文章之前,我已经使用 Vim (主要是用的 VS Code 的 Neovim 插件)和 $\LaTeX$ 一段时间了,之前一直都是使用 VS Code 和 $\LaTeX$ 插件的解决方案,但是最终还是觉得 Neovim 的实现更加优雅,也更符合我的习惯和解决我的一些痛点:

  • 经常使用 Windows Terminal
  • VS Code 的 Neovim 插件时不时会遇到一些无法解决的 Bug
  • 使用 Neovim 插件没办法实现一些自定义的操作和更改配置,这点在我要增加一些功能的时候尤为难受
  • 加快启动和编译的速度,特别是针对大文件
  • 保留上个世纪程序员的炫酷

参考了很多解决方案,都没有一个比较完美的符合我痛点的配置,于是只好自己根据现有的解决方案改良了一下,主要的功能有:

  • 语法高亮
  • $\LaTeX$ 正向搜索、反向搜索
  • 文件检索、模糊查找
  • 整合 Lazygit 实现版本管理
  • 采用 Lua 编写,更加符合 Neovim 的习惯
  • 利用 VimTeX 实现编译、查看 $\LaTeX$ 文件
  • 支持 LSP 自动补全、代码提示(支持 $\LaTeX$, C++)
  • 格式化代码(支持 $\LaTeX$, C++)
  • 支持在 Neovim 中刷 LeetCode
  • 支持中英输入法混用(在 Normal 模式英文输入法,在 Insert 模式下中文输入法)
  • ……

什么是 Neovim

如果你听过编辑器之神 Vim 和神之编辑器 Emacs 的话,那么就很好理解 Neovim 了,它就是 Vim 的一个社区版,如果你对它的历史感兴趣,可以到 Neovim 的官网 查看。

关于 Vim 和 Neovim 的历史还可以查看: Vim 和 Neovim 的前世今生 · jdhao’s digital space

一些可能有用的链接

快速入门

快捷键速查表

在哪里找插件

学习 Vim & Neovim

配置 Neovim

第三方博客的介绍:

中文博客

英文博客

为什么是 Neovim 而不是 Vim

遇到问题请看我

一些建议

其他链接

安装 Neovim

由于我使用 Windows 10 的 scoop 软件来管理安装其他软件,所以只需要一行命令就能安装:

1scoop install main/neovim

如果是其他的安装方法可以参考 官方文档

如果你还不熟悉 Vim 的操作,可以打开 Neovim,然后进入命令模式,输入下面的代码就可以进入一个大概30分钟的交互式教程:

1:Tutor

配置 Neovim

无论是开箱即用还是自己配置,最终目的都是为了方便自己,切莫本末倒置。也不必追求一次性就将自己的配置做到最优,可以在使用中发现缺少什么再去补全,这样会使得整个过程更加容易一些,当然如果想要体验一下完全体还是建议先下载几个开箱即用的配置试试看。

开箱即用

如果不想自己配置 Neovim 也有很多开箱即用的配置可以参考:

打造属于自己的 Neovim

Windows 10 中 Neovim 的配置文件一般在 ~/AppData/Local/nvim/init.vim (Windows) 这个路径下, ~ 表示当前用户的目录,比如用户名为 Beta 的用户的路径一般为 C:/Users/Abel/AppData/Local/nvim/init.vim 。Neovim 启动时会加载 init.vim 文件,所以只需要在这个文件中进行配置就可以。

我的配置文件会加上大部分的注释,基本上是自解释的,如果还有不懂的部分,比如 og 分别是什么,可以参考官方给出的 文档,下面给出我的配置文件的结构,以下默认当前文件夹是在前面提到的 nvim 下:

 1~/AppData/Local/nvim
 2│   init.lua -- 自动加载
 3│   lazy-lock.json
 4 5 6└───lua
 7    ├───config --存放配置文件
 8    │       keymaps.lua -- 按键映射设置
 9    │       lazy.lua -- lazy.nvim 懒加载插件用于管理插件
10    │       options.lua -- 原生 Neovim 支持的设置
1112    └───plugins

如何生成文件树:利用 Windows 10 的 tree 命令:

1tree /f >tree.txt

会将当前目录下的文件树的结果导出到 tree.txt 文件中,如果没有这个文件则会创建文件并写入结果。

配置文件

init.lua 文件是 Neovim 启动时会加载的配置文件,可以按照文件树结构来安排各种设置,便于分类和查找:

1-- ---------- 本地配置 ---------- --
2require("config.options") -- 选项
3require("config.keymaps") -- 按键设置
4
5-- ---------- 插件管理 ---------- --
6require("config.lazy") -- Lazy.nvim 进行插件管理

options.lua 文件主要放了 Neovim 原本就支持的一些设置,包括行号、高亮、编码等等,所以会显得比较杂乱:

 1-- local g = vim.g
 2-- local opt = vim.opt
 3
 4-- opt.completeopt = "menu, menuone, noselect, noinsert", -- 补全选项设置
 5
 6-- leader 按键设置
 7-- g.mapleader = " "
 8-- g.maplocalleader = "\\"
 9
10local options = {
11
12  -- GENERAL
13  timeoutlen = 500,               -- time to wait for a mapped sequence to complete (in milliseconds), 键盘快捷键等待时间
14  updatetime = 300,               -- faster completion (4000ms default), 更新检查间隔时间
15  swapfile = false,               -- creates a swapfile, 禁止创建 swap 文件
16  undofile = true,                -- enable persistent undo
17  writebackup = false,            -- if a file is being edited by another program, it is not allowed to be edited, 禁止写入备份文件
18  backup = false,  				  -- 禁止创建备份文件
19  confirm = true,  				  -- 没有保存或文件只读时弹出确认
20
21  -- APPEARANCE
22  fileencoding = "utf-8",         -- the encoding written to a file, 保存文件的时候使用 UTF-8 编码
23  encoding = "UTF-8", 			  -- 当处理文本的时候使用 UTF-8 编码
24  -- guifont = "monospace:h17",      -- the font used in graphical neovim applications
25  background = "dark",            -- colorschemes that can be light or dark will be made dark, 设置背景为暗色
26  termguicolors = true,           -- set term gui colors (most terminals support this), 开启终端真彩色支持
27  conceallevel = 0,               -- so that `` is visible in markdown files
28  number = true,                  -- set numbered lines, 显示行号
29  relativenumber = true,          -- set relative numbered lines, 使用相对行号
30  -- numberwidth = 2,                -- set number column width to 2 {default 4}
31  signcolumn = "yes",             -- always show the sign column, otherwise it would shift the text each time, 左侧始终显示符号列
32  cursorline = true,              -- highlight the current line, 高亮当前行
33  -- colorcolumn = "100",             -- highlight vertical colorcolumn (moved to after/python.lua), 右侧第 100 列显示颜色参考线
34  wrap = true,                    -- display lines as one long line, 启用折行
35  showbreak = "  ",               -- set indent of wrapped lines
36  cmdheight = 1,                  -- space in the neovim command line for displaying messages, 命令行高度
37  pumheight = 10,                 -- pop up menu height, 补全菜单高度为 10 行
38  wildmenu = true, 				  -- 显示补全菜单
39  -- showmode = false,               -- we don't need to see things like -- INSERT -- anymore
40  splitbelow = true,              -- force all horizontal splits to go below current window, 水平分屏默认在下方
41  splitright = true,              -- force all vertical splits to go to the right of current window, 垂直分屏默认在右侧
42  scrolloff = 999,                  -- minimal number of screen lines to keep above and below the cursor, 光标上下保持 999 行距离,实现类似 Typora 的打字机的效果
43  sidescrolloff = 8,              -- minimal number of screen columns either side of cursor if wrap is `false`, 光标左右保持 8 列距离
44  shortmess = "filnxtToOFc",      -- which errors to suppress
45  mousemoveevent = true,
46  -- shortmess:append "atI", 		  -- 隐去启动的提示信息
47
48  -- INDENT
49  tabstop = 4,                    -- insert 4 spaces for a tab, Tab 键相当于 4 个空格
50  shiftwidth = 4,                 -- the number of spaces inserted for each indentation, 自动缩进时移动 4 个空格
51  softtabstop = 4,                -- insert 2 spaces for a tab, 编辑时 Tab 键为 4 个空格
52  expandtab = true,               -- convert tabs to spaces, Tab 替换为空格
53  breakindent = true,             -- tab wrapped lines
54  linebreak = true,               -- companion to wrap, don't split words
55  backspace = "indent,eol,start", -- allow backspace on indent, end of line or insert mode start position
56  smarttab = true, 				  -- 开启智能 Tab
57  shiftround = true,              -- 使用 >> 和 << 移动时对齐到 shiftwidth 的倍数
58  cindent = true,				  -- C 文件自动缩进
59  autoindent = true,			  -- 新行缩进对齐到当前行
60  smartindent = true,			  -- 开启智能缩进
61
62  -- EDIT
63  -- spell = true,                   -- turns on spellchecker, 支持拼写检查
64  -- spelllang = { 'en_us', 'cjk' },        -- sets spelling dictionary, 对英文进行拼写检查, 忽略中文的拼写检查
65  clipboard = "unnamedplus",      -- allows neovim to access the system clipboard, 使用系统剪贴板
66  mouse = "a",                    -- allow the mouse to be used in neovim, 开启鼠标支持
67  mousescroll = "ver:2,hor:4",    -- change the speed of the scroll wheel
68  ignorecase = true,              -- ignore case in search patterns, 搜索时不区分大小写
69  smartcase = true,               -- smart case, 搜索包含大写字母时,自动区分大小写
70  hlsearch = true, 				  -- 搜索高亮
71  incsearch = true, 			  -- 输入搜索模式时,每输入一个字符,就自动跳到第一个匹配的结果
72  showmatch = true, 			  -- 高亮匹配的括号
73  virtualedit = "block",          -- vitualblock mode doesn't get stuck at the end of line
74  inccommand = "split",           -- shows all inline replacements in split
75  autoread = true,				  -- 外部文件修改自动加载
76  whichwrap = "<,>,[,]",		  -- 光标移到行首或行尾时,可跨行移动
77  list = false,					  -- 不显示不可见字符
78  listchars = "space:·,tab:>-",   -- 空格和 Tab 的显示方式
79
80}
81
82-- turns on all values in options table above
83for k, v in pairs(options) do
84  vim.opt[k] = v
85end

在 Neovim/Vim 中直接输入 / 就可以查找,比如 /include 就是查找文件中包含 include 的词,同样有大小写敏感,要关闭大小写敏感,可以使用命令 vim.o.ignorecase = true

查看查找的历史记录可以输入 / 之后用方向键来查找之前查找的记录。当然这需要在查找之后按下回车进行实际的查找才会进行记录,否则如果只是在命令中查找而不按下回车键是不会进行记录的。

如果记得之前查找历史中的某个开头的字母,比如之前运用过 /search 命令查找了 search 这个单词,然后之后又进行了多次查询,并且在查询之后都按下了回车键,这会把查找历史记录下来,那么想要快速找到之前的某个查找记录,那么就可以先输入 /sea 然后按下方向键就可以在以 sea 开头的查找记录中跳转。

当然 : 的命令模式也有类似以上的功能,但是 : 命令的历史记录和 / 命令的历史记录是分开的。

搜索当前光标指示的单词,当然可以使用 / 命令手动输入当前光标所指示的单词,但是也可以用 * 来直接搜索当前光标所指示的单词在文本中出现的下一个位置,这样不容易在 / 输入中拼写错误,而 # 命令向相反的方向做同样的事情。不过这两个命令会自动进行全字匹配,如果想要部分匹配的话可以用命令 g#g*

keymaps.lua 主要存放一些经常用的快捷键(可以自己设置):

1-- 暂时还没有

lazy.lua 文件是一个管理 Neovim 插件的 插件,具体的设置可以参考 官方文档

 1-- 安装 lazy.nvim 插件
 2local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
 3if not (vim.uv or vim.loop).fs_stat(lazypath) then
 4  local lazyrepo = "https://github.com/folke/lazy.nvim.git"
 5  local out = vim.fn.system({
 6  				"git", 
 7  				"clone", 
 8  				"--filter=blob:none", 
 9  				"--branch=stable", 
10  				lazyrepo, 
11  				lazypath })
12  if vim.v.shell_error ~= 0 then
13    vim.api.nvim_echo({
14      { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
15      { out, "WarningMsg" },
16      { "\nPress any key to exit..." },
17    }, true, {})
18    vim.fn.getchar()
19    os.exit(1)
20  end
21end
22vim.opt.rtp:prepend(lazypath)
23
24-- 设置 lazy.nvim 插件
25require("lazy").setup({
26  spec = {
27    -- 安装插件
28    -- VimTeX 主要用于支持 LaTeX 的功能
29    {
30      "lervag/vimtex",
31      lazy = false,     -- VimTeX 不需要懒加载
32      -- tag = "v2.15", -- 取消注释以固定在某个版本
33      init = function()
34        -- 下面是有关 VimTeX 的设置
35        -- VimTeX 在 Windows 中如果能找到 SumatraPDF 就会自动设置用它打开
36        -- vim.g.vimtex_view_method = "SumatraPDF"
37      end
38    },
39  },  
40  checker = { enabled = true }, -- 自动检查插件更新
41  -- 不想使用 Nerd Font,用Unicode的图标替代
42  ui = {
43    icons = { -- 各种元素的图标配置
44      cmd = "⌘",
45      config = "🛠",
46      event = "📅",
47      ft = "📂",
48      init = "⚙",
49      keys = "🗝",
50      plugin = "🔌",
51      runtime = "💻",
52      require = "🌙",
53      source = "📄",
54      start = "🚀",
55      task = "📌",
56      lazy = "💤 ",
57    },
58  },

这里有个坑,安装 lazy.nvim 是要先安装 git 的,而且安装之后在 Neovim 中执行 :checkhealth lazy 时可能会遇到和 luarocks 有关的报错,我的解决方案是通过 Scoop 安装 luarockslua

1scoop install main/luarocks
2scoop install main/lua

插件

lazy.nvim:用于插件管理的一个插件,可以进行快速地安装、卸载、更新插件。

vimtex:Vimtex 是一个专门为 Vim 和 Neovim 设计的 LaTeX 插件,它提供了包括语法高亮、自动补全、编译支持、预览和错误检查等功能。

neovim-session-manager:Session manager是一个类似于 VS Code 管理文件夹的进程管理插件,能够保存当前进程到一个文件中方便后面直接打开。

我的相关配置文件 sessions.lua

 1return {
 2  "Shatur/neovim-session-manager",
 3  commit = 'a0b9d25154be573bc0f99877afb3f57cf881cce7', -- replace with the desired commit hash
 4  event = "VimEnter",
 5  dependencies = {
 6    "nvim-lua/plenary.nvim",
 7    "stevearc/dressing.nvim",
 8    "nvim-telescope/telescope-ui-select.nvim",
 9  },
10  config = function()
11    local Path = require('plenary.path')
12    local config = require('session_manager.config')
13    require('session_manager').setup({
14      -- sessions_dir = Path:new(vim.fn.stdpath('data'), 'sessions'), -- The directory where the session files will be saved.
15      sessions_dir = Path:new(vim.fn.stdpath('config'), 'sessions'), -- The directory where the session files will be saved.
16      -- session_filename_to_dir =  '~/.config/nvim/sessions/', -- Function that replaces symbols into separators and colons to transform filename into a session directory.
17      -- dir_to_session_filename = '~/.config/nvim/sessions/', -- Function that replaces separators and colons into special symbols to transform session directory into a filename. Should use `vim.uv.cwd()` if the passed `dir` is `nil`.
18      -- path_replacer = '__', -- The character to which the path separator will be replaced for session files.
19      -- colon_replacer = '++', -- The character to which the colon symbol will be replaced for session files.
20      autoload_mode = config.AutoloadMode.Disabled, -- Define what to do when Neovim is started without arguments. See "Autoload mode" section below.
21      autosave_last_session = true, -- Automatically save last session on exit and on session switch.
22      autosave_ignore_not_normal = true, -- Plugin will not save a session when no buffers are opened, or all of them aren't writable or listed.
23      autosave_ignore_dirs = {}, -- A list of directories where the session will not be autosaved.
24      autosave_ignore_filetypes = { -- All buffers of these file types will be closed before the session is saved.
25        'gitcommit',
26        'gitrebase',
27      },
28      autosave_ignore_buftypes = {}, -- All buffers of these bufer types will be closed before the session is saved.
29      autosave_only_in_session = true, -- Always autosaves session. If true, only autosaves after a session is active.
30      max_path_length = 80,  -- Shorten the display path if length exceeds this threshold. Use 0 if don't want to shorten the path at all.
31    })
32  end,
33}

dressing.lua

  1return {
  2  "stevearc/dressing.nvim",
  3  event = "VeryLazy",
  4  config = function()
  5    require('dressing').setup({
  6      input = {
  7        -- Set to false to disable the vim.ui.input implementation
  8        enabled = true,
  9
 10        -- Default prompt string
 11        default_prompt = "Input:",
 12
 13        -- Can be 'left', 'right', or 'center'
 14        prompt_align = "center",
 15
 16        -- When true, <Esc> will close the modal
 17        insert_only = true,
 18
 19        -- When true, input will start in insert mode.
 20        start_in_insert = true,
 21
 22        -- These are passed to nvim_open_win
 23        override = function(conf)
 24          -- This is the config that will be passed to nvim_open_win.
 25          -- Change values here to customize the layout
 26          return conf
 27        end,
 28        border = "rounded",
 29        -- 'editor' and 'win' will default to being centered
 30        relative = "cursor",
 31
 32        -- These can be integers or a float between 0 and 1 (e.g. 0.4 for 40%)
 33        prefer_width = 40,
 34        width = nil,
 35        -- min_width and max_width can be a list of mixed types.
 36        -- min_width = {20, 0.2} means "the greater of 20 columns or 20% of total"
 37        max_width = { 140, 0.9 },
 38        min_width = { 20, 0.2 },
 39
 40        -- Window transparency (0-100)
 41        -- winblend = 20, -- causing errors
 42        -- Change default highlight groups (see :help winhl)
 43        -- winhighlight = "", -- causing errors
 44
 45        -- Set to `false` to disable
 46        mappings = {
 47          n = {
 48            ["<Esc>"] = "Close",
 49            ["<CR>"] = "Confirm",
 50          },
 51          i = {
 52            ["<C-c>"] = "Close",
 53            ["<CR>"] = "Confirm",
 54            ["<Up>"] = "HistoryPrev",
 55            ["<Down>"] = "HistoryNext",
 56          },
 57        },
 58
 59
 60        -- see :help dressing_get_config
 61        get_config = nil,
 62      },
 63      select = {
 64        -- Set to false to disable the vim.ui.select implementation
 65        enabled = true,
 66
 67        -- Priority list of preferred vim.select implementations
 68        backend = { "telescope", "fzf_lua", "fzf", "builtin", "nui" },
 69
 70        -- Trim trailing `:` from prompt
 71        trim_prompt = true,
 72
 73        -- Options for telescope selector
 74        -- These are passed into the telescope picker directly. Can be used like:
 75        -- telescope = require('telescope.themes').get_ivy({...})
 76        telescope = nil,
 77
 78        -- Options for fzf selector
 79        fzf = {
 80          window = {
 81            width = 0.5,
 82            height = 0.4,
 83          },
 84        },
 85
 86        -- Options for fzf_lua selector
 87        fzf_lua = {
 88          winopts = {
 89            width = 0.5,
 90            height = 0.4,
 91          },
 92        },
 93
 94        -- Options for nui Menu
 95        nui = {
 96          position = "50%",
 97          size = nil,
 98          relative = "editor",
 99          border = {
100            style = "rounded",
101          },
102          buf_options = {
103            swapfile = false,
104            filetype = "DressingSelect",
105          },
106          -- win_options = {
107          --   winblend = 10, -- might also cause errors
108          -- },
109          max_width = 80,
110          max_height = 40,
111          min_width = 40,
112          min_height = 10,
113        },
114
115        -- Options for built-in selector
116        builtin = {
117          -- These are passed to nvim_open_win
118          override = "NW",
119          border = "rounded",
120          -- 'editor' and 'win' will default to being centered
121          relative = "editor",
122
123          -- Window transparency (0-100)
124          -- winblend = 10, -- causing errors
125          -- Change default highlight groups (see :help winhl)
126          -- winhighlight = "", -- causing errors
127
128          -- These can be integers or a float between 0 and 1 (e.g. 0.4 for 40%)
129          -- the min_ and max_ options can be a list of mixed types.
130          -- max_width = {140, 0.8} means "the lesser of 140 columns or 80% of total"
131          width = nil,
132          max_width = { 140, 0.8 },
133          min_width = { 40, 0.2 },
134          height = nil,
135          max_height = 0.9,
136          min_height = { 10, 0.2 },
137
138          -- Set to `false` to disable
139          mappings = {
140            ["<Esc>"] = "Close",
141            ["<C-c>"] = "Close",
142            ["<CR>"] = "Confirm",
143          },
144
145          -- override = function(conf)
146          --   -- This is the config that will be passed to nvim_open_win.
147          --   -- Change values here to customize the layout
148          --   return conf
149          -- end,
150        },
151
152        -- Used to override format_item. See :help dressing-format
153        format_item_override = {},
154
155        -- see :help dressing_get_config
156        get_config = nil,
157      },
158    })
159  end
160}

进阶版 Neovim

WSL 中使用 Neovim + $\LaTeX$ + VimTeX + Sioyek + Lazygit

可以参考 我的个人配置

结合 Neovim 和 $\LaTeX$

可以参考的链接

我的解决方案

根据 这个配置进行改进

keymaps.lua 的内容:

  1local opts = { noremap = true, silent = true } -- noremap 禁止递归映射,silent 禁止显示命令。
  2
  3-- local term_opts = { silent = true }
  4
  5-- Shorten function name
  6local keymap = vim.api.nvim_set_keymap
  7-- local map = vim.keymap.set -- for conciseness
  8
  9--Remap space as leader key
 10vim.g.mapleader = " " -- 设置空格为 Leader Key
 11-- vim.g.maplocalleader = " "
 12
 13
 14-------------------- General Keymaps --------------------
 15
 16-- delete single character without copying into register
 17-- keymap("n", "x", '"_x', opts)
 18-- keymap("v", "p", '"_p', opts)
 19
 20-- Unmappings 解绑快捷键,<C-z>、gc、gcc 被设置为无操作(<nop>),用于禁用这些快捷键。
 21keymap("n", "<C-z>", "<nop>", opts)
 22keymap("n", "gc", "<nop>", opts)
 23keymap("n", "gcc", "<nop>", opts)
 24
 25-- NOTE: not sure I will uses these cmp-vimtex commands
 26-- Search from hovering over cmp-vimtex citation completion
 27-- vim.keymap.set("i", "<C-z>", function() 
 28--   require('cmp_vimtex.search').search_menu()
 29-- end)
 30-- vim.keymap.set("i", "<C-z>", function() 
 31--   require('cmp_vimtex.search').perform_search({ engine = "arxiv" })
 32-- end)
 33
 34-- NOTE: prefer to use whichkey
 35-- Surround 
 36-- vim.keymap.set("v", '<C-s>', 'S', { remap = true }) -- see surround.lua
 37
 38
 39-- Spelling "<C-s>" 调用 telescope 插件的 spell_suggest,提供拼写建议,光标处展示一个小窗口。
 40vim.keymap.set("n", "<C-s>", function()
 41  require("telescope.builtin").spell_suggest(require("telescope.themes").get_cursor({
 42      previewer = false,
 43      layout_config = {
 44        width = 50,
 45        height = 15,
 46      }
 47    })
 48  )
 49end, { remap = true })
 50-- vim.keymap.set("n", "<C-s>", "z=", { remap = true}) 
 51-- keymap("n", "<C-s>", "<cmd>Telescope spell_suggest<cr>", { remap = true})
 52
 53-- Kill search highlights 按 <Enter> 清除高亮显示的搜索结果。
 54keymap("n", "<CR>", "<cmd>noh<CR>", opts)
 55
 56
 57-- Find project files <Ctrl-p> 启动 Telescope 插件中的 find_files 函数,用于查找项目文件。
 58vim.keymap.set("n", "<C-p>", "<cmd>Telescope find_files<CR>", { remap = true })
 59  -- function ()
 60  --   require('telescope.builtin').find_files(require('telescope.themes').get_dropdown({previewer = false}))
 61  -- end, 
 62
 63
 64-- Toggle comments <Ctrl-/> 用于切换当前行和选择区域的行注释。
 65keymap('n', '<C-_>', '<Plug>(comment_toggle_linewise_current)', opts)
 66keymap('x', '<C-_>', '<Plug>(comment_toggle_linewise_visual)', opts)
 67
 68
 69-- Open help on word 按 <Shift-m> 打开光标处单词的帮助文档。
 70keymap("n", "<S-m>", ':execute "help " . expand("<cword>")<cr>', opts)
 71
 72
 73-- Fix 'Y', 'E' Y 键重新映射为复制到行尾,E 映射为跳转到上一个单词结尾。
 74keymap("n", "Y", "y$", opts)
 75keymap("n", "E", "ge", opts)
 76keymap("v", "Y", "y$", opts)
 77keymap("v", "E", "ge", opts) -- causes errors with luasnip autocmp
 78
 79
 80-- Better window navigation 使用 <C-h>, <C-j>, <C-k>, <C-l> 快速在窗口间导航。
 81keymap("n", "<C-h>", "<C-w>h", opts)
 82keymap("n", "<C-j>", "<C-w>j", opts)
 83keymap("n", "<C-k>", "<C-w>k", opts)
 84keymap("n", "<C-l>", "<C-w>l", opts)
 85
 86
 87-- Resize with arrows <A-Left> 和 <A-Right> 用于调整窗口宽度。
 88-- keymap("n", "<C-Up>", ":resize -2<CR>", opts)
 89-- keymap("n", "<C-Down>", ":resize +2<CR>", opts)
 90-- keymap("n", "<A-Left>", ":vertical resize -2<CR>", opts)
 91-- keymap("n", "<A-Right>", ":vertical resize +2<CR>", opts)
 92-- keymap("n", "<A-h>", ":vertical resize -2<CR>", opts)
 93-- keymap("n", "<A-l>", ":vertical resize +2<CR>", opts)
 94
 95
 96-- Navigate buffers <TAB> 和 <S-TAB> 在缓冲区之间切换。
 97-- keymap("n", "<TAB>", ":bnext<CR>", opts)
 98-- keymap("n", "<S-TAB>", ":bprevious<CR>", opts)
 99-- keymap("n", "<BS>", ":BufferLineMoveNext<CR>", opts)
100-- keymap("n", "<S-BS>", ":BufferLineMovePrev<CR>", opts)
101
102
103-- Drag lines <Alt-j> 和 <Alt-k> 用于拖动行。
104keymap("n", "<A-j>", "<Esc>:m .+1<CR>==", opts)
105keymap("n", "<A-k>", "<Esc>:m .-2<CR>==", opts)
106keymap("x", "<A-j>", ":move '>+1<CR>gv-gv", opts)
107keymap("x", "<A-k>", ":move '<-2<CR>gv-gv", opts)
108keymap("v", "<A-j>", ":m'>+<CR>gv", opts)
109keymap("v", "<A-k>", ":m-2<CR>gv", opts)
110
111-- Horizontal line movments -- <S-h> 和 <S-l> 用于跳到行的开头和结尾。
112keymap("v", "<S-h>", "g^", opts)
113keymap("v", "<S-l>", "g$", opts)
114keymap("n", "<S-h>", "g^", opts)
115keymap("n", "<S-l>", "g$", opts)

options.lua 的内容:

 1local options = {
 2
 3  -- GENERAL
 4  timeoutlen = 500,               -- time to wait for a mapped sequence to complete (in milliseconds), 键盘快捷键等待时间
 5  updatetime = 300,               -- faster completion (4000ms default), 更新检查间隔时间
 6  swapfile = false,               -- creates a swapfile, 禁止创建 swap 文件
 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,           -- 禁止创建备份文件
10  confirm = true,           -- 没有保存或文件只读时弹出确认
11
12  -- APPEARANCE
13  fileencoding = "UTF-8",         -- the encoding written to a file, 保存文件的时候使用 UTF-8 编码
14  encoding = "UTF-8",             -- 当处理文本的时候使用 UTF-8 编码
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,                  -- set 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  -- colorcolumn = "100",             -- highlight vertical colorcolumn (moved to after/python.lua), 右侧第 100 列显示颜色参考线
25  wrap = true,                    -- display lines as one long line, 启用折行
26  showbreak = "  ",               -- set indent of wrapped lines
27  cmdheight = 1,                  -- space in the neovim command line for displaying messages, 命令行高度
28  pumheight = 10,                 -- pop up menu height, 补全菜单高度为 10 行
29  wildmenu = true,                -- 显示补全菜单
30  -- showmode = false,               -- we don't need to see things like -- INSERT -- anymore
31  splitbelow = true,              -- force all horizontal splits to go below current window, 水平分屏默认在下方
32  splitright = true,              -- force all vertical splits to go to the right of current window, 垂直分屏默认在右侧
33  scrolloff = 999,                  -- minimal number of screen lines to keep above and below the cursor, 光标上下保持 999 行距离,实现类似 Typora 的打字机的效果
34  sidescrolloff = 8,              -- minimal number of screen columns either side of cursor if wrap is `false`, 光标左右保持 8 列距离
35  -- shortmess = "filnxtToOFc",      -- which errors to suppress
36  -- mousemoveevent = true,
37  -- shortmess:append "atI",      -- 隐去启动的提示信息
38
39  -- INDENT
40  tabstop = 4,                    -- insert 4 spaces for a tab, Tab 键相当于 4 个空格
41  shiftwidth = 4,                 -- the number of spaces inserted for each indentation, 自动缩进时移动 4 个空格
42  softtabstop = 4,                -- insert 2 spaces for a tab, 编辑时 Tab 键为 4 个空格
43  expandtab = true,               -- convert tabs to spaces, Tab 替换为空格
44  breakindent = true,             -- tab wrapped lines
45  linebreak = true,               -- companion to wrap, don't split words
46  backspace = "indent,eol,start", -- allow backspace on indent, end of line or insert mode start position
47  smarttab = true,                -- 开启智能 Tab
48  shiftround = true,              -- 使用 >> 和 << 移动时对齐到 shiftwidth 的倍数
49  cindent = true,                 -- C 文件自动缩进
50  autoindent = true,              -- 新行缩进对齐到当前行
51  smartindent = true,             -- 开启智能缩进
52
53  -- EDIT
54  -- spell = true,                   -- turns on spellchecker, 支持拼写检查
55  -- spelllang = { 'en_us', 'cjk' },        -- sets spelling dictionary, 对英文进行拼写检查, 忽略中文的拼写检查
56  clipboard = "unnamedplus",      -- allows neovim to access the system clipboard, 使用系统剪贴板
57  mouse = "a",                    -- allow the mouse to be used in neovim, 开启鼠标支持
58  -- mousescroll = "ver:2,hor:4",    -- change the speed of the scroll wheel
59  ignorecase = true,              -- ignore case in search patterns, 搜索时不区分大小写
60  smartcase = true,               -- smart case, 搜索包含大写字母时,自动区分大小写
61  hlsearch = true,                -- 搜索高亮
62  incsearch = true,               -- 输入搜索模式时,每输入一个字符,就自动跳到第一个匹配的结果
63  showmatch = true,               -- 高亮匹配的括号
64  virtualedit = "block",          -- vitualblock mode doesn't get stuck at the end of line
65  inccommand = "split",           -- shows all inline replacements in split
66  autoread = true,                -- 外部文件修改自动加载
67  whichwrap = "<,>,[,]",          -- 光标移到行首或行尾时,可跨行移动
68  list = false,                   -- 不显示不可见字符
69  listchars = "space:·,tab:>-",   -- 空格和 Tab 的显示方式
70
71}
72
73-- turns on all values in options table above
74for k, v in pairs(options) do
75  vim.opt[k] = v
76end

autocmds.lua 的内容:

 1local api = vim.api
 2
 3-- close help, man, qf, lspinfo with 'q' 为 man、help、qf 和 lspinfo 文件类型创建自动命令,按 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定义了 set_terminal_keymaps 函数,在终端模式中设置快捷键:<esc> 映射为 <C-c>,可用来快速退出终端模式。
15<C-h>, <C-j>, <C-k>, <C-l> 在不同窗口之间导航。当打开终端时(TermOpen),自动调用 set_terminal_keymaps()。
16]]
17function _G.set_terminal_keymaps()
18  local opts = { buffer = 0 }
19  vim.keymap.set('t', '<esc>', [[<C-c>]], opts)
20  vim.keymap.set('t', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
21  vim.keymap.set('t', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
22  vim.keymap.set('t', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
23  vim.keymap.set('t', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
24  -- vim.keymap.set('t', '<C-w>', [[<C-\><C-n><C-w>]], opts)
25end
26
27vim.api.nvim_create_autocmd({ "TermOpen" }, {
28  pattern = { "term://*" }, -- use term://*toggleterm#* for only ToggleTerm
29  command = "lua set_terminal_keymaps()",
30})
31
32-- Autolist markdown mappings
33--[[
34在 Markdown 文件中自动设置键映射,用于管理有序或无序列表:
35<CR>、o、O 用于插入新列表项。
36<tab>、<S-tab> 在插入模式下重新计算列表缩进。
37dd、d 删除列表项并重新计算。
38设置 tabstop、shiftwidth 和 softtabstop 为 2 个空格,符合 Markdown 语法要求。
39]]
40function _G.set_markdown_keymaps()
41  vim.api.nvim_buf_set_keymap(0, "i", "<CR>", "<CR><cmd>AutolistNewBullet<cr>", {})
42  vim.api.nvim_buf_set_keymap(0, "n", "o", "o<cmd>AutolistNewBullet<cr>", {})
43  vim.api.nvim_buf_set_keymap(0, "n", "O", "O<cmd>AutolistNewBulletBefore<cr>", {})
44  vim.api.nvim_buf_set_keymap(0, "i", "<tab>", "<Esc>><cmd>AutolistRecalculate<cr>a<space>", {})
45  vim.api.nvim_buf_set_keymap(0, "i", "<S-tab>", "<Esc><<cmd>AutolistRecalculate<cr>a", {})
46  vim.api.nvim_buf_set_keymap(0, "n", "dd", "dd<cmd>AutolistRecalculate<cr>", {})
47  vim.api.nvim_buf_set_keymap(0, "v", "d", "d<cmd>AutolistRecalculate<cr>", {})
48  vim.api.nvim_buf_set_keymap(0, "n", ">", "><cmd>AutolistRecalculate<cr>", {})
49  vim.api.nvim_buf_set_keymap(0, "n", "<", "<<cmd>AutolistRecalculate<cr>", {})
50  vim.api.nvim_buf_set_keymap(0, "n", "<C-c>", "<cmd>AutolistRecalculate<cr>", {})
51  vim.api.nvim_buf_set_keymap(0, "n", "<C-n>", "<cmd>lua HandleCheckbox()<CR>", {})
52  vim.opt.tabstop = 2
53  vim.opt.shiftwidth = 2
54  vim.opt.softtabstop = 2
55end
56
57vim.api.nvim_create_autocmd({ "BufEnter", "BufReadPre", "BufNewFile" }, {
58  pattern = { "*.md" },
59  command = "lua set_markdown_keymaps()",
60})

functions.lua 的内容:

1-- 用于在 Neovim 中查找光标下的单词,具体功能如下:
2function SearchWordUnderCursor()
3    local word = vim.fn.expand('<cword>') -- 获取光标下的单词
4    require('telescope.builtin').live_grep({ default_text = word }) -- 调用 Telescope 插件的 live_grep 功能
5end

bootstrap.lua 的内容:

 1-- BOOTSTRAP LAZY
 2local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
 3if not vim.loop.fs_stat(lazypath) then
 4  vim.fn.system({
 5    "git",
 6    "clone",
 7    "--filter=blob:none",
 8    "https://github.com/folke/lazy.nvim.git",
 9    "--branch=stable", -- latest stable release
10    lazypath,
11  })
12end
13vim.opt.rtp:prepend(lazypath)
14
15require("lazy").setup({
16  { import = "neotex.plugins" },    -- main plugins directory
17  { import = "neotex.plugins.lsp" } -- lsp plugins directory
18}, {
19  install = {
20    colorscheme = { "gruvbox" },
21  },
22  checker = {
23    enabled = true,
24    notify = false,
25  },
26  change_detection = {
27    notify = false, 
28  },
29  ui = {
30    icons = {
31      cmd = "⌘",
32      config = "🛠",
33      event = "📅",
34      ft = "📂",
35      init = "⚙",
36      keys = "🗝",
37      plugin = "🔌",
38      runtime = "💻",
39      require = "🌙",
40      source = "📄",
41      start = "🚀",
42      task = "📌",
43      lazy = "💤 ",
44    },
45  },
46})

遇到的一些问题及其解答:

  • 快捷键如何映射正斜杠:使用 _ 代替 /1

  • 如何实现实时预览和正反向搜索:在 Neovim 中输入 :help vimtex 找到和 sumatraPDF 相关的章节,里面介绍了如何进行正反向搜索的设置,这里主要介绍如何解决在 xelatex 编译下,实时预览时,SumatraPDF 不会自动刷新PDF的问题,具体的操作和更加详细的细节可以参考 XeLaTeX ans SumatraPDF live update · Issue #1410 · lervag/vimtex

    • 创建一个 .latexmkrc 文件,并将其放置在 C:\Users\My_Username\ 目录下。文件内容如下:

      $xelatex = "xelatex -file-line-error -synctex=1 -interaction=nonstopmode -recorder %S"
      
    • 需要注意的是,虽然支持了 xelatex 的正向实时预览的功能,但是可能会使得 xelatex 编译的性能有所下降,如果不需要这个功能了就将 C:\Users\My_Username\ 目录下的 .latexmkrc 文件删除。

相关插件介绍

结合 Neovim 和 C++

可以参考的链接

需要注意的点

如果要实现 C++ 的代码格式化,要先在需要格式化的 .cpp 文件目录下创建一个 .clang-format 文件,写入自己配置的代码格式化的要求,或者使用现有的代码格式化的类型,比如使用 Google 的规范:

1clang-format -style=Google -dump-config > .clang-format

然后在 Neovim 中使用 <leader> 键加上 af 对 C++ 代码进行格式化。

如果没有安装 clang-format,要先安装 llvm

1scoop install main/llvm

代码提示的功能还需要安装 clangd

1scoop install main/clangd

相关插件介绍

结合 Neovim 和 LeetCode

需要注意的点

如果要进入刷 LeetCode 的界面需要在命令行中输入(如果修改了默认的存储位置变成当前目录,记得注意一下当前的目录是否是要存储的位置):

1nvim leetcode.nvim

我自己的配置文件leetcode.lua

 1return {
 2    "kawre/leetcode.nvim",
 3    -- event = "VeryLazy",
 4    build = ":TSUpdate html",
 5    dependencies = {
 6        "nvim-telescope/telescope.nvim",
 7        "nvim-lua/plenary.nvim", -- required by telescope
 8        "MunifTanjim/nui.nvim",
 9
10        -- optional
11        "nvim-treesitter/nvim-treesitter",
12        "nvim-tree/nvim-web-devicons",
13    },
14    opts = {
15        -- configuration goes here
16
17        ---@type lc.storage
18        storage = {
19            home = vim.fn.getcwd(), -- Store the resolution in the current repository
20            cache = vim.fn.stdpath("cache") .. "/leetcode", -- Store in the default nvim appdata repository
21        },
22        cn = { -- leetcode.cn
23            enabled = true, ---@type boolean
24            translator = true, ---@type boolean
25            translate_problems = true, ---@type boolean
26        },
27    }, 
28}

相关的插件介绍

结合 Neovim 和 AI

需要注意的点

如果要更改默认的接受 Copilot 建议的快捷键,可以在 Neovim 中输入如下命令在 Copilot 插件的文档中找到相关的说明:

:Copilot help

相关插件介绍