### [Learn Vimscript the Hard Way](https://learnvimscriptthehardway.stevelosh.com/)
TODO [Vim Script ! ](https://ithelp.ithome.com.tw/articles/10234362)
### Vimscript
撰寫 Vim 腳本(Vim script)函數的方法如下:
1. **開始函數:** 在 Vim 腳本中,函數以 `function` 關鍵字開始,後接空格和函數名稱。
```
function MyFunction()
```
2. **函數主體:** 在函數的開始和結束之間,可以撰寫相關的 Vim 指令,以實現你想要的功能。
```
function MyFunction()
" 這裡撰寫你的指令
endfunction
```
3. **參數傳遞:** 你可以在函數括號內指定參數,以便在函數內部使用。
```
function Greet(name)
echo "Hello, " . a:name . "!"
endfunction
```
4. **返回值:** 如果你想要從函數中返回值,可以使用 `return` 關鍵字。
```
function Add(a, b)
return a + b
endfunction
```
5. **調用函數:** 使用 `call` 關鍵字來調用你撰寫的函數。
```
call MyFunction()
```
6. **保存腳本:** 將你的 Vim 腳本保存在 `~/.vimrc` 或其他 Vim 設定文件中,以便在 Vim 中使用這些函數。
### 在函數中調用其他函數
```
function SayHello(name)
echo "Hello, " . a:name . "!"
endfunction
function GreetUser()
" 調用 SayHello 函數並傳遞參數
call SayHello("Alice")
endfunction
```
### 調用系統命令
```
function ListFiles()
let result = system("ls")
echo result
endfunction
```
### execute
在 Vim 腳本中,`execute` 命令通常在需要動態生成和執行 Vim 命令時使用。這在以下情況下特別有用:
1. **動態命令生成:** 如果你需要根據條件動態生成 Vim 命令並執行它們,可以使用 `execute`。這種情況下,你可以將變數的值插入到命令中。
```
let my_command = "echo 'Hello, World!'"
execute my_command
```
2. **使用變數作為命令:** 當你需要將變數的值作為命令名稱時,可以使用 `execute`。
```
let cmd_name = "echo"
execute cmd_name "Hello, Execute!"
```
3. **在循環中使用:** 如果你需要在循環中執行不同的命令,可以使用 `execute` 來動態生成並執行這些命令。
```
for i in range(1, 5)
execute "echo 'Iteration " . i . "'"
endfor
```
4. **處理特殊字符:** 有時你可能需要在命令中處理特殊字符,這些字符可能會干擾命令的解析。`execute` 可以幫助你在命令中處理這些情況。
總之,`execute` 命令允許你在 Vim 腳本中動態生成和執行命令,以增強你的腳本的靈活性和功能。然而,請確保適當地處理變數和特殊字符,以避免潛在的問題。
### 比較差異的作法
```bash
vimdiff file1.txt file2.txt
```
### [surround.vim](https://github.com/tpope/vim-surround)
It's easiest to explain with examples. Press `cs"'` inside
"Hello world!"
to change it to
'Hello world!'
Now press `cs'<q>` to change it to
<q>Hello world!</q>
To go full circle, press `cst"` to get
"Hello world!"
To remove the delimiters entirely, press `ds"`.
Hello world!
Now with the cursor on "Hello", press `ysiw]` (`iw` is a text object).
[Hello] world!
Let's make that braces and add some space (use `}` instead of `{` for no
space): `cs]{`
{ Hello } world!
Now wrap the entire line in parentheses with `yssb` or `yss)`.
({ Hello } world!)
Revert to the original text: `ds{ds)`
Hello world!
Emphasize hello: `ysiw<em>`
<em>Hello</em> world!
Finally, let's try out visual mode. Press a capital V (for linewise
visual mode) followed by `S<p class="important">`. 或者選擇後 `St` 輸入
```html
<p class="important">
<em>Hello</em> world!
</p>
```
This plugin is very powerful for HTML and XML editing, a niche which
currently seems underfilled in Vim land. (As opposed to HTML/XML
*inserting*, for which many plugins are available). Adding, changing,
and removing pairs of tags simultaneously is a breeze.
The `.` command will work with `ds`, `cs`, and `yss` if you install
[repeat.vim](https://github.com/tpope/vim-repeat).
**選擇並加上 Html Tag**
要使用 vim 的 surround 插件將選擇的內容加上 tag,你可以按照以下步驟進行:
1. 首先,確保你已經安裝了 vim-surround 插件。你可以通過在 vimrc 文件中添加引用來安裝它:
```vim
Plugin 'tpope/vim-surround'
```
2. 在你的 vim 編輯器中,使用 `v` 鍵來進入可視模式,然後選擇你要加上 tag 的內容。
3. 輸入 `S` 進入 surround 模式,然後輸入要加上的 tag,例如 `p` 可以加上 `<p>` 及 `</p>` tag。
4. 按下 `Esc` 退出 surround 模式,你會看到你選擇的內容現在已經被包裹在 tag 內。
舉例來說,假設你想要將下面這段文字加上 `<div>` 及 `</div>` tag:
```
Hello, World!
```
按照上述步驟,你可以進行以下操作:
1. 進入可視模式並選擇文字。
2. 輸入 `S<div>`。
3. 按下 `Esc`。
在這之後,你的文字將會變成以下格式:
```
<div>
Hello, World!
</div>
```
使用 vim 的 surround 插件可以使包裹文本以 tag 的操作更加輕鬆和方便。祝你使用愉快!
---
### :r 讀取內容
在 Vim 中,:r 是一個命令,用於將指定文件或緩衝區的內容插入到當前光標位置下方。:r 命令後可以跟著文件名或緩衝區名,表示從該文件或緩衝區中讀取內容。
:r 命令的格式如下:
```vim
:r {file}
```
其中 {file} 是要插入內容的文件名或緩衝區名。插入的內容將出現在當前光標位置的下方。
這個命令在許多情況下都很有用,例如當你想要將其他文件的內容插入到當前文件中的特定位置,或者當你想要在當前緩衝區中的特定位置插入其他緩衝區的內容時。這可以幫助你更有效地編輯和組織文件的內容。
---
### 生成數字序列
在 Vim 中,可以使用 :put = 命令搭配 VimScript 的 range() 函數來生成數字序列。下面是使用 Vim 的 :put 命令和 range() 函數來生成序列的步驟:
1. 進入命令行模式:按下 Esc 鍵退出插入模式,然後輸入冒號 : 進入命令行模式。
1. 執行 :put 命令:在命令行中輸入 :put =range(1, 10),其中 1 和 10 是序列的起始值和結束值。按下 Enter 執行該命令。
1. 序列生成完成:Vim 將在當前游標位置插入由 1 到 10 的序列。
### 洗牌
```bash
:%!shuf
# 這將使用Linux的shuf命令對文本進行洗牌,從而打亂數字的順序。
```
### Buffer 用法
每個打開的文件在 Vim 中都會被存儲在一個 buffer 中,而你可以在不同的 buffer 之間切換、操作和編輯文本。
以下是一些關於 Vim buffer 的基本用法教學:
1. **打開文件並創建 buffer**:
- 使用 `vim` 命令打開文件:`vim filename`
- 使用 `:e filename` 命令在當前編輯器中創建一個新的 buffer。
2. **切換 buffer**:
- 在 Normal 模式下,使用 `:bnext` 或 `:bn` 切換到下一個 buffer。
- 使用 `:bprev` 或 `:bp` 切換到上一個 buffer。
- 使用 `:bfirst` 切換到第一個 buffer。
- 使用 `:blast` 切換到最後一個 buffer。
- 使用 `:b<number>`(例如 `:b2`)切換到特定編號的 buffer。
3. **列出所有 buffer**:
- 在 Normal 模式下,使用 `:ls` 或 `:buffers` 命令列出所有已打開的 buffer。
4. **刪除 buffer**:
- 使用 `:bd` 命令關閉(刪除)當前的 buffer,但不會關閉窗口。
- 使用 `:bd<number>`(例如 `:bd2`)關閉特定編號的 buffer。
5. **在不同窗口中顯示 buffer**:
- 使用 `:split` 或 `:sp` 在水平分割窗口中打開一個新的 buffer。
- 使用 `:vsplit` 或 `:vsp` 在垂直分割窗口中打開一個新的 buffer。
6. **切換到其他窗口**:
- 使用 `Ctrl + w` 然後按 `w` 在窗口之間切換焦點。
- 使用 `Ctrl + w` 然後按 `h`、`j`、`k` 或 `l` 在不同的窗口之間進行導航。
### Map 的差異
在 Vim 中,`nnoremap`、`nmap` 和 `map` 都是用於建立按鍵映射的命令,但它們之間存在一些差異。以下是它們的解釋和區別:
1. `nnoremap`:這是 "non-recursive mapping" 的縮寫,表示非遞歸映射。當你使用 `nnoremap` 創建按鍵映射時,它將確保映射不受其他映射的影響。換句話說,即使你在映射的命令中使用了其他映射,這些被嵌套的映射不會被觸發。這在避免不必要的行為和循環映射中很有用。
2. `nmap`:這是 "normal mode mapping" 的縮寫,表示在正常模式(Normal Mode)下的映射。使用 `nmap` 創建的映射會在正常模式下生效,並且可能受到其他映射的影響,如果你在映射的命令中使用了其他映射。
3. `map`:這是一個通用的映射命令,不僅僅局限於正常模式。使用 `map` 創建的映射可能在各種模式下(正常模式、插入模式、命令模式等)都生效。然而,由於它會影響所有模式,所以可能會產生一些不預期的行為。
如果設定(`<C-UP>`)的映射沒有生效,有幾個可能的原因,讓我們一一檢查:
1. **終端機支援**: 確保你的終端機(或终端模擬器)能夠識別 `<C-Up>` 這樣的組合鍵。有些終端機可能不支援所有的組合鍵,或者需要特定的配置才能正確識別它們。
2. **映射碼**: `<C-Up>` 可能有不同的映射碼,具體取決於你的終端機。你可以使用 `Ctrl + V`(按住 Ctrl 鍵的同時按 V 鍵)來插入鍵盤輸入的原始碼。例如,`Ctrl + V` 然後 `Ctrl + Up`,看看你得到了什麼映射碼,然後在映射中使用它。
3. **配置文件**: 確保你的映射命令位於正確的配置文件中。對於大多數情況,你應該將這些映射添加到 `~/.vimrc`(或類似的配置文件)中。
4. **衝突映射**: 檢查是否有其他的映射或插件使用了 `<C-Up>` 作為映射。這可能會導致映射衝突,使你的映射無效。你可以使用 `:verbose map <C-Up>` 命令來查看是否有其他映射使用了相同的按鍵組合。
5. **重新載入配置**: 如果你在配置文件中進行了更改,確保你重新載入了配置或者重新啟動了 Vim。
### autocmd
在 Vim 編輯器中,`autocmd` 是「自動命令」(Auto Command)的縮寫。它是一種功能強大的設定方式,用於在特定事件發生時自動執行一系列的 Vim 命令。這些事件可以包括打開文件、保存文件、進入特定模式等等。`autocmd` 讓用戶能夠根據自己的需要,在不同情況下自動執行特定的操作。
舉個例子來說,假設你希望每次打開一個 Python 文件時,自動進入「插入模式」並設定縮進,你可以使用 `autocmd` 來實現這個需求。以下是一個示例的 `autocmd` 設定:
```
autocmd FileType python autocmd BufEnter *.py startinsert | set expandtab tabstop=4 shiftwidth=4
```
這行 Vim 腳本是用來設定當進入 Python 文件(`.py` 擴展名)時的自動行為。讓我們逐行解釋這個腳本:
1. `autocmd`: 這是 Vim 中的自動命令開始的部分,表示接下來是一個自動命令的定義。
2. `FileType python`: 這是自動命令的觸發事件,它表示當文件的類型被識別為 Python 時,該自動命令將被觸發。這種類型的識別是通過 Vim 識別文件類型的機制實現的。
3. `autocmd BufEnter *.py`: 在文件類型識別為 Python 的情況下,這部分指定了另一個觸發事件,即在切換到擴展名為 `.py` 的文件時觸發。
4. `startinsert`: 這是在觸發事件時要執行的第一個操作。`startinsert` 命令會進入「插入模式」,這意味著當你切換到 Python 文件時,Vim 會自動進入編輯模式,方便你開始編輯內容。
5. `|`: 這個符號表示在一個命令結束後執行另一個命令。在這個腳本中,它將 `startinsert` 命令和後面的命令分隔開。
6. `set expandtab tabstop=4 shiftwidth=4`: 這部分是第二個在觸發事件時執行的操作。這裡使用 `set` 命令設定了幾個編輯器選項:`expandtab` 設置為展開為空格,`tabstop` 設置為 4 個空格寬度,`shiftwidth` 設置為 4 個空格寬度。這些設置將確保在編輯 Python 文件時,Tab 鍵會被展開為 4 個空格,並且縮進也是 4 個空格。
```
" 自定義函式,用於處理 Python 檔案
function! ProcessPythonFile()
" 這裡可以寫你希望在處理 Python 檔案時執行的任何操作
echo "Processing Python file..."
" 更多操作...
endfunction
" 自動命令:當文件類型為 python 時呼叫自定義函式
autocmd FileType python call ProcessPythonFile()
```
### 常用的「自動命令事件」
以下是一些常用的 Vim 自動命令事件,它們可以幫助你根據不同的情況自動執行命令:
1. **BufRead**: 當從磁盤讀取文件內容到緩衝區時觸發,通常在打開文件時使用。
2. **BufReadPre**: 在讀取文件內容到緩衝區之前觸發,可以在讀取前進行一些處理。
3. **BufWrite**: 當將緩衝區中的內容寫入到磁盤文件時觸發,通常在保存文件時使用。
4. **BufWritePre**: 在寫入文件內容到磁盤之前觸發,可以在寫入前進行一些處理。
5. **FileType**: 當文件類型被識別時觸發,通常在打開文件或切換到不同文件時使用。
6. **CursorMoved**: 當游標移動到不同位置時觸發,可以用於更新狀態欄或其他相關操作。
7. **InsertEnter**: 當進入插入模式時觸發,可以在進入插入模式時執行一些操作。
8. **InsertLeave**: 當退出插入模式時觸發,可以在退出插入模式時執行一些操作。
9. **VimEnter**: 當 Vim 完全啟動並載入配置時觸發,可以在 Vim 啟動後執行初始化操作。
10. **ColorScheme**: 當更改顏色方案時觸發,可以在更改主題時進行相關的配置調整。
11. **WinEnter**: 當進入窗口(分割屏幕)時觸發,可以在切換到窗口時執行一些操作。
12. **WinLeave**: 當退出窗口(分割屏幕)時觸發,可以在離開窗口時執行一些操作。
13. **BufEnter**: 當切換到緩衝區(文件)時觸發,可以在切換文件時執行一些操作。
14. **BufLeave**: 當離開緩衝區(文件)時觸發,可以在離開文件時執行一些操作。
若 file.txt 存有需要開啟的檔案
```
path/to/file1.txt
path/to/file2.txt
```
開啟這些檔案並加入 buffer
```
vim $(cat file.txt)
```
### 按 = 格式化程式碼採用四個空格
在你的 `.vimrc` 或 `init.vim` 文件中添加以下行:
```vim
" 將 Tab 換成四個空格
set tabstop=4 " 設定 Tab 鍵的寬度為 4 個空格
set softtabstop=4 " 設定在插入模式中按 Tab 鍵時使用 4 個空格
set shiftwidth=4 " 設定自動縮進寬度為 4 個空格
set expandtab " 將 Tab 鍵轉換為空格
" 啟用自動縮進
set smartindent
set autoindent
```
這樣的設定確保了在插入模式中按下 Tab 鍵時,Vim 將插入四個空格,而不是 Tab 字符。同時,在使用 `=` 鍵格式化程式碼時,Vim 也將根據這些設定使用四個空格進行縮進。这是一种常见的设置,使得代码风格更加一致。
### 巨集
要使用Vim的巨集功能,可以按照以下步驟進行:
1. 錄製巨集:進入Normal模式,按下"q"鍵後接一個字母(用來指定巨集的名稱),然後進行需要錄製的操作步驟。操作完畢後再按下"q"鍵停止錄製。
1. 執行巨集:在Normal模式下輸入 "@" 後接巨集的名稱(剛剛錄製時指定的字母),然後按下Enter鍵即可執行巨集。
1. 重複執行巨集:若要重複執行巨集,可以在Normal模式下輸入一個數字(表示執行幾次)後再接 "@" 和巨集的名稱,按下Enter鍵即可重複執行。
1. `:reg` 命令用於顯示當前 vim 緩衝中的暫存器內容。透過這個命令可以查看、複製或刪除已複製的文字內容。
1. 存儲巨集:若要將巨集永久保存,可以將巨集存入vimrc文件中。可以使用以下命令:`:let @a='巨集內容'` 中的 'a' 是巨集的名稱。