面向产品经理的Emacs教程:11. 进一步提升Emacs效率

· 2598字 · 6分钟

1 课程回顾 🔗

经过上一节课,我们学习了如何在Emacs里通过Avy快速跳转到屏幕上任何一个字符的位置,通过 multiple-cursors 进行多光标编辑,我们在Emacs里编辑文本的效率大大提升。

本节课,我们将学习如何通过配置,进一步提升Emacs的效率。

2 让Emacs的目录变得更加干净 🔗

我们通过 no-littering 插件将原本放在 .emacs.d 目录下的一些配置信息或动态信息,转移到 etcvar 子目录里,让配置目录更加简洁清爽。

(use-package no-littering
  :ensure t)

当我们安装配置完这个插件后,我们别忘了,将 第7课:Emacs的补全强化 - Yasnippet模板补全章节 里的 snippets 文件夹移动到 .emacs.d/etc/yasnippet/ 文件夹下:

mv ~/.emacs.d/snippets ~/.emacs.d/etc/yasnippet/

现在 .emacs.d 下的目录结构如下:

/Users/randolph/.emacs.d/
├── README.org
├── early-init.el
├── elpa
├── etc
│   ├── gnus
│   └── yasnippet
│       └── snippets
├── init.el
├── lisp
│   ├── init-base.el
│   ├── init-completion.el
│   ├── init-edit.el
│   ├── init-org.el
│   ├── init-tools.el
│   └── init-ui.el
└── var
    ├── auto-save
    ├── eww
    ├── gnus
    ├── org
    ├── recentf-save.el
    ├── save-place.el
    └── savehist.el
...

3 让Emacs记住一些历史信息 🔗

我们打开一些文件,输入一些命令,这些命令的历史都是数据,而数据都是有价值的,一个最浅显的价值就是通过让Emacs记住一些历史信息,让我们直接从历史信息中再次执行。

3.1 让Emacs记住迷你缓冲区历史信息 🔗

我们通过Emacs自带的 savehist 插件,来记住迷你缓冲区的历史,如执行过的命令等。在设置这个插件之前,无论何时,我们按下 M-x 显示的命令都是一样的:

我们来配置一下 savehist

(use-package savehist
  :ensure nil
  :hook (after-init . savehist-mode)
  :config
  ;; Allow commands in minibuffers, will affect `dired-do-dired-do-find-regexp-and-replace' command:
  (setq enable-recursive-minibuffers t)
  (setq history-length 1000)
  (setq savehist-additional-variables '(mark-ring
                                        global-mark-ring
                                        search-ring
                                        regexp-search-ring
                                        extended-command-history))
  (setq savehist-autosave-interval 300))

当我们配置完这个插件并开启了 savehist-mode ,我们先随便执行一些命令,然后我们再次按下 M-x 可以看到我们最新执行过的命令已经排在了最上面,如果我们短时间内还需要再执行一次该命令的话,只需要按下 C-nC-p 来移动光标即可,非常方便:

3.2 让Emacs记住关闭文件时的位置 🔗

我们通过Emacs自带的 save-place 插件,来记住每个文件关闭时光标所在的位置,当我们再次打开这个文件时,自动跳转到记住的位置。

;; 自动记住每个文件的最后一次访问的光标位置
(use-package saveplace
  :ensure nil
  :hook (after-init . save-place-mode))

我们在设置这个插件之前,我们每次进入 emacs-config.org 文件时,都是下面这样的:

此时,如果我们打开了 save-place-mode ,并将光标移动到某一个标题行,然后关闭这个文件,我们再次打开这个文件时,光标会自动跳转到关闭时的位置,非常方便:

3.3 让Emacs记住最近打开的文件历史 🔗

我们通过Emacs自带的 recentf 插件,来记住Emacs最近打开的文件历史。

(use-package recentf
  :ensure nil
  :defines no-littering-etc-directory no-littering-var-directory
  :hook (after-init . recentf-mode)
  :custom
  (recentf-max-saved-items 300)
  (recentf-auto-cleanup 'never)
  ;; `recentf-add-file' will apply handlers first, then call `string-prefix-p'
  ;; to check if it can be pushed to recentf list.
  (recentf-filename-handlers '(abbreviate-file-name))
  (recentf-exclude `(,@(cl-loop for f in `(,package-user-dir
                                           ,no-littering-var-directory
                                           ,no-littering-etc-directory)
                                collect (abbreviate-file-name f))
                     ;; Folders on MacOS start
                     "^/private/tmp/"
                     "^/var/folders/"
                     ;; Folders on MacOS end
                     ".cache"
                     ".cask"
                     ".elfeed"
                     "elfeed"
                     "bookmarks"
                     "cache"
                     "ido.*"
                     "persp-confs"
                     "recentf"
                     "undo-tree-hist"
                     "url"
                     "^/tmp/"
                     "/ssh\\(x\\)?:"
                     "/su\\(do\\)?:"
                     "^/usr/include/"
                     "/TAGS\\'"
                     "COMMIT_EDITMSG\\'")))

配置完这个插件,我们再次按下 C-x C-f 打开文件时,可以看到我们最近打开的目录和文件都排在了最上面,我们可以通过移动光标来快速选择,非常方便:

事实上,当我们按下 C-x b 键切换buffer时(对应的 consult-buffer 命令),我们也可以看到最近打开的文件历史也列了出来:


事实上,我们可以到 ~/.emacs.d/var/ 目录下,看到 savehist.el, save-place.el, recentf-save.el, 分别对应着上面三个插件的记录文件,里面记录着一些历史信息:

;;; Automatically generated by ‘recentf’ on Mon Jan  9 22:06:19 2023.

(setq recentf-list
      '(
        "~/.emacs.d.scratch/emacs-config.org"
        ))

(setq recentf-filter-changer-current 'nil)


;; Local Variables:
;; coding: utf-8-emacs
;; End:

4 撤销增强 🔗

我们在编辑文本时,常常会写错,需要撤销,Emacs自带撤销,你可以使用 C-/C-x u 来撤销,使用 C-M-_ 来重做。可以通过连续按这两个快捷键来达到持续撤销和持续重做的目的。

但是自带的撤销和重做不够直观,我们可以通过 undo-tree 插件,显示一个可视化的撤销、重做系统。

(use-package undo-tree
  :ensure t
  :hook (after-init . global-undo-tree-mode)
  :config
  ;; don't save undo history to local files
  (setq undo-tree-auto-save-history nil)
  )

当我们安装完这个插件,并打开 undo-tree-mode 后,我们可以看到,当我们按下 C-x u 时,会出现一个可视化的树状结构,树上的每一个点都是一个编辑历史状态,我们可以通过 C-nC-p 来选择历史状态,进而实现可视化的撤销和重做。这样不仅直观,而且可以防止多按出差错。

5 自动保存 🔗

很多时候,我们在编辑某个文档时,常常会忘记按下 C-x C-s 来保存,没有及时保存的后果我就不多说了。因此,也诞生出了很多自动保存的插件,Emacs自己也带着自动保存的机制,不过我们已经在 第6课:改变Emacs的一些编辑行为 - 备份设置章节 里禁用了Emacs自带的自动保存。

这里,我们通过 super-save 插件来实现自动保存,它的优点是可以根据一些行为来触发自动保存,如窗口切换:

(use-package super-save
  :ensure t
  :hook (after-init . super-save-mode)
  :config
  ;; Emacs空闲是否自动保存,这里不设置
  (setq super-save-auto-save-when-idle nil)
  ;; 切换窗口自动保存
  (add-to-list 'super-save-triggers 'other-window)
  ;; 查找文件时自动保存
  (add-to-list 'super-save-hook-triggers 'find-file-hook)
  ;; 远程文件编辑不自动保存
  (setq super-save-remote-files nil)
  ;; 特定后缀名的文件不自动保存
  (setq super-save-exclude '(".gpg"))
  ;; 自动保存时,保存所有缓冲区
  (defun super-save/save-all-buffers ()
    (save-excursion
      (dolist (buf (buffer-list))
        (set-buffer buf)
        (when (and buffer-file-name
                   (buffer-modified-p (current-buffer))
                   (file-writable-p buffer-file-name)
                   (if (file-remote-p buffer-file-name) super-save-remote-files t))
          (save-buffer)))))
  (advice-add 'super-save-command :override 'super-save/save-all-buffers)
  )

当我们安装配置完这个插件,并打开 super-save-mode 时,我们编辑完当前缓冲区,切换缓冲区,或者切换窗体时,Emacs会自动帮你保存,非常方便:

6 crux系统增强 🔗

在今天课程的最后,介绍一下 crux 插件,它提供了一系列的增强,如移动增强、删除增强等优化功能。

我们先来安装配置一下:

(use-package crux
  :ensure t
  :bind (("C-a" . crux-move-beginning-of-line)
         ("C-x 4 t" . crux-transpose-windows)
         ("C-x K" . crux-kill-other-buffers)
         ("C-k" . crux-smart-kill-line)
         ("C-c r" . crux-rename-file-and-buffer)
         ("C-x DEL" . crux-kill-line-backwards))
  :config
  (crux-with-region-or-buffer indent-region)
  (crux-with-region-or-buffer untabify)
  (crux-with-region-or-point-to-eol kill-ring-save)
  (defalias 'rename-file-and-buffer #'crux-rename-file-and-buffer))

在安装这个增强插件前,当我们按下 C-k 删除行的快捷键时,Emacs只会将当前光标到行尾的字符都删除。而我们安装完这个插件,并使用 crux-smart-kill-line 来代替Emacs的 kill-line 时,我们可以看到,当当前光标到行尾没有字符时,它会智能地删除当前行(将当前光标到行首的内容删除),非常方便:

另外在安装该插件前,我们按下 C-a 移动到行首时,它不管行首有没有空格,直接移动到行首,当我们使用 crux-move-beginning-of-line 来代替Emacs自带的 move-beginning-of-line 后,我们按下 C-a 它会首先移动到第一个非空白字符的地方,再按下 C-a 它会再跳到行首位置,非常方便:

crux 增强插件还有很多有意思的系统增强,你可以按下 M-x crux 来查看和研究:

7 结语 🔗

经过今天的课程,我们通过让Emacs记住历史,让Emacs的撤销更加直观,让Emacs智能的自动保存,并通过 crux 增强Emacs的一些行为,让Emacs变得更加高效。

在Emacs的世界,远不止这些手段,还有非常多其他的插件或代码能让Emacs变的更高效。而且高效这个词是因人而异的,不同的人有不同的工作习惯,因为Emacs那伟大的自由,你可以根据自己的喜好和习惯来调教Emacs,这像不像一个养成游戏呢😄

配置文件的快照见:emacs-config-l11.org

你也可以在 这里 查看最新的配置文件。