Emacs builtin mode 功能介绍

作为上古神器,长达数十年的维护历史,不断有新功能加入,不断有旧功能被遗忘,属于正常现象。

1 个赞

学习学习~ :rofl: :slightly_smiling_face:

有了Org以后,outline都已经快被遗忘了。

有没有在任意的 buffer 中建立目录的功能? 比如

;;; Predicates
...
;;; Utilities
...
;;; Publics
...

然后旁边就能有个目录 buffer 我可以直接跳过去。

没明白什么意思

就是类似把代码分成几个章节的功能?不知道这样说能不能理解

imenu? 把不同的块写到不同的buffer里?

类似 imenu ,但是要更自定义一些,而不是根据语法来的。这样就可以通过注释来实现了

不是很清楚这有什么用处,大佬你可以尝试实现一下。

imenu 本身也是通过正则匹配的,我当时帮别人修 ahk-mode 的 bug 时搞过类似的:

image

;imenu 开头的注释就可以被 imenu 捕捉到

感觉用 outline 可以凑合用啊。

修改 outline-regrex 类似为 .* ;;;;; 这样的。

我都是优先使用内置包,不够用了就用第三方或者自己扩展

3 个赞

outline的部份可以用这个:

目录buffer我昨天正好写了一个。感觉没有想象中的那么有用,尤其是在小屏幕。

https://github.com/casouri/lunarymacs/blob/master/site-lisp/sidebar.el

sidebar

6 个赞

Changelog:

  • 2020-07-02 增加了shell-command-on-region的一个使用场景 (以ydcv为例)

shell-command-on-region的妙用

在注释看到不认识的单词,一般做法是复制、打开终端、然后调用外部程序 ydcv来翻译。

最近发现了shell-command-on-region之后,可以省掉前2个步骤了!

例如papaya单词不认识,那么选中它,然后M-| (shell-command-on-region)运行一下,输入ydcv然后执行。如果输出内容比较少,则 直接会在echo area处显示(当resize-mini-windows不为nil时由 max-mini-window-height决定)。如果想强制它输出在buffer下(方便复制),可以在 上面再封装一层、例用advice机制,或者提前创建一个名叫*Shell Command Output*buffer

以下是一个advice的例子(不推荐使用advice,有较大的侵入性,这里只是做个演示)

(define-advice shell-command-on-region (:around (func &rest args))
  (let ((max-mini-window-height 0))
    (apply func args)))

甚至可以直接封装一个叫做ydcv的命令来完成这个工作!

(defun ydcv (beg end)
  (interactive "r")
  (let ((max-mini-window-height 0))
    (shell-command-on-region beg end "ydcv")))

当然还可以有ydcv-at-point, ydcv-dwim等一系列函数!

9 个赞

一人血书求更(

在写了在写了(

woman和info蛮好用的(

楼主加油,又发掘出好些忽略的built-in好工具

我也加几个内置的 mode, 直接上代码, 不需要解释.

(global-prettify-symbols-mode t)
(global-display-fill-column-indicator-mode t)
(savehist-mode t)
(recentf-mode t)
(save-place-mode t)
(electric-pair-mode t)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)

不过还是要提示下, 你打开越多的 mode, emacs 速度越慢 …

1 个赞

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

20 个赞