# Vim 高级功能

2024年8月08日14分钟阅读

- FormalSciences/ComputerScience
- GettingStarted/CommandLineTools
- Vim

## 高级技巧

### 高级文本操作

#### 正则表达式

功能 | 命令或表达式 | 说明
--- | --- | ---
向前搜索 | `/pattern` | 向前搜索匹配的模式
向后搜索 | `?pattern` | 向后搜索匹配的模式
全文替换 | `:%s/pattern/replacement/g` | 全文替换所有匹配的模式
当前行替换 | `:s/pattern/replacement/g` | 替换当前行所有匹配的模式
删除行首空白 | `:%s/^\s\+//g` | 删除每行开头的空白字符
删除行尾空白 | `:%s/\s\+$//g` | 删除每行结尾的空白字符
匹配任意字符 | `.` | 匹配任意字符
匹配数字字符 | `\d` | 匹配数字字符
匹配非数字字符 | `\D` | 匹配非数字字符
匹配字母或数字字符 | `\w` | 匹配字母或数字字符
匹配非字母或数字字符 | `\W` | 匹配非字母或数字字符
匹配行首 | `^` | 匹配行首
匹配行尾 | `$` | 匹配行尾

#### 多行编辑

功能 | 命令 | 说明
--- | --- | ---
行可视模式 | `V` | 进入行可视模式
字符可视模式 | `v` | 进入字符可视模式
块可视模式 | `Ctrl+v` | 进入块可视模式
在每行开头添加 | `:%s/^/#/` | 使用正则表达式在每行开头添加 `#`
在每行结尾添加 | `:%s/$/;/` | 使用正则表达式在每行结尾添加 `;`

#### 宏录制与播放

功能 | 命令 | 说明
--- | --- | ---
录制宏 | `qx ... q` | 开始录制宏，`x` 是寄存器名，执行一系列命令后停止录制
播放宏 | `@x` | 播放寄存器 `x` 中的宏
重复播放宏 | `@@` | 重复播放上一个宏
多次播放宏 | `10@x` | 播放寄存器 `x` 中的宏 10 次

### VimScript

#### 基本语法

VimScript 是 Vim 的脚本语言，用于扩展和定制 Vim 的功能。以下是一些基本语法：

    " 这是一个注释

    " 变量
    let myvar = 42           " 整数变量
    let mystr = "Hello"      " 字符串变量

    " 条件语句
    if myvar > 0
        echo "Positive"
    elseif myvar == 0
        echo "Zero"
    else
        echo "Negative"
    endif

    " 循环语句
    let i = 0
    while i < 5
        echo i
        let i += 1
    endwhile

    for item in [1, 2, 3, 4, 5]
        echo item
    endfor

#### 函数和变量

    " 定义函数
    function! MyFunction(arg)
        echo a:arg
    endfunction

    " 调用函数
    call MyFunction("Hello")

    " 局部变量
    function! MyFunction()
        let l:localVar = "I am local"
        echo l:localVar
    endfunction

    " 全局变量
    let g:globalVar = "I am global"
    echo g:globalVar

#### 编写和调试简单的 VimScript 脚本

编写脚本：

将 VimScript 代码写入 `.vim` 文件，例如 `myplugin.vim`：

    " myplugin.vim
    function! SayHello()
        echo "Hello, Vim!"
    endfunction
    command! SayHello call SayHello()

加载脚本：

将脚本放入 Vim 的 `plugin` 目录，启动 Vim 自动加载：

    mkdir -p ~/.vim/plugin
    cp myplugin.vim ~/.vim/plugin/

调试脚本：

使用 `echo` 命令输出调试信息：

    echo "Debug info: " . someVar

使用 `:messages` 查看所有输出信息。

### 自动化

#### 使用自动命令

自动命令（autocommand）允许在特定事件发生时自动执行命令，例如文件保存、打开等。

    augroup MyAutoCmd
        autocmd!
        autocmd BufWritePost *.txt :echo "Text file saved!"
    augroup END

事件 | 说明 | 权重
--- | --- | ---
`BufReadPost` | 文件读取后 | 5
`BufWritePost` | 文件写入后 | 5
`BufNewFile` | 新建文件 | 4
`FileType` | 文件类型检测 | 5
`BufEnter` | 缓冲区进入 | 4
`BufLeave` | 缓冲区离开 | 4
`VimEnter` | Vim 启动后 | 5
`VimLeave` | Vim 退出前 | 5
`WinEnter` | 窗口进入 | 3
`WinLeave` | 窗口离开 | 3

#### 配置文件模板

在 `~/.vim/templates/` 目录中创建模板文件，例如 `python_template.py`：

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    Created on <++>

    @author: <++>
    """

    def main():
        pass

    if __name__ == "__main__":
        main()

使用自动命令应用模板:

    augroup MyTemplates
        autocmd!
        autocmd BufNewFile *.py 0r ~/.vim/templates/python_template.py
    augroup END

## 高效工作流

### 版本控制集成

#### 使用 Vim-fugitive

安装 vim-fugitive：

在 `vimrc` 文件中添加以下内容（以 vim-plug 为例）：

    call plug#begin('~/.vim/plugged')
    Plug 'tpope/vim-fugitive'
    call plug#end()

基本用法：

功能 | 命令 | 说明
--- | --- | ---
查看 Git 状态 | `:Gstatus` | 打开一个新窗口显示当前 Git 仓库的状态。可以在该窗口中导航和操作。
Git 添加 | `-` | 在 `:Gstatus` 窗口中，将光标移动到文件名上，按 `-` 号将文件添加到索引。
Git 提交 | `:Gcommit` | 打开一个新的缓冲区输入提交信息，完成后保存并关闭缓冲区即可提交。
Git 推送 | `:Gpush` | 将本地提交推送到远程仓库。
Git 拉取 | `:Gpull` | 从远程仓库拉取最新的代码。
Git 日志 | `:Glog` | 显示 Git 提交日志，可以在日志中导航和查看每个提交的详细信息。
Git 分支 | `:Gbranch` | 显示和管理 Git 分支。

#### 常用 Git 命令

在 Vim 中，使用 vim-fugitive 可以执行常见的 Git 命令。同时你也可以在 Vim 外部使用 Git 命令行工具：

功能 | 命令 | 说明
--- | --- | ---
克隆仓库 | `git clone <repository_url>` | 克隆一个远程仓库到本地。
查看状态 | `git status` | 查看当前仓库的状态。
添加文件 | `git add <file>` | 添加文件到索引。
提交更改 | `git commit -m "Commit message"` | 提交已添加的更改。
推送到远程仓库 | `git push` | 将本地提交推送到远程仓库。
拉取最新代码 | `git pull` | 从远程仓库拉取最新的代码。
创建新分支 | `git checkout -b <new_branch>` | 创建一个新的分支并切换到该分支。
合并分支 | `git merge <branch>` | 将指定分支合并到当前分支。

### 项目管理

#### NERDTree

在 `vimrc` 文件中添加以下内容（以 vim-plug 为例）：

    call plug#begin('~/.vim/plugged')
    Plug 'preservim/nerdtree'
    call plug#end()

打开/关闭 NERDTree

    :NERDTreeToggle

或者添加快捷键映射：

    nnoremap <C-n> :NERDTreeToggle<CR>

在 NERDTree 中导航

- 使用 `j` 和 `k` 键上下移动
- 使用 `o` 键打开文件或目录
- 使用 `x` 键关闭目录

显示隐藏文件

    :NERDTreeShowHidden

#### 配置项目相关设置

项目特定的 vimrc

在项目根目录下创建一个 `.vimrc` 文件，包含项目特定的 Vim 配置。然后在主 `vimrc` 中添加以下内容：

    if filereadable("path/to/project/.vimrc")
        source path/to/project/.vimrc
    endif

自动切换项目配置

可以使用 `vim-rooter` 插件自动切换项目根目录并加载项目特定的配置。在 `vimrc` 中添加以下内容：

    call plug#begin('~/.vim/plugged')
    Plug 'airblade/vim-rooter'
    call plug#end()
    let g:rooter_patterns = ['.git', '.hg', '.svn', 'Makefile']

### 代码补全与调试

#### YouCompleteMe 代码补全

YouCompleteMe 是一个强大的代码补全插件，需要编译安装。具体步骤如下：

1. 安装依赖（以 Ubuntu 为例）：

       sudo apt install build-essential cmake python3-dev

2. 安装 YouCompleteMe：

       git clone https://github.com/ycm-core/YouCompleteMe.git ~/.vim/bundle/YouCompleteMe
       cd ~/.vim/bundle/YouCompleteMe
       git submodule update --init --recursive
       python3 install.py --all

3. 在 `vimrc` 中添加以下内容：

       call plug#begin('~/.vim/plugged')
       Plug 'ycm-core/YouCompleteMe'
       call plug#end()

#### Deoplete 代码补全

Deoplete
是另一种流行的代码补全插件，基于 Neovim。

1. 安装依赖（以 Neovim 为例）：

       pip install neovim

2. 在 `vimrc` 中添加以下内容：

       call plug#begin('~/.vim/plugged')
       Plug 'Shougo/deoplete.nvim', {'do': ':UpdateRemotePlugins'}
       Plug 'Shougo/neosnippet.vim'
       Plug 'Shougo/neosnippet-snippets'
       call plug#end()

       let g:deoplete#enable_at_startup = 1

#### Vimspector 代码调试

在 `vimrc` 文件中添加以下内容（以 vim-plug 为例）：

    call plug#begin('~/.vim/plugged')
    Plug 'puremourning/vimspector'
    call plug#end()

基本配置：

`.vimspector.json` 文件，定义调试配置，例如：

    {
        "configurations": {
            "Launch": {
                "adapter": "debugpy",
                "configuration": {
                    "request": "launch",
                    "program": "${workspaceFolder}/your_script.py",
                    "console": "integratedTerminal"
                }
            }
        }
    }

使用：

1. 启动调试会话：

       :VimspectorLaunch

2. 设置断点： 将光标移动到需要设置断点的行，按 `F9` 键。

3. 继续执行、单步执行和停止调试： 使用 `F5`、`F10`、`F11` 和 `F12` 键进行调试控制。

## 性能优化

### 启动优化

#### 延迟加载插件

延迟加载插件可以显著提高 Vim 的启动速度，只在需要时加载插件。

使用 vim-plug 进行延迟加载：

1. 在 `vimrc` 中配置延迟加载：

       call plug#begin('~/.vim/plugged')
       Plug 'tpope/vim-fugitive', { 'on': 'Gstatus' }
       Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
       call plug#end()

   以上配置将 vim-fugitive 插件仅在执行 `:Gstatus` 命令时加载，NERDTree 插件仅在执行 `:NERDTreeToggle` 命令时加载。

使用 lazy.nvim 插件管理器：

lazy.nvim 是一个专门用于延迟加载插件的插件管理器。

1. 安装 lazy.nvim：

       git clone https://github.com/folke/lazy.nvim.git ~/.vim/pack/lazy/start/lazy.nvim

2. 配置延迟加载：

       call lazy#load_plugin('nerdtree', { 'on': 'NERDTreeToggle' })

#### 精简配置文件

移除不必要的配置：

定期检查 `vimrc` 文件，移除不再使用的配置和插件，以减少 Vim 的启动时间和运行负担。

分离插件配置：

将插件的配置分离到独立的文件中，以保持 `vimrc` 简洁。例如，将 NERDTree 的配置放在 `~/.vim/plugin/nerdtree.vim` 中：

    " ~/.vim/plugin/nerdtree.vim
    nnoremap <C-n> :NERDTreeToggle<CR>

使用本地配置：

根据项目需求，在项目根目录下创建 `.vimrc` 或 `.vim/` 目录，存放项目特定的配置文件，以避免在全局配置中添加过多内容。

### 系统集成

#### 将 Vim 与 Tmux 结合使用

tmux 是一个终端复用器，允许你在一个终端窗口中运行多个会话，与 Vim 结合使用可以大大提高工作效率。

安装 tmux：

在 Linux 或 MacOS 中，可以使用包管理器安装 tmux：

    sudo apt install tmux   # Debian/Ubuntu
    brew install tmux       # macOS

功能 | 命令 | 说明
--- | --- | ---
启动 tmux 会话 | `tmux` | 启动一个新的 tmux 会话
新建会话 | `tmux new -s session_name` | 创建一个名为 `session_name` 的新会话
附加会话 | `tmux attach -t session_name` | 附加到一个名为 `session_name` 的会话
列出会话 | `tmux ls` | 列出所有 tmux 会话
杀死会话 | `tmux kill-session -t session_name` | 杀死一个名为 `session_name` 的会话
分离会话 | `Ctrl-b d` | 分离当前会话
新建窗口 | `Ctrl-b c` | 创建一个新窗口
切换窗口 | `Ctrl-b n` | 切换到下一个窗口
切换窗口 | `Ctrl-b p` | 切换到上一个窗口
重命名窗口 | `Ctrl-b ,` | 重命名当前窗口
分割窗格 | `Ctrl-b %` | 垂直分割当前窗格
分割窗格 | `Ctrl-b "` | 水平分割当前窗格
切换窗格 | `Ctrl-b o` | 切换到下一个窗格
关闭窗格 | `Ctrl-b x` | 关闭当前窗格
同步窗格 | `Ctrl-b :setw synchronize-panes on` | 在所有窗格中同步输入
切换会话 | `Ctrl-b s` | 列出所有会话并切换

与 Vim 集成：

在 `vimrc` 中添加快捷键映射，方便与 tmux 交互：

    nnoremap <silent> <Leader>h :TmuxNavigateLeft<CR>
    nnoremap <silent> <Leader>j :TmuxNavigateDown<CR>
    nnoremap <silent> <Leader>k :TmuxNavigateUp<CR>
    nnoremap <silent> <Leader>l :TmuxNavigateRight<CR>

需要安装 `christoomey/vim-tmux-navigator` 插件：

    call plug#begin('~/.vim/plugged')
    Plug 'christoomey/vim-tmux-navigator'
    call plug#end()

#### 在终端中使用 Vim

在终端中使用 Vim 可以提高工作效率，特别是当你需要频繁切换编辑器和命令行时。

配置终端：

选择一个支持丰富功能的终端，例如 `iTerm2`（macOS）、`Alacritty`（跨平台）、`GNOME Terminal`（Linux）。

终端快捷键配置：

根据需要配置终端快捷键，方便打开 Vim。例如，在 `iTerm2` 中，可以设置快捷键快速打开新的终端窗口或标签，并启动 Vim。

Shell 集成：

在 `~/.bashrc` 或 `~/.zshrc` 中添加别名和函数，提高使用 Vim 的效率：

    alias vi="vim"
    alias svi="sudo vim"
    alias vrc="vim ~/.vimrc"

    # 快速打开项目目录中的 Vim
    function vproj() {
        cd ~/projects/$1 && vim
    }

使用 FZF 进行文件搜索：

FZF 是一个命令行模糊查找工具，可以与 Vim 集成，快速搜索和打开文件。

1. 安装 FZF：

       git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
       ~/.fzf/install

2. 在 `vimrc` 中配置 FZF：

       call plug#begin('~/.vim/plugged')
       Plug 'junegunn/fzf'
       Plug 'junegunn/fzf.vim'
       call plug#end()

       " 使用 FZF 查找文件
       nnoremap <Leader>f :Files<CR>