article_image

就中文而言,输出方式从纸笔转向键盘,其影响可能远比我们想象的更大。撇开纸张空间感的丧失不谈,就思想的输出经由键盘和“输入法”完成的这一道转换,就足以带来对文字掌控感的减弱。或许这就是有些作家坚持以纸笔写作的原因。不过,本文无意深入麦克卢汉的理论,只是基于此初步提出一个观点(当然,未经详细论证,严格的读者也可将其作为本文的一个假设):一款好的输入法,核心要求是降低输入过程(由选词等操作带来的)的思维负担,使输入者的思想落于屏幕的过程尽可能接近“如臂使指”的状态。正如Rime的slogan:“聪明的输入法懂我心意。”

但输入法显然读取不了你的思维。退而求其次,它能做的就是呈现输入者的输入偏好,用过往经验来推测当前所需。在这方面,Rime是一个出色的学习者,用户的每一次输入都会被忠实地记录,并反映在此后的每一次输入中,真正做到了“下次一定”。

然而,如果你同时使用多个设备,这种忠实可能会打一些折扣。其一是,输入记录需要及时同步,否则在A设备上教过的,在B设备上还得再教一遍。这尚且可以借助Rime本身的同步机制+勤快的手动同步实现。其二是输入类似“哆啦A梦”“AirPods Pro”等中英混输或英文词汇,或是想要实现原生输入法的“文本替换”功能(如输入“shen jiao suo”时出现“深圳证券交易所”候选),必须基于用户词库(含用户词典及自定义短语)实现,而这些文件是Rime自带的同步机制所不覆盖的。如果日常频繁添加新的类似词汇,就要经历一个复杂的过程——在Mac上打开对应文档增减词汇1,再通过局域网将更新后的yaml或txt手动上传2到手机,最后在手机上点击部署——仅仅是想方便地打出“哆啦A梦”,却足足使出了把大象放进冰箱的架势。

好在,Rime的所有配置文件都以文件的形式毫无隐藏地保存在本地并向用户开放。我在Mac上使用鼠须管,在i(Pad )OS设备上使用“仓”输入法(hamster),它们与一众自动化工具协力,竟拼凑出了一套能够以比较高效的方式实现(半)自动化同步的方案。

两类重要文件及其同步思路

在谈同步之前,首先要理解我们同步的是什么。使用Rime输入时,出现哪些候选词以及候选词排列的顺序,取决于两类文件,需要在各个设备间同步的对象也正是这两类文件。前文在述及Rime多设备使用问题时提及的两个问题,正与这两类文件对应。

第一类文件是输入法自动生成的“用户数据”(User Data),即用户配置文件夹(/Users/<用户名>/Library/Rime)下的<词典名>.userdb文件夹,它是输入法对用户输入的自动记录,包括实际上屏(即在候选列表中选中,完成输入)过的所有词汇及其上屏次数。在使用中,该文件夹会在一定时间自动更新;用户进行Rime自带的“用户数据同步”操作(Mac菜单栏点击Rime图标后可见此选项,移动端打开仓输入法app-其他设置-RIME-RIME同步)时,也会自动更新一次。

第二类是“用户词典”(<词典名>.dict.yaml)以及“自定义短语”(custom_phrase.txt),本文将其合称为用户词库。之所以将其归于一类,是因为它们存在以下共同点:

  1. 均由用户自行维护,词汇的创建、修改、删除通过编辑yaml或txt文档完成;
  2. 用户创建的词汇,输入码与输出值可以不存在拼音上的对应关系,如输入“shen jiao suo”出现“深圳证券交易所”候选,输入“shen fen”出现你的身份证号候选。也正因如此,中英混输才可以实现;
  3. 无法通过输入法自带的同步功能被同步。

只有当某个词汇被包含在用户数据或用户词库中时,才可能在候选词列表中被列出。在优先级上,自定义短语>用户数据>用户词典,用户词典中的词汇可以经由历史上屏进入用户数据,进而提高候选时的优先级。

第一类文件的同步,输入法自带的“用户数据同步”(Sync User Data)功能就可以实现,该功能甚至可以将用户不同设备之间的输入记录进行同步与合并,使不同设备的输入记录以合理的算法叠加。其分步骤基本原理如下:3

  1. 用户点击同步按钮
  2. installation.yaml中获取installation_idsync_dir
  3. sync_dir 文件夹下生成 installation_id 文件夹
  4. Rime 会将 用户文件夹 下所有文件写入到步骤 3中文件夹
  5. 根据 <词典名>.userdb/* 下的文件,生成一个快照文件 <词典名>.userdb.txt
  6. 将快照文件内容与 sync 文件夹下其他文件夹的同名快照文件进行对比,更新当前步骤 5中<词典名>.userdb/* 下的文件
  7. 将更新后的快照文件放入步骤 3中文件夹

只要将几个设备的 sync_dir 都设置为某一云盘下的同一位置,用户数据文件就可以在多设备之间手动同步。进一步地,辅以“用户数据同步”功能的自动触发,同步方案涉及用户数据的部分就得以实现。

Alt text
用户数据同步思路简图

第二类文件的同步则没有在输入法本身的层面得到支持,需要用户自行探索方案。最理想的方案是:多个设备上的配置文件存储在同一云盘中,任何一个设备上的改变都可以实时上传到云盘,并同步到其他设备的配置文件夹下,进而经定期重新部署达到一致体验。但在i(Pad )OS上,这套方案显然行不通——Rime的配置文件在仓输入法的应用文件夹下,但该应用文件夹无法被设置为云盘同步位置。

退而求其次,可以用iCloud作为中转站,用Hazel监测鼠须管的配置文件夹,将其变动实时同步至云,再进一步用快捷指令将云盘上最新的配置文件同步(复制)进移动端仓输入法的配置文件夹。这样,就完成了配置文件从Mac到移动端的单向同步。于是用户词典文件的同步也可以打通。

Alt text
用户词库同步思路简图

用户词库的同步

我们先来讲第二类文件,即用户词库的同步方案。除经常性地需要同步用户词库外,其他配置文件也有可能需要偶尔同步至移动端,因此我选择将鼠须管的配置文件全量同步(Full Sync)至iCloud。全量同步要实现的目的是将Mac本地的所有配置文件即时、完整地上传到云端,且在本地配置文件发生变化的同时,所有变动也要实时更新至云端。在此基础上,Mac端的配置文件就可以用于覆盖手机端的原有文件,达到从Mac到移动端设备的单向同步的效果。

具有监测文件夹内容并实现各种自动化操作的Hazel是实现Mac到iCloud同步的最佳选择。我将被监测的文件夹设为鼠须管的配置文件夹(/Users/<用户名>/Library/Rime,如果你并不想要全量同步,可以在这一步限缩被监测的文件的范围);将同步目标路径设在iCloud“文稿”文件夹下(具体为/Users/<用户名>/Documents/Rime/FullSync/mba2022)。

Alt text
Hazel全量同步

仓输入法对鼠须管单向同步的承接(即用户词典从iCloud到移动端输入法的配置文件夹的过程)与用户数据同步在同一快捷指令中进行,详见下文。

用户数据的同步

Mac端

Rime自带的同步功能以设置installation.yaml文档为前提,建议将installation_id设置为设备名以便于区分,并添加如下行:

sync_dir: "/Users/<用户名>/Library/Mobile Documents/iCloud~dev~fuxiao~app~hamsterapp/Documents/sync" # iCloud上仓的同步文件夹下的位置。不可设置到“文稿”文件夹下,否则仓同步时会提示写入权限问题

设置完成后,可以通过执行以下shell脚本替代点击输入法的“同步用户数据”选项(脚本来自GitHub,nsdont ):

#!/bin/bash

cd ~/Library/Rime
DYLD_LIBRARY_PATH="/Library/Input Methods/Squirrel.app/Contents/Frameworks" "/Library/Input Methods/Squirrel.app/Contents/MacOS/Squirrel" --quit
DYLD_LIBRARY_PATH="/Library/Input Methods/Squirrel.app/Contents/Frameworks" "/Library/Input Methods/Squirrel.app/Contents/MacOS/rime_dict_manager" -s

用户数据将会出现在sync_dir路径下的installation_id文件夹中。

尤需注意,用户数据同步时,若继续输入可能导致配置文件损坏,所以在选取自动化方式的时候,我比较保守地采取了Keyboard Maestro中的"At system sleep"作为触发机制,即在系统进入休眠状态时运行上述脚本,而不是定时或启动时(有血的教训,多亏此前有进行全量备份)。这样基本可以实现每日的数次同步,同时避免潜在的损坏风险。

此外,我还创建了运行以上脚本的LaunchBar动作,命名为Rime Sync,以便需要时通过LaunchBar手动同步。

移动端

同样需要设置installation.yaml 文档,该文档位于应用文件夹下的Rime文件夹下。同样建议将installation_id设置为设备名,并添加如下行:

sync_dir: "/private/var/mobile/Library/Mobile Documents/iCloud~dev~fuxiao~app~hamsterapp/Documents/sync" 
## 注意,iOS的iCloud路径写法与Mac端不同!

运行i(Pad )OS的移动端缺乏好用的自动化工具,所以我选择使用快捷指令及其自动化来实现该平台的用户数据同步,这是全方案最不够“自动”之处。

Alt text
Shortcuts

该快捷指令大致可以分三步。

第一步是打开前文用户数据同步部分中提到鼠须管的sync_dir的位置,并提示是否继续。文件夹打开后,你可以查看要同步的文件是否已下载到本地,必要时可以手动点击下载,等到页面显示下载完成后,点击确认进入下一步。这一步的目的在于保证iCloud上的userdb.txt文档下载到本地,以便仓输入法进行数据同步操作。

第二步是把Hazel的同步文件夹下的有需要的文件(图示为custom_phrase.txt与我自定义的用户词典custom.dict.yaml)覆盖保存至仓输入法应用文件夹下的相应位置。打开文件夹与提示继续两个操作的目的与前一步相同。

第三步是打开仓输入法应用,便于用户手动点击“Rime同步”和“重新部署”。“Rime同步”用于同步用户数据,“重新部署”用于载入第二步操作更新的配置文件,二者均位于“其他设置-RIME”界面下。

该快捷指令也命名为RimeSync,因此在Mac上,为防止混淆,可以呼出LaunchBar搜索框后按⌘+⌥+I,在Shortcuts中取消勾选此动作。

该快捷指令可以设置为(伪)自动化,每天定时提示运行。

整体配置的备份

备份,准确地说是全量备份(Full Backup)。盖Rime配置文件繁多,我常担心某次修改导致输入法整体发生暂时不可察的问题,或是某次自动化操作导致未预料到的配置损坏(如前文提到同步用户数据时使用Rime输入可能会导致),故有不定期做全量备份的习惯,以备不时之需。备份文件的要求是独立于原文件、体积小而完整,能够使输入法整体回退至备份产生时的状态。

本文本意在介绍同步方案,但鉴于同步与备份的需求其实同时存在,不如一并介绍备份方案(相比同步非常简单),也算是让本文的方案更加完整。

Mac端

在Mac端,我创建了运行下列代码的LaunchBar动作,命名为Rime Backup,需要时通过LaunchBar手动创建备份:

##!/bin/bash

source_folder="/Users/<用户名>/Library/Rime" # Rime配置文件夹的路径
icloud_backup_folder="/Users/<用户名>/Documents/Rime/FullBackup" # 备份文件夹的路径,iCloud上的文档文件夹下的Rime/FullBackup
current_time=$(date +"%Y%m%d%H%M%S")

## 设置备份文件名
backup_file_name="<设备名>_${current_time}.tar.gz" 

## 创建备份文件
tar -zcf "${icloud_backup_folder}/${backup_file_name}" -C "${source_folder}" .

该脚本运行完毕后,会在icloud_backup_folder设定的备份文件夹下创建以<设备名>_<创建时间>命名的tar.gz压缩文件,后生成的文件不会替换旧文件,便于追溯到更多的版本。为防止备份文件过多挤占空间,我对备份文件夹也进行了Hazel监测:若备份文件夹内文件超过5个且存在最久的备份文件创建时长超过30天,则删除之。

Alt text
Hazel备份管理

移动端

在移动端,仓输入法提供了“软件备份”功能(其他设置-软件备份-➕),会生成一个包含输入法整体配置的zip压缩文件,存放在应用文件夹下的“Backup”文件夹内。你也可以把它移动或复制到其他位置。

小结

从两个平台的操作来看,整个方案示意图如下:

Alt text
导图

至此,方案整体已呈现完毕,类似思路也可以用于其他云盘。整体实现并不算优雅,但,“It just works”。有更优秀的方案或改进,欢迎朋友们移步slack交流。


  1. 当然,除了手动增减,也可以使用LaunchBar等自动化工具提高增减词汇的效率
  2. 这是软件自身提供的方案,要更快一点,可以用AirDrop投送,用Files接收,再保存至输入法的应用文件夹下。
  3. 引自Rime 输入法指北 | Jiz4oh's Life。这套过程我没有在官网找到说明,但实际使用下来,确实如此。