“实战 Elisp”系列旨在讲述我使用 Elisp 定制 Emacs 的经验,抛砖引玉,还请广大 Emacs 同好不吝赐教——如果真的有广大 Emacs 用户的话,哈哈哈。
序言
理论上,开发人员是不允许操作生产环境的,更别说是像商品、订单这样的重要业务数据。不过对小公司来说,后台系统往往不是很完善,总有一些需求让运营或客服部门的同事操作起来捉襟见肘,不得不寻求开发人员的帮助。
通常这些部门的同事会给过来一批需要处理的商品或订单的 ID,我会将它们粘贴到一个脚本中,并将脚本放到生产环境的机器上运行,以实现他们的ad hoc需求。ID 一般用Excel
文件,或在线文档的方式提供过来,将它们粘贴到脚本的源码中之后,还要为它们添加必要的引号和逗号,以满足所用语言的语法要求。比如下图就是直接粘贴后,VSCode 提示错误的样子
![651ed98323f4e333a5c2b26d83fc520e.png](https://i-blog.csdnimg.cn/blog_migrate/9d209064f5b4bdd70fd62767610a1b72.png)
那么,怎样才能不失逼格地给这批 ID 加上前后的引号及行末的逗号呢?
八仙过海,各显神通
有很多方法可以完成这个任务,比如借助 VSCodemulti-cursor[1]功能,手动添加前后缀
![851aabc322404a63503502a834f6c3cc.gif](https://i-blog.csdnimg.cn/blog_migrate/62d84617e8d9f28af5832b0e9b7c039b.gif)
当要添加光标的位置处于同一列时,更适合用 VSCode 的另一个功能在下面添加光标
(快捷键是command+option+↓
)来实现,免去了一遍遍点击鼠标的烦恼。multi-cursor
所敲入的每个光标还可以在各自的行上沿同方向移动不同的距离,适合处理每行长度不一致的情况。
也可以用 Vim 中的列编辑模式[2],操作体验差不多,还可以比 VSCode 按更少的键——起码不需要一直压着option
键。
![d0c090ea8e908be284f586d54da82143.gif](https://i-blog.csdnimg.cn/blog_migrate/da44adfdb8d627a5ec430468396c2826.gif)
但列编辑模式不方便在行末追加内容——必须先在第一行的末尾敲入一个空格,往右移动依次光标,然后才能继续用列编辑模式批量添加后缀。
Emacs 也有类似列编辑模式的功能,它的string-insert-rectangle
命令比 Vim 的更便于添加后缀。但它没有默认的快捷键,需要先按下M-x
,再输入命令名并回车,略为繁琐(尽管命令名可以自动补全)。
![ecc8848a8400f50dbcb065de015e037e.gif](https://i-blog.csdnimg.cn/blog_migrate/ec61c502bf124010c13dcea12eba782c.gif)
除了各家编辑器内置的功能,命令行工具也适合完成这种处理,比如可以用sed
➜ /tmp cat b
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
➜ /tmp sed -e "s/^/'/" -i '' b
➜ /tmp sed -e "s/$/',/" -i '' b
➜ /tmp cat b
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
有些从在线文档上复制下来的 ID 会有一行空行存在于两两之间,如果是在命令行的话,只需要先用grep
筛选一遍即可,可组合性比编辑器更强。
美中不足的是,用sed
处理后需要手动将文件b
的内容粘贴到脚本中——如果是用 Emacs 的话,也可以用C-x i
让编辑器在光标处直接插入该文件的内容。
如果可以寸步不离 Emacs,通过简单的命令或快捷键来完成这个操作,岂不美哉?
自己动手,丰衣足食
用上自定义的 Elisp 函数后的效果如下
![64c144e672f5d8cfd8273db98c065eb9.gif](https://i-blog.csdnimg.cn/blog_migrate/8e2f7b930870c13a27173c93e80eb875.gif)
其实实现思路很简单:
- 首先用户会选中一片要添加前后缀的区域;
- 使用
buffer-substring-no-properties
函数复制这个 region 中的字符串,绑定为text
; - 用
read-from-minibuffer
提示并读取用户输入待添加的前后缀字符串; - 用
split-string
将text
切割为一行行的字符串,给每一行添加前后缀,再用mapconcat
拼回一个字符串; - 用
delete-region
删除被选中的内容,然后用insert
插入新的字符串。
最终的 Elisp 函数的定义如下
(defun lt--insert-at-start-end ()
"为TEXT中的每一行添加PREFIX前缀和SUFFIX后缀。"
(interactive)
(let* ((text (buffer-substring-no-properties (mark) (point)))
(prefix (read-from-minibuffer "插入的前缀:"))
(suffix (read-from-minibuffer "插入的后缀:"))
(lines (split-string text))
(decorated-lines
(mapcar (lambda (line)
(concat prefix line suffix))
lines))
(new-text (mapconcat 'identity decorated-lines "n")))
(delete-region (mark) (point))
(insert new-text)))
欢迎读者朋友中的 Emacs 用户也来使用使用;-)
阅读原文
参考资料
[1]
multi-cursor: https://code.visualstudio.com/docs/editor/codebasics#_multiple-selections-multicursor
[2]
列编辑模式: http://www.uni-koeln.de/~pbogusze/posts/ViM_column_mode_edit.html