入门
模式与基本移动
Vim 是模式编辑器——不同模式服务于不同目的。Esc 可从 任何其他模式返回普通模式。hjkl 键让双手保持在主键盘行。w/b 按单词移动,0/$ 移动到行首/行尾,gg/G 跳到文件开头/末尾,:N 跳到第 N 行。
# Vim Modes
# Normal mode (Esc) - default, for navigation
# Insert mode (i) - for typing text
# Visual mode (v) - for selecting text
# Command mode (:) - for Ex commands
# Basic movement (Normal mode)
h # left
j # down
k # up
l # right
w # next word start
b # previous word start
0 # beginning of line
$ # end of line
gg # first line
G # last line
:42 # go to line 42退出与保存
ZZ 和 ZQ 是最快的退出方式——无需按冒号。:x 仅在文件已修改时写入(保留 mtime),而 :wq 总是写入。:w! 在文件系统权限允许时覆盖只读标记。使用 :qa! 退出多个已修改的缓冲区。
:w # write (save) file
:w! # force write (override read-only)
:q # quit
:q! # force quit (discard changes)
:wq # write and quit
:x # write only if changed, then quit
ZZ # same as :x (write if changed, quit)
ZQ # quit without saving (like :q!)
:w newfile.txt # save as new file
:sav newfile.txt # save as new file and switch to it
:wa # write all buffers
:xa # write all changed buffers and exit
:qa! # force quit all (discard everything)帮助系统
Vim 的帮助全面且带超链接。Ctrl-] 跟随标签(链接),Ctrl-T 返回。帮助记法:i_CTRL-N 表示插入模式下的 Ctrl-N,'number'(带引号)表示选项。:helpgrep 一次搜索所有帮助文件——用 :cn/:cp 在匹配间导航。K 调用光标下关键词的 man 手册(可通过 'keywordprg' 配置)。
:help # main help
:help subject # help on subject (e.g. :help insert)
:help i_CTRL-N # help on Ctrl-N in insert mode
:help 'number' # help on the 'number' option (quotes)
:helpgrep pattern # search all help files for pattern
:cn / :cp # next/prev helpgrep match
K # man page for word under cursor (Normal mode)
Ctrl-] # jump to tag under cursor (follow link)
Ctrl-T # jump back from tag (pop tag stack)
:helptags ~/.vim/doc # regenerate help tags for a doc directory单词与字符移动
小写移动(w/b/e)将标点视为单词分隔符——适合代码。大写移动(W/B/E)仅将空白视为分隔符——适合散文。e/E 移动到下一个单词的结尾;ge/gE 移动到上一个单词的结尾(少用但很方便)。
# Word motions (punctuation-aware)
w # next word start
b # previous word start
e # end of next word
ge # end of previous word
# WORD motions (whitespace-only delimiters, uppercase)
W # next WORD start
B # previous WORD start
E # end of next WORD
gE # end of previous WORD
# Word boundaries:
# word: sequence of word-characters OR sequence of punctuation
# WORD: anything separated by whitespace
# Examples (cursor on 'a' in "foo.bar baz"):
# w -> 'bar' (punctuation splits words)
# W -> 'baz' (only whitespace splits WORDS)行移动
0 和 $ 跳到绝对行首/行尾(包括空白)。^ 和 g_ 跳过行首/行尾的空白——通常正是你想要的。当 'wrap' 开启时,g0/g$ 在屏幕行上操作,而 0/$ 在逻辑行上操作。| 跳转到指定列号。
0 # first column (absolute start)
^ # first non-blank character
$ # end of line (last character)
g_ # last non-blank character
g0 # start of screen line (with wrap)
g$ # end of screen line (with wrap)
gm # middle of screen line
gM # middle of text line
| # column N (e.g. 10| = column 10)
+ # first non-blank of next line
- # first non-blank of previous line
_ # first non-blank of current line [count down]文件与屏幕移动
H/M/L 在可见屏幕内跳转。Ctrl-d/u 滚动半页(比整页 Ctrl-f/b 更不易迷失方向)。zz/zt/zb 将当前行滚动到屏幕中间/顶部/底部而不移动光标——在编辑时保持上下文极为有用。N% 跳到文件的百分比位置。
gg # go to first line
G # go to last line
Ngg / NG # go to line N (e.g. 50gg or 50G)
:N # go to line N (Ex command)
H # top of screen (High)
M # middle of screen
L # bottom of screen (Low)
N% # jump to N% of the file
Ctrl-f # scroll forward (full page)
Ctrl-b # scroll backward (full page)
Ctrl-d # scroll down (half page)
Ctrl-u # scroll up (half page)
zz # scroll current line to middle
zt # scroll current line to top
zb # scroll current line to bottom插入文本
基本插入 (i, I)
i/I 在光标前/行首插入。a/A 在光标后/行尾插入。gi 返回上次插入位置(标记 '^)——当你按 Esc 做了点别的又想继续输入时很方便。gI 跳到绝对第 1 列,忽略前导空白。
i # insert before cursor
I # insert at first non-blank (same as ^i)
gi # insert at last insert position (also sets mark)
gI # insert at column 1 (same as 0i)
a # insert after cursor
A # insert at end of line (same as $a)
# Examples:
# foo|bar + i -> foo|bar (cursor stays, type before)
# foo|bar + I -> |foobar (cursor at first non-blank)
# foo|bar + A -> foobar| (cursor at end)
# gi returns to where you last left insert mode —
# very useful after escaping to run a Normal-mode command.新开行 (o, O)
o 和 O 在光标下方/上方新开一行并进入插入模式。这是添加行的最快方式——无需将光标定位到行尾。缩进从周围行自动复制(由 'autoindent' 控制)。
o # open new line BELOW cursor, enter insert
O # open new line ABOVE cursor, enter insert
# Before (cursor on middle line):
# line one
# li|ne two
# line three
# After 'o':
# line one
# line two
# | <- new blank line, insert mode
# line three
# After 'O':
# line one
# | <- new blank line, insert mode
# line two
# line three修改命令 (c, C, s, S)
c{motion} 删除 motion 目标并进入插入模式——最灵活的编辑命令。C 是 c$(修改到行尾),S 是 cc(修改整行)。s 删除一个字符并进入插入;可与计数结合如 3s。ciw/caw 使用文本对象(见专门章节)。
cw / ce # change to end of word
cb # change backward to word start
c$ / C # change to end of line
cc / S # change entire line
c0 # change to beginning of line
c^ # change to first non-blank
ct, # change up to (but not including) next ','
cfx # change up to and including next 'x'
ciw # change inner word (no surrounding whitespace)
caw # change a word (with surrounding whitespace)
cap # change around paragraph
s # substitute: delete char under cursor, insert
S # substitute: delete entire line, insert (like cc)替换模式 (r, R, gr)
r 替换单个字符并立即返回普通模式(无模式切换)。R 进入替换模式,输入会覆盖字符——退格键会恢复原字符,不像插入模式那样只是删除。处理制表符时使用 gr/gR(虚拟替换)——它保留制表符对齐而不是移动文本。
r{x} # replace single char under cursor with x
gr{x} # virtual replace (doesn't shift tabs)
R # enter Replace mode (overwrite until Esc)
gR # virtual Replace mode (tabs stay aligned)
3r{x} # replace 3 chars with x (single char only)
# In Replace mode, typing overwrites existing text
# but Backspace restores the original characters.
# Tabs are preserved with virtual replace (gr/gR).
# Examples:
# abc|def + rx -> abc|xef (cursor advances)
# abc|def + R -> enter Replace mode
# type 'XYZ' -> abcXYZ|f
# Backspace -> abcXY|def (original restored)特殊插入
:r !cmd 将 shell 命令输出插入缓冲区——非常适合粘贴命令输出、日期、文件列表。在插入模式下,Ctrl-r 后跟寄存器名插入该寄存器;Ctrl-r = 计算 Vimscript 表达式并插入结果。Ctrl-k 通过输入两个 ASCII 字符插入二合字符(特殊字符)。
:r file.txt # insert contents of file below cursor
:r !command # insert output of shell command
:0r !date # insert date at top of file
:r !ls -la # insert directory listing
# Insert with special registers
Ctrl-r = # expression register: evaluate, insert result
Ctrl-r " # insert unnamed register
Ctrl-r % # insert current filename
# Insert from current file path
:i! !pwd # insert pwd output (no autoindent)
# Non-ASCII / digraphs (in insert mode)
Ctrl-k {ch1}{ch2} # digraph: e.g. Ctrl-k e' produces é
:digraphs # list available digraphs插入模式快捷键
Ctrl-h/w/u 在插入模式下相当于退格/删除单词/删除行。Ctrl-t/Ctrl-d 在不离开插入模式的情况下调整缩进——对代码至关重要。Ctrl-n/Ctrl-p 从缓冲区和标签中完成关键词。Ctrl-o 执行单个普通命令后返回插入(如 Ctrl-o zz 居中)。Ctrl-g u 打断撤销链,让长插入可分段撤销。
# In insert mode:
Ctrl-h # delete char before cursor (Backspace)
Ctrl-w # delete word before cursor
Ctrl-u # delete to start of line
Ctrl-t # indent current line (one shiftwidth)
Ctrl-d # dedent current line (one shiftwidth)
Ctrl-n # keyword completion (forward)
Ctrl-p # keyword completion (backward)
Ctrl-o # execute one Normal command, return to insert
Ctrl-r {reg} # insert register contents
Ctrl-a # insert text typed in last insert mode
Ctrl-@ # insert last text + Esc (like Ctrl-a then Esc)
Ctrl-g u # break undo sequence (start new undo block)
Ctrl-] # trigger abbreviation without inserting编辑命令(删除/复制/粘贴)
删除命令
d{motion} 是通用的删除操作符——可与任何 motion 结合。dd 删除整行。x 是 dl(删除字符)的快捷方式。被删除的文本进入无名寄存器(以及寄存器 1)。将 d 与文本对象(ciw、dib)结合可实现强大编辑。J 将下一行合并到当前行,插入一个空格。
x # delete char under cursor (also 'dl')
X # delete char before cursor (also 'dh')
dd # delete current line
dw # delete to next word start
de # delete to end of word
d$ / D # delete to end of line
d0 # delete to beginning of line
d^ # delete to first non-blank
dgg # delete from cursor to first line
dG # delete from cursor to last line
J # join next line (removes leading whitespace, inserts space)
gJ # join next line without inserting space
3dd # delete 3 lines
dW # delete WORD (whitespace-separated)复制 (Yank)
y{motion} 复制文本而不删除。yy 复制行。与 d(有 x 作为快捷方式)不同,y 没有单字符快捷方式——必须使用 motion。复制总是更新寄存器 0,便于与删除区分。使用文本对象:ya( 复制括号周围,yi" 复制引号内部。
y # yank {motion} (no character shortcut)
yy / Y # yank current line
yw # yank to next word start
ye # yank to end of word
y$ # yank to end of line
y0 # yank to beginning of line
yG # yank to end of file
ygg # yank to beginning of file
5yy # yank 5 lines
ya( # yank around parentheses
yi" # yank inside double quotes
yt, # yank up to (not including) next comma
# Yanked text goes to:
# " (unnamed register)
# 0 (yank register, only updated by y)粘贴 (Put)
p 在光标后粘贴(行向数据则粘贴到下方);P 在前面粘贴。gp/gP 将光标移到粘贴文本的末尾——在链式操作时很有用。]p/[p 重新缩进粘贴的行以匹配周围。剪贴板寄存器(+)在 'clipboard' 设置正确时与系统剪贴板共享。
p # paste after cursor (linewise: line below)
P # paste before cursor (linewise: line above)
gp # paste after, leave cursor on last pasted char
gP # paste before, leave cursor on last pasted char
]p # paste after, reindent to match
[p # paste before, reindent to match
"+p # paste from system clipboard
"*p # paste from primary selection (X11)
# Linewise vs charwise:
# yy + p -> pasted as a new line below
# y$ + p -> pasted after cursor on same line
# Counts: 3p pastes the register 3 times.大小写转换
~ 切换单个字符并前进。g~/gu/gU 是可与 motion 或文本对象配合的操作符。在可视模式下,U/u/~ 作用于选区。使用 gUiw 将当前单词大写,gUU 将整行大写。这些是非破坏性操作——只改变大小写。
~ # toggle case of char under cursor (advances)
3~ # toggle case of next 3 chars
g~{motion} # toggle case of motion
gu{motion} # lowercase motion
gU{motion} # uppercase motion
g~~ # toggle case of current line
guu # lowercase current line
gUU # uppercase current line
g~~gg # toggle case to first line
# Visual mode:
# U # uppercase selection
# u # lowercase selection
# ~ # toggle case of selection
# Examples:
# hello + gUw -> HELLO
# HELLO + guw -> hello
# hello + g~w -> HELLO合并与拆分行
J 用单个空格连接行;gJ 连接但不插入任何内容。:join 作用于范围。gq 是格式化操作符——它将行折行到 'textwidth'(通常为 80),并尊重 'formatoptions'。使用 gqip 重排段落,gqq 重排单行。设置 'textwidth=80' 启用自动折行。
J # join next line with current (inserts space)
gJ # join next line without inserting space
3J # join next 3 lines into one
:[range]join # join lines in range (also :j)
:[range]join! # join without inserting space
# Splitting a line:
# In insert mode, press Enter (autoindent applies)
# In normal mode: r<Enter> replaces char with newline
# Break a long line at column 80 (with 'textwidth'):
gq{motion} # format motion text to 'textwidth'
gqq # format current line
gqip # format paragraph
gvgq # format visual selection
# Set text width:
:set textwidth=80重复与撤销
. 重复上一次修改——Vim 中最有用的键。u/Ctrl-r 是撤销/重做。U 撤销当前行上的所有修改。:earlier/:later 可按时间或计数穿越,甚至跨分支(Vim 保留撤销树)。使用 :undolist 查看分支。@: 重复上一个 Ex 命令,& 重复上一次替换。
. # repeat last change (most powerful key in Vim)
u # undo
Ctrl-r # redo
U # undo all changes on current line
:Nu # undo N changes
:earlier 10m # revert to state 10 minutes ago
:later 5 # redo 5 changes
:undolist # show undo tree branches
# Repeat with counts:
5. # repeat last change 5 times
# Repeat Ex commands:
@: # repeat last :command
& # repeat last :s (substitute)
# Repeat macros/marks across files:
:& # repeat last substitute on current line查找与替换
基本查找
/ 和 ? 向前/向后搜索;n/N 重复。* 搜索光标下的整个单词(带单词边界),g* 搜索任何子串匹配。:noh 清除当前高亮直到下次搜索。设置 'hlsearch' 持久高亮所有匹配,'incsearch' 在输入时增量匹配。
/pattern # search forward for pattern
?pattern # search backward
n # repeat search (same direction)
N # repeat search (opposite direction)
* # search forward for word under cursor
# # search backward for word under cursor
g* # search forward (loose, matches substring)
g# # search backward (loose)
# Search history:
# Press / then Up/Down to recall previous searches
# Clear search highlighting:
:nohlsearch # or :noh
# Toggle 'hlsearch' permanently:
:set hlsearch!搜索选项
'ignorecase' + 'smartcase' 是推荐的组合:除非你的模式包含大写字母,否则不区分大小写。\c/\C 按搜索覆盖大小写。\v 启用 'very magic' 模式,许多字符无需转义即成为特殊字符——更简洁的正则语法。搜索偏移(e、b)将光标相对于匹配定位。
:set ignorecase # case-insensitive search (ic)
:set smartcase # case-sensitive if pattern has uppercase
:set hlsearch # highlight all matches (hls)
:set incsearch # show match as you type (is)
:set wrapscan # wrap around end of file (ws)
:set gdefault # add 'g' flag to all :s by default
# Per-search case override:
/foo\c # case-insensitive search for foo
/foo\C # case-sensitive search for foo
# Use very-magic mode (less escaping):
/foo\v(.+)@<=(bar) # very magic regex
# Search offsets:
/foo/e # cursor on last char of match
/foo/e+2 # cursor 2 chars past match
/foo/b-1 # cursor 1 char before match搜索模式(正则)
Vim 正则与 PCRE 不同——+、=、{、(、| 需要反斜杠。使用 \v 前缀启用 'very magic' 模式,这些字符无需转义即成为特殊字符(更接近 PCRE)。\< \> 标记单词边界。\d/\w/\s 是字符类。使用 \(...\) 作为捕获组,\1/\2 作为反向引用。
# Standard Vim regex (default magic mode)
. # any char
* # zero or more (preceding atom)
\+ # one or more
\= # zero or one (optional)
\{n,m} # between n and m
^ $ # start/end of line
\< \> # word boundaries
[abc] # char class (a, b, or c)
[^abc] # negated char class
\( \) # group
\1 \2 # backreference
\| # or
# Predefined classes:
\d \D # digit / non-digit
\w \W # word char / non-word
\s \S # whitespace / non-whitespace
# Very magic (\v prefix) — less escaping:
/\v\w+\s+\w+ # word, spaces, word (no backslashes needed)
/\v(%d+) # capture one-or-more digits替换命令
:[range]s/pattern/replacement/flags 是替换命令。:% 表示整个文件。不带 'g' 标志时每行只替换第一个匹配;'g' 替换所有。'c' 要求确认(y/n/a/q/l)。使用 \v 启用 very-magic 简化分组语法。捕获组在替换中引用为 \1、\2。
:[range]s/old/new/[flags]
# Basic:
:s/old/new/ # replace first 'old' on current line
:s/old/new/g # replace all 'old' on current line
:%s/old/new/g # replace all in whole file
:%s/old/new/gc # confirm each replacement
:%s/old/new/gi # case-insensitive
# Range examples:
:5,10s/old/new/g # lines 5-10
:.,$s/old/new/g # current line to end
:'a,'bs/old/new/g # from mark a to mark b
:'<,'>s/old/new/g # visual selection
:1,$s/old/new/g # whole file (same as %)
# Replace with capture groups:
:%s/\(\w\+\),\(\w\+)/\2,\1/ # swap two comma-separated words
:%s/\v(\w+),(\w+)/\2,\1/ # same with very-magic替换标志与特殊替换
常用标志:g(全部)、c(确认)、i(不区分大小写)、n(仅计数)。替换中的 & 插入匹配的文本。\u/\U/\l/\L 修改替换的大小写。使用 \r 插入换行(\n 在替换中是空字节)。'n' 标志非常适合只计数匹配而不做任何更改。
# Flags:
g # all occurrences on each line (not just first)
c # confirm each substitution
i # ignore case
I # don't ignore case
e # don't error if no match
p # print last substituted line
n # count matches, don't substitute
# Special chars in replacement:
& # the matched text
\0 # the matched text (same as &)
\1..\9 # capture groups
\u # next char uppercase
\U # rest of string uppercase (until \e or \E)
\l \L # lowercase (single / until \e)
\r # split into new line
\n # null byte (use \r for newline)
# Examples:
:%s/foo/&bar/g # foo -> foobar
:%s/\v(\w+)/\U\1/g # uppercase every word
:%s/, /,\r/g # split lines on ', '
:%s/old/new/gn # count matches only全局命令 (:g)
:g 在每行匹配模式的行上运行 Ex 命令——强大的'全局'编辑器。:v(或 :g!)在不匹配的行上运行。可与任何 Ex 命令结合:d(删除)、m(移动)、t(复制)、s(替换)、normal(运行普通模式命令)。:g 默认从上到下处理。
:[range]g/pattern/cmd # run cmd on each matching line
:[range]g!/pattern/cmd # run cmd on NON-matching lines
:v/pattern/cmd # same as :g! (inverse)
# Common uses:
:g/^$/d # delete all blank lines
:g/TODO/d # delete all lines with TODO
:g/pattern/p # print all matching lines
:g/pattern/normal @a # run macro a on each matching line
:g/pattern/m0 # move matching lines to top (reverse order)
:g/pattern/t$ # copy matching lines to end
:g/pattern/s/old/new/g # substitute on matching lines only
# Combined with Ex range:
:g/^#/s/foo/bar/g # in lines starting with #, replace foo with bar
# Multiple commands per match:
:g/pattern/d|t0 # delete then copy (chained with |)可视化模式
可视化模式类型
v/V/Ctrl-v 选择字符/行/块。gv 重新选择上次的可视选择——便于重新应用操作。o 移动到选区的另一端(这样你可以向任一方向扩展)。对于块模式,O 移动到同一行的另一个角。
v # charwise visual (select characters)
V # linewise visual (select whole lines)
Ctrl-v # blockwise visual (select rectangle)
gv # reselect last visual selection
# In visual mode:
o / O # move cursor to other end of selection (corner for block)
Esc / v # exit visual mode (toggle)
# Quick selections from normal mode:
vap # select around paragraph
vip # select inside paragraph
i" # then press v... actually ciw etc. work directly
# Switching between types:
# v then V -> linewise (extends to whole lines)
# V then v -> charwise
# Ctrl-v -> blockwise可视化操作
一旦有了选区,d/c/y/x 按预期工作。= 自动缩进(非常适合代码重排)。>/< 缩进/取消缩进一个 shiftwidth。! 通过 shell 命令过滤选区并用输出替换。在可视模式下按 : 会自动填充 '<,'> 作为范围,因此 :s/old/new/g 只在选区上运行。
# In visual mode, press:
d / x # delete selection
c / s # change selection (delete, enter insert)
y # yank (copy) selection
~ # toggle case of selection
u / U # lowercase / uppercase selection
> # indent selection
< # dedent selection
= # auto-indent selection (reformat)
!cmd # filter through external command
:r !cmd # (after yank) paste command output
# Replace entire selection with a char:
r{x} # replace every char with x
# Print line numbers of selection:
g Ctrl-g # count words/chars/lines in selection
# Search within selection (after selecting, type :):
# '<,'>s/old/new/g -- range auto-filled块可视化技巧
可视块(Ctrl-v)是 Vim 最强大的功能之一。I 和 A 在块前/后插入——文本在 Esc 后复制到每一行。这是为多行添加注释前缀或追加后缀的最简单方法。c 修改整个块;r{x} 用 x 替换每个字符。当行长度相似时块编辑才能正常工作。
# Enter block visual: Ctrl-v
# Select a column rectangle, then:
I # insert BEFORE block (text typed appears in front)
# Type text, then Esc -> inserted on every line of block
A # insert AFTER block (text appears at end of each line)
# Esc propagates the insert to all lines
c # change block (delete, enter insert; Esc propagates)
r{x} # replace every char in block with x
# Common use cases:
# 1. Add a comment to a column of lines:
# Ctrl-v select first column, I, type '# ', Esc
# 2. Add semicolons at end of selected lines:
# Ctrl-v select end column, $A;, Esc
# 3. Delete a column:
# Ctrl-v select, d
# 4. Replace a column with same char:
# Ctrl-v select, r;行可视化模式
V 选择整行。V 之后常用操作是 d/y/>/</= 来操作它们。:m 移动选区(如 :'<,'>m0 移到顶部)。:t 复制。'< 和 '> 是上次可视选区开始/结束的标记——在脚本中很有用。gv 重新选择上次的可视范围。
V # enter linewise visual
5V # select 5 lines (current + 4 below)
ggVG # select entire file
:'<,'> # range referring to last visual selection
# After selecting lines (V), useful commands:
d # delete lines
y # yank lines (linewise)
> # indent lines
< # dedent lines
= # auto-indent lines
:m +2 # move selection down 2 lines
:m -3 # move selection up 3 lines
:t . # duplicate lines (copy below selection)
:g/^/m0 # reverse line order (whole file)
# Reselect last visual:
gv # reselect last visual selection
'< # mark: start of last visual
'> # mark: end of last visual可视化与文本对象
文本对象在可视模式下也工作——它们扩展当前选区。vi( 选择括号内部;va( 包括括号。重复文本对象(vawaw)进一步扩展。这通常比手动定位光标更快。与操作符结合:ciw 修改内部单词,无论光标在其内的哪个位置。
# In visual mode, text objects EXTEND the selection:
# After pressing v (charwise), type:
aw # extend selection to include next 'a word'
iw # extend selection to inner word
ab # around brackets ()
ib # inside brackets ()
aB # around braces {}
iB # inside braces {}
a" # around double-quoted string
i" # inside double-quoted string
ap # around paragraph
ip # inside paragraph
# Repeated text objects extend selection:
# vaw -> select word + trailing space
# vawaw -> extend to next word + space
# Switch between inner and around:
# vi( -> select inside parens
# va( -> extend to include the parens可视化查找与编号
在可视模式下按 : 会预填充 '<,'> 作为范围——替换只在选区上运行。要搜索可视选区,使用 y/ 然后 Ctrl-r " Enter(将寄存器粘贴到搜索中)。可视块中的 g Ctrl-a 创建递增序列——从一列相同数字生成编号列表(1、2、3、...)极为有用。
# Search within visual selection:
# 1. Visually select (v/V/Ctrl-v)
# 2. Press : -> :'<,'> appears
# 3. Type s/old/new/g -> substitute only in selection
# Search for current visual selection (forward):
# In visual mode, type:
# \V then / (very-nomagic, escapes regex chars)
# Or use a plugin (e.g. vim-visual-star-search)
# Manual method:
# y/ then Ctrl-r " Enter -> search for selection
# Increment/decrement numbers (visual block):
# Select a column of numbers (Ctrl-v)
Ctrl-a # increment every number in selection by 1
Ctrl-x # decrement every number in selection by 1
g Ctrl-a # increment with running counter (1,2,3,...)
g Ctrl-x # decrement with running counter
# Example: turn 0,0,0,0 into 1,2,3,4:
# Ctrl-v select column, g Ctrl-a缓冲区
缓冲区基础
缓冲区是内存中的文件。:e 将文件打开到新缓冲区。:ls 列出所有缓冲区及状态标志(% = 当前,# = 交替,+ = 已修改,h = 隐藏)。:b N 按编号切换;:b name 按唯一前缀切换。Ctrl-6(或 :b#)在当前和交替缓冲区之间切换——极为常用。
:e file.txt # open file in new buffer (current window)
:enew # new empty buffer
:ls / :buffers # list all buffers
:b N # go to buffer N (by number from :ls)
:b name # go to buffer by name (unique prefix)
:bn # next buffer
:bp # previous buffer
:b# / Ctrl-6 # alternate buffer (last edited)
:ball # open all buffers in horizontal splits
:vertical ball # open all buffers in vertical splits
# Buffer list symbols:
# % current window's buffer
# # alternate buffer
# a active (loaded and visible)
# h hidden (loaded but not visible)
# - not modifiable
# = read-only
# + modified缓冲区导航
:bn/:bp 循环缓冲区。Ctrl-6 在两个最近的缓冲区之间切换——来回切换的最快方式。设置了 'hidden' 时,从已修改缓冲区切换不会强制保存——Vim 会隐藏它。如果忘了缓冲区编号,使用 :ls 然后 :b N。fzf.vim 等插件让模糊缓冲区切换快得多。
:bn / :bnext # next buffer (wraps around)
:bp / :bprev # previous buffer
:bf / :bfirst # first buffer
:bl / :blast # last buffer
:b# # alternate buffer (Ctrl-6)
:N b # go to buffer number N (e.g. 3b)
:b name<tab> # tab-complete buffer name
:ls then :b N # two-step navigation
# Faster navigation (set in vimrc):
:nmap <C-n> :bn<CR>
:nmap <C-p> :bp<CR>
# Jump to a buffer with fuzzy matching (with fzf.vim):
:Buffers # fuzzy-select from buffer list
# Hide current buffer without saving (if 'hidden' is set):
:hide # or :bn with 'set hidden'缓冲区操作
:bd 从列表中移除缓冲区(文件关闭)。:bw 还清除标记和缓冲区局部变量。:%bd | e# 删除除当前外的所有缓冲区——常见的清理模式。:bufdo 在每个缓冲区中运行 Ex 命令——对全局替换很强大,但要注意错误(用 ! 忽略,或给 :s 加 'e' 标志)。
:bd / :bdelete # delete current buffer
:bd N # delete buffer N
:bd name # delete buffer by name
:bw / :bwipeout # wipe buffer (also clears marks, vars)
:N,N bd # delete buffers in range
:%bd # delete all buffers
:%bd | e# # delete all but current
:bn! # force switch (don't save current)
:wall # write all buffers
:bufdo cmd # run cmd in every buffer
:bufdo! cmd # same but ignore errors
# Useful patterns:
:bufdo %s/old/new/ge # substitute in all buffers
:bufdo setlocal nowrap # apply setting to all buffers
# Save and quit current buffer:
:wq # write current and quit (closes window)隐藏缓冲区
设置 'set hidden'(强烈推荐)后,可以从已修改缓冲区切换而无需保存——Vim 将它们保留在内存中。不设 'hidden' 时,Vim 阻止切换直到你保存或用 ! 丢弃。:ls 显示 'h' 表示隐藏缓冲区,'+' 表示已修改。此设置对高效多文件编辑至关重要。
:set hidden # allow switching from modified buffers
:set nohidden # force save/abandon when switching
# With 'hidden' set:
# :bn # switch even if current is modified (no save)
# :q # if buffer is modified, prompts to save
# :qa! # quit all without saving
# :wa # write all (hidden + visible)
# Buffer with changes still in memory:
:ls # shows 'h' flag for hidden, '+' for modified
# Recover list of hidden buffers:
:ls h # only hidden buffers
# Save a hidden buffer:
:w # save current (if visible)
:N w # save buffer N
:wall # save all buffers
# Common workflow with hidden:
# :e file1 -> make changes -> :e file2 -> :e file1 (changes preserved)参数列表
参数列表是与缓冲区列表分开的列表——它是命令行传入的文件集合或用 :args 设置的。:n/:prev 在其中导航。:argdo 在每个参数列表文件中运行 Ex 命令——非常适合批量处理如 :argdo %s/foo/bar/ge | update。参数列表通常比缓冲区列表更聚焦。
# Open files in arglist:
vim file1.txt file2.txt # initial args
:args file1 file2 file3 # replace arglist
:argadd file4 # add to arglist
:arga *.py # add all Python files
:argdelete file2 # remove from arglist
# Navigate arglist:
:n / :next # next file in arglist
:prev / :Next # previous file
:first # first file
:last # last file
:rewind # rewind to first file
# Process all files:
:argdo %s/old/new/ge # substitute in every arg file
:argdo set ff=unix | w # convert line endings in all
# Show current arglist:
:args # show files (current marked with [ ])缓冲区列表管理
:ls 列出缓冲区,:ls! 包括未列出的(已删除但被记住的)。使用 :sb 在分割中打开缓冲区而不改变当前窗口的缓冲区。没有内置的'最近关闭缓冲区'撤销,但存在插件。:bufdo vimgrepadd 后跟 :copen 可通过 quickfix 列表搜索所有打开的缓冲区。
:ls # list all buffers
:ls! # list including unlisted buffers
:files # alias for :ls
# Move current buffer to a specific position:
:N b N # buffer number N
# Quickly inspect related files:
:b <tab> # tab-complete buffer names
:b #<tab> # buffers matching '#'
# Find buffer containing a pattern:
:vimgrep /pattern/ % # current buffer only
:bufdo vimgrepadd /pattern/ % # all buffers (then :copen)
# Open buffer in a specific window:
:sb N # open buffer N in horizontal split
:vertical sb N # open buffer N in vertical split
:tab split +b N # open buffer N in new tab
# Restore closed buffers:
# (No built-in, but plugins like vim-molten or
# vim-restore-buffers can help)标记与跳转
设置标记
标记是文件中的命名位置。小写(a-z)是缓冲区局部的;大写(A-Z)是跨 Vim 会话持久化的文件标记。编号标记(0-9)由 Vim 自动设置——0 是 Vim 上次关闭时的位置,1-9 是最近关闭的 9 个文件。:marks 列出它们,:delm 删除。
m{a-zA-Z} # set mark at cursor position
ma # set mark 'a' (lowercase, buffer-local)
mA # set mark 'A' (uppercase, file mark)
m' # set the unnamed mark (jump before/after)
# Lowercase marks (a-z):
# Local to current buffer
# Lost when buffer is unloaded
# Uppercase marks (A-Z):
# File marks — preserved across sessions
# Work even after the file is closed
# Numbered marks (0-9):
# Set automatically by Vim
# 0 = position when Vim was last closed
# 1-9 = positions of last 9 closed files
# View marks:
:marks # list all marks
:marks a b c # specific marks
:delm! a # delete mark 'a' (force)跳转到标记
`(反引号)跳到精确位置(行+列);'(撇号)跳到标记行的第一个非空白字符。`A 打开包含标记 A 的文件,即使它已关闭。`. 跳到你上次修改文本的位置,`[ 和 `] 界定上次复制/删除的区域,`< 和 `> 界定上次可视选区。
\`{a-zA-Z} # jump to mark (line AND column)
'{a-zA-Z} # jump to mark (line only, column 1)
\`a # jump to mark 'a' (exact position)
'a # jump to line of mark 'a'
\`A # jump to file mark 'A' (opens file if closed)
\`. # jump to position of last change in this buffer
\`" # jump to position when file was last closed
\`[ # jump to start of last yanked/changed text
\`] # jump to end of last yanked/changed text
\`< # jump to start of last visual selection
\`> # jump to end of last visual selection
\`^ # jump to last insert position (also gi)
# Jump to next/prev mark in alphabetical order:
:[count]next # (no built-in, requires plugin)跳转列表
Vim 保留重要光标移动的跳转列表。Ctrl-o/Ctrl-i 在其中向后/向前移动。'重要'意味着跳转(G、gg、搜索、标记跳转、标签跳转)——不是 j/k/w 等常规 motion。:jumps 显示列表。跳转列表是按窗口的,并在 viminfo/shada 中跨会话持久化。
Ctrl-o # jump BACK in jumplist (older positions)
Ctrl-i # jump FORWARD in jumplist (newer positions)
Tab # same as Ctrl-i
:ju # show jumplist (:jumps)
# What counts as a jump?
# - Movement commands: G, gg, H, M, L, %
# - Search: /, ?, n, N, *, #
# - Mark jumps: 'x, `x (NOT mm)
# - Buffer switch: Ctrl-6, :b, :e
# - Tag jumps: Ctrl-]
# NOT counted: j, k, w, b, h, l (regular motions)
# Max jumplist size: 100 entries by default
:set jumpoptions=stack # treat jumplist like a stack
# Clear jumplist:
:clearjumps # or :clj修改列表
修改列表跟踪编辑位置(不是导航)。g; 跳到上一个编辑,g, 跳到下一个。用于回溯你的修改:'我刚才在哪里工作?'。:changes 显示列表。与跳转列表不同,修改列表是按缓冲区的。与 `.` 结合可获取当前缓冲区中最后一次修改。
g; # go to OLDER position of last change
g, # go to NEWER position of last change
:changes # list changelist
# Each entry shows:
# change number, line, column, text of change
# What counts as a change?
# - Any insertion, deletion, or substitution
# - Records the position BEFORE the change
# Differences from jumplist:
# - Changelist tracks EDITS, not movements
# - Per-buffer (not per-window)
# - Limited to 100 entries
# Combine with marks:
\`. # last change position in current buffer
g; # previous change position
# Common pattern: g;g;g; to walk back through edits文件标记 (A-Z)
大写标记(A-Z)是文件标记——它们记住文件和位置,跨 Vim 会话持久化(存储在 viminfo 中)。在 foo.txt 中设置 mA 后,你可以用 `A 从任何地方返回到该位置,即使重启 Vim 后也行。将它们用作项目中重要文件/位置的书签。
# Setting a file mark:
mA # set mark 'A' at cursor (in current file)
mB # set mark 'B' (in current file)
# Jumping to a file mark:
\`A # if file is open: jump to position
\`A # if file is closed: open it, then jump
'A # jump to first non-blank of mark's line
# File marks persist across Vim sessions:
# Stored in viminfo (or shada in Neovim)
# Restored on next Vim launch
# Use cases:
# 1. Bookmark a function: mA in function definition
# 2. Quick jump between files: `A, `B
# 3. Project navigation: set marks in important files
# Listing file marks:
:marks A-Z # show only file marks
# Deleting:
:delm A # delete file mark A (must be in its file)内置特殊标记
Vim 自动设置特殊标记。`. 是上次修改,`[ 和 `] 界定上次复制/删除的区域,`< 和 `> 界定上次可视选区,`^ 是插入模式上次结束的位置(gi 跳到那里并重新进入插入)。`" 是文件上次关闭时的位置——用于恢复工作。
\`. # position of last change in current buffer
\`" # position when file was last exited
\`[ # start of last yanked/changed text
\`] # end of last yanked/changed text
\`< # start of last visual selection
\`> # end of last visual selection
\`^ # position where insert mode was last stopped
\`' # position before latest jump (where you came FROM)
# Common uses:
\`[\`] # operate on last yanked range: \`[v\`]U (uppercase it)
\`<\`> # re-select last visual: \`<v\`> or gv
# Re-select last visual selection:
gv # easier than \`<v\`>
# Re-select last pasted text:
\`]v\`[ # or use a mapping: nnoremap gp \`]v\`[
# Return to last insert position:
gi # jump to `^ and enter insert mode文本对象
单词与句子对象
文本对象让你在语义单元上操作。'aw'(around word)包括尾部空白——daw 闭合间隙。'iw'(inner word)保留空白——diw 留下空白。as/ap 是句子/段落版本。重复对象(dawaw)扩展选区。与 d/c/y/v 操作符配合最为有用。
# Operators (d/c/y/v) + text object:
aw # 'a word' - word + trailing whitespace
iw # 'inner word' - word only (no whitespace)
aW # 'a WORD' - WORD + trailing whitespace
iW # 'inner WORD' - WORD only
as # 'a sentence' - sentence + trailing space
is # 'inner sentence' - sentence only
ap # 'a paragraph' - paragraph + trailing blank line
ip # 'inner paragraph' - paragraph only
# Examples:
daw # delete word + trailing space (closes gap)
diw # delete word only (leaves whitespace)
cas # change sentence (with trailing space)
yap # yank paragraph (with trailing blank line)
gqip # format (wrap) inner paragraph
# Repeated: dawaw extends to next word括号对象
括号对象作用于 ()、[]、{}、<>。a(around)包括括号;i(inner)排除括号。ci( 修改括号内的内容而不删除括号——完美用于编辑函数参数。嵌套时作用于最内层一对。at/it 作用于 HTML/XML 标签(如 cit 修改标签内部内容)。
# Brackets (any of ( [ { <):
ab / ib # around / inside ()
aB / iB # around / inside {} (also a{ / i{)
a( / i( # same as ab / ib
a[ / i[ # around / inside []
a{ / i{ # same as aB / iB
a< / i< # around / inside <>
# Examples:
ci( # change text inside ( ... )
daB # delete {...} block including braces
yi[ # yank text inside [...]
vaB # visually select around {...}
# Special: 'tag' objects (HTML/XML):
at / it # around / inside <tag>...</tag>
# Tip: works with mismatched brackets too:
# ci) on (foo bar) changes 'foo bar'
# Nested: ci( in ((a)(b)) changes innermost引号对象
引号对象(a"/i"、a'/i'、a`/i`)作用于引号字符串。光标不需要在引号内——Vim 会找到最近的一对。ci" 修改字符串内容而不删除引号——对编辑字符串字面量极为有用。'a' 包括引号,'i' 排除引号。
a" # around double-quoted string (includes quotes)
i" # inside double-quoted string (no quotes)
a' # around single-quoted string
i' # inside single-quoted string
a\` # around backtick-quoted string
i\` # inside backtick-quoted string
# Examples:
ci" # change text inside "..."
da" # delete "..." (including quotes)
yi' # yank text inside '...'
va\` # visually select around \`...\`
# Cursor can be ANYWHERE on the line — Vim finds the
# nearest quote pair containing or following the cursor.
# Special: with counts
3a" # around 3 consecutive quoted strings
# Tip: ci" when cursor is on the quote itself works too句子与段落对象
句子以 . ! ? 后跟空白(或段落中断)结束。段落是由空行分隔的文本块。'a' 包括尾部空白,'i' 排除它。与操作符配合很有用:gqap 重排段落,>ip 缩进段落,das 删除句子。( 和 ) motion 在句子之间跳转。
# Sentence: ends with . ! ? followed by whitespace
as / is # around / inner sentence
# Paragraph: blocks of text separated by blank lines
ap / ip # around / inner paragraph
# Examples:
das # delete a sentence
cip # change inside paragraph
vap # select around paragraph (with trailing blank)
# Differences:
# 'a' (around): includes trailing whitespace/blank line
# 'i' (inner): no trailing whitespace
# Use cases:
# gqap # reformat (wrap) the paragraph
# >ap # indent the paragraph
# vip # select inside paragraph
# :'<,'>s/old/new/g # substitute in selected paragraph
# Sentence motion commands (not objects):
( # previous sentence start
) # next sentence start标签与 URL 对象(需插件)
内置的 at/it 作用于 HTML/XML 标签。cit 修改标签内部内容,dat 删除包括开/闭标签的整个标签。对于嵌套标签,it 选择最内层,然后 vat 向外扩展。插件添加更多对象:vim-textobj-url(au/iu)、vim-indent-object(ai/ii 用于同缩进块——对代码极好)。
# Built-in tag object (HTML/XML):
at / it # around / inside <tag>...</tag>
# Examples:
cit # change inner tag text: <p>text</p> -> <p>|</p>
dat # delete entire tag: <p>text</p> -> (gone)
vit # visually select inner tag text
yat # yank entire tag including <tag>...</tag>
# For nested tags, 'it' selects the innermost:
# <div><p>text</p></div>
# cit on 'text' changes 'text' only
# vat extends selection outward
# URL objects (require a plugin like vim-textobj-url):
# au / iu # around / inside URL
# Indent objects (require vim-indent-object):
# ai / ii # around / inside same-indent block
# aI / iI # entire indentation level
# Common plugin combos:
# vai # select around indent block (great for code)使用文本对象(配方)
文本对象与任何操作符(d/c/y/v/>/</=)结合实现强大编辑。ciw 修改单词而无需精确定位光标。ci"/ci(/ci[ 修改引号/括号内部。gqip 重排段落。掌握这些是在 Vim 中以思维速度编辑的关键。
# Common editing recipes using text objects:
# Word:
ciw # change word (regardless of cursor position in it)
daw # delete word + space (closes gap)
yiw # yank inner word (no whitespace)
# Quotes:
ci" # change inside "..."
ci'\` # change inside '...' or \`...\`
da" # delete the entire string (with quotes)
# Brackets:
ci( # change inside (...) -- great for args
daB # delete {...} block (function body)
ci[ # change inside [...]
# Sentences & paragraphs:
cas # change a sentence
dap # delete a paragraph
gqip # reformat paragraph
# HTML tags:
cit # change tag content
vat # select tag, then vat again to extend
# Combos with counts:
2daw # delete two words
c2aw # change two words寄存器
寄存器基础
寄存器是 Vim 的剪贴板。"ayy 将行复制到寄存器 a,"ap 从 a 粘贴。有许多寄存器:命名(a-z)、追加(A-Z)、编号(1-9)和特殊(无名 "、复制 0、剪贴板 + 等)。:reg 列出它们。在插入模式下,Ctrl-r {reg} 插入寄存器。大写字母追加到寄存器。
# Registers store text. 10 named (a-z), 10 append (A-Z),
# 9 numbered (1-9), and several special ones.
"ay # yank into register 'a' (then motion: "ayy, "ayw)
"ap # paste from register 'a'
"ad # delete into register 'a' (e.g. "add)
"Ay # APPEND to register 'a' (uppercase = append)
# View all registers:
:reg # list all registers
:reg a b c # list specific registers
:reg + # show clipboard register
# Use a register with operators:
"aD # delete to end of line into 'a'
"byy # yank line into 'b'
"cp # paste register 'c'
# Insert mode: Ctrl-r + register
Ctrl-r a # insert contents of register 'a'
Ctrl-r = # expression register (compute, insert)
# Search from a register:
/ then Ctrl-r a # search register 'a' contents命名与编号寄存器
命名寄存器(a-z)由用户控制;A-Z 追加到 a-z。编号寄存器(1-9)自动跟踪最近的删除——1 是最近的,每次新删除向下移动。寄存器 0 只保存上次的复制(删除不会覆盖它)——对先复制后删除的工作流有用。"- 保存小的(子行)删除。
# Named registers (a-z, A-Z):
"ayy # yank line into 'a'
"byiw # yank inner word into 'b'
"Ayy # append yanked line to 'a' (uppercase)
# Numbered registers (1-9) — auto-filled by deletes:
"1 # last delete (largest)
"2 # second-to-last delete
... # shift older with each new delete
"9 # oldest tracked delete
# Small delete register:
"- # stores deletes < 1 line (e.g. dw)
# Yank register (separate from deletes):
"0 # last YANK only (not affected by deletes)
# Examples:
"0p # paste last yank (won't paste a delete)
"1p # paste last delete
". # last inserted text (read-only)
"% # current file name (read-only)特殊寄存器
特殊寄存器:". = 上次插入的文本,"% = 当前文件,"/ = 上次搜索,": = 上次命令。"_ 是黑洞——写入它的内容被丢弃(用于不希望污染其他寄存器的删除)。"+ 是系统剪贴板,"* 是 X11 主选区。"= 计算 Vimscript 表达式并插入结果。
# Read-only registers:
". # last inserted text
"% # current file name
"# # alternate file name
": # last Ex command
"/ # last search pattern
# Read/write registers:
"0 # last yank (not overwritten by deletes)
"- # last small delete (less than one line)
"_ # black hole register (discard, like /dev/null)
"= # expression register (evaluate Vimscript)
# Clipboard / selection:
"+ # system clipboard (Ctrl-C / Ctrl-V)
"* # primary selection (X11 middle-click)
# Examples:
"_dd # delete line without saving to register
"+y # yank to system clipboard (then Ctrl-V elsewhere)
"*p # paste from X11 primary selection
# Expression register (in insert mode):
Ctrl-r =strftime('%Y-%m-%d')<CR>
# inserts today's date
# Black hole: "_ prevents updating other registers.寄存器中的宏
宏存储在寄存器中——用 qa 录制会将按键写入寄存器 a,@a 播放。因为它们是寄存器,你可以检查它们(:reg a)、通过粘贴/修改/重新复制来编辑它们,或用 :let @a = '...' 保存到 vimrc。在字符串字面量中用 \<Esc> 转义特殊键。
# Macros are stored in registers, just like yanked text.
# Record a macro into register 'a':
qa # start recording into 'a'
... # perform actions
q # stop recording
# Play back the macro:
@a # play macro 'a' once
@@ # play last macro again (the one just played)
5@a # play macro 'a' 5 times
:reg a # view the recorded keystrokes
# Edit a macro:
:let @a = "..." # set register 'a' directly
# Or: paste the register, edit, yank back:
"ap # paste macro keystrokes
# ... edit the text ...
"ayy # yank edited version back into 'a'
# Save a macro to vimrc:
:let @a = "0iHello \<Esc>" # escaped special keys
# Apply macro to a range:
:%normal @a # run macro 'a' on every line追加与黑洞寄存器
大写寄存器字母追加:"Ayy 追加到寄存器 a(对构建文本或多步宏非常有用)。黑洞寄存器 "_ 丢弃写入它的任何内容——删除不会更新编号/无名/复制寄存器。当你想删除文本而不覆盖上次复制时使用它。
# Append to a register (use UPPERCASE letter):
"ayy # yank line into 'a'
"Ayy # APPEND another line to 'a'
"Ayiw # APPEND a word to 'a'
# After: register 'a' contains both.
# Black hole register "_:
"_d # delete without affecting other registers
"_dd # delete line, doesn't update "1, "0, "-
"_c # change without saving deleted text
"_x # delete char, nothing saved
# Why use black hole?
# - Keep your yank register ("0) intact while deleting
# - Avoid polluting numbered registers
# Example: yank a line, then delete another (without
# losing the yank):
"ayy # yank into 'a'
"_dd # delete line WITHOUT touching 'a' or '0
"ap # paste the original yank
# When clipboard=unnamed, "_d still bypasses clipboard.剪贴板与选区
"+ 是系统剪贴板(GUI 应用中的 Ctrl-C/Ctrl-V),"* 是 X11 主选区(中键粘贴)。设置 :set clipboard=unnamedplus 后,复制和粘贴直接进入系统剪贴板——无需 "+ 前缀。在 Linux 上,你可能需要安装 xclip/xsel(X11)或 wl-clipboard(Wayland)。
# System clipboard register:
"+y # yank to system clipboard
"+p # paste from system clipboard
"+dd # delete line to clipboard
"+P # paste before cursor from clipboard
# X11 primary selection (Linux, middle-click):
"*y # yank to primary selection
"*p # paste from primary selection
# Make the system clipboard the default:
:set clipboard=unnamedplus # use '+ for unnamed register
:set clipboard=unnamed # use '* for unnamed register
# Then yank/paste go to clipboard automatically:
yy # yanks to system clipboard (with above setting)
p # pastes from system clipboard
# Check what's in the clipboard:
:reg + # show clipboard contents
# On Linux, install a clipboard tool if missing:
# xclip or xsel for X11
# wl-clipboard for Wayland宏
录制宏
q{letter} 开始录制到寄存器;再按 q 停止。录制的按键可用 @{letter} 重放。录制时,使用一致的 motion——优先用 0、^、$、w、e 而不是依赖列的 j/k。在批量应用前先在几行上测试。
q{a-z} # start recording into register {a-z}
... # perform actions (keystrokes recorded)
q # stop recording
# Example: wrap each word in quotes on a line:
qa # start recording into 'a'
0 # go to first column
i" # insert opening quote
Esc
e # go to end of word
a" # append closing quote
Esc
w # move to next word
q # stop recording
# Now @a will wrap one more word.
# Recording tips:
# - Use 0/^-positioned motions (not j/k)
# - Use commands that work regardless of line length
# - Test on a few lines before applying broadly
# View the recorded macro:
:reg a # see keystrokes in register 'a'播放宏
@a 播放宏一次,@@ 重放上次的宏,N@a 播放 N 次。要将宏应用到多行,可视选择它们并运行 :normal @a,或用 :%normal @a 对整个文件。宏在出错时停止(如搜索失败),所以 999@a 可安全处理到文件末尾。:g/pattern/normal @a 只在匹配行上运行。
@a # play macro 'a' once (in current buffer)
@@ # replay the LAST macro played
5@a # play macro 'a' 5 times
100@a # play 'a' up to 100 times (stops on error)
# Play across multiple lines:
# 1. Visually select lines (V)
# 2. :normal @a # play 'a' on each selected line
# Or:
:%normal @a # play on every line in file
:5,20normal @a # play on lines 5-20
:g/pattern/normal @a # play on lines matching pattern
# Recursive macros:
# If macro 'a' contains @a, it'll recurse.
# Add a 'j' at the end to move to next line.
# Common pattern: process all matching lines:
# qa0f:x...jq # record macro moving down 1 line
# :%s/pattern//gn # count matches
# 100@a # play up to 100 times编辑宏
因为宏存储在寄存器中,你可以编辑它们。粘贴寄存器("ap),修改文本,然后重新复制回去("ay$ 或 "ayy)。或使用 :let @a = '...' 加键转义(\<Esc>、\<CR>)。当你犯了小错误时,这比从头重新录制复杂宏容易得多。
# Macros are just text in registers — you can edit them.
# Method 1: paste, edit, yank back:
"ap # paste register 'a' into buffer
# ... edit the pasted text (modify keystrokes) ...
0"ay$ # yank the line back into 'a'
# Method 2: set the register directly with :let
:let @a = "0iHello \<Esc>"
# Note: special keys need \<Esc> notation in strings
# Method 3: edit in a scratch buffer:
:edit
"ap # paste macro
# edit
"ayy # yank back to 'a'
:bdelete
# Common edits:
# - Add 'j' at the end to advance to next line
# - Remove a step that you don't need
# - Replace a hard-coded search with a generic one
# Show the macro as keystrokes:
:reg a # view current 'a' contents递归宏
递归宏调用自身直到出错——通常在搜索失败时。关键:录制前先清空寄存器(let @a = ''),否则宏内的第一次 @a 调用会播放旧内容。当失败的搜索停止递归时,宏自动终止。非常适合全局查找替换模式。
# A macro can call itself, enabling recursion.
# Example: change every 'foo' to 'bar' in a column:
# (search-based macro)
# Steps to set up recursive macro 'a':
# 1. Clear register 'a':
:let @a = ''
# 2. Start recording:
qa
# 3. Search for 'foo':
/foo<CR>
# 4. Replace with 'bar' (ciwbar<Esc>):
ciwbar<Esc>
# 5. Call itself:
@a
# 6. Stop recording:
q
# Now @a runs until search fails (no more 'foo').
# The recursion stops automatically on the first error
# (when /foo finds nothing).
# Tip: clear the register first, otherwise the FIRST
# call also replays the old contents of 'a'.
# Run:
@a # processes all 'foo' in file带计数的宏
N@a 播放宏 N 次——但它在任何错误时提前停止,所以 999@a 可安全处理到文件末尾。:bufdo normal @a 在每个缓冲区中运行宏,:argdo 在每个参数列表文件中运行。:g/pattern/normal @a 只在匹配行上运行。宏内的计数(如 5j)按每次播放重复,而不是按宏。
# Apply a count to a macro:
5@a # play macro 'a' 5 times
N@a # play up to N times (stops on error)
# Useful: large count to process until end-of-file
999@a # play 'a' up to 999 times (errors stop it)
# Macros with counts INSIDE:
# If your macro starts with '5j', each play jumps 5 lines
# Combine with visual selection (block):
# Ctrl-v to select, then :normal @a
# plays 'a' on each line in the block
# Process every Nth line:
:let i = 0
:g/^/if i % 3 == 0 | normal @a | endif
# (plays 'a' on every 3rd line)
# Apply with a delay (avoid blocking):
# No built-in, but plugins can defer
# Repeat across buffers:
:bufdo normal @a # play 'a' in every buffer
:argdo normal @a # play 'a' in every arg file跨文件与跨行宏
:[range]normal @a 在范围内每行运行宏——将宏应用到多行的最常见方式。在宏结尾加 'j' 让每次迭代前进到下一行。:bufdo/:argdo 跨缓冲区/文件运行。添加 | update 保存每个修改的文件。使用 ! 在错误后继续(如 :bufdo!)。
# Apply a macro to every line in a range:
:[range]normal @a
:%normal @a # whole file
:5,20normal @a # lines 5-20
:'<,'>normal @a # visual selection
:g/pattern/normal @a # only matching lines
# Apply across buffers:
:bufdo normal @a # every buffer
:argdo normal @a # every arglist file
# Save modified buffers after macro run:
:argdo normal @a | update # save each that changed
# Best practice: include 'j' (move down) at end of macro
# so it advances to the next line for :normal usage.
# Example macro for processing CSV rows:
# qa 0f,dt,j q # cut field at comma, move down
# :%normal @a # apply to every line
# Abort on error vs. continue:
:bufdo! normal @a # continue even if a buffer errors
# Debug: play macro step-by-step (no built-in, but
# :set lazyredraw off + slow key timing helps).折叠
折叠方法
foldmethod 控制折叠的创建方式。'manual' 让你用 zf 创建折叠。'indent' 按缩进自动折叠(适合代码)。'syntax' 使用语法规则(语言感知)。'marker' 使用文件文本中的 {{{ }}}。'expr' 用于自定义逻辑。手动折叠在关闭文件时会丢失,除非你 :mkview 保存。
:set foldmethod=manual # fold by hand (zf)
:set foldmethod=indent # fold by indent level
:set foldmethod=expr # fold by 'foldexpr'
:set foldmethod=syntax # fold by syntax rules
:set foldmethod=marker # fold by {{{ }}} markers
:set foldmethod=diff # fold unchanged text in diff
# Recommended defaults:
:set foldmethod=indent # great for code
:set foldlevel=2 # show first 2 levels
# Per-method notes:
# manual - zf to create, zd to delete
# indent - automatic, based on shiftwidth
# syntax - automatic, requires syntax file support
# marker - persistent (saved in file as {{{ }}})
# expr - custom logic via 'foldexpr'
# Persistent manual folds across sessions:
:mkview # save folds (and other view state)
:loadview # restore them
# Or set:
:set viewoptions=folds # what :mkview saves手动折叠
在手动模式下,zf 创建折叠(如 zf3j 折叠接下来 3 行)。zd 删除一个折叠,zD 递归删除,zE 消除窗口中的所有折叠。可视模式 + zf 折叠选区。使用 foldmethod=marker 时,在注释中放置 {{{ 和 }}} 创建存储在文件中的持久折叠——对在版本控制中共享折叠结构有用。
# Manual fold commands (foldmethod=manual):
zf{motion} # create fold over motion (e.g. zf3j)
zF # create fold over current line(s)
zd # delete fold at cursor
zD # delete fold recursively (nested)
zE # eliminate ALL folds in window
zj / zk # move to next/prev fold start
[z / ]z # move to fold start/end
# Select then fold (visual):
V zf # visually select lines, then fold
# Create fold for a range:
:5,20fold # fold lines 5-20
# Fold using a marker (manual mode):
# Place markers in the file (with foldmethod=marker):
function Foo() " {{{
echo "hi"
endfunction " }}}
# When foldmethod=marker, the {{{ }}} create persistent
# folds stored in the file text itself.折叠打开/关闭命令
zo/zc 打开/关闭折叠;za 切换。zO/zC/zA 递归作用于嵌套折叠。zr/zm 全局调整折叠级别(一次一级)。zR 打开所有,zM 关闭所有——快速重置的方法。zj/zk 在折叠之间跳转,[z/]z 跳到当前折叠的开始/结束。
zo # open fold (one level)
zc # close fold (one level)
za # toggle fold (open <-> closed)
zO # open fold recursively (all levels)
zC # close fold recursively (all levels)
zA # toggle fold recursively
zr # reduce fold level by 1 (open one level everywhere)
zm # increase fold level by 1 (close one level everywhere)
zR # open ALL folds (reduce to level 0)
zM # close ALL folds (fold everything)
# Navigation in/around folds:
zj # next fold start (down)
zk # previous fold end (up)
[z # start of current open fold
]z # end of current open fold
# Move with folds intact (don't open):
# Use j/k normally — they may skip closed folds
# Set 'foldopen' to control what opens folds折叠导航与编辑
j/k 可能根据 'foldopen' 跳过关闭的折叠。zj/zk 在折叠边界之间导航。折叠行上的 yy/dd 将所有折叠行作为单元操作(行向)。在关闭的折叠内输入会打开它。配置 'foldopen' 控制哪些 motion 打开折叠(如移除 'search' 在搜索时保持折叠关闭)。
# Fold-related motions:
zj # next fold start (move down)
zk # previous fold end (move up)
[z # start of current open fold
]z # end of current open fold
# What opens a fold when triggered?
:set foldopen=block,hor,mark,percent,quickfix,
search,tag,undo
# Defaults open folds on most motions.
# To make j/k NOT open folds:
:set foldopen-=block
# Editing a closed fold:
# Typing inside a closed fold opens it.
# 'o' or 'O' on a fold line opens a new line.
# Search inside closed folds:
# Default behavior depends on 'foldopen'.
# :set foldopen-=search # don't open on search
# Yank/paste on folded lines:
# yy yanks ALL lines in the fold (linewise)
# dd deletes ALL lines in the fold
# Paste over a fold:
# p with a linewise register replaces the folded region折叠选项
foldlevel 控制折叠保持打开的深度(越高=越开放)。foldlevelstart=99 启动时全部打开。foldcolumn 显示带折叠状态指示器的侧边栏。foldminlines 防止微小折叠。要跨会话持久化折叠,在 BufWinLeave 时 :mkview,在 BufWinEnter 时 :loadview——常见的 autocmd 模式。
:set foldmethod=indent # folding method
:set foldlevel=2 # show folds deeper than this
:set foldlevelstart=99 # start with all folds open
:set foldminlines=3 # min lines to form a fold
:set foldcolumn=4 # 4-char column showing fold state
:set foldenable # enable folding (default on)
:set foldclose=all # auto-close folds when cursor leaves
:set foldopen=block,hor,mark,percent,quickfix,search,tag,undo
:set foldtext=foldtext() # text to show on a closed fold
:set fillchars=fold:\ , # chars for fold display
# Common combo for code:
:set foldmethod=indent
:set foldlevelstart=10
:set foldnestmax=10 # max nesting depth
# Custom fold text:
:set foldtext=MyFoldText()
function MyFoldText()
return '+++ ' . (v:foldend - v:foldstart + 1) . ' lines +++'
endfunction
# Persistent folds across sessions:
:set viewoptions=folds,cursor
:autocmd BufWinLeave * mkview
:autocmd BufWinEnter * silent loadview嵌套折叠与折叠级别
折叠分层嵌套。'foldlevel' 决定保持打开的最深级别——foldlevel=0 关闭所有,99 打开所有。zr/zm 按 1 调整,zR/zM 是极端值。'foldnestmax' 限制嵌套深度以避免深度嵌套代码中的失控折叠。自定义 foldtext 函数让你控制关闭折叠上显示的内容。
# Folds can nest. 'foldlevel' controls which are open:
:set foldlevel=0 # all folds closed
:set foldlevel=1 # only top-level open
:set foldlevel=99 # all open
# Display current fold level:
:echo &foldlevel
# Increase/decrease by 1:
zr # reduce (open one level everywhere)
zm # more (close one level everywhere)
zR # open ALL folds (set foldlevel to 99)
zM # close ALL folds (set foldlevel to 0)
# Limit nesting:
:set foldnestmax=10
# Each indent level adds a fold level.
# Useful for deeply-nested code:
# function outer() {
# function inner() { <- foldlevel 2
# function deep() { <- foldlevel 3
# }
# }
# }
# Custom foldtext for nested folds:
:set foldtext=NeatFoldText()
function! NeatFoldText()
let line = getline(v:foldstart)
let n = v:foldend - v:foldstart + 1
return line . ' (' . n . ' lines)'
endfunction窗口分割
分割窗口
:split/:vsplit 分割当前窗口——默认都显示同一个缓冲区(更改同步)。:split file 在新分割中打开文件。:new/:vnew 创建空缓冲区。Ctrl-w s/v 是键盘快捷方式。加数字前缀设置新窗口的大小(:10split 创建 10 行高的窗口)。
:split / :sp # horizontal split (current file)
:vsplit / :vs # vertical split (current file)
:split file.txt # split + open file
:vsplit file.txt # vsplit + open file
:new # horizontal split with empty buffer
:vnew # vertical split with empty buffer
:5split / :5vsplit # split with 5 rows/cols
# Quick splits (Normal mode):
Ctrl-w s # split horizontally (same as :split)
Ctrl-w v # split vertically (same as :vsplit)
Ctrl-w n # new horizontal split (empty)
Ctrl-w q # close window (same as :q)
# Split with size hints:
:10split file.txt # split with height 10
:vert 30split file # vertical split with width 30
# Reopen current file in a new split:
Ctrl-w s # same buffer, two views (sync scroll optional)窗口导航
Ctrl-w 后跟 h/j/k/l 在窗口之间导航(记忆法:hjkl 与移动一样)。Ctrl-w w 循环到下一个窗口。为了速度,许多用户将 Ctrl-h/j/k/l 直接映射到窗口导航。Ctrl-w p 返回之前使用的窗口——在两个窗口之间来回切换时很有用。
Ctrl-w h # left window
Ctrl-w j # below window
Ctrl-w k # above window
Ctrl-w l # right window
Ctrl-w w # cycle to next window (wraps)
Ctrl-w W # cycle to previous window
Ctrl-w t # top-left window
Ctrl-w b # bottom-right window
Ctrl-w p # previous (last accessed) window
# Faster (with mapping):
:nmap <C-h> <C-w>h
:nmap <C-j> <C-w>j
:nmap <C-k> <C-w>k
:nmap <C-l> <C-w>l
# In terminal mode:
Ctrl-w N # exit terminal mode (to Normal)
Ctrl-w h/j/k/l # navigate (after exiting terminal mode)
# List windows in current tab:
:ls # also shows windows' buffers窗口调整大小
Ctrl-w +/-/</> 按 1 调整大小;加计数前缀(10 Ctrl-w +)进行更大步进。Ctrl-w _ 最大化高度,Ctrl-w | 最大化宽度。Ctrl-w = 均衡所有窗口。精确调整使用 :resize N(高度)和 :vertical resize N(宽度)。设置 'mouse=a' 后可直接拖动状态行和分隔符。
Ctrl-w = # equalize all window sizes
Ctrl-w + # increase height by 1
Ctrl-w - # decrease height by 1
Ctrl-w > # increase width by 1
Ctrl-w < # decrease width by 1
Ctrl-w _ # maximize height (current window)
Ctrl-w | # maximize width (current window)
10 Ctrl-w + # increase height by 10
# Ex commands for precise resize:
:resize 20 # set height to 20 (horizontal split)
:resize +5 # increase height by 5
:resize -5 # decrease height by 5
:vertical resize 80 # set width to 80 (vertical split)
:vertical resize +10 # increase width by 10
# Mouse: drag the status line / vertical separator
# (with :set mouse=a)
# Auto-resize on split:
:set equalalways # default: auto-equalize on split/close
:set noequalalways # don't auto-resize窗口移动
Ctrl-w H/J/K/L 将当前窗口移到远端边缘(大写 = 该侧全屏)。Ctrl-w r/R 在布局内旋转窗口。Ctrl-w x 与下一个窗口交换。Ctrl-w T 将窗口移到新标签页。一个巧妙的技巧:Ctrl-w K/H 还可在水平和垂直方向之间转换。
Ctrl-w H # move current window to far LEFT (full height)
Ctrl-w J # move current window to BOTTOM (full width)
Ctrl-w K # move current window to TOP (full width)
Ctrl-w L # move current window to far RIGHT (full height)
Ctrl-w r # rotate windows DOWN/RIGHT
Ctrl-w R # rotate windows UP/LEFT
Ctrl-w x # exchange current window with next
Ctrl-w T # move current window to a NEW tab page
# Move split orientation:
Ctrl-w K # if vertical, become horizontal (and move to top)
Ctrl-w H # if horizontal, become vertical (and move to left)
# Example: convert a vertical split to horizontal:
:vsplit # creates vertical split
Ctrl-w H # moves it to the left, becoming horizontal
# Reopen current buffer in a new tab:
Ctrl-w T # current window moves to a new tab窗口排列
Ctrl-w = 均衡窗口大小。:ball 为每个缓冲区打开一个窗口——一次查看所有内容很有用。Ctrl-w r/R 在布局内旋转窗口。要保存和恢复完整的窗口布局(包括缓冲区、折叠等),使用 :mksession 和 :source。每个标签页维护自己的窗口布局。
# Equalize window sizes:
Ctrl-w = # equalize height and width
# Stack layouts:
# Vertical splits side by side, horizontal splits stacked
# Example setup:
# :vsplit -> | win1 | win2 |
# :split -> | win1 | win3 |
# | | win2 |
# Cycle through layouts (with plugins like golden-ratio,
# or use built-in rotation):
Ctrl-w r # rotate down/right
Ctrl-w R # rotate up/left
# Distribute buffers across windows:
:ball # one window per buffer (horizontal)
:vertical ball # one window per buffer (vertical)
# Layouts persist within a tab page.
# Save current layout to a session:
:mksession mylayout.vim
# Restore:
:source mylayout.vim
# Tab page = a collection of windows
:tabnew # new tab with one window关闭窗口
:q 关闭窗口(如果是最后一个则退出 Vim)。:close(或 Ctrl-w c)关闭窗口但不会关闭最后一个。:only(Ctrl-w o)关闭所有其他窗口。设置了 'hidden' 时,关闭带已修改缓冲区的窗口会隐藏它而不是强制保存决定。:only! 即使已修改也强制关闭其他窗口。
:q / :quit # close current window (errors if last)
:q! # close without saving
:wq # save and close
:close / Ctrl-w c # close window (won't close last)
:only / Ctrl-w o # close all OTHER windows
:hide # hide current buffer in window (close window)
# Save and close splits:
:xa # save all and exit (close all windows)
:wqa # same as :xa
# Closing a window with modified buffer:
# - :q prompts: "Save changes?"
# - :q! discards
# - :wq saves and closes
# - :hide (with 'hidden' set) keeps buffer in memory
# Close every window except the current:
:only # or Ctrl-w o
# Errors if other windows have unsaved changes:
:only! # force-close other windows
# When you close the last window, Vim exits.
# To prevent accidental exit:
:q! on last window still exits Vim.标签页
标签页创建
:tabnew/:tabedit 创建新标签页。vim -p file1 file2 在启动时将每个文件打开在自己的标签页中。每个标签页包含一个或多个窗口——标签是布局,不是单个文件。Ctrl-w T 将当前窗口移入新标签页。标签非常适合分隔不相关的工作上下文(如每个项目区域一个标签)。
:tabnew # new tab with empty buffer
:tabedit file.txt # new tab opening file
:tab split # new tab with current buffer in a split
:tabfind file.txt # new tab, find file in 'path'
# Open multiple files in tabs at startup:
vim -p file1.txt file2.txt file3.txt
# From inside Vim, open files in tabs:
:args *.py | argdo tabe %
# Or one-by-one:
:tabe file1.txt
:tabe file2.txt
# Keyboard shortcut (common mapping):
:nmap <C-t> :tabnew<CR>
# Open current buffer in a new tab (move window):
# Ctrl-w T (move current window to a new tab page)
# Each tab page has its own window layout
# (multiple splits/windows per tab allowed)标签页导航
gt/gT 切换标签页(普通模式)。Ngt 直接跳到标签 N(从 1 开始)。:tabs 列出所有标签页及其窗口。常见映射 Ctrl-Tab/Ctrl-S-Tab 或 <leader>1/2/3 用于快速标签切换。标签默认循环。每个标签维护自己的窗口布局(分割等)。
:tabnext / :tabn # next tab
:tabprevious / :tabp # previous tab
:tabfirst / :tabr # first tab
:tablast / :tabl # last tab
gt # next tab (Normal mode)
gT # previous tab
3gt # go to tab 3
:tabn 3 # go to tab 3 (Ex command)
# Common mappings (Vim default):
:nmap <C-Tab> :tabnext<CR>
:nmap <C-S-Tab> :tabprevious<CR>
# Or use leader keys:
:nmap <leader>1 1gt
:nmap <leader>2 2gt
:nmap <leader>3 3gt
# Cycle behavior:
# gt at last tab wraps to first
# gT at first tab wraps to last
# To disable wrap:
:set tabpagemax=50 # max tabs (not wrap-related)
# Show all tabs:
:tabs # list tabs with their windows标签页操作
:tabc 关闭当前标签;:tabo 关闭其他所有标签。:tabm N 将当前标签移到位置 N(0 = 第一个)。:tabdo 在每个标签中运行 Ex 命令——对跨标签工作区的全局操作有用。关闭标签会关闭其所有窗口;设置了 'hidden' 时已修改缓冲区会被保留。
:tabclose / :tabc # close current tab
:tabclose! / :tabc! # force close (discard changes)
:tabonly / :tabo # close all OTHER tabs
:tabonly! / :tabo! # force close others
# Reorder tabs:
:tabmove / :tabm 0 # move current tab to position 0 (first)
:tabm # move to last position
:tabm 2 # move to position 2
:tabm +1 # move right by 1
:tabm -1 # move left by 1
# Quick keyboard reordering (no default, common mapping):
:nmap <leader>tm :tabmove<Space>
# Run a command in every tab:
:tabdo cmd # run cmd in every tab page
# Example:
:tabdo %s/old/new/ge # substitute in every tab's first window
# Each tab can hold multiple windows/splits.
# 'Tabclose' closes all windows in the tab.标签页布局与多窗口
每个标签页维护独立的窗口布局(分割、大小、位置)。每个标签可以有多个窗口。Ctrl-w T 将窗口移入自己的新标签页。:set showtabline=2 始终显示标签栏。标签最适合用作工作区分隔符(如每个项目区域一个标签),每个都有自己的布局。
# Each tab page has its own window layout.
# Create a tab with a 3-window layout:
:tabnew # new tab
:vsplit # split vertically (2 windows)
:split # split horizontally (3 windows)
# Now tab has: [win1] [win2]
# [win3]
# Add a buffer to current tab:
:e file.txt # replaces current window's buffer
# Move a window to its own tab:
Ctrl-w T # window becomes a new tab page
# Show tab line (always):
:set showtabline=2 # 0=never, 1=multi-tab, 2=always
# Tab page-local options:
:setlocal ... # option applies only to current tab's windows
:tabdo setlocal ... # apply across all tabs
# Tab label customization (status line):
:set guitablabel=%t # show filename in GUI tab label
# Common use case: one tab per project area:
# Tab 1: source files
# Tab 2: tests
# Tab 3: docs
# Each with its own split layout.标签页选项与标签
showtabline 控制标签栏(0=从不,1=仅多标签时,2=始终)。你可以用返回格式字符串的函数完全自定义 tabline——用于显示修改状态、缓冲区名、标签编号。guitablabel/guitabtooltip 自定义 GUI Vim。标签从 1 开始编号。
:set showtabline=2 # always show tab bar (0=never, 1=auto)
:set tabpagemax=50 # max tabs creatable
:set hidden # allow switching tabs with unsaved changes
# Custom tab labels (terminal Vim):
:set tabline=%!MyTabLine()
function! MyTabLine()
let s = ''
for i in range(tabpagenr('$'))
let n = i + 1
let s .= '%' . n . 'T'
let s .= (n == tabpagenr() ? '%#TabLineSel#' : '%#TabLine#')
let s .= ' [' . n . '] '
let buflist = tabpagebuflist(n)
let bufname = bufname(buflist[0])
let s .= empty(bufname) ? '[No Name]' : fnamemodify(bufname, ':t')
let s .= ' '
endfor
let s .= '%T%#TabLineFill#'
return s
endfunction
# GUI tab labels:
:set guitablabel=%t # show filename
:set guitabtooltip=%f # show full path on hover
# Quickly switch with number:
:nmap <leader>t :tabs<CR>标签页命令
:tabs 列出标签及其窗口。:tabdo 在每个标签中运行 Ex 命令。:tab ball 为每个缓冲区打开自己的标签。<C-w>gf 在新标签中打开光标下的文件。使用标签分组相关文件(每个功能/区域一个标签)。对于跨标签操作,:tabdo 是主力——与 windo 配合用于多窗口标签。
:tabs # list all tabs and their windows
:tabdo cmd # run cmd in every tab
:tab ball # open each buffer in its own tab
:tab help subject # open help in a new tab
:tab split # split current window into new tab
# Quickly duplicate a tab's layout:
# (no built-in, but possible with sessions)
# Or manually: create a new tab, re-open buffers
# Open file under cursor in a new tab:
:nmap gf :tabe <cfile><CR>
# (or use the built-in <C-w>gf)
# Common workflow:
# 1. Group related files in tabs
# 2. Use gt/gT to switch
# 3. Use :tabdo for cross-tab operations
# Save all tabs' buffers:
:tabdo windo w # write every window in every tab
# (or simpler)
:wall # write all buffers (across all tabs)
# Close all tabs but keep buffers:
# (no single command — use :tabo + :b then :bd)配置(.vimrc)
.vimrc 基础
$MYVIMRC 是你的 vimrc 文件路径——:edit $MYVIMRC 打开它,:source $MYVIMRC 在编辑后重新加载。runtimepath 控制 Vim 在哪里查找语法文件、插件等。使用 :verbose set option? 查看选项最后在哪里设置的——对调试冲突插件极为有用。
# vimrc location:
# Unix: ~/.vimrc (or ~/.vim/vimrc)
# Windows: ~/_vimrc (or ~/vimfiles/vimrc)
# Neovim: ~/.config/nvim/init.vim
# Reload vimrc after editing:
:source $MYVIMRC # or :so %
# Edit vimrc quickly:
:edit $MYVIMRC # $MYVIMRC = path to your vimrc
# Runtime path (where Vim looks for scripts):
:set runtimepath?
# Add a custom path:
:set runtimepath+=~/.vim/custom
# Conditional config (only in terminal Vim):
if !has('gui_running')
set mouse=a
endif
# Per-filetype settings (in vimrc or ftplugin/):
:autocmd FileType python setlocal expandtab shiftwidth=4
# Check where an option was set:
:verbose set tabstop?基本设置
这些是常见的生活质量设置。relativenumber + number 显示混合编号——相对于光标的行号便于跳转,当前行显示绝对行号。showmatch 闪烁匹配的括号。wildmenu 用菜单增强 :命令 补全。scrolloff 在光标周围保持可见上下文——永不在屏幕边缘编辑。
set nocompatible # Vim mode (not Vi)
set number # show line numbers
set relativenumber # relative line numbers (great for jumps)
set cursorline # highlight current line
set cursorcolumn # highlight current column
set showcmd # show partial commands in status
set showmode # show current mode (insert, visual...)
set showmatch # highlight matching brackets
set wildmenu # better command-line completion
set wildmode=longest:full,full # completion style
set laststatus=2 # always show status line
set ruler # show cursor position
set backspace=indent,eol,start # backspace through everything
set encoding=utf-8 # default encoding
set scrolloff=5 # keep 5 lines above/below cursor
set sidescrolloff=5 # keep 5 cols left/right of cursor
set mouse=a # enable mouse (all modes)缩进
tabstop 控制制表符显示为多少列。shiftwidth 是 <<、>> 和自动缩进使用的缩进量。softtabstop 使退格键在 expandtab 关闭时也删除正确的列数。expandtab 将制表符转换为空格——推荐以保持一致性。:retab 在更改设置后转换现有的制表符/空格。
set autoindent # copy indent from previous line
set smartindent # smart auto-indent for code (basic)
set cindent # C-style indenting (more language-aware)
set expandtab # use spaces instead of tabs
set tabstop=4 # tab key inserts 4-column tabs visually
set shiftwidth=4 # indent/outdent amount (<<, >>, autoindent)
set softtabstop=4 # backspace removes 4 cols even with tabs
set shiftround # round indent to multiple of shiftwidth
set smarttab # tab key respects shiftwidth at line start
# Toggle tabs vs spaces:
:set expandtab! # toggle
:retab # convert existing tabs<->spaces
# Filetype-specific indent:
:filetype plugin indent on
# Then in ~/.vim/ftplugin/python.vim:
# setlocal expandtab shiftwidth=4
# Quick indent/dedent in Normal mode:
>> # indent current line
<< # dedent current line
5>> # indent 5 lines搜索设置
ignorecase + smartcase 是推荐的组合:除非你的模式包含大写字母,否则不区分大小写。hlsearch 高亮所有匹配;incsearch 在输入时增量显示匹配。常见映射:<leader>h 切换 hlsearch,或 :noh 清除当前高亮。Vim 8.2+ 可通过 shortmess 显示搜索计数。
set ignorecase # case-insensitive search
set smartcase # case-sensitive if pattern has uppercase
set hlsearch # highlight all matches (hls)
set incsearch # show match as you type (is)
set wrapscan # wrap search around end of file (ws)
# Toggle search highlight:
:nmap <leader>h :set hlsearch!<CR>
# Or clear current highlight:
:nmap <leader>nh :nohlsearch<CR>
# Show search count (Vim 8.2+):
:set shortmess-=S
:set shortmess+=S # search stats in command line
# Search in visual selection:
:vmap * y/\V<C-R>"<CR>
# Use very-magic mode by default (advanced):
# No built-in, but a search mapping can prepend \v
# Improved '*' (don't jump on first press):
:nmap * *N
# Disable highlighting until next search:
:nohlsearch显示设置
wrap + linebreak 在单词边界(而非词中)折行以提高可读性。list + listchars 显示制表符、尾随空白和不间断空格。colorcolumn 标记一列(如 80 表示行长度限制)。termguicolors 在现代终端中启用真 24 位颜色。splitright/splitbelow 控制新分割出现的位置。
set wrap # wrap long lines
set linebreak # wrap at word boundaries (not mid-word)
set textwidth=80 # auto-wrap at 80 chars when typing
set showbreak=+++ # marker for wrapped lines
set list # show invisible chars
set listchars=tab:>-,trail:.,extends:>,precedes:<
set fillchars=fold:-,vert:\| # chars for folds/vsplits
set colorcolumn=80 # highlight column 80
set signcolumn=yes # always show sign column (LSP)
set conceallevel=0 # don't conceal chars
set splitright # new vsplit on the right
set splitbelow # new split below
set termguicolors # 24-bit color (if terminal supports)
set background=dark # or 'light' — adjusts color scheme
# Color scheme:
:colorscheme desert
# Or with a plugin (e.g. vim-colors-solarized):
:colorscheme solarized映射按键
始终使用 *noremap 变体(nnoremap、vnoremap 等)作为个人映射——它们不递归,避免意外行为。<leader> 是可自定义的前缀键(默认反斜杠;许多人设为逗号或空格)。<CR> 是回车,<Esc> 是退出,<C-x> 是 Ctrl-X。为常见命令如保存/退出映射 leader 快捷方式。
# Map families:
:map # normal, visual, select, operator-pending
:nmap # normal mode only
:imap # insert mode only
:vmap # visual + select mode
:xmap # visual mode only
:smap # select mode only
:omap # operator-pending mode only
:cmap # command-line mode only
:tmap # terminal mode only
# Non-recursive (RECOMMENDED):
:nnoremap # normal mode, non-recursive
:vnoremap # visual mode, non-recursive
:inoremap # insert mode, non-recursive
:cnoremap # command-line mode, non-recursive
# Examples:
nnoremap <leader>w :w<CR> # save with leader-w
nnoremap <leader>q :q<CR> # quit
inoremap jk <Esc> # Esc with jk
nnoremap <C-h> <C-w>h # window nav
# Leader key (default is \):
:let mapleader = ','
:let maplocalleader = '\\'
# Special keys:
# <CR> <Esc> <Tab> <Space> <C-x> <A-x> <M-x> <F1>-<F12>
# <Up> <Down> <Left> <Right> <leader> <localleader>插件(vim-plug)
vim-plug 基础
vim-plug 是最流行的现代插件管理器。在 call plug#begin 和 plug#end 之间声明插件。每行 Plug 指定一个 GitHub 仓库(user/repo)。添加插件后,:source $MYVIMRC 然后 :PlugInstall 下载它们。你可以固定到标签、分支或提交以保证稳定性。插件安装到 'plugged' 目录。
# Installation (Unix):
# curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
# https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
# In vimrc:
call plug#begin('~/.vim/plugged')
Plug 'junegunn/fzf.vim' " GitHub repo: user/repo
Plug 'tpope/vim-surround' " another plugin
Plug 'morhetz/gruvbox' " colorscheme
Plug 'preservim/nerdtree' " file explorer
call plug#end()
# After editing vimrc:
:source $MYVIMRC # or restart Vim
:PlugInstall # install all declared plugins
# Plugin directory structure:
# ~/.vim/plugged/<plugin-name>/
# Pin to a specific commit/tag/branch:
Plug 'tpope/vim-fugitive', { 'tag': 'v3.0' }
Plug 'user/repo', { 'branch': 'dev' }
Plug 'user/repo', { 'commit': 'abc123' }插件管理命令
:PlugInstall 安装新插件,:PlugUpdate 更新所有,:PlugClean 移除未列出的,:PlugStatus 显示它们的状态。'do' 钩子在安装后运行命令——用于需要构建或安装二进制文件的插件。'on'/'for' 选项启用延迟加载(仅在命令/文件类型触发时加载)——改善启动时间。
:PlugInstall # install newly added plugins
:PlugUpdate # update all plugins
:PlugClean # remove plugins no longer in vimrc
:PlugStatus # show plugin status (loaded, errored)
:PlugUpgrade # update vim-plug itself
:PlugDiff # review changes from last update
:PlugSnapshot # generate a snapshot of plugin versions
# Post-install hooks:
Plug 'user/repo', { 'do': ':GoInstallBinaries' }
Plug 'user/repo', { 'do': './install.sh' }
Plug 'user/repo', { 'do': 'npm install' }
# Lazy loading (load only when needed):
Plug 'user/repo', { 'on': 'CommandName' } " on command
Plug 'user/repo', { 'for': 'python' } " for filetype
Plug 'user/repo', { 'on': ['Cmd1', 'Cmd2'] }
# Frozen plugin (don't update):
Plug 'user/repo', { 'frozen': 1 }
# Disable a plugin temporarily:
# (no built-in, but comment out the Plug line and :PlugClean)常用必备插件
常用必备:fzf 用于模糊查找文件/缓冲区/文本(比 :find 快得多),vim-surround 用于编辑文本周围的引号/括号/标签,vim-fugitive 用于 Git 集成,vim-commentary 用于快速注释(gc 操作符),NERDTree 用于文件浏览器侧边栏,vim-airline 用于更好的状态行,以及像 gruvbox 这样的好配色方案。
" Fuzzy finder (requires fzf binary):
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
" :Files :GFiles :Buffers :Rg
" Surround (cs/ds/ys for surroundings):
Plug 'tpope/vim-surround'
" cs"' change " to '
" ds" delete surrounding "
" ysiw) surround word with ()
" Fugitive (Git integration):
Plug 'tpope/vim-fugitive'
" :G :Gstatus :Gcommit :Gpush
" Commentary (gc to toggle comments):
Plug 'tpope/vim-commentary'
" gcc comment line
" gc{motion} comment motion
" NERDTree (file explorer sidebar):
Plug 'preservim/nerdtree'
" :NERDTree :NERDTreeToggle
" Airline (status line):
Plug 'vim-airline/vim-airline'
" Gruvbox (colorscheme):
Plug 'morhetz/gruvbox'插件配置
使用 'on'/'for' 延迟加载插件——它们仅在触发时加载,改善启动时间。插件特定配置通常使用 vimrc 中设置的 g:pluginname_var 变量,或 ~/.vim/after/plugin/ 中的文件。'do' 钩子在安装/更新后运行构建步骤。在 vimrc 中设置 g:loaded_pluginname=1 可完全阻止插件加载。