强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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 匹配 catdog
^ 行首 ^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 全局正则替换

交互式替换中的操作

按键 说明
ySPC 替换当前匹配并跳到下一个
nDEL 跳过当前匹配
! 替换所有剩余匹配
^ 回到上一个匹配
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))

4.5 Imenu

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 章:编辑技巧