在 Linux 桌面环境中,Rime 输入法具有很强的可定制能力。除了词库、快捷键和候选数量,也可以借助 Lua 动态生成当前日期、时间和星期。
目标效果如下:
riqi → 2026年7月26日、2026-07-26、2026/07/26
shijian → 10:35、10:35:42
xianzai → 2026-07-26 10:35:42
xingqi → 星期日
这类功能看似只是增加几行配置,实际排查过程中却遇到了几个容易误判的问题:
- 编译配置中已经存在 Lua translator,但候选没有出现;
- 部署命令返回成功,不等于功能实际可用;
- 候选窗口出现,不等于动态候选出现;
- 当前图形会话使用的输入法,可能并不是正在配置的 Rime;
- 直接修改
build/目录虽然暂时有效,却会在重新部署后被覆盖; - 在交互式终端中使用严格退出选项,可能导致整个终端窗口关闭。
本文整理完整过程,并总结一套更可靠的处理方法。
一、运行环境与需求
测试环境为:
- Arch Linux
- KDE Plasma Wayland
- Fcitx5
- Fcitx5-Rime
- librime 1.17
- librime-lua 插件
- 朙月拼音简化字方案:
luna_pinyin_simp
用户原本已经将每页候选数量改为 9,但修改位置位于:
<Rime 用户目录>/build/
build/ 是 Rime 的编译产物目录。这里的文件会在重新部署时被重新生成,因此不适合保存长期自定义配置。
正确做法是把自定义内容放在用户数据目录:
<Rime 用户目录>/
例如:
<Rime 用户目录>/
├── rime.lua
├── lua/
│ └── date_time.lua
├── luna_pinyin_simp.custom.yaml
└── build/
二、先确认 Lua 支持是否存在
动态日期和时间需要 librime-lua。
在 Arch Linux 中,新版 librime 软件包通常已经包含 Lua 插件,不一定需要额外安装独立软件包。
可以检查:
pacman -Q fcitx5 fcitx5-rime librime rime-luna-pinyin lua
再确认插件文件:
ls -l <librime-lua 插件路径>
pacman -Qo <librime-lua 插件路径>
如果能看到对应的 Lua 插件文件,并且该文件属于 librime 软件包,说明 Lua 支持已经安装。
三、不要继续修改 build 目录
候选数量应写入:
luna_pinyin_simp.custom.yaml
例如:
patch:
"menu/page_size": 9
动态 Lua translator 也应通过同一个补丁挂载:
patch:
"menu/page_size": 9
"engine/translators/@before 3": lua_translator@date_time_translator
这样重新部署后:
- 每页仍然显示 9 个候选;
- Lua translator 会继续存在;
- 不需要再次手工修改编译后的 schema。
四、第一次配置:编译成功,但功能没有出现
最初的配置采用了单文件内联 Lua 写法,将 translator 直接定义在 rime.lua 中。
部署命令返回:
rime_deployer 返回值:0
fcitx5-remote 返回值:0
编译后的 schema 也能找到:
lua_translator@date_time_translator
候选数量同样保持为:
menu:
page_size: 9
从静态配置看,一切似乎都成功了。
但实际输入时:
riqi
候选仍然只是:
日期
日起
日企
……
输入:
shijian
看到的仍然是:
时间
事件
实践
……
输入 xianzai 和 xingqi 也只是普通拼音词典候选,没有任何动态日期、时间或星期。
这说明:
配置被编译进去,不代表 Lua translator 在运行时真正生成了候选。
五、不能把“候选窗口出现”当作成功
排查过程中曾经出现一个典型误判:
- 自动化测试输入了
riqi; - 屏幕上出现了 Rime 候选窗口;
- 因此被报告为“真实验证成功”。
但截图中显示的仍然只是普通词典候选,并没有当前日期。
真正的成功标准必须是候选中明确出现动态值,例如:
2026年7月26日
2026-07-26
2026/07/26
20260726
2026年7月26日 星期日
同理:
shijian
必须出现测试时的真实时间,而不是只有“时间”这个普通词语。
因此验收时不能只检查:
rime_deployer是否返回 0;- schema 中是否包含 Lua translator;
- 候选窗口是否出现。
必须检查:
- 动态候选内容是否真实存在;
- 日期和时间是否与系统当前时间一致;
- 候选是否位于可见页;
- 当前输入法是否确实是 Rime。
六、一个容易忽略的根因:当前输入法不是 Rime
继续排查后发现,图形会话中实际激活的输入法一度不是 Rime,而是:
keyboard-us
这种情况下,即使 Rime 配置完全正确,也不会由 Rime 处理输入。
检查当前输入法:
fcitx5-remote -n
如果返回:
keyboard-us
说明当前并未使用 Rime。
切换到 Rime:
fcitx5-remote -s rime
fcitx5-remote -o
再次检查:
fcitx5-remote -n
预期返回:
rime
这一步非常关键。
在输入法排查中,经常会花大量时间检查词库、Lua、schema 和日志,却忽略了当前正在运行的根本不是目标输入法。
七、采用标准 Lua 模块结构
为了避免单文件内联方式在不同版本之间产生加载差异,最终改为更标准的模块化结构。
1. rime.lua
路径:
<Rime 用户目录>/rime.lua
内容:
date_time_translator = require("date_time")
rime.lua 只负责加载入口,不再保存全部 translator 实现。
2. lua/date_time.lua
路径:
<Rime 用户目录>/lua/date_time.lua
该模块负责:
- 判断输入编码;
- 读取系统时间;
- 生成日期、时间、星期候选;
- 返回 translator 函数。
结构示意如下:
local weekdays = {
[1] = "星期日",
[2] = "星期一",
[3] = "星期二",
[4] = "星期三",
[5] = "星期四",
[6] = "星期五",
[7] = "星期六",
}
local function translator(input, seg)
local now = os.date("*t")
local weekday = weekdays[now.wday]
local function emit(text, comment)
local candidate = Candidate(
"date_time",
seg.start,
seg._end,
text,
comment
)
candidate.quality = 1000
yield(candidate)
end
if input == "riqi" then
emit(
string.format(
"%d年%d月%d日",
now.year,
now.month,
now.day
),
"日期"
)
emit(os.date("%Y-%m-%d"), "日期")
emit(os.date("%Y/%m/%d"), "日期")
emit(os.date("%Y%m%d"), "日期")
emit(
string.format(
"%d年%d月%d日 %s",
now.year,
now.month,
now.day,
weekday
),
"日期与星期"
)
elseif input == "shijian" then
emit(os.date("%H:%M"), "时间")
emit(os.date("%H:%M:%S"), "时间")
elseif input == "xianzai" then
emit(os.date("%Y-%m-%d %H:%M:%S"), "当前日期时间")
elseif input == "xingqi" then
emit(weekday, "星期")
end
end
return translator
这里给候选设置较高的 quality,是为了避免动态候选被普通拼音词典候选压到后面。
如果 Lua translator 已经运行,但动态候选排在第二页甚至更后面,看起来也会像“功能没有生效”。
八、重新部署与重新加载
标准部署命令:
RIME_DIR="<Rime 用户目录>"
rime_deployer \
--build \
"$RIME_DIR" \
"<Rime 共享数据目录>" \
"$RIME_DIR/build"
重新加载 Fcitx5:
fcitx5-remote -r
必要时重启 Fcitx5 用户服务:
systemctl --user restart <Fcitx5 用户服务名称>
然后重新切换到 Rime:
fcitx5-remote -s rime
fcitx5-remote -o
服务名称可能因会话而异,不应在其他机器上直接照抄。可以先查询:
systemctl --user list-units | grep -i fcitx
九、避免在交互式终端中使用 set -e
排查期间还出现了一个与输入法无关、但很容易引起误会的问题。
一段命令开头使用了:
set -euo pipefail
随后某条检查命令返回非零状态,导致当前交互式 Bash 直接退出。
如果终端模拟器设置为“Shell 退出后关闭窗口”,表现就会像:
一执行命令,整个终端突然关闭。
这并不代表终端损坏。
其中:
set -e:命令失败时退出 Shell;set -u:引用未定义变量时退出;set -o pipefail:管道中任一命令失败,整个管道视为失败。
这些选项适合放在独立脚本或子 Shell 中,不适合直接粘贴进当前正在使用的交互式终端。
错误示例:
set -euo pipefail
command -v some_command
更安全的交互式写法是:
command -v some_command || echo "未找到命令"
或者:
(
set -euo pipefail
# 需要严格检查的命令
)
即使子 Shell 退出,也不会关闭当前终端。
十、修改前应保留可追溯备份
Rime 配置属于长期使用的个人资产。修改前应保留原文件,并使用可追溯命名。
推荐格式:
原文件名.YYYYMMDD-HHMMSS
时间戳取原文件的修改时间,而不是备份执行时间。
例如:
FILE="<Rime 用户目录>/rime.lua"
if [ -e "$FILE" ]; then
STAMP="$(date -r "$FILE" '+%Y%m%d-%H%M%S')"
cp -a -- "$FILE" "${FILE}.${STAMP}"
fi
不建议使用:
rime.lua.bak
rime.lua.bak.1
rime.lua.old
这些命名难以判断备份对应的具体版本和时间。
十一、最终验收结果
完成修复后,真实图形会话中的测试结果为:
输入 riqi
候选出现:
2026年7月26日
2026-07-26
2026/07/26
20260726
2026年7月26日 星期日
输入 shijian
候选出现当前系统时间:
10:35
10:35:42
输入 xianzai
候选出现完整日期时间:
2026-07-26 10:35:42
输入 xingqi
候选出现:
星期日
同时确认:
fcitx5-remote -n
返回:
rime
每页候选数量仍然保持为:
menu:
page_size: 9
用户词库、学习数据和同步数据均未删除。
十二、这次排查最重要的经验
1. 部署成功不等于功能成功
exit 0
只能说明部署程序没有报告错误,不能证明动态功能已经出现在输入法中。
2. 编译配置存在不等于运行时生效
即使 schema 中能够找到:
lua_translator@date_time_translator
也仍需验证 Lua 是否实际加载并产生候选。
3. 候选窗口出现不等于目标候选出现
普通词库同样会显示候选窗口。验收必须检查具体候选内容。
4. 首先确认当前输入法
在深入研究 Lua 之前,应先运行:
fcitx5-remote -n
确认当前确实是 rime。
5. 动态候选可能被普通词典压到后面
Lua translator 即使正常运行,也可能因为候选权重不足而排到后页。必要时应提高候选 quality。
6. 用户配置不要写进 build
长期配置应放在:
*.custom.yaml
rime.lua
lua/
build/ 只用于编译结果和验收。
7. 自动化验收必须检查结果语义
截图中出现候选框,只能证明输入法做出了响应。只有截图中真正出现当前日期、时间和星期,才算功能完成。
结语
Rime 的动态日期时间功能本身并不复杂,真正容易出错的是配置层、编译层、运行层和当前输入法状态之间的混淆。
一套可靠的处理顺序应当是:
确认 Lua 插件
→ 确认当前输入法为 Rime
→ 使用用户层 custom 配置
→ 使用标准 Lua 模块结构
→ 重新部署
→ 重新加载
→ 在真实应用中检查动态候选
只要把“静态配置正确”和“运行结果正确”分开验证,这类问题就能得到稳定、可重复的解决。