Emacs builtin mode 功能介绍

Changelog:

  • 2020-08-22 增加了winner-undotransient-map搭配的例子
  • 2020-08-22 增加了strokes-mode的介绍
  • 2020-08-25 增加了webjump的介绍
  • 2020-08-30 增加了transient-map的小技巧

winner-mode

winner-mode是一个全局的minor mode,它的主要功能是记录窗体的变动。例如当前有 2 个窗口,然后你关了一个,这时可以通过winner-undo来恢复。还可以再winner-redo 来撤销刚才的undo.

它默认按键绑定为:

C-c Left winner-undo

C-c Right winner-redo

如果不想它绑定在C-c前缀按键上,可以通过

(setq winner-dont-bind-my-keys nil)

来禁止。

建议配置:

(use-package winner-mode
  :ensure nil
  :hook (after-init . winner-mode))

同时,它也可以应用在ediff上,恢复由ediff导致的窗体变动。

(use-package ediff
  :ensure nil
  :hook (ediff-quit . winner-undo)

winner-undo 搭配 transient-map

如果平常有注意观察text-scale-adjust (C-x C-=) 的行为,会发现只需要 按全一次C-x C-=,之后可以只按+-或者0来缩放字体。而如果触发了 其他按钮则会退出这个状态,它背后主要依赖transient-map机制。

我们可以仿照着写一个transient-winner-undo的版本,在需要连续执行winner-undo的 时候只需要按一个u就好了。

(defun transient-winner-undo ()
  "Transient version of `winner-undo'."
  (interactive)
  (let ((echo-keystrokes nil))
    (winner-undo)
    (message "Winner: [u]ndo [r]edo")
    (set-transient-map
     (let ((map (make-sparse-keymap)))
       (define-key map [?u] #'winner-undo)
       (define-key map [?r] #'winner-redo)
       map)
     t)))

着实方便许多!

strokes

如果你想用鼠标来控制Emacs的行为,有点像现在浏览器上的鼠标手势。不过它只能识别 鼠标移动轨迹所描绘的形状,不能判断它的方向。

  1. 执行strokes-mode打开minor-mode
  2. 执行strokes-global-set-stroke在弹出的buffer内使用Shift+鼠标左键(也可以用中键) 绘出想作为快捷操作的大致形状,假设是一个 C 的形状,然后鼠标右键结束绘制。稍后 会提示输入与stroke对应的命令,假设是strokes-help
  3. 移动鼠标,使得它的轨迹是个 C 的形状
  4. Shift+鼠标中键以执行与这个stroke对应的命令,也就是strokes-help

想要更详细的信息?请M-x strokes-help.

webjump

你想在Emacs里快速调用搜索引擎搜索吗?原来这个功能早已经内置了!

由于webjump-sites早已有默认值了,如果想急着体验一下可以立即M-x webjump。其原 理也是相当简单,通过用户选择它想要用的搜索引擎+查询内容构造出实际url,然后通过 browse-url调用托管给浏览器。

我的配置是这样的:

(use-package webjump
  :ensure nil
  :bind ("C-c /" . webjump)
  :custom
  (webjump-sites '(
                   ;; Emacs.
                   ("Emacs Home Page" .
                    "www.gnu.org/software/emacs/emacs.html")
                   ("Savannah Emacs page" .
                    "savannah.gnu.org/projects/emacs")

                   ;; Internet search engines.
                   ("DuckDuckGo" .
                    [simple-query "duckduckgo.com"
                                  "duckduckgo.com/?q=" ""])
                   ("Google" .
                    [simple-query "www.google.com"
                                  "www.google.com/search?q=" ""])
                   ("Google Groups" .
                    [simple-query "groups.google.com"
                                  "groups.google.com/groups?q=" ""])
                   ("Wikipedia" .
                    [simple-query "wikipedia.org" "wikipedia.org/wiki/" ""]))))

如果只是想要简单的查询,那么可以作为 engine-mode的内置替换方案了。

当然,还可以配置多级查询选项,可参考webjump-to-iwin的实现。

transient-map 小技巧

因为transient-map的优先级比其他keymap都要高,所以可以将它当作菜单来使用。

如果嫌set-transient-map用起来不方便,可以使用hydra代替。

编辑时拷贝 (配合 avy)

如果在编辑文字时发现要拷贝一个url,但是当前窗口内有多个url,类似的场景如下:

/// url1: https://www.google.com
/// url2: https://www.baidu.com
/// url3: https://duckduckgo.com
int foo(int x) {
    const char* url = "";
}

想要为url赋值为注释内的 3 个 url 之一。

  1. 首先将光标移动到想复制的url
  2. 再将这个url复制到kill-ring当中
  3. 再回到原来的位置
  4. 再粘贴
(defhydra hydra-copy (:color blue)
  "Copy"
  ("w" copy-word-at-point "word")
  ("u" copy-url-at-point "url")
  ("q" nil "cancel"))

(defun copy-url-at-point ()
  "Copy url at point."
  (interactive)
  (save-excursion
    (avy-goto-word-or-subword-1)
    (kill-new (thing-at-point 'url))))

这里使用hydra来偷懒一下。

效果图: hydra

21 个赞