Emacs 完全指南 / 第 04 章:移动与导航
第 04 章:移动与导航
4.1 高级移动命令
在第 3 章中我们介绍了基本的光标移动。本章将深入更强大的导航方式。
单词与符号移动
| 快捷键 |
命令 |
说明 |
M-f |
forward-word |
前进一个单词 |
M-b |
backward-word |
后退一个单词 |
C-M-f |
forward-sexp |
前进一个 S-表达式 |
C-M-b |
backward-sexp |
后退一个 S-表达式 |
M-@ |
mark-word |
选中下一个单词 |
C-M-@ |
mark-sexp |
选中下一个 S-表达式 |
提示: S-表达式(S-expression)在不同模式下有不同含义:
- 在 Elisp 中:匹配括号对
- 在 C/Python 中:匹配大括号或圆括号
- 在 HTML 中:匹配标签对
段落与页面移动
| 快捷键 |
命令 |
说明 |
M-{ |
backward-paragraph |
上一个段落 |
M-} |
forward-paragraph |
下一个段落 |
M-g g |
goto-line |
跳转到指定行 |
M-g c |
goto-char |
跳转到指定字符位置 |
函数级移动(编程模式)
| 快捷键 |
命令 |
说明 |
C-M-a |
beginning-of-defun |
函数开头 |
C-M-e |
end-of-defun |
函数末尾 |
C-M-h |
mark-defun |
选中整个函数 |
;; 示例:在 Python 文件中
;; C-M-a 跳转到当前 def/class 的开头
;; C-M-e 跳转到当前 def/class 的末尾
;; C-M-h 选中整个函数
(defun demo-function ()
"这是一个示例函数。"
(message "Hello")
(message "World"))
;; 光标在此处时 C-M-a 跳转到 (defun
;; 光标在此处时 C-M-e 跳转到最后的 )
空白字符感知移动
;; 使用 subword-mode 处理驼峰命名
(global-subword-mode 1)
;; M-f 现在会在 camelCase 的每个单词边界处停止
;; 例如:myVariableName → my|Variable|Name
;; 使用 hungry-delete 模式删除所有连续空白
(use-package hungry-delete
:config
(global-hungry-delete-mode 1))
4.2 搜索
Emacs 提供了多种搜索方式,从简单的增量搜索到强大的正则搜索。
增量搜索(Isearch)
| 快捷键 |
命令 |
说明 |
C-s |
isearch-forward |
向前增量搜索 |
C-r |
isearch-backward |
向后增量搜索 |
C-s C-s |
— |
搜索上一次的关键词 |
C-s M-p |
— |
搜索历史上一条 |
C-s M-n |
— |
搜索历史下一条 |
Isearch 中的快捷键
| 按键 |
说明 |
RET |
结束搜索,停留在当前位置 |
C-g |
取消搜索,回到起始位置 |
C-s |
继续搜索下一个 |
C-r |
继续搜索上一个 |
M-c |
切换大小写敏感 |
M-r |
切换正则模式 |
C-w |
将光标处单词加入搜索 |
M-s C-e |
将光标到行尾加入搜索 |
M-s o |
搜索结果出现在 occur 缓冲区 |
搜索流程示例:
1. C-s → 进入增量搜索
2. 输入 "def" → 实时高亮匹配
3. C-s → 跳转到下一个匹配
4. C-s → 继续跳转
5. RET → 停留在当前位置
正则搜索流程:
1. C-M-s → 进入正则增量搜索
2. 输入 "def \\w+" → 匹配 def 后跟任意单词
3. C-s → 跳转到下一个匹配
正则搜索
| 快捷键 |
命令 |
说明 |
C-M-s |
isearch-forward-regexp |
正则向前搜索 |
C-M-r |
isearch-backward-regexp |
正则向后搜索 |
Emacs 正则表达式速查
| 表达式 |
说明 |
示例 |
. |
任意字符 |
a.c 匹配 abc, a1c |
* |
零次或多次 |
ab*c 匹配 ac, abc, abbc |
+ |
一次或多次 |
ab+c 匹配 abc, abbc |
? |
零次或一次 |
ab?c 匹配 ac, abc |
[...] |
字符集 |
[aeiou] 匹配元音 |
[^...] |
排除字符集 |
[^0-9] 匹配非数字 |
\b |
单词边界 |
\bdef\b 匹配完整的 def |
\w |
单词字符 |
\w+ 匹配一个或多个单词字符 |
\( ... \) |
分组 |
\(ab\)+ 匹配 ab, abab |
\1 |
反向引用 |
\(.\)\1 匹配重复字符如 aa |
| |
或 |
cat|dog 匹配 cat 或 dog |
^ |
行首 |
^def 匹配行首的 def |
$ |
行尾 |
end$ 匹配行尾的 end |
注意: Emacs 的正则语法与 PCRE(Perl 风格)有区别:
- 分组用
\( \) 而非 ( )
+, ?, | 需要转义为 \+, \?, \|
\( 和 \) 用于分组,( 和 ) 匹配字面括号
Occur 模式
;; M-s o 或 M-x occur
;; 在当前缓冲区中搜索匹配行,结果出现在 *Occur* 缓冲区
;; 使用示例:
M-s o TODO RET
;; → *Occur* 缓冲区列出所有包含 TODO 的行
;; 在 *Occur* 中按 RET 跳转到对应位置
;; 按 e 进入编辑模式,可直接编辑匹配的行
4.3 全局搜索与替换
替换命令
| 快捷键 |
命令 |
说明 |
M-% |
query-replace |
交互式替换 |
C-M-% |
query-replace-regexp |
正则交互式替换 |
M-x replace-string |
— |
全局替换(不询问) |
M-x replace-regexp |
— |
全局正则替换 |
交互式替换中的操作
| 按键 |
说明 |
y 或 SPC |
替换当前匹配并跳到下一个 |
n 或 DEL |
跳过当前匹配 |
! |
替换所有剩余匹配 |
^ |
回到上一个匹配 |
e |
编辑替换字符串 |
q |
结束替换 |
C-r |
进入递归编辑(修改后再继续) |
C-w |
删除匹配并进入递归编辑 |
多文件搜索与替换
;; 方法 1:使用 grep
M-x grep ; 在文件中搜索
M-x rgrep ; 递归目录搜索(推荐)
;; rgrep 使用示例:
M-x rgrep RET
Search for: function_name
Files: *.py
Directory: ~/project/
;; 方法 2:使用 consult(推荐的现代方案)
(use-package consult
:bind (;; 项目内搜索
("C-c s" . consult-grep)
("C-c r" . consult-ripgrep)))
;; 方法 3:使用 wgrep(在 grep 结果中编辑)
(use-package wgrep
:config
(setq wgrep-auto-save-buffer t))
;; wgrep 工作流:
;; 1. M-x rgrep 搜索结果
;; 2. C-c C-p 在 grep 结果中进入编辑模式
;; 3. 直接编辑匹配的文本
;; 4. C-c C-e 应用更改到原始文件
;; 5. C-x C-s 保存
替换中的正则捕获
场景:将 "function_name(args)" 替换为 "args => function_name"
搜索正则:\(\w+\)(\(.+\))
替换为: \2 => \1
示例:
原文:calculate(total)
结果:total => calculate
4.4 书签(Bookmarks)
书签让你快速跳转到文件中的特定位置,甚至跨越不同文件。
基本书签操作
| 快捷键 |
命令 |
说明 |
C-x r m |
bookmark-set |
设置书签 |
C-x r b |
bookmark-jump |
跳转到书签 |
C-x r l |
bookmark-bmenu-list |
列出所有书签 |
C-x r M |
bookmark-set-no-overwrite |
设置书签(不覆盖) |
书签操作流程
1. 导航到目标位置
2. C-x r m → 输入书签名称 → RET
3. 在任何时候:
C-x r b → 输入书签名称 → RET → 跳转到该位置
管理书签:
C-x r l → 打开书签列表
d → 标记删除
x → 执行删除
r → 重命名
RET → 跳转到选中的书签
;; 书签自动保存
(setq bookmark-save-flag 1) ; 每次设置书签后自动保存
;; 书签文件位置
(setq bookmark-default-file "~/.emacs.d/bookmarks")
;; 使用 bm 包获得可视化的书签
(use-package bm
:bind (("<f2>" . bm-toggle)
("<f3>" . bm-next)
("<S-f3>" . bm-previous)
("C-c b l" . bm-show-all))
:config
(setq bm-highlight-style 'bm-highlight-line-and-fringe))
Imenu 可以快速跳转到当前文件中的函数、类、变量等定义。
| 快捷键 |
命令 |
说明 |
M-g i |
imenu |
打开 Imenu 菜单 |
M-x idomenu |
— |
Ido 增强版 Imenu |
;; 使用 consult-imenu(推荐)
(use-package consult
:bind ("M-g i" . consult-imenu)
:config
(setq consult-imenu-config
'((emacs-lisp-mode :toplevel "Functions"
:types ((?f "Functions" font-lock-function-name-face)
(?v "Variables" font-lock-variable-name-face)
(?m "Macros" font-lock-keyword-face)))
(python-mode :toplevel "Functions"
:types ((?f "Functions" font-lock-function-name-face)
(?c "Classes" font-lock-type-face))))))
;; 使用 imenu-list(侧边栏显示)
(use-package imenu-list
:bind ("C-' " . imenu-list-smart-toggle)
:config
(setq imenu-list-focus-after-activation t
imenu-list-auto-resize t))
4.6 Projectile(项目管理)
Projectile 是 Emacs 中最流行的项目管理包,它提供了项目级别的导航和操作。
安装与配置
(use-package projectile
:diminish projectile-mode
:config
(projectile-mode +1)
;; 设置项目搜索路径
(setq projectile-project-search-path '("~/projects/" "~/work/"))
;; 使用本机索引(更快)
(setq projectile-indexing-method 'alien)
;; 排除目录
(setq projectile-globally-ignored-directories
'(".git" "node_modules" ".venv" "__pycache__" "target"))
:bind-keymap
("C-c p" . projectile-command-map))
核心命令
| 快捷键 |
命令 |
说明 |
C-c p f |
projectile-find-file |
项目内查找文件 |
C-c p g |
projectile-grep |
项目内搜索 |
C-c p r |
projectile-replace |
项目内替换 |
C-c p d |
projectile-find-dir |
查找目录 |
C-c p b |
projectile-switch-to-buffer |
项目内切换缓冲区 |
C-c p k |
projectile-kill-buffers |
关闭项目缓冲区 |
C-c p s s |
projectile-run-shell |
在项目根目录打开 shell |
C-c p s e |
projectile-run-eshell |
在项目根目录打开 eshell |
C-c p p |
projectile-switch-project |
切换项目 |
C-c p S |
projectile-save-project-buffers |
保存项目所有缓冲区 |
C-c p i |
projectile-invalidate-cache |
清除项目缓存 |
C-c p ! |
projectile-run-shell-command-root |
在项目根目录执行命令 |
使用场景
场景 1:快速切换到项目中的某个文件
C-c p f → 输入文件名片段 → TAB 补全 → RET
场景 2:在整个项目中搜索某个函数名
C-c p g → 输入搜索词 → RET → 浏览 grep 结果
场景 3:切换到另一个项目
C-c p p → 选择项目 → 自动进入该项目的文件查找
场景 4:在项目根目录运行测试
C-c p ! → npm test RET
Consult + Projectile
;; 使用 consult-projectile 集成两者优势
(use-package consult-projectile
:bind ("C-c p s" . consult-projectile))
4.7 Ace-Jump / Avy(快速跳转)
Avy 让你通过输入少量字符就跳转到屏幕上任意可见位置。
安装与配置
(use-package avy
:bind (("C-:" . avy-goto-char) ; 跳转到指定字符
("C-'" . avy-goto-char-2) ; 跳转到指定双字符
("M-g w" . avy-goto-word-1) ; 跳转到指定单词
("M-g e" . avy-goto-symbol-1)) ; 跳转到指定符号
:config
(setq avy-background t
avy-all-windows t
avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
使用流程
1. C-: (avy-goto-char)
→ 输入一个字符,如 "d"
→ 屏幕上所有 "d" 字符都被标记为 a, s, f, g, h...
→ 按对应字母跳转到目标位置
2. C-' (avy-goto-char-2)
→ 输入两个字符,如 "th"
→ 更精确的匹配,跳转标记更少
3. M-g w (avy-goto-word-1)
→ 输入单词首字母
→ 跳转到以该字母开头的单词
4.8 跳转历史与寄存器
寄存器(Registers)
寄存器可以存储文本、位置、数字等。
| 快捷键 |
命令 |
说明 |
C-x r SPC r |
point-to-register |
将位置存入寄存器 |
C-x r j r |
jump-to-register |
跳转到寄存器中的位置 |
C-x r s r |
copy-to-register |
将选区复制到寄存器 |
C-x r i r |
insert-register |
插入寄存器内容 |
C-x r n r |
number-to-register |
将数字存入寄存器 |
C-x r + r |
increment-register |
给寄存器中的数字加值 |
寄存器使用示例:
存储位置:
C-x r SPC a → 将当前位置存入寄存器 a
... 编辑其他位置 ...
C-x r j a → 跳回寄存器 a 的位置
存储文本:
选择文本 → C-x r s x → 复制到寄存器 x
在其他位置 → C-x r i x → 插入寄存器 x 的内容
4.9 本章小结
| 功能 |
工具 |
核心快捷键 |
| 基本移动 |
内置 |
C-f/b/n/p, M-f/b |
| 搜索 |
Isearch |
C-s, C-r, C-M-s |
| 替换 |
query-replace |
M-%, C-M-% |
| 书签 |
Bookmarks |
C-x r m/b/l |
| 符号跳转 |
Imenu |
M-g i |
| 项目导航 |
Projectile |
C-c p f/g/p |
| 快速跳转 |
Avy |
C-:, C-' |
| 寄存器 |
Registers |
C-x r SPC/j |
4.10 扩展阅读
← 上一章 第 03 章:基本操作 | 下一章 → 第 05 章:编辑技巧