Files
rime-frost/lua/aux_code.lua

277 lines
9.5 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- https://github.com/HowcanoeWang/rime-lua-aux-code
local AuxFilter = {}
-- local log = require 'log'
-- log.outfile = "aux_code.log"
function AuxFilter.init(env)
-- log.info("** AuxCode filter", env.name_space)
AuxFilter.aux_code = AuxFilter.readAuxTxt(env.name_space)
local engine = env.engine
local config = engine.schema.config
-- 設定預設觸發鍵為分號,並從配置中讀取自訂的觸發鍵
env.trigger_key = config:get_string("key_binder/aux_code_trigger") or "`"
-- 设定是否显示辅助码,默认为显示
env.show_aux_notice = config:get_string("key_binder/show_aux_notice") or 'true'
if env.show_aux_notice == "false" then
env.show_aux_notice = false
else
env.show_aux_notice = true
end
----------------------------
-- 持續選詞上屏,保持輔助碼分隔符存在 --
----------------------------
env.notifier = engine.context.select_notifier:connect(function(ctx)
-- 含有輔助碼分隔符才處理
if not string.find(ctx.input, env.trigger_key) then
return
end
local preedit = ctx:get_preedit()
local removeAuxInput = ctx.input:match("([^,]+)" .. env.trigger_key)
local reeditTextFront = preedit.text:match("([^,]+)" .. env.trigger_key)
-- ctx.text 隨著選字的進行oaoaoa 有如下的輸出:
-- ---- 有輔助碼 ----
-- >>> 啊 oaoaau
-- >>> 啊吖 oaau
-- >>> 啊吖啊au
-- ---- 無輔助碼 ----
-- >>> 啊 oaoa
-- >>> 啊吖 oa
-- >>> 啊吖啊;
-- 這邊把已經上屏的字段 (preedit:text) 進行分割;
-- 如果已經全部選完了,分割後的結果就是 nil否則都是 吖卡 a 這種字符串
-- 驗證方式:
-- log.info('select_notifier', ctx.input, removeAuxInput, preedit.text, reeditTextFront)
-- 當最終不含有任何字母時 (候選),就跳出分割模式,並把輔助碼分隔符刪掉
ctx.input = removeAuxInput
if reeditTextFront and reeditTextFront:match("[a-z]") then
-- 給詞尾自動添加分隔符,上面的 re.match 會把分隔符刪掉
ctx.input = ctx.input .. env.trigger_key
else
-- 剩下的直接上屏
ctx:commit()
end
end)
end
----------------
-- 閱讀輔碼文件 --
----------------
function AuxFilter.readAuxTxt(txtpath)
-- log.info("** AuxCode filter", 'read Aux code txt:', txtpath)
if AuxFilter.cache then
return AuxFilter.cache
end
local defaultFile = 'moqi_aux_code.txt'
local userPath = rime_api.get_user_data_dir() .. "/lua/aux_code/"
local fileAbsolutePath = userPath .. txtpath .. ".txt"
local file = io.open(fileAbsolutePath, "r") or io.open(userPath .. defaultFile, "r")
if not file then
log.info("Unable to open auxiliary code file.")
return {}
end
local auxCodes = {}
for line in file:lines() do
if line ~= nil and line ~= "" then -- 检查 line 是否为空
local line_ = line:match("[^\r\n]+") -- 去掉換行符,不然 value 是帶著 \n 的
local key, value = line_:match("([^=]+)=(.+)") -- 分割 = 左右的變數
if key and value then
auxCodes[key] = auxCodes[key] or {}
table.insert(auxCodes[key], value)
end
end
end
file:close()
-- 確認 code 能打印出來
-- for key, value in pairs(AuxFilter.aux_code) do
-- log.info(key, table.concat(value, ','))
-- end
AuxFilter.cache = auxCodes
return AuxFilter.cache
end
-- local function getUtf8CharLength(byte)
-- if byte < 128 then
-- return 1
-- elseif byte < 224 then
-- return 2
-- elseif byte < 240 then
-- return 3
-- else
-- return 4
-- end
-- end
-- 輔助函數,用於獲取表格的所有鍵
local function table_keys(t)
local keys = {}
for key, _ in pairs(t) do
table.insert(keys, key)
end
return keys
end
-----------------------------------------------
-- 計算詞語整體的輔助碼
-- 目前定義為
-- 把字或词组的所有辅码,第一个键堆到一起,第二个键堆到一起
-- 例子:
-- 候选(word) = 拜日
-- 【拜】 的辅码有 charAuxCodes=
-- p a
-- p u
-- u a
-- u f
-- u u
-- 【日】 的辅码有 charAuxCodes=
-- o r
-- r i
-- a a
-- u h
-- (竖着拍成左右两个字符串)
-- 第一个辅码键的不重复列表为fullAuxCodes[1]= urpao
-- 第二个辅码键的不重复列表为fullAuxCodes[2]= urhafi
-- -----------------------------------------------
function AuxFilter.fullAux(env, word)
local fullAuxCodes = {}
-- log.info('候选词:', word)
for _, codePoint in utf8.codes(word) do
local char = utf8.char(codePoint)
local charAuxCodes = AuxFilter.aux_code[char] -- 每個字的輔助碼組
if charAuxCodes then -- 輔助碼存在
for _, code in ipairs(charAuxCodes) do
for i = 1, #code do
fullAuxCodes[i] = fullAuxCodes[i] or {}
fullAuxCodes[i][code:sub(i, i)] = true
end
end
end
end
-- 將表格轉換為字符串
for i, chars in pairs(fullAuxCodes) do
fullAuxCodes[i] = table.concat(table_keys(chars), "")
end
return fullAuxCodes
end
-----------------------------------------------
-- 判斷 auxStr 是否匹配 fullAux
-----------------------------------------------
function AuxFilter.match(fullAux, auxStr)
if #fullAux == 0 then
return false
end
local firstKeyMatched = fullAux[1]:find(auxStr:sub(1, 1)) ~= nil
-- 如果辅助码只有一个键,且第一个键匹配,则返回 true
if #auxStr == 1 then
return firstKeyMatched
end
-- 如果辅助码有两个或更多键,检查第二个键是否匹配
local secondKeyMatched = fullAux[2] and fullAux[2]:find(auxStr:sub(2, 2)) ~= nil
-- 只有当第一个键和第二个键都匹配时,才返回 true
return firstKeyMatched and secondKeyMatched
end
------------------
-- filter 主函數 --
------------------
function AuxFilter.func(input, env)
local context = env.engine.context
local inputCode = context.input
-- 分割部分正式開始
local auxStr = ''
-- 判断字符串中是否包含輔助碼分隔符
if not string.find(inputCode, env.trigger_key) then
-- 没有输入辅助码引导符则直接yield所有待选项不进入后续迭代提升性能
for cand in input:iter() do
yield(cand)
end
return
else
-- 字符串中包含輔助碼分隔符
local trigger_pattern = env.trigger_key:gsub("%W", "%%%1") -- 處理特殊字符
local localSplit = inputCode:match(trigger_pattern .. "([^,]+)")
if localSplit then
auxStr = string.sub(localSplit, 1, 2)
-- log.info('re.match ' .. local_split)
end
-- 更新逻辑:没有匹配上就不出现再候选框里,提升性能
-- local insertLater = {}
-- 遍歷每一個待選項
for cand in input:iter() do
local cand_ = cand
local auxCodes = AuxFilter.aux_code[cand.text] -- 僅單字非 nil
local fullAuxCodes = AuxFilter.fullAux(env, cand.text)
-- 查看 auxCodes
-- log.info(cand.text, #auxCodes)
-- for i, cl in ipairs(auxCodes) do
-- log.info(i, table.concat(cl, ',', 1, #cl))
-- end
-- 給待選項加上輔助碼提示
if env.show_aux_notice and auxCodes and #auxCodes > 0 then
local codeComment = table.concat(auxCodes, ',')
-- 處理 simplifier
if cand:get_dynamic_type() == "Shadow" then
local shadowText = cand.text
local shadowComment = cand.comment
local originalCand = cand:get_genuine()
cand_ = ShadowCandidate(originalCand, originalCand.type, shadowText,
originalCand.comment .. shadowComment .. '(' .. codeComment .. ')')
else
cand.comment = '(' .. codeComment .. ')'
end
end
-- 過濾輔助碼
if #auxStr == 0 then
-- 沒有輔助碼、不需篩選,直接返回待選項
yield(cand_)
elseif #auxStr > 0 and fullAuxCodes and (cand.type == 'user_phrase' or cand.type == 'phrase') and
AuxFilter.match(fullAuxCodes, auxStr) then
-- 匹配到辅助码的待选项,直接插入到候选框中( 获得靠前的位置 )
yield(cand_)
else
-- 待选项字词 没有 匹配到当前的辅助码,插入到列表中,最后插入到候选框里( 获得靠后的位置 )
-- table.insert(insertLater, cand)
-- 更新逻辑:没有匹配上就不出现再候选框里,提升性能
end
end
-- 把沒有匹配上的待選給添加上
-- for _, cand in ipairs(insertLater) do
-- yield(cand)
-- end
-- 更新逻辑:没有匹配上就不出现再候选框里,提升性能
end
end
function AuxFilter.fini(env)
env.notifier:disconnect()
end
return AuxFilter