快,五秒钟内回答:macOS 和 Emacs 有什么共同点?
你可能说,太简单了,两个名字里都有一个 MAC?
没毛病……但考虑到本文的主题不是化妆品,我们还是看看苹果自己的回答:
[macOS 的] 文本系统具有一套通用的组合键机制,完全可由用户重新设定,[…] 标准组合键包含大量与 Emacs 兼容的 Control 组合键 […]
如果你是 macOS 的老用户,可能已经知道这是在说什么:在 macOS 上编辑文本时,除了人尽皆知的 Command-C/V/X/A 等等,系统还支持一整套涵盖了光标移动、文本选择、编辑插入等功能的组合键(keybindings),其中很多来源于经典编辑器 Emacs,并且从八九十年代的 macOS 前身 NeXTSTEP 一直延续至今。
初试身手
那么,这些组合键都能做什么,相比于如今更常用的版本有什么优势呢?下面这张动图可以帮你建立一个初步印象:
不难看出,这些组合键的特点是都以 Control 键为基础,而且虽然涉及很多移动光标操作,但都没有用到任何方向键。因此,掌握熟练之后,可以省去很多移动手腕去摸鼠标和方向键的功夫,减少疲劳并提高编辑效率。
插曲:交换 Control 和 Caps Lock 键
在继续跟随后文上手之前,我非常建议通过系统设置把 Control 和 Caps Lock 键交换位置。需要承认,这肯定不是一个特别大众的设置方法,但据我观察不乏拥趸,而且用过的很少不说好。
为什么建议这么改?如你应该已经发现的那样,Cocoa 文本组合键重度依赖 Control。因此,如果你习惯使用这套组合键,将 Control 键放在 Caps Lock 键的位置,比每次都伸出「兰花指」去键盘左下角的原键位要舒服得多。事实上,这也是早期 IBM 电脑用过的经典布局,后来又被 HHKB 等品牌沿用——甚至苹果的官方支持都将它作为改法示例。
要修改这个设置,首先打开「系统设置」的「键盘」部分,点按右侧的「键盘快捷键」,然后选择左侧列表中的「修饰键」。在弹出的面板中,先确认上方选择的是当前使用的键盘,然后将 Control 键和 Caps Lock 键的操作分别改为对方即可。
乍看起来,使用这些组合键要记一堆字母,有一定学习门槛。但只要掌握了规律,记起来其实是很快的:
首先,大多操作都是「Control-字母键」的组合,其中的字母基本就是操作对应的单词首字母:向后(backward)、向前(forward)、上一行(previous)、下一行(next)、行尾(end)、删除(delete)、交换前后字符(transpose)、插入换行并使光标留在原地(open-line)等。一个例外是移动到行首的 Control-A,据当事人回忆,这只是因为……A 是字母表之首而已。很多历史就是这么任性。
其次,更复杂的组合键主要是在移动操作的基础上演变而来:加上 Shift,就变成了移动光标并选择;加上 Option,就变成了以单词为单位移动(甚至支持基础的中文分词)。如果同时加上 Option 和 Shift?当然就是以单词为单位移动并选择。
一组比较有年代感、可能需要额外解释的操作是 Control-K 和 Control-Y。K 的意思是 kill,功能是从当前光标处删除到段尾,并把删除的内容暂存到一个称为 kill ring 的容器中;Y 的意思是 yank,把之前 kill 的东西「抽」出来,放回当前光标位置。(如果连续按多次 Control-K 后再按 Control-Y,之前吃掉的多行会被合并在一起放出来。)
抛开这对莫名其妙的术语——上世纪七八十年代黑客有些独特的脑回路是可以理解的——可以姑且将其理解成独立于系统剪贴板、只适用于当前窗口的特殊剪切和粘贴。对于长文和代码编辑场景,这种从一行中间往后剪切、同时又不挤占剪贴板的能力是很实用的。
追本溯源
当然,即使你之前完全没有听说过这些组合键,这也不是你的问题。
一方面,它们确实年代久远、讨论不多;另一方面,macOS 也几乎没有给它们提供任何「曝光」的机会:不仅没有在菜单栏中列举,连「系统设置」中的快捷键设置都难觅踪影,唯一比较正式的提及也藏在官方「Mac 键盘快捷键」列表的深处,可能主要只有 Emacs 的真爱粉能通过肌肉记忆偶然发现。
但就算这套组合键再隐晦,既然存在于系统中,它总得有个来头,也总得在什么地方留下些痕迹吧?
答案是肯定的。操作系统的主要任务之一就是为应用程序做好各种「幕后工作」。而这些幕后工作中,很重要的一项就是文本处理,包括字符显示、格式排版、文本编辑等等。
在 macOS 中,负责文本处理的组件称为「Cocoa 文本系统」(Cocoa text system),是 Cocoa(macOS 原生应用 API)的一部分。本文介绍的这套 Emacs 风格组合键,就是由 Cocoa 文本系统负责响应的。
至于系统默认的组合键,上面介绍的只是冰山一角,完整的「目录」位于 /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict
。这是一个二进制编码的属性列表(plist)文件,本身不方便阅读。如果你安装了 Xcode,可以直接双击打开查看内容。或者,也可以运行:
plutil -convert json -o - /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict | jq --ascii-output --sort-keys . > StandardKeyBinding.dict
其中,plutil
将原文件转化为 JSON 格式,打印到标准输出;jq
(需要安装)转换其中的一些特殊字符为 Unicode 码位,并按键名排序;最后写入当前目录。(想偷懒可以直接看我保存的结果。)
这里乱七八糟的符号有点多,但仍然有章法。大致的格式是:每个组合键用一个键—值对表示,键名是指定物理按键的字符串,值是一个数组,表示按下该组合键时要调用的一个或一组操作(称为「选择器」[selector])。
其中,表示物理按键的字符主要是:
符号 | 含义 |
---|---|
^ |
Control |
~ |
Option |
$ |
Shift |
@ |
Command |
小写字母 | 对应字母键本身 |
大写字母 | Shift 加对应字母键 |
以 \u 开头的 Unicode 码位序列 |
对应的 ASCII 控制字符按键或苹果的私有保留码位按键 |
更完整的说明可参见 Jacob Rus 最早写于 2006 年的指南;事实上,Rus 此文基本是网络上所有介绍 Cocoa 文本组合键文章的共同参考资料。
至于按键要对应的操作,则都是驼峰拼写、冒号结尾的方法,命名均来自 AppKit 中负责响应输入的 NSResponder(有个文档,虽然内容少到等于没有);但其实一般用户并不需要关注这些开发上的细节,看单词就足以猜出大部分意思。
照此「翻译」,我们就得知了所有 macOS 中「隐藏」的 Cocoa 文本组合键(排除了一些过于常见、没有实际功能和现代 Mac 上找不到的组合键):
更完整 Cocoa 文本操作整理仍然可参考 Rus 的列表。从中也可以看出,这些操作几乎涵盖了文本编辑的方方面面:除了插入、删除、剪切、大小写转换、翻页、选中等通用文本操作,还包括针对富文本格的字体、样式和版式操作,甚至还有保存和关闭文档、调节窗口位置和大小等针对文本编辑环境的操作;系统内置的组合键只用到其中很小一部分。
插曲:自动重复多次组合键
Vim 用户一定很喜欢它用「数字 + 操作键」重复多次操作的功能,例如 10j
就可以下移光标 10 次,5dw
就可以向前删除 5 个单词等等。
对此,Cocoa 文本系统表示……我也行。但需要做一个设置。打开终端,执行:
defaults write -g NSRepeatCountBinding -string "^r"
然后重新登录让修改生效,就可以启用重复组合键功能,并将 Control-R 设置为引导组合键(也可以自己指定,语法如上文所述)。以后,只要先按下 Control-R,然后按下需要重复的次数,最后按要重复的组合键,就可以连续「开火」了。
在下面的例子中,我们使用 Control-R 引导,分别重复了 5 次 Control-N(向下一行)和 10 次 Control-K(删除到行尾)操作。
改出花样
既然默认组合键是以配置文件的形式储存的,一个自然的想法就是:能不能自定义这些组合键配置呢?
当然可以。正如苹果在文档中所说,用户可以通过在 ~/Library/KeyBindings/
创建一个名为 DefaultKeyBinding.dict
的 plist 文件,自定义新的组合键(或者覆盖自带组合键)。