写在前面#
之前主要使用的文本编辑器是 VS Code,但是在使用 ssh 插件连接研究所的服务器和超级计算机时总会遇到各种问题,因此我开始寻找一个 CLI 的替代方案。因为之前学过一点 Vim(并且偶尔会用用),就抱着试一试的心态在服务器上配置了 neovim,结果经过测试发现:
- 插件的安装没有任何问题
- 即使隔了一层 login shell,配色方案也依旧可以保留
(非常重要) - 使用 LSP 后,定义查找和补全体验与 VS Code 相差无几
- 纯键盘操作很流畅
非常 geek,但想用鼠标的时候也很方便
基于这些原因,我准备将 neovim 作为服务器端主要的编辑器(在本地写代码实在很难有能超越 VS Code 的方案)。现简要记录作为备忘录。
参考资料#
最实用入门教程:$ vimtutor
#
“从入门到放弃类”教程#
- 中文:Vim 从入门到精通
- 英文:Vim-Galore
neovim 官方文档#
配置参考#
- LazyVim 官方文档(推荐)
- AstroNvim 官方文档
- 掘金小册 - Neovim 配置实战(有点过时,配置不够简洁)(已弃用!)
- 从零开始配置 Neovim (Nvim)
- neovim 入门指南(博主在持续更新)
Vim 基础笔记#
Buffer, window and tab#
摘录自官方文档:
- A buffer is the in-memory text of a file.
- A window is a viewport on a buffer.
- A tab page is a collection of windows.
快捷键拾遗(nvim)#
U
:撤消在一行中所做的改动
视为 操作 而非 撤销;不可用CTRL-R
来重做J
:将下一行的内容合并至本行行末CTRL-G
:显示当前编辑文件中当前光标所在行位置以及文件状态信息CTRL-O
:回到之前的位置
CTRL-I
: 跳转到较新的位置%
:查找配对的括号:s/old/new/g
:替换 old 为 new
:#,#s/old/new/g
:#,# 代表替换操作的若干行中首尾两行的行号
:%s/old/new/g
:替换整个文件中的每个匹配串
:%s/old/new/gc
:找到整个文件中的每个匹配串,并且对每个匹配串提示是否进行替换- 在
Command
模式下:
Ctrl+R "
插入最近一次复制/剪切/删除的内容。
Ctrl+R 0
插入最近一次复制的内容。
Ctrl+F
选择一条历史命令(包括当前正在键入的命令)来编辑。(normal 模式下输入q:
也可达到同样效果)
neovim 配置#
-
2024/04/03 更新 :AstroNvim 在更新到 v4 后把自己变成了 LazyVim 的“又一个插件”,所以也可以直接用 LazyVim 来配置。
我在尝试之后,还是乖乖地把 AstroNvim 从 v3 的配置迁移到了 v4。具体配置可以在我的 dotfiles 仓库找到。AstroNvim 好!
-
2023/10/14 更新 :已经转投 AstroNvim 的怀抱!
以前根据掘金小册摸索出来的配置有时不太稳定,并且如果要跟上各个插件的更新,配置的定期维护成本也非常高,所以建议还是从社区提供的框架(比如我用的 AstroNvim)开始配置。
完全由自己折腾的配置已弃用,如果有兴趣的话,可以参考本文附录、掘金小册和我的 neovim-config 仓库。
结语#
如此这般,Vim 的用法也大概会了,neovim 也总算是美化得差不多了,终于可以开始享受快乐 geek 编程啦!话虽如此,刚开始时适应 Vim 的操作逻辑很困难,并且折腾一个漂亮好用的 neovim 环境也非常麻烦。对比之下,VS Code 不用折腾几乎开箱即用,并且在不少场景下很难被 neovim 替代,所以依旧是一个非常推荐的本地文本编辑器。
总之,不管用哪一款软件,它们终究是工具,适合好用才是最重要的,可不要有 xxx 使用者的优越感哦~
附录:从零折腾 nvim 配置#
(已弃用,仅作纪念)
网上的资料给出了一些基本配置,但是我还是对照着官方文档自己重新折腾了一遍(还是得自己花时间调整)。完整配置请参考我的 github 仓库。
我的 ~/.config/nvim
文件夹大致结构如下:
.
├── init.lua
└── lua
├── basic.lua
├── colorscheme.lua
├── keymaps.lua
├── plugin-config
⋮
└── plugins.lua
所有 lua
文件夹中的配置都需要在 init.lua
中导入,具体例子为:
…
require('basic')
require('plugin-config.nvim-tree')
…
基础设置(UI、缩进、搜索及其他)#
细节请参考 neovim 官方文档。创建 lua/basic.lua
,添加:
-- Hint: use `:h <option>` to figure out the meaning if needed
-- Basic UI config
vim.opt.number = true -- Show absolute line number
vim.opt.signcolumn = "yes" -- Sign column for showing status
vim.opt.colorcolumn = "80" -- Reference for the line length
vim.opt.scrolloff = 8 -- Number of screen lines to keep above and below the cursor
vim.opt.cursorline = true -- Highlight cursor line
vim.opt.cmdheight = 1 -- Number of screen lines to use for the command-line
vim.opt.termguicolors = true -- Enable 24-bit RGB color in the TUI
vim.opt.splitbelow = true -- open new vertical split bottom
vim.opt.splitright = true -- open new horizontal splits right
vim.opt.showtabline = 2 -- Always show tabline
vim.opt.showmode = false -- Hide mode hint like "-- INSERT --"
-- Completion UI config
vim.opt.completeopt = "menuone,noselect,noinsert" -- List of options for Insert mode completion
vim.opt.shortmess = vim.o.shortmess .. 'c' -- Don't give ins-completion-menu messages
vim.opt.pumheight = 10 -- Number of lines for the completion menu
-- CMD UI config
vim.cmd([[ autocmd TermOpen * setlocal nonumber ]]) -- Turn off the terminal line number
-- Show space as dot
vim.opt.list = true -- Show invisible characters
vim.opt.listchars = "space:·"
-- Indent config
vim.opt.tabstop = 8 -- Number of spaces that a <Tab> in the file counts for
vim.opt.softtabstop = 2 -- Number of spaces that a <Tab> counts for while performing editing operations
vim.opt.shiftwidth = 2 -- Number of spaces to use for each step of (auto)indent
vim.opt.expandtab = true -- Use the appropriate number of spaces to insert a <Tab>
vim.opt.shiftround = true -- Round indent to multiple of 'shiftwidth' (N * shiftwidth)
vim.opt.autoindent = true -- Copy indent from current line when starting a new line
vim.opt.smartindent = true -- Do smart autoindenting when starting a new line
-- Search config
vim.opt.incsearch = true -- Search as characters are entered
vim.opt.ignorecase = true -- ignore case in searches by default
vim.opt.smartcase = true -- but make it case sensitive if an uppercase is entered
vim.opt.hlsearch = false -- Do not highlight matches
-- Disable netrw to use nvim-tree
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
-- Set leader key (for keymaps)
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
-- Misc
vim.opt.clipboard = 'unnamedplus' -- Use system clipboard
vim.opt.autoread = true -- Automatically read the file when it is modified outside
vim.opt.whichwrap = '<,>,[,]' -- Use <Left> <Right> to jump to next line
vim.opt.mouse = "a" -- Allow the mouse to be used in neovim
vim.opt.updatetime = 1000 -- If this many milliseconds nothing is typed the swap file will be written to disk
vim.opt.timeoutlen = 500 -- Time in milliseconds to wait for a mapped sequence to complete
基础快捷键设置#
细节请参考 neovim 官方文档。创建 lua/keymaps.lua
,添加:
-- Alias
local map = vim.keymap.set
local opts = { noremap = true, silent = true }
-- Split screen
map('n', '<leader>s', '<C-w>s', opts)
map('n', '<leader>v', '<C-w>v', opts)
map('n', '<leader>c', '<C-w>c', opts) -- Close current
map('n', '<leader>o', '<C-w>o', opts) -- Close Others
-- Move cursor amoung windows
map('n', '<A-j>', '<C-w>j', opts)
map('n', '<A-k>', '<C-w>k', opts)
map('n', '<A-h>', '<C-w>h', opts)
map('n', '<A-l>', '<C-w>l', opts)
-- Window resizing
map('n', '<C-Up>', ':resize +2<CR>', opts)
map('n', '<C-Down>', ':resize -2<CR>', opts)
map('n', '<C-Left>', ':vertical resize -2<CR>', opts)
map('n', '<C-Right>', ':vertical resize +2<CR>', opts)
-- Terminal mode
map('n', '<leader>t', ':new | resize -6 | terminal<CR>', opts)
map('t', '<Esc>', '<C-\\><C-n>', opts)
-- Continuous indentation in Visual mode
map('v', '<', '<gv', opts)
map('v', '>', '>gv', opts)
-- Move multiple lines in Visual mode
map('v', 'J', ":move '>+1<CR>gv=gv")
map('v', 'K', ":move '<-2<CR>gv=gv")
-- Scroll window
map('n', '<C-j>', '4j', opts)
map('v', '<C-j>', '4j', opts)
map('n', '<C-k>', '4k', opts)
map('v', '<C-k>', '4k', opts)
后续插件的快捷键设置也会保存在这个文件中。
插件管理器及 UI 美化#
默认已安装某一款 Nerd Fonts。
首先安装插件管理器 lazy.nvim。根据 README,创建 lua/plugins.lua
并添加如下内容:
-- Bootstrap for lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
…
})
完成后重启 nvim,然后输入 :Lazy
应该就能看到效果了!接下来就可以美化 UI 了!
下面的配置基本参考官方文档就可以完成,所以我只给出一个使用 lazy.nvim 安装插件的例子,其他的插件就只记录名称和作用以及一些值得一提的额外配置。我的插件快捷键设置都放在了对应的插件配置文件里,这样在想禁用某个插件的时候,只要在 init.lua
中注释掉相应的 require 就可以完全屏蔽掉所有相关配置。不明白的地方也可以参考我的 github 仓库。
Colorscheme: Catppuccin(主题)#
选使用人数多的一般不会出大问题。
- 在
lua/plugins.lua
中的require("lazy").setup()
部分添加:
require("lazy").setup({
-- catppuccin
{
"catppuccin/nvim"
name = "catppuccin",
priority = 1000,
},
})
- 创建
lua/theme.lua
,添加以下内容:
local colorscheme = 'catppuccin-frappe'
local status_ok, _ = pcall(vim.cmd, 'colorscheme ' .. colorscheme)
if not status_ok then
vim.notify('colorscheme ' .. colorscheme .. ' not found!')
return
end
更好的语法高亮支持:nvim-treesitter#
注意官方给出的 Folding 配置有点问题,要改成:
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
vim.opt.foldlevel = 99
侧栏文件浏览:nvim-tree#
后面如果要用 project 插件的话需要在 setup 中加这么几行:
-- For project.nvim
sync_root_with_cwd = true,
update_focused_file = {
enable = true,
update_root = true,
},
respect_buf_cwd = true,
有一个追加设置记录在这里:
-- Quit after last buffer has been closed
vim.cmd([[
autocmd BufEnter * ++nested if winnr('$') == 1 && bufname() == 'NvimTree_' . tabpagenr() | quit | endif
]])
快捷键设置大概是这样的:
map("n", "<leader>m", ":NvimTreeToggle<CR>", opt) -- Open & close tree
添加顶部标签页:bufferline#
除了掘金小册里提供的美化配置,我还改了一下关闭图标:buffer_close_icon = '✕'
。快捷键设置:
…
-- bufferline
map("n", "<C-t>", ":enew<CR>", opt) -- Create new buffer
map("n", "<C-h>", ":BufferLineCyclePrev<CR>", opt)
map("n", "<C-l>", ":BufferLineCycleNext<CR>", opt)
map("n", "<C-w>", ":Bdelete<CR>", opt) --Close Tabs by vim-bbye
添加底部状态栏:lualine#
美化配置可以参考掘金小册里提供的。
模糊搜索:telescope#
注意要安装依赖:
brew install rg
brew install fd
- 项目管理插件:project
快速注释代码:Comment#
在 plugin-config/comment.lua
中,我这样设置了快捷键:
comment.setup({
toggler = {
line = "<C-/>",
},
opleader = {
line = "<C-/>",
},
})
注意:
- neovim 将
Ctrl + /
识别为<C-/>
还是<C-_>
要根据具体的系统环境来决定。
自定义启动画面:dashboard#
我使用的是 hyper
主题,plugin-config/dashboard.lua
中的配置如下:
db.setup({
theme = "hyper",
config = {
header = {
[[]],
[[ Customed something ]],
[[]],
},
project = { enable = false, },
mru = { limit = 13 },
shortcut = {
{
icon = " ",
desc = "Projects",
action = "Telescope projects",
key = "p",
},
{
icon = " ",
desc = "Update",
action = "Lazy update",
key = "u"
},
{
icon = " ",
desc = "Files",
action = "Telescope find_files",
key = "f",
},
},
footer = {
"Customed something"
},
},
})
自动补全及 LSP#
这一部分的配置略有些复杂,可以交叉参考 掘金小册 和 从零开始配置 Neovim(Nvim)(nvim-cmp 以及 nvim-lspconfig 的官方文档看起来不是很友善)。当然,最终配置还是可以参考我的 github 仓库(里面可能有一些小小的修改)。
自动补全:nvim-cmp#
请参考官方文档。安装 cmp 时还需要安装 Snippet 引擎:LuaSnip。
自动格式化代码:formatter#
请参考官方文档。我的配置如下:
local status, formatter = pcall(require, "formatter")
if not status then
vim.notify("formatter not found")
return
end
formatter.setup {
filetype = {
sh = require("formatter.filetypes.sh").shfmt,
python = require("formatter.filetypes.python").black,
rust = require("formatter.filetypes.rust").rustfmt,
},
}
-- Keymaps
local map = vim.keymap.set
local opts = { noremap = true, silent = true }
map("n", "<A-F>", ":Format<CR>", opts)
设置好后,可以用 Mason 来安装对应的 formatter(在菜单 5 中可以找到)。像 rustfmt 这种安装 rust 时就已经装好的则不需要再次安装。
LSP 管理:mason & mason-lspconfig#
请参考官方文档。
LSP 配置:nvim-lspconfig#
请参考官方文档。(比较麻烦!)
LSP UI 配置#
- lspkind
- …