Neovim-配置筆記

把一些基本的概念記錄下來。

補充知識

1. 什麼是 <CR>

注意到有些指令後面有 <CR>(carriage return) 這個字,這個背後的含義其實很簡單,就是幫你按下 Enter 來執行這個指令的意思。

2. 什麼是 Buffer

簡單來說可以想成是「分頁(Tab)」的意思,不過實際上還是有些差異。

3. 在 lua 中寫 vim 指令

有些時候你可能會在官方文件中看到類似這樣的配置:

1
2
3
4
5
let g:VM_maps = {}
let g:VM_maps['Find Under'] = '<C-d>' " replace C-n
let g:VM_maps['Find Subword Under'] = '<C-d>' " replace visual C-n
let g:VM_maps["Select Cursor Down"] = '<M-C-Down>' " start selecting down
let g:VM_maps["Select Cursor Up"] = '<M-C-Up>' " start selecting up

但如果你是用 lua 來撰寫的話,可以改寫成這樣子:

1
2
3
4
5
6
7
vim.cmd([[
let g:VM_maps = {}
let g:VM_maps['Find Under'] = '<C-d>'
let g:VM_maps['Find Subword Under'] = '<C-d>'
let g:VM_maps['Add Cursor Down'] = '<C-n>'
let g:VM_maps['Add Cursor Up'] = '<C-p>'
]])

Packer.vim 的相關指令

  • PackerInstall 安裝套件
  • PackerUpdate 更新套件
  • PcakerSync 更新套件並產生一個 packer_compiled.lua,可以想成是緩存的概念吧,主要是用來提升載入速度而存在的

基本結構

1
2
3
4
5
6
7
├── README.md
├── init.lua // nvim 的進入點(基本上就是把所有 lua 的東西引入)
├── lua // 放 lua 相關的檔案
│   └── user
│   ├── options.lua
└── plugin
└── packer_compiled.lua

附註:user 資料夾是為了避免 .lua 撞名而開的

打開 .config/nvim/lua/user/options.lua 可以看到一些內容:

1
2
3
4
5
6
7
vim.opt.backup = false                          -- creates a backup file
vim.opt.clipboard = "unnamedplus" -- allows neovim to access the system clipboard
vim.opt.cmdheight = 1 -- more space in the neovim command line for displaying messages
vim.opt.completeopt = { "menuone", "noselect" } -- mostly just for cmp
vim.opt.conceallevel = 0 -- so that `` is visible in markdown files
vim.opt.fileencoding = "utf-8" -- the encoding written to a file
vim.opt.hlsearch = true -- highlight all matches on previous search pattern

主要用來設定 nvim 的基本配置,如果想知道所有能設定的內容與細節的話,可以下 :help options 來搜尋。

接著 init.lua 的內容是這樣:

1
require "user.options"

注意在引入的時候不需要把完整路徑跟副檔名填入(跟 ES Module 在引入的感覺有點像),像這樣 lua.user.options.lua,只需要 user.options 即可。

Keymaps

打開 .config/nvim/lua/user/keymaps.lua 會看到底下內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-- 用變數儲存 vim.keymap.set 這個函式
local keymap = vim.keymap.set
-- 共用的 options
local opts = { silent = true }

--Remap space as leader key
keymap("", "<Space>", "<Nop>", opts)
vim.g.mapleader = " "

-- Modes
-- normal_mode = "n",
-- insert_mode = "i",
-- visual_mode = "v",
-- visual_block_mode = "x",
-- term_mode = "t",
-- command_mode = "c",

-- Normal --
-- Better window navigation
keymap("n", "<C-h>", "<C-w>h", opts)
keymap("n", "<C-j>", "<C-w>j", opts)
keymap("n", "<C-k>", "<C-w>k", opts)
keymap("n", "<C-l>", "<C-w>l", opts)

-- Resize with arrows
keymap("n", "<C-Up>", ":resize -2<CR>", opts)
keymap("n", "<C-Down>", ":resize +2<CR>", opts)
keymap("n", "<C-Left>", ":vertical resize -2<CR>", opts)
keymap("n", "<C-Right>", ":vertical resize +2<CR>", opts)

-- Navigate buffers
keymap("n", "<S-l>", ":bnext<CR>", opts)
keymap("n", "<S-h>", ":bprevious<CR>", opts)

-- Clear highlights
keymap("n", "<leader>h", "<cmd>nohlsearch<CR>", opts)

-- ....

這邊只解釋主要的部分:

vim.g.mapleader = " "

這是用來設定 <leader>(常用快捷鍵),之後就可以用 <leader>h 的方式來表示(「空白鍵 + h)

keymap("n", "<leader>h", "<cmd>nohlsearch<CR>", opts)

他只是一個用來設定快捷鍵函式,需要的參數為:

1
map('模式', '按键', '映射为XX', opts)

Plugin

先來介紹這裡會用到的 Plugin Manager。為了可以用 lua 來撰寫 config,所以這邊會用的是
packer.nvim
,基本上就跟 vim-plug 是差不多的東西。唯一的差別在於 vim-plug 只能寫 vim script,但 packer.nvim 可以寫 lua。

接下來看到 .config/nvim/lua/user/plugins.lua,這邊我直接寫中文註解,看完你大概就知道這個檔案在幹嘛了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
local fn = vim.fn

-- 自動安裝 Packer(如果目前沒有)
local install_path = fn.stdpath "data" .. "/site/pack/packer/start/packer.nvim"
if fn.empty(fn.glob(install_path)) > 0 then
PACKER_BOOTSTRAP = fn.system {
"git",
"clone",
"--depth",
"1",
"https://github.com/wbthomason/packer.nvim",
install_path,
}
print "Installing packer close and reopen Neovim..."
vim.cmd [[packadd packer.nvim]]
end

-- 只要儲存這個檔案就自動執行 PackerSync(Packer 的指令)
vim.cmd [[
augroup packer_user_config
autocmd!
autocmd BufWritePost plugins.lua source <afile> | PackerSync
augroup end
]]

-- 如果找不到 packer 就直接跳掉(不往下執行)
local status_ok, packer = pcall(require, "packer")
if not status_ok then
return
end

-- 用 popup 來顯示目前的安裝進度(預設是分割一個新視窗)
packer.init {
display = {
open_fn = function()
return require("packer.util").float { border = "rounded" }
end,
},
}

-- 到這邊才是真正跟安裝套件有關的 code
return packer.startup(function(use)
use "wbthomason/packer.nvim" -- 套件二
use "nvim-lua/popup.nvim" -- 套件二
use "nvim-lua/plenary.nvim" -- 套件三

-- Automatically set up your configuration after cloning packer.nvim
-- Put this at the end after all plugins
if PACKER_BOOTSTRAP then
require("packer").sync()
end
end)

安裝好的套件可以從 /Users/peanu/.local/share/nvim/site/pack/packer/start 找到。(簡單來說就是 nvim/site 裡面)

至於 nvim 裡面的其他檔案或資料夾是用來給套件存放一些資料用的,不用太在意。

Lazy Loading

簡單來說你可以設定某些套件不要在一開始打開 nvim 的時候直接載入,例如這個官方範例:

1
2
3
4
5
6
7
return require('packer').startup(function(use)
use 'wbthomason/packer.nvim'
use '9mm/vim-closer'

-- Lazy loading:
-- Load on specific commands
use {'tpope/vim-dispatch', opt = true, cmd = {'Dispatch', 'Make', 'Focus', 'Start'}}

附註:use 後面可以接一個 lua 的 Table(一種資料型態)

當我這樣子設定後 tpope/vim-dispatch 就只會在我輸入 :Dispatch:Make 等等的指令後才會被載入。

順道一提,只要是設定 Lazy Loading 的套件都會出現在 /Users/peanu/.local/share/nvim/site/pack/packer/opt 裡。

Error handling

一般來說當 nvim 打開時若找不到套件的話,就會直接噴一個全屏的 Error 給你看,像這樣:

example1-error-handle

如果是用 vim script 的話是沒辦法做錯誤處理的,這邊目前的寫法是這樣子:

1
2
3
4
5
require "user.options"
require "user.keymaps"
require "user.plugins"
-- vim script
vim.cmd "colorscheme tokyonight-moon"

但如果是用 lua 的話就不一樣了,我們可以改成這樣子:

1
2
3
4
require "user.options"
require "user.keymaps"
require "user.plugins"
require "user.colorscheme"

並填入這樣的內容:

1
2
3
4
5
6
7
8
9
10
11
-- 想引入的主題
local colorscheme = "tokyonight-moon"

-- pcall 回傳第一個值是狀態,第二個是 module 的回傳值(以這例子來說沒有所以就用 _ 表示)
-- ".." 是字串連結的意思
local status_ok, _ = pcall(vim.cmd, "colorscheme " .. colorscheme)
-- 如果不 ok 的話就在狀態列顯示錯誤訊息
if not status_ok then
vim.notify("colorscheme " .. colorscheme .. " not found!")
return
end

這樣子當套件載入失敗時就只會顯示訊息,不會好像整個程式都壞掉了一樣:

example1-plugs-error

設定套件的 mapping

基本上設定快捷鍵的方式就是先知道你想要的指令是什麼?,並且在設定對應的按鍵。

來說,你可以在 config 中這樣子寫:

1
2
3
4
5
6
7
8
9
10
11
mapping = {
-- <C-k> 對應到往前一個選項選
["<C-k>"] = cmp.mapping.select_prev_item(),
-- <C-k> 對應到往下一個選項選
["<C-j>"] = cmp.mapping.select_next_item(),
-- <C-k> 移動 doc 中的滾軸
["<C-b>"] = cmp.mapping(cmp.mapping.scroll_docs(-1), { "i", "c" }),
-- <C-k> 移動 doc 中的滾軸
["<C-f>"] = cmp.mapping(cmp.mapping.scroll_docs(1), { "i", "c" }),
-- 略....
}

Telescope

功能

  • :Telescope find_files 找檔案
  • :Telescope git_branches 找分支(目前 pwd 位置)
  • :Telescope live_grep 全域搜尋關鍵字(需安裝 ripgrep

視窗開啟後的快捷鍵可參考 telescope.lua 檔案的內容。

React-Environment-Variable Vim-LSP 筆記
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×