强曰为道

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

第 04 章:移动与导航

第 04 章:移动与导航

4.1 高级移动命令

在第 3 章中我们介绍了基本的光标移动。本章将深入更强大的导航方式。

单词与符号移动

快捷键命令说明
M-fforward-word前进一个单词
M-bbackward-word后退一个单词
C-M-fforward-sexp前进一个 S-表达式
C-M-bbackward-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 ggoto-line跳转到指定行
M-g cgoto-char跳转到指定字符位置

函数级移动(编程模式)

快捷键命令说明
C-M-abeginning-of-defun函数开头
C-M-eend-of-defun函数末尾
C-M-hmark-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-sisearch-forward向前增量搜索
C-risearch-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-sisearch-forward-regexp正则向前搜索
C-M-risearch-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 mbookmark-set设置书签
C-x r bbookmark-jump跳转到书签
C-x r lbookmark-bmenu-list列出所有书签
C-x r Mbookmark-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 iimenu打开 Imenu 菜单
M-x idomenuIdo 增强版 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 fprojectile-find-file项目内查找文件
C-c p gprojectile-grep项目内搜索
C-c p rprojectile-replace项目内替换
C-c p dprojectile-find-dir查找目录
C-c p bprojectile-switch-to-buffer项目内切换缓冲区
C-c p kprojectile-kill-buffers关闭项目缓冲区
C-c p s sprojectile-run-shell在项目根目录打开 shell
C-c p s eprojectile-run-eshell在项目根目录打开 eshell
C-c p pprojectile-switch-project切换项目
C-c p Sprojectile-save-project-buffers保存项目所有缓冲区
C-c p iprojectile-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 rpoint-to-register将位置存入寄存器
C-x r j rjump-to-register跳转到寄存器中的位置
C-x r s rcopy-to-register将选区复制到寄存器
C-x r i rinsert-register插入寄存器内容
C-x r n rnumber-to-register将数字存入寄存器
C-x r + rincrement-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
搜索IsearchC-s, C-r, C-M-s
替换query-replaceM-%, C-M-%
书签BookmarksC-x r m/b/l
符号跳转ImenuM-g i
项目导航ProjectileC-c p f/g/p
快速跳转AvyC-:, C-'
寄存器RegistersC-x r SPC/j

4.10 扩展阅读


← 上一章 第 03 章:基本操作 | 下一章 → 第 05 章:编辑技巧