2023-11-20 00:00:41
有朋友提了个 issue 后发现的,Rime 实现全拼双拼混输很简单,只要在拼写运算 speller/algebra
下把 xform
替换为 derive
就可以了。
非常适合初学双拼时使用。
例如小鹤双拼的 z 键:
- xform/(.)ou$/$1Ⓩ/
- xlit/Ⓩ/z/
ou
最终转为了韵母的 z,输入 zz
就可以得到「走 zou」了,xform
(变形)不保留原型,(.)ou
就没了,改为保留原型的 abbrev
(派生)就可以同时支持全拼和双拼了。(官方文档 - 拼写运算的运算子)
为了全拼双拼混输的显示效果,也要清空 translator/preedit_format
中对双拼转全拼的转换。
例如全拼的 jing(静)与小鹤双拼的 ji’ng(技能),Rime 默认 jing 永远排在 ji’ng 前面,这不太符合双拼为主的情况。
正好全拼的长词优先在这里可以发挥作用了,用 long_word_filter.lua
将「技能」提到「静」的前面。
雾凇拼音 - 小鹤双拼的补丁示例:
# double_pinyin_flypy.custom.yaml
patch:
# 双拼不转换为全拼编码
translator/preedit_format: []
# 在 engine/filters 插入长词优先的 Lua
engine/filters:
- lua_filter@*corrector
- reverse_lookup_filter@radical_reverse_lookup
- lua_filter@*autocap_filter
- lua_filter@*pin_cand_filter
- lua_filter@*long_word_filter # 增加长词优先
- lua_filter@*reduce_english_filter
- simplifier@emoji
- simplifier@traditionalize
- lua_filter@*search@radical_pinyin
- uniquifier
# 长词优先设置为提升 10 个词到第 1 个位置
long_word_filter:
count: 10
idx: 1
# xform 变形改为 derive 派生
speller/algebra:
- derive/^([jqxy])u$/$1v/
- derive/^([aoe])([ioun])$/$1$1$2/
- derive/^([aoe])(ng)?$/$1$1$2/
- derive/iu$/Ⓠ/
- derive/(.)ei$/$1Ⓦ/
- derive/uan$/Ⓡ/
- derive/[uv]e$/Ⓣ/
- derive/un$/Ⓨ/
- derive/^sh/Ⓤ/
- derive/^ch/Ⓘ/
- derive/^zh/Ⓥ/
- derive/uo$/Ⓞ/
- derive/ie$/Ⓟ/
- derive/(.)i?ong$/$1Ⓢ/
- derive/ing$|uai$/Ⓚ/
- derive/(.)ai$/$1Ⓓ/
- derive/(.)en$/$1Ⓕ/
- derive/(.)eng$/$1Ⓖ/
- derive/[iu]ang$/Ⓛ/
- derive/(.)ang$/$1Ⓗ/
- derive/ian$/Ⓜ/
- derive/(.)an$/$1Ⓙ/
- derive/(.)ou$/$1Ⓩ/
- derive/[iu]a$/Ⓧ/
- derive/iao$/Ⓝ/
- derive/(.)ao$/$1Ⓒ/
- derive/ui$/Ⓥ/
- derive/in$/Ⓑ/
- xlit/ⓆⓌⓇⓉⓎⓊⒾⓄⓅⓈⒹⒻⒼⒽⒿⓀⓁⓏⓍⒸⓋⒷⓃⓂ/qwrtyuiopsdfghjklzxcvbnm/
效果展示:
2023-03-16 00:03:36
用 ChatGPT 写一些小脚本真是太方便了。
GPT-4 发布后试了试,还是蛮不错的,代码是 ChatGPT 生成的。
几个来回就可以编写一个能正常使用的油猴脚本:
(略,HTML 代码)
在 https://chdbits.co/bakatest.php 有如上内容。
我要为这个网页编写一个油猴脚本。
通过自动获取 ChatGPT 的 API 来解析此问题的答案,供用户参考。
将内容输出到 `#outer > h1` 的下面,同时输出你提取到的问题内容和答案,以便我看看你是否提取正确。
获取错啦。
问题的获取路径是 `#outer > form > table > tbody > tr:nth-child(1) > td`
选项的获取路径是 `#outer > form > table > tbody > tr:nth-child(2) > td`
使用这个 API:
```
curl https://api.openai.com/v1/chat/completions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Say this is a test!"}],
"temperature": 0.7
}'
```
响应格式为:
```
{
"id":"chatcmpl-abc123",
"object":"chat.completion",
"created":1677858242,
"model":"gpt-3.5-turbo-0301",
"usage":{
"prompt_tokens":13,
"completion_tokens":7,
"total_tokens":20
},
"choices":[
{
"message":{
"role":"assistant",
"content":"\n\nThis is a test!"
},
"finish_reason":"stop",
"index":0
}
]
}
```
它没有最近的互联网数据,所以还是需要把 API 的使用方式发给它。
然后它就帮我写好了,我不用复习 JavaScript,不用看油猴脚本的教程和文档,也不用查 @grant
等等标记是干嘛的。
可以再继续要求它改进一些,比如换个输出位置,优化 prompt,自动选中正确回答,支持单选题和多选题等等。
效果展示:
安装: https://greasyfork.org/zh-CN/scripts/461944-chd-quiz-answer
2023-01-20 00:33:36
雾凇拼音,功能齐全,词库体验良好,长期更新修订,仓库:iDvel/rime-ice
.
├── default.yaml # 一些全局设置
├── rime_ice.schema.yaml # 全拼方案
├── double_pinyin*.yaml # 双拼方案
├── rime_ice.dict.yaml # 挂载词库
├── cn_dicts/ # 词库目录
├── melt_eng.schema.yaml # 英文方案,作为次翻译器挂载到拼音方案
├── melt_eng.dict.yaml # 挂载词库
├── en_dicts/ # 词库目录
├── radical_pinyin.schema.yaml # 部件拆字方案,作为反查挂载到拼音方案
├── radical_pinyin.dict.yaml # 部件拆字词库
├── custom_phrase.txt # 自定义短语
├── symbols_v.yaml # 全拼 v 模式
├── symbols_caps_v.yaml # 双拼 V 模式
├── opencc/ # 词语映射,Emoji
├── rime.lua # 引入 Lua 脚本
├── lua/ # 各个 Lua 脚本
├── squirrel.yaml # 鼠须管的前端配置文件
└── weasel.yaml # 小狼毫的前端配置文件
支持了全拼和部分双拼。
对于英文输入做了一些 hack,详见优化英文输入体验。
启用了自定义短语,全拼为 custom_phrase.txt
,双拼为 custom_phrase_double.txt
需要手动创建。
将 Rime 默认的「/」模式改为了「v」模式,全拼为小写 v 开头,双拼为大写 V 开头,分别在 symbols_v.yaml
和 symbols_caps_v.yaml
中定义。
支持了 Emoji 和部分词语映射,在 opencc/
文件夹中定义。
Lua 设置:
可在 rime.lua
查看所有的 Lua 脚本,提取了一些可配置的选项出来,触发关键字及前缀都可以直接在方案里修改,不用修改 .lua
文件。
以词定字:的快捷键写在了 default.yaml
,因为可能和方括号翻页冲突,其余的 Lua 都在方案文件中设定,参考注释即可。
长词优先:默认是提升 2 个词提到第 4 个位置。
以词定字:默认快捷键为左右中括号 [
]
,分别取第一个和最后一个字。
日期时间:全拼的触发编码为 rq sj xq dt ts
,双拼为 date time week datetime timestamp
。
农历:全拼 nl
,双拼 lunar
。
在 rime.lua
中还有一些默认未启用的脚本,可参考注释自行配置。
一些前缀功能的默认设置:
symbols:全拼 v
开头、双拼大写 V
开头
部件拆字的反查:uU
开头,反查时前缀会消失影响打英文所以设定为两个字母,或可改成一个非字母符号。
部件拆字的辅码:`
触发。
Unicode:大写 U
开头,如 U62fc
得到「拼」。
数字、金额大写:大写 R
开头,如 R1234
得到「一千二百三十四、壹仟贰佰叁拾肆元整」。
农历指定日期:大写 N
开头,如 N20240210
得到「二〇二四年正月初一」。
置顶候选项:
自定义短语 custom_phrase 实现置顶是以一个新的高权重的 table_translator 诞生一个新的词汇。
如果在 custom_phrase 里写了 的 de
,输入 de 时「的」排在了候选项最前面,接着经过去重,拼音翻译器自己的「的」没了,只保留了 custom_phrase 的「的」。
由于两个翻译器之间无法造词,所以「的」这个字失去了造词效果,因此之前建议只写非完整拼音的编码,如 的 d
。
现在由 pin_cand_filter.lua
实现置顶,这个 Lua 仅仅是调整候选项的顺序(没有创造词汇编码的功能),被置顶的「的」仍然是拼音翻译器自己的「的」,可以造词,也就可以置顶完整的拼音。
此功能通过对比去掉空格后的 cand.preedit
来实现,编码一致时,按顺序置顶配置中的词汇;
并与 env.engine.context:get_preedit().text
的字母部分做对比来实现在句子中时仍然置顶。
简单来说,default.yaml
是入口文件,决定了一份配置使用哪些方案,可以只保留自己需要的方案。
里面还有一些特殊设定,候选词个数、方案选单、中西文切换等等,另外将一些所有方案较为通用的配置项也写在 default
里了,再在方案中引用。
方案文件 rime_ice.schema.yaml
(全拼)或 double_pinyin*.yaml
(双拼)是最主要的配置文件,所有功能的引用和实现都在方案文件中。
自定义短语、opencc、symbols 等等是引用的哪个文件、启用了什么 Lua 等等,都是在方案文件中体现的。
melt_eng
与 radical_pinyin
没有作为单独的输入方案,而是作为辅助功能挂载到拼音方案中,以支持在拼音方案下输入英文和拼字。
因为中英文的词库文件较多,rime_ice.dict.yaml
与 melt_eng.dict.yaml
也是作为入口文件,将具体词库放到了文件夹中,让配置目录清爽一些。
配置中基本都写了注释,如果只做小修改,通读一遍即可。
因为没有找到一份比较好的词库,干脆自己维护一个。综合了几个不错的词库,精心调教了很多。
主要维护的词库:
8105
字表。base
基础词库。ext
扩展词库,小词库。tencent
扩展词库,大词库。维护内容主要是异形词、错别字的校对,错误注音的修正,缺失的常用词汇的增添,词频的调整。
欢迎在词库方面提 issue,我会及时更新修正。
Rime 自带的「朙月拼音·简化字」方案其实是繁体词库加上一个自动繁转简的设定,出词仍旧是经过 OpenCC 转换,用户词典中保存的输入历史还是繁体的。
简体用户推荐使用简体词库,引入一些第三方词库也比较方便,还可以避免 OpenCC 的少数转换错误,修订异形词时也只需要按照大陆简体标准修订。
已经为 ext
词库完成注音。
tencent
词库包含的多音字过于庞大,对于没有编码的词库文件,Rime 会根据方案的字表进行自动注音。
当含有多音字的词组缺少编码字段时,自动注音程序会利用权重百分比高于 5% 的读音进行组合、生成全部可能的注音。—— Rime 输入方案设计书
如果不做处理,多音字可以被多种注音打出来,有一些会造成困扰,比如「没发展」可以被 mo fa zhan(魔法战)打出来。
目前的解决方案:
保证 tencent
词库只被一种音注音,手动注音其他音。
例如「的 de di」,手动注音包含 di 音的所有词汇,然后确保字表权重 de * 0.05 > di
;
对于「长 chang zhang」这样不易区分的,全部注音并用勤劳的双手完成校对。
两字词统一放到 base.dict.yaml
中,便于平时修订和调频。
因为两字词的排序基本决定了词库舒适度,重码较多,所以都加上注音和权重,并大量增删和调频。
扩展词库的两字词都没有自动加入,平时扩充时都是肉眼检查后再添加。
主词库缺少了很多常用词和流行小短句,挂载扩展词库后体验会好很多。
ext.dict.yaml
一些平时随手的扩充。
tencent.dict.yaml
只取了腾讯词向量的一百万个词条,算是比较平衡的选择,
扩展的词库默认权重为 100,因为不写权重时,Rime 默认给到的权重比 1 还小,输入长句时,初始的候选项有很大可能会被意料之外的两字词及单字挤占。比如想输入「抽根烟 / 再看看」,当「抽根烟」这个词没有权重时,默认候选项是「抽根 / 淹在 / 看看」。
一些桌面发行版:
鼠须管 Squirrel —— 官方 macOS 发行版
小狼毫 Weasel —— 官方 Windows 发行版
Linux 下有 ibus-rime、fcitx-rime、fcitx5,不太了解。
一些参考、文档、教程:
配置中并没有列出所有属性的可选项,有特殊需求可以看看文档。
建议将 官方 wiki 和 方案制作详解 下载下来放在一起,需要查找一些配置项的时候,全局搜索一下即可。
还有很多,已经很全面了,下面的只是结合本配置随便写一点。
如果用大字表,推荐安装花园明朝字体,或者两分官网推荐的天珩字库。
然后推荐霞鹜文楷,它能识别简体的「𰻝𰻝面 biang biang mian」中的「𰻝」😄,而且拿它做 Rime 的字体也不错。
配置目录 / 用户文件夹:
鼠须管: ~/Library/Rime
小狼毫: %APPDATA%\Rime
共享目录 / 程序文件夹:
/Library/Input Methods/Squirrel.app/Contents/SharedSupport
<安装目录>\data
自己的配置放到配置目录里就可以。共享目录提供了一些自带的方案及各项默认配置,可以直接引用;无特殊需求,不要修改共享目录的文件。
比如 opencc 简繁转换的配置可以直接书写 s2t.json
,因为共享目录里已经有相关文件了。
注意编辑器的缩进配置。
Rime 的 YAML 配置文件需要严格的缩进,使用两个空格缩进,不要用 Tab。
词库文件的词条是用 Tab 分割的:
拼音 pin yin 1234
拼音<Tab>pin<Space>yin<Tab>1234
完成部署后,首先在 default.yaml
中查看呼出方案选单的快捷键。
build/
目录是部署后自动生成的,不要修改,出错时可以看看里面生成的是否正确。
首次部署较慢,主要是拼音方案词库很大,如果下次部署前没有修改词库,就会很快完成部署。
translator/enable_user_dict
是默认开启的,即记录用户输入内容。
用户词典类型 translator/db_class
的值默认为 userdb
,即二进制文件,输入过的内容会记录在 *.userdb/
文件夹中,只有在同步后才能在同步目录看到人类可读的用户词典;另一个值是 tabledb
,会直接在配置目录生成一个人类可读的 txt 文件。如有多平台同步需求,使用默认值 userdb
。
Rime 的配置可以很灵活复杂,比如设置一个快捷键:
xxx.schema.yaml
中设定;xxx.custom.yaml
中设定;default.yaml
或 defaut.custom.yaml
中,再在方案中引用;比如我想让所有方案共用同一套快捷键,不用写很多份。写在 default
中就比较合适,然后再在多个方案中进行引用:
# 1. 在 default.yaml 或 default.custom.yaml 中配置
key_binder:
bindings:
# ... 相关快捷键配置
##############################
# 2. 在多个方案 xxx.schema.yaml 或 xxx.custom.yaml 中引用
key_binder:
import_preset: default # 从 default 继承快捷键的相关配置
import_preset
是导入成套的配置。
__include
是在当前位置包含另一 YAML 节点的内容。
具体用法参考官方 wiki。
下面是一个典型的示例:
# 方案文件 xxx.schema.yaml
punctuator:
# 可以用以下任何方式搞定:
# __include: punctuation:/ # 从共享目录引入预设的 punctuation.yaml
# import_preset: symbols # 从共享目录引入预设的 symbols.yaml
full_shape:
__include: default:/punctuator/full_shape # 从 default.yaml 导入配置
half_shape:
__include: default:/punctuator/half_shape # 从 default.yaml 导入配置
symbols:
__include: symbols_v:/symbols # 从 symbols_v.yaml 导入配置
# 也可以直接在这里配置:
# full_shape:
# ...
# half_shape:
# ...
# symbols:
# ...
文件名为 xxx.custom.yaml
,内容以 patch:
开头的,是补丁文件,注意缩进,可以对原配置进行覆盖和追加。
xxx.schema.yaml
的补丁文件是 xxx.custom.yaml
default.yaml
squirrel.yaml
就是把结尾的 .yaml
改成 .custom.yaml
具体语法参考官方 wiki:定製指南
patch:
"一级设定项/二级设定项/三级设定项": 新的设定值
"另一个设定项": 新的设定值
"再一个设定项": 新的设定值
"含列表的设定项/@n": 列表第n个元素新的设定值,从0开始计数
"含列表的设定项/@last": 列表最后一个元素新的设定值
"含列表的设定项/@before 0": 在列表第一个元素之前插入新的设定值(不建议在补靪中使用)
"含列表的设定项/@after last": 在列表最后一个元素之后插入新的设定值(不建议在补靪中使用)
"含列表的设定项/@next": 在列表最后一个元素之后插入新的设定值(不建议在补靪中使用)
"含列表的设定项/+": 与列表合并的设定值(必须为列表)
"含字典的设定项/+": 与字典合并的设定值(必须为字典,注意YAML字典的无序性)
patch 时支持用 /
来分隔节点,打补丁时可以这样写(比如有如下文件 rime_ice.custom.yaml
):
patch:
a/b: new_value
c/d/e: new_value
但是非补丁的文件只能展开来写(比如 rime_ice.schema.yaml
):
a:
b: value
c:
d:
e: value
# 以 patch: 开头,后面的内容都需要缩进
patch:
##### 修改单项
# 正确 ✅ 这种方式只覆盖 Shift_L,不影响其他选项
ascii_composer/switch_key/Shift_L: commit_code
# 错误 ❌ 这样导致 switch_key 下将只有 Shift_L 一个选项
ascii_composer/switch_key:
Shift_L: commit_code
##### 如果有较多修改项,可以直接全部复制过来再修改
ascii_composer:
good_old_caps_lock: false
switch_key:
Caps_Lock: commit_code
Shift_L: commit_code
Shift_R: noop
Control_L: noop
Control_R: noop
##### 结尾的 /+ 表示在原基础上追加
# 保留已有的快捷键,追加一个逗号句号翻页
key_binder/bindings/+:
- { when: paging, accept: comma, send: Page_Up }
- { when: has_menu, accept: period, send: Page_Down }
如果选项是数组,比如 switches
,得用 switches/@n:
什么的,可读性不好,改多了就乱了,万一原始方案文件更改了顺序就会造成错误,不如全部复制过来再改。
由于 Rime 的设计,拼音词库中并不适用非拼音编码:
hello hello
世界 s j
蒙奇·D·路飞 meng qi d lu fei
非拼音编码 asdasdasd
Rime 在部署时会综合词库中所有音节和拼写规则生成一个映射表,如果开启了简拼,过多的英文单词会导致打字时极其卡顿。上面单个的编码也会导致 s
、j
、d
结尾时无法响应超级简拼。
英文建议放到英文方案,非常规的注音建议放到自定义短语 custom_phrase.txt
。
词库默认的列是:
---
name: 词库名
version: "版本号"
sort: by_weight(按权重排序) | original(按码表顺序排序)
columns: # 不写 columns 属性时,默认顺序为:
- text # 词汇
- code # 编码
- weight # 权重
- stem # 造词码(不知道是啥,好像和拼音方案没有关系)
...
你好 ni hao 123
对于没有注音,又想设置权重的词库文件,修改列即可:
---
name: xxx
version: "1"
sort: by_weight
columns:
- text # 词汇
- weight # 权重
...
你好 123
词库文件以 .dict.yaml
结尾。
词库由具体方案指定:
# rime_ice.schema.yaml
translator:
dictionary: rime_ice # 挂载词库文件 rime_ice.dict.yaml
可以把所有词条堆在这个文件,也可以将这个文件作为一个入口,通过 import_tables
再挂载多个词库:
# rime_ice.dict.yaml
---
name: rime_ice
version: "1"
import_tables:
- mydict # 挂载配置目录下的 mydict.dict.yaml
- cn_dicts/mydict2 # 挂载 cn_dicts/ 目录下的 mydict2.dict.yaml
...
# mydict.dict.yaml
---
name: mydict
version: "1"
sort: by_weight
...
你好 ni hao 1
世界 shi jie 1
词库名 xxx.dict.yaml
和词库中的属性 name: xxx
可以不同,但建议设置为一样的。
其他类型的词库,可以通过 一些脚本 或 深蓝词库转换 转为 Rime 格式的。
在 custom_phrase.txt
中可以放置一些特定的词汇与编码,比如输入 vmail 得到自己的邮箱,输入 vphone 得到手机号,输入 vuser 得到用户名等等。
我自己的理解:每个方案都有一个主翻译器,例如拼音;也可以增加一个次翻译器,例如英文;还可以再增加其他的,例如自定义文本。
custom_phrase.txt
文件内的字词会占据最高权重,即排在候选项的最前面。(默认是这样的,但可以通过 initial_quality
调整各个翻译器的权重)
自定义文本不与其他翻译器互相造词,如果使用了完整编码,那么这个字或词将无法参与造词,即自造词无法被记住。
所以建议只固定非完整编码的字词,「的de」应为「的d」,「是shi」应为「是s」,「仙剑xianjian」应为「仙剑xj」。
注意全拼的
a o e
也是完整拼写,不宜将a o e
的单字写进自定义文本,否则「啊 哦 呃」无法进行造词。
💡 置顶已经由 pin_cand_filter.lua
实现,可参与造词。
installation.yaml
文件在第一次部署后会自动生成,在这里可以编辑当前设备的 ID 和同步目录,如:
# 本机的 ID 标志,默认是一串 UUID
# 生成的文件夹是这个名字,可以改成更好识别的名称
installation_id: "MBP-001"
# 同步的路径,默认是当前配置目录下的 `sync/`
sync_dir: "/file/path/sync"
在你输入过内容后,配置目录下会生成 *.userdb/
文件夹,里面是二进制的用户词典。
点击「同步用户数据」后,Rime 会和配置目录下的 *.userdb/
进行双向更新同步,并在同步目录(/file/path/sync/MBP-001
)下生成的 *.userdb.txt
,里面都是输入过的内容。
同步目录里还有其他一些没用的文件,Rime 额外单向备份了配置目录下的 YAML 和 TXT 文件,但只有根目录的,比如文件夹里的词库、八股文模型、
rime.lua
就没有被同步过来。
⚠️ Windows 用户注意 YAML 语法,反斜杠在双引号中转义,在单引号中不转义:
sync_dir: "c:\\file\\path\\sync"
sync_dir: 'c:\file\path\sync'
将所有平台的 sync_dir
设定为同一个目录,比如 iCloud、Dropbox 的目录。
多个设备在这个目录中会生成并列的文件夹,里面是用户词典。
PC-1 里点【同步】,通过网盘同步到 PC-2,PC-2 再点同步,才可以获得 PC-1 输入过的内容。
如果之前在用别的方案,如 pinyin_simp
或 luna_pinyin
。
pinyin_simp.userdb.txt
或 luna_pinyin[_simp].userdb.txt
放到同步目录rime_ice.userdb.txt
#@/db_name
为 rime_ice
如果之前用的是繁体词库,还需要提前做一个简繁转换,注意不要把 Tab 全转为空格了。
简单的方法,比如 Mac 上通过 VSCode 打开 ➡️ 全选 ➡️ 左上角 Code ➡️ 服务 ➡️ 将文本转换为简体中文。
或者用 opencc:
$ opencc -c t2s -i in.txt -o out.txt
方案中有几个开关(switches
),比如简繁开关、Emoji 开关、中英标点开关。。。
如果设定了 reset,值为 0 或 1,则默认使用第一个或第二个值,即便使用时修改了,切换程序后还是默认值。
如果想让输入法永远记住,需要取消设置 reset
,并在 default.custom.yaml
中写入 save_options
。
*永远记住的前提是通过方案选单选择,而不是快捷键切换 (╯’-’)╯︵┻━┻
比如删除英文输入,所有的相关配置是这些:
# dependencies 下的:
- melt_eng
# engine/translators 下的:
- table_translator@melt_eng
melt_eng:
dictionary: melt_eng
拼字方案同样,此外还有一些 Lua 的功能,直接在 engine
下注释掉那一行就禁用了。
在 squirrel[.custom].yaml
或 weasel[.custom].yaml
中配置鼠须管或小狼毫的皮肤,各平台的前端并不一致,鼠须管的皮肤无法用在小狼毫上。
这里有一个鼠须管内置皮肤的展示图:NavisLab/rime-pifu(图片备份),小狼毫自带皮肤预览。
需要自己设计皮肤的,鼠须管推荐用这个图形化的皮肤设计器,鼠须管主要维护者写的:LEOYoon-Tsaw/Squirrel-Designer
小狼毫的在线设计网页:RIME 西米 (小狼毫维护者的)、 润笔
【中州韵】 /tmp/rime.ibus.*
【小狼毫】 %TEMP%\rime.weasel.*
【鼠须管】 $TMPDIR/rime.squirrel.*
日志级别分为 INFO
WARNING
ERROR
,查看示例:
$ cat $TMPDIR/rime.squirrel.INFO
鼠须管我经常碰到一个小问题,有时候都弹通知报错了,但是日志是空的,根本没有这个文件。可以直接结束鼠须管进程,它自动重启后就好了。
可以删除自造词,或降低词库中已有词语的权重(回到原始权重,不是降到最低)。
想永久删除一个词库中存在的词汇,只能编辑词库,重新部署。
如果各位有在使用过程中有发现什么错别字,希望可以提个 issue。
这功能挺好用的,每次用别人的电脑打字都会怀念这个功能。
已经默认开启,可以使用 Tab 或 Shift + Tab 在拼音中前后移动。
对于「xian西安」「tian提案」这种拼音,如果想切到「xi、ti」的后面,只能用左右方向键移动。
另外 Shift + ⌫ 可以删除单个汉字的拼音。
按下空格会上屏汉字,按下回车会上屏字母(可临时输入一些词库中没有的英文)。
以输入「虐心 nue’xin」为例:
nuexin
。nve xin
。(u → v,中间有空格)translator/preedit_format
这里会影响输入框和 shift + 回车时的显示,比如是显示 nue、nve 或 nüe。
如果是双拼方案,preedit_format
还可以选择是否在输入框进行转换,比如小鹤双拼输入 zz
时,是显示 zz
还是 zou
。
要设置双拼不转换为全拼,可以直接把 preedit_format
及下面那些 xform
都删除,或者这样打补丁:
patch:
translator/preedit_format: []
opencc 除了做简繁转换,也可以做词语映射。
比如想输入摄氏度的符号 °C ,可以自定义文本 custom_phrase.txt
中写上:
°C sheshidu
但这样,这个符号会顶到第一个候选项,重码时影响平时打汉字。推荐用 opencc 的方法,Emoji 就是这样实现的。
摄氏度 摄氏度 °C
足球 足球 ⚽
输入内容<Tab>响应内容1<Space>响应内容2<Space>响应内容3...
输入 摄氏度
,第一个候选项是其本身,后续则是映射的其他内容。类似输入 提手旁
会得到 提手旁 扌
,输入 相泽南
会得到 相泽南 相沢みなみ
等等都是这么做的。
这个「输入内容」其本身应该在词库中存在,否则只能输入过一次后才会有响应。
还有个用法是 show_in_comment: true
,可以让「响应内容」放到 comment
里面。
show_in_comment: true
可以实现显示英文单词的翻译,类似哈利路亚输入法,尝试过加入这个功能,一是没有找到比较好的简短翻译数据;二是 Rime 的 comment
区域并不是一个独立存在的窗口,翻译和候选项挤在一起看起来乱糟糟的。
「東風破早梅,向暖一枝開。」
东风破 plum 是 Rime 官方的一个配置管理工具。
下面是一个简单使用示例,可以在任意文件夹下运行(使用前请备份并清空配置目录):
$ git clone --depth=1 https://github.com/rime/plum
$ cd plum
$ bash rime-install iDvel/rime-ice:others/recipes/full
得,这就安装完了雾凇拼音。
全量更新,再用一次 full 配方即可:
$ bash rime-install iDvel/rime-ice:others/recipes/full
单独更新词库可以用另一个配方:
$ bash rime-install iDvel/rime-ice:others/recipes/all_dicts
例如小鹤双拼,可以在首次安装后再自动打一个补丁:
bash rime-install iDvel/rime-ice:others/recipes/config:schema=flypy
可以查看配置仓库中的 *.recipe.yaml
配方文件,来查看这个配方到底更新了什么。
2023-01-19 00:09:28
在 macOS 中利用 Hammerspoon 自动切换输入法。
因为 Rime 目前的中英切换不是特别好用:
Rime 全局状态功能的进展:global input session, state shared by all client apps #294
我希望的是:无论当前是什么输入法,切换到 iTerm,就是英文,离开 iTerm,回到我原先的输入法。
类似于 Alfred 目前的功能(高级设置中的 Force Keyboard 设置为 ABC)。
我在 Typora 写中文,呼出 Alfred,变成英文输入法,用完了回到 Typora,变回中文输入法。
代码参考于:ibreathebsb/hammerspoon自动切换输入法.lua
使用方法:放到 ~/.hammerspoon/init.lua
重新部署就可以了。
可以用 Cmd + Ctrl + .
来查看当前窗口的 name 或 path;
可以在 Hammerspoon 的控制台输入 hs.keycodes.currentSourceID()
来查看当前输入法的 ID。
做的修改:
-- 当选中某窗口按下 ctrl+command+. 时会显示应用的路径、名字等信息
hs.hotkey.bind({'ctrl', 'cmd'}, ".", function()
hs.pasteboard.setContents(hs.window.focusedWindow():application():path())
hs.alert.show("App path: " .. hs.window.focusedWindow():application():path() .. "\n" .. "App name: " ..
hs.window.focusedWindow():application():name() .. "\n" .. "IM source id: " ..
hs.keycodes.currentSourceID(), hs.alert.defaultStyle, hs.screen.mainScreen(), 3)
end)
-- 这里指定中文和英文输入法的 ID
local function Chinese()
hs.keycodes.currentSourceID("im.rime.inputmethod.Squirrel.Rime")
end
local function English()
hs.keycodes.currentSourceID("com.apple.keylayout.ABC")
end
-- 指定程序
local appInputMethod = {
iTerm2 = English,
['EuDic LightPeek'] = English,
Bitwarden = English,
SnippetsLab = English,
['微信'] = Chinese,
}
-- activated 时切换到指定的输入法,deactivated 时恢复之前的状态
currentID = ""
function applicationWatcher(appName, eventType, appObject)
if (eventType == hs.application.watcher.activated) then
for app, fn in pairs(appInputMethod) do
if app == appName then
currentID = hs.keycodes.currentSourceID()
fn()
end
end
end
if eventType == hs.application.watcher.deactivated then
for app, fn in pairs(appInputMethod) do
if app == appName then
hs.keycodes.currentSourceID(currentID)
currentID = hs.keycodes.currentSourceID()
end
end
end
end
appWatcher = hs.application.watcher.new(applicationWatcher):start()
-- 输入法切换提示
-- hs.keycodes.inputSourceChanged(function()
-- if hs.keycodes.currentMethod() == nil then
-- hs.alert.show("ABC", hs.alert.defaultStyle, hs.screen.mainScreen(), 2)
-- else
-- hs.alert.show("拼音", hs.alert.defaultStyle, hs.screen.mainScreen(), 2)
-- end
-- end)
小问题:
无法识别 Alfred 的窗口,不过 Alfred 自带这个功能,和本配置功能一样。
本来想弄个提示的,但是每次切换时都会产生意料之外的多次切换,比如「ABC → ABC → ABC」或「ABC → 拼音 → ABC」,不知为何中间发生了多次切换,这导致菜单栏的输入法图标发生了一阵短暂而急促的抖动,不过好在结果都是正确的。
我看 Alfred 自己的功能也有这个问题,不知道有没有可能是 macOS 的 Bug。
最后只好注释掉 hs.alert.show
的提示了。
2023-01-08 19:49:29
累计布局偏移 Cumulative Layout Shift(CLS)是一项 Web 指标。
布局偏移如图所示,元素突然变化的高度影响了用户交互体验:
一般给图片一个高度就可以了,但最好是能自动化,而不是手写。
看到了这篇博文 累计布局偏移修复方案改进 —— 自动生成图片宽高,不过他是从腾讯云对象存储获取的图片宽高,而我都将图片存储在了 Hugo 配置目录的 static/img/
文件夹。
我平时在 Markdown 里都是直接写的 path:
![](/img/example.webp)
参考 How to prevent CLS in Hugo,利用 Hugo 的 Render Hooks 功能重新渲染图片相关代码,获取图片的宽高,在 <img>
标签里加上 width
和 height
属性。
不知道为什么照他的办法,在配置中加入了 mounts
相关属性,仍然不起作用,不太会前端和 Hugo,摸索着改了改。
创建 layouts/_default/_markup/render-image.html
文件:
<p>
{{ if hasPrefix .Destination "/img" }}
{{ $img := os.ReadFile (path.Join "/static" .Destination) | resources.FromString .Destination }}
{{ if ne $img.MediaType.SubType "svg" }}
<img loading="lazy"
src="{{ .Destination | safeURL }}"
alt="{{ .Text }}"
width="{{ $img.Width }}"
height="{{ $img.Height }}"
style="max-width: 100%; height: auto;"
/>
{{ end }}
{{ if or (not $img) (eq $img.MediaType.SubType "svg") }}
<img loading="lazy" src="{{ .Destination | safeURL }}" alt="{{ .Text }}" />
{{ end }}
{{ else }}
<img loading="lazy" src="{{ .Destination | safeURL }}" alt="{{ .Text }}" />
{{ end }}
</p>
在他的基础上手动加上了 /static
地址前缀,不然这个 os.ReadFile
方法一直报错;
加上了 style="max-width: 100%; height: auto;"
,保持宽度超过父容器的图片的比例;
套了个 if else
,只处理图片地址为 /img
开头的本地图片,并可以显示网络图片,但是网络图片仍然会产生偏移。
我用的是 Hugo PaperMod 主题,主页的封面图也存在这个问题,得修改 cover.html
,看不太懂,我看上面那位博主是修改的这里,确实起作用。
修改最外层的 {{- else }}
里的内容(Hugo PaperMod 6.0 版本),和之前的一样,就是替换一下 src
和 alt
的属性值:
{{- else }}{{/* For absolute urls and external links, no img processing here */}}
{{- if $addLink }}<a href="{{ (.Params.cover.image) | absURL }}" target="_blank"
rel="noopener noreferrer">{{ end -}}
<!-- <img loading="lazy" src="{{ (.Params.cover.image) | absURL }}" alt="{{ $alt }}"> -->
<!-- 修改,将上面那行改成下面这些: -->
{{ if hasPrefix .Params.cover.image "/img" }}
{{ $img := os.ReadFile (path.Join "/static" .Params.cover.image) | resources.FromString .Params.cover.image }}
{{ if ne $img.MediaType.SubType "svg" }}
<img loading="lazy"
src="{{ .Params.cover.image | safeURL }}"
alt="{{ $alt }}"
width="{{ $img.Width }}"
height="{{ $img.Height }}"
style="max-width: 100%; height: auto;"
/>
{{ end }}
{{ if or (not $img) (eq $img.MediaType.SubType "svg") }}
<img loading="lazy" src="{{ .Params.cover.image | safeURL }}" alt="{{ $alt }}" />
{{ end }}
{{ else }}
<img loading="lazy" src="{{ .Params.cover.image | safeURL }}" alt="{{ $alt }}" />
{{ end }}
{{- end }}
2022-11-25 20:09:31
上一篇博文用修改 ~/Library/KeyBindings/DefaultKeyBinding.dict
的方法修改按键绑定,但很多地方依然无法响应新的键位设置,体验比较割裂,于是换到 Karabiner。
在 DefaultKeyBinding.dict
中,用 Ctrl+h 来向左移动,macOS 是通过这样实现的:
"^h" = "moveBackward:";
如果想继续实现 Shift+left(向左移动时选中文本)这个功能,还得需要调用另一个方法:
"^H" = "moveBackwardAndModifySelection:";
苹果原生的方式是直接作用的,比如删除到行首(Ctrl + u)就等于一步操作:直接删除到行首。
Karabiner 要实现删除到行首,它是先通过 Command + Shift + left 来选中光标之前所有的文本,再按下删除键,这样的方式来实现的。
影响可能是有的,比如终端上无法响应,如果自己定义了一个 Ctrl + u,反而还覆盖了其本身正常的功能,不过可以屏蔽掉不需要的 App。
另外无须单独实现带选区的那种,因为 Ctrl+h 已经被映射为左箭头了,自己再加上 Shift 就可以了。
Karabiner 还可以实现更多的功能,比如作者直接写了个全局 Vim 映射,还可以启动 App,设置只限定特定设备、特定 App 等等,功能着实强大,还开源免费。
~/.config/karabiner/assets/complex_modifications
增加自己的规则。官方文档:https://karabiner-elements.pqrs.org/docs/
社区分享:https://ke-complex-modifications.pqrs.org/
建议查看官方文档熟悉一点小例子,然后下载别人实现类似的功能的 JSON 代码来参考。
文档最下面有个 External JSON generators,比如用这个 Karabiner Complex Modification 可以自动生成 JSON,不过简单的映射还是直接写 JSON 方便。
原始的 Emacs-like 键位:
Ctrl + ...
a 移动到行首
e 移动到行尾
b 左
f 右
p 上
n 下
h 往左删除一个
d 往右删除一个
w 往左删除单词
u 往左删除到行首
k 往右删除到行尾
自定义的的键位:
Ctrl + ...
a 移动到行首
e 移动到行尾
h 左
l 右
k 上
j 下
o 插入一行
s 往左删除一个
d 往右删除一个
u 往左删除到行首
i 往右删除到行尾
w 往左删除单词
pnbf 仍然可以使用,没有冲突。
a e 不进行任何改动,我还没有发现有不支持的地方。
w u 的功能虽然和上面一样,但有些地方比如 Typora 就不支持,自己实现一遍确保全局有效。
将代码保存到 ~/.config/karabiner/assets/complex_modifications
。
因为这个 issue#2774 没有解决,还不能全局限定或屏蔽某 App,代码像面条一样,frontmost_application_unless
相关配置每次修改时都需要同时改动多处地方。
{
"title": "Dvel's hjkl",
"rules": [
{
"description": "(1) CapsLock 短按为 Esc,组合为 Control",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "caps_lock",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "left_control",
"lazy": true
}
],
"to_if_alone": [
{
"key_code": "escape"
}
]
}
]
},
{
"description": "(2) Ctrl + hjkl 移动光标,排除 JetBrains",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "left_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "down_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "up_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "right_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
}
]
},
{
"description": "(3) Ctrl + aeosduiw,排除 JetBrains 和终端",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "o",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"left_command"
]
},
{
"key_code": "return_or_enter"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "s",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "delete_or_backspace"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "d",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "delete_forward"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "u",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"left_command",
"left_shift"
]
},
{
"key_code": "delete_or_backspace"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "i",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"left_command",
"left_shift"
]
},
{
"key_code": "delete_forward"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "w",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"option",
"shift"
]
},
{
"key_code": "delete_or_backspace"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
}
]
},
{
"description": "(4) Option [+ Shift] + hjkl",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"option"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"option"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"option"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"option"
]
}
]
}
]
}
]
}