目录

在emacs 中快速对区域进行符号包裹的简洁方案(类似vim-surround)

1 前言

写代码或者是一些富文本文件时, 经常会遇到这样的场景: 已经写好了一串代码或者文字, 想要方便地给这些东西加上一个符号包括起来, 例如对一个条件判断语句 a==b 加上括号变成 (a==b) , 或者对一段markdown 或 org 文件加上标记. 如果每次都需要手动在开始和结尾的地方加上左括号和右括号, 无疑非常麻烦.

2 常见方案

vim 给出了 vim-surround 方案, 功能强大但按键稍微繁琐. emacs 的实现方案非常多, 右 paredit, smartparents, parinfer, awesome-pair 等, 它们的功能强大提供了多种对于s-exp 的操作, wrap pair 只是其中的一个非常小的功能, 前两个似乎还存在一些性能问题.

这些包都比较重且我们使用的功能相对较少, 无疑会增大学习成本和个人配置的维护压力. 因此我把目光转向了 emacs 的内置方案.

3 内置方案与修改

emacs 中有一个 insert-parentheses 的函数, 默认绑定在 "M-(" 按键, 可以在一段选定的文字附近添加 “(” 和 “)”, 看起来已经满足我们的部分需求了. 文档如下:

(defun insert-parentheses (&optional arg)
  "Enclose following ARG sexps in parentheses.
Leave point after open-paren.
A negative ARG encloses the preceding ARG sexps instead.
No argument is equivalent to zero: just insert `()' and leave point between.
If `parens-require-spaces' is non-nil, this command also inserts a space
before and after, depending on the surrounding characters.
If region is active, insert enclosing characters at region boundaries.

This command assumes point is not in a string or comment."
  (interactive "P")
  (insert-pair arg ?\( ?\)))

仅有一个对于小括号的补全当然不能满足我们的需求, 可以发现, 这个函数的关键在于对 insert-pair 传递的第三和第四个函数, insert-pair 的代码实现较为复杂, 我们这里不多展开, 模仿 insert-parentheses 简单修改便得到如下的函数, 分别对应 ' ', " ", ` ', * *, [ ], { } 等情况.

(defun insert-quotations (&optional arg)
  "Enclose following ARG sexps in quotation marks.
  Leave point after open-paren."
  (interactive "*P")
  (insert-pair arg ?\' ?\'))

(defun insert-quotes (&optional arg)
  "Enclose following ARG sexps in quotes.
  Leave point after open-quote."
  (interactive "*P")
  (insert-pair arg ?\" ?\"))

(defun insert-backquote (&optional arg)
  "Enclose following ARG sexps in quotations with backquote.
  Leave point after open-quotation."
  (interactive "*P")
  (insert-pair arg ?\` ?\'))

(defun insert-star (&optional arg)
  "Enclose following ARG sexps in stars.
Leave point after open-quotation."
  (interactive "*P")
  (insert-pair arg ?\* ?\*))

(defun insert-bracket (&optional arg)
  "Enclose following ARG sexps in brackets.
Leave point after open-quotation."
  (interactive "*P")
  (insert-pair arg ?\[ ?\]))

(defun insert-curly (&optional arg)
  "Enclose following ARG sexps in curly braces.
Leave point after open-quotation."
  (interactive "*P")
  (insert-pair arg ?\{ ?\}))

(defun insert-equate (&optional arg)
  "Enclose following ARG sexps in equations.
Leave point after open-quotation."
  (interactive "*P")
  (insert-pair arg ?\= ?\=))

然后将这些函数分别绑定到自己喜欢的按键就可以使用了. 当然, 还可以根据需要对上面的函数添加更复杂的符号, 比如 html 的相关标记等. emacs 内置功能简单而强大.