Set up rime-frost basic configuration
This commit is contained in:
62
lua/autocap_filter.lua
Normal file
62
lua/autocap_filter.lua
Normal file
@@ -0,0 +1,62 @@
|
||||
--[[
|
||||
#302@abcdefg233 #305@Mirtle
|
||||
|
||||
自动大写英文词汇:
|
||||
- 部分规则不做转换
|
||||
- 输入首字母大写,候选词转换为首字母大写: Hello → Hello
|
||||
- 输入至少前 2 个字母大写,候选词转换为全部大写: HEllo → HELLO
|
||||
|
||||
大写时无法动态调整词频
|
||||
--]]
|
||||
local function autocap_filter(input, env)
|
||||
local code = env.engine.context.input -- 输入码
|
||||
local codeLen = #code
|
||||
local codeAllUCase = false
|
||||
local codeUCase = false
|
||||
-- 不转换:
|
||||
if codeLen == 1 or -- 码长为 1
|
||||
code:find("^[%l%p]") -- 输入码首位为小写字母或标点
|
||||
then -- 输入码不满足条件不判断候选项
|
||||
for cand in input:iter() do
|
||||
yield(cand)
|
||||
end
|
||||
return
|
||||
---- 输入码全大写
|
||||
-- elseif code == code:upper() then
|
||||
-- codeAllUCase = true
|
||||
-- 输入码前 2 - n 位大写
|
||||
elseif code:find("^%u%u+.*") then
|
||||
codeAllUCase = true
|
||||
-- 输入码首位大写
|
||||
elseif code:find("^%u.*") then
|
||||
codeUCase = true
|
||||
end
|
||||
|
||||
local pureCode = code:gsub("[%s%p]", "") -- 删除标点和空格的输入码
|
||||
for cand in input:iter() do
|
||||
local text = cand.text -- 候选词
|
||||
local pureText = text:gsub("[%s%p]", "") -- 删除标点和空格的候选词
|
||||
-- 不转换:
|
||||
if
|
||||
text:find("[^%w%p%s]") or -- 候选词包含非字母和数字、非标点符号、非空格的字符
|
||||
text:find("%s") or -- 候选词中包含空格
|
||||
pureText:find("^" .. code) or -- 输入码完全匹配候选词
|
||||
(cand.type ~= "completion" and -- 单词与其对应的编码不一致
|
||||
pureCode:lower() ~= pureText:lower()) -- 例如 PS - Photoshop
|
||||
then
|
||||
yield(cand)
|
||||
-- 输入码前 2~10 位大写,候选词转换为全大写
|
||||
elseif codeAllUCase then
|
||||
text = text:upper()
|
||||
yield(Candidate(cand.type, 0, codeLen, text, cand.comment))
|
||||
-- 输入码首位大写,候选词转换为首位大写
|
||||
elseif codeUCase then
|
||||
text = text:gsub("^%a", string.upper)
|
||||
yield(Candidate(cand.type, 0, codeLen, text, cand.comment))
|
||||
else
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return autocap_filter
|
||||
275
lua/aux_code.lua
Normal file
275
lua/aux_code.lua
Normal file
@@ -0,0 +1,275 @@
|
||||
-- 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; 有如下的輸出:
|
||||
-- ---- 有輔助碼 ----
|
||||
-- >>> 啊 oaoa;au
|
||||
-- >>> 啊吖 oa;au
|
||||
-- >>> 啊吖啊;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 是否为空
|
||||
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 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
|
||||
90
lua/aux_code/log.lua
Normal file
90
lua/aux_code/log.lua
Normal file
@@ -0,0 +1,90 @@
|
||||
--
|
||||
-- log.lua
|
||||
--
|
||||
-- Copyright (c) 2016 rxi
|
||||
--
|
||||
-- This library is free software; you can redistribute it and/or modify it
|
||||
-- under the terms of the MIT license. See LICENSE for details.
|
||||
--
|
||||
|
||||
local log = { _version = "0.1.0" }
|
||||
|
||||
log.usecolor = true
|
||||
log.outfile = nil
|
||||
log.level = "trace"
|
||||
|
||||
|
||||
local modes = {
|
||||
{ name = "trace", color = "\27[34m", },
|
||||
{ name = "debug", color = "\27[36m", },
|
||||
{ name = "info", color = "\27[32m", },
|
||||
{ name = "warn", color = "\27[33m", },
|
||||
{ name = "error", color = "\27[31m", },
|
||||
{ name = "fatal", color = "\27[35m", },
|
||||
}
|
||||
|
||||
|
||||
local levels = {}
|
||||
for i, v in ipairs(modes) do
|
||||
levels[v.name] = i
|
||||
end
|
||||
|
||||
|
||||
local round = function(x, increment)
|
||||
increment = increment or 1
|
||||
x = x / increment
|
||||
return (x > 0 and math.floor(x + .5) or math.ceil(x - .5)) * increment
|
||||
end
|
||||
|
||||
|
||||
local _tostring = tostring
|
||||
|
||||
local tostring = function(...)
|
||||
local t = {}
|
||||
for i = 1, select('#', ...) do
|
||||
local x = select(i, ...)
|
||||
if type(x) == "number" then
|
||||
x = round(x, .01)
|
||||
end
|
||||
t[#t + 1] = _tostring(x)
|
||||
end
|
||||
return table.concat(t, " ")
|
||||
end
|
||||
|
||||
|
||||
for i, x in ipairs(modes) do
|
||||
local nameupper = x.name:upper()
|
||||
log[x.name] = function(...)
|
||||
|
||||
-- Return early if we're below the log level
|
||||
if i < levels[log.level] then
|
||||
return
|
||||
end
|
||||
|
||||
local msg = tostring(...)
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
local lineinfo = info.short_src .. ":" .. info.currentline
|
||||
|
||||
-- Output to console
|
||||
print(string.format("%s[%-6s%s]%s %s: %s",
|
||||
log.usecolor and x.color or "",
|
||||
nameupper,
|
||||
os.date("%H:%M:%S"),
|
||||
log.usecolor and "\27[0m" or "",
|
||||
lineinfo,
|
||||
msg))
|
||||
|
||||
-- Output to log file
|
||||
if log.outfile then
|
||||
local fp = io.open(log.outfile, "a")
|
||||
local str = string.format("[%-6s%s] %s: %s\n",
|
||||
nameupper, os.date(), lineinfo, msg)
|
||||
fp:write(str)
|
||||
fp:close()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return log
|
||||
40502
lua/aux_code/moqi_aux_code.txt
Normal file
40502
lua/aux_code/moqi_aux_code.txt
Normal file
File diff suppressed because it is too large
Load Diff
209
lua/calc_translator.lua
Normal file
209
lua/calc_translator.lua
Normal file
@@ -0,0 +1,209 @@
|
||||
-- 计算器插件
|
||||
-- author: https://github.com/ChaosAlphard
|
||||
local calc = {}
|
||||
|
||||
function calc.init( env )
|
||||
local config = env.engine.schema.config
|
||||
env.prefix = config:get_string( 'calculator/prefix' ) or 'cC'
|
||||
env.show_prefix = config:get_bool( 'calculator/show_prefix' ) -- set to true to show prefix in preedit area
|
||||
-- env.decimalPlaces = config:get_string('calculator/decimalPlaces') or '4'
|
||||
end
|
||||
|
||||
local function startsWith( str, start ) return string.sub( str, 1, string.len( start ) ) == start end
|
||||
|
||||
local function truncateFromStart( str, truncateStr ) return string.sub( str, string.len( truncateStr ) + 1 ) end
|
||||
|
||||
local function yield_calc_cand( seg, cand_text, cand_comment, cand_preedit, show_prefix )
|
||||
local cand = Candidate( 'calc', seg.start, seg._end, cand_text, cand_comment )
|
||||
cand.quality = 99999
|
||||
if not show_prefix then cand.preedit = cand_preedit end
|
||||
yield( cand )
|
||||
end
|
||||
|
||||
-- 函数表
|
||||
local calcPlugin = {
|
||||
-- e, exp(1) = e^1 = e
|
||||
e = math.exp( 1 ),
|
||||
-- π
|
||||
pi = math.pi,
|
||||
}
|
||||
|
||||
-- random([m [,n ]]) 返回m-n之间的随机数, n为空则返回1-m之间, 都为空则返回0-1之间的小数
|
||||
local function random( ... ) return math.random( ... ) end
|
||||
-- 注册到函数表中
|
||||
calcPlugin['rdm'] = random
|
||||
calcPlugin['random'] = random
|
||||
|
||||
-- 正弦
|
||||
local function sin( x ) return math.sin( x ) end
|
||||
calcPlugin['sin'] = sin
|
||||
|
||||
-- 双曲正弦
|
||||
local function sinh( x ) return math.sinh( x ) end
|
||||
calcPlugin['sinh'] = sinh
|
||||
|
||||
-- 反正弦
|
||||
local function asin( x ) return math.asin( x ) end
|
||||
calcPlugin['asin'] = asin
|
||||
|
||||
-- 余弦
|
||||
local function cos( x ) return math.cos( x ) end
|
||||
calcPlugin['cos'] = cos
|
||||
|
||||
-- 双曲余弦
|
||||
local function cosh( x ) return math.cosh( x ) end
|
||||
calcPlugin['cosh'] = cosh
|
||||
|
||||
-- 反余弦
|
||||
local function acos( x ) return math.acos( x ) end
|
||||
calcPlugin['acos'] = acos
|
||||
|
||||
-- 正切
|
||||
local function tan( x ) return math.tan( x ) end
|
||||
calcPlugin['tan'] = tan
|
||||
|
||||
-- 双曲正切
|
||||
local function tanh( x ) return math.tanh( x ) end
|
||||
calcPlugin['tanh'] = tanh
|
||||
|
||||
-- 反正切
|
||||
-- 返回以弧度为单位的点相对于x轴的逆时针角度。x是点的横纵坐标比值
|
||||
-- 返回范围从−π到π (以弧度为单位),其中负角度表示向下旋转,正角度表示向上旋转
|
||||
local function atan( x ) return math.atan( x ) end
|
||||
calcPlugin['atan'] = atan
|
||||
|
||||
-- 反正切
|
||||
-- atan( y/x ) = atan2(y, x)
|
||||
-- 返回以弧度为单位的点相对于x轴的逆时针角度。y是点的纵坐标,x是点的横坐标
|
||||
-- 返回范围从−π到π (以弧度为单位),其中负角度表示向下旋转,正角度表示向上旋转
|
||||
-- 与 math.atan(y/x) 函数相比,具有更好的数学定义,因为它能够正确处理边界情况(例如x=0)
|
||||
local function atan2( y, x ) return math.atan2( y, x ) end
|
||||
calcPlugin['atan2'] = atan2
|
||||
|
||||
-- 将角度从弧度转换为度 e.g. deg(π) = 180
|
||||
local function deg( x ) return math.deg( x ) end
|
||||
calcPlugin['deg'] = deg
|
||||
|
||||
-- 将角度从度转换为弧度 e.g. rad(180) = π
|
||||
local function rad( x ) return math.rad( x ) end
|
||||
calcPlugin['rad'] = rad
|
||||
|
||||
-- 返回两个值, 无法参与运算后续, 只能单独使用
|
||||
-- 返回m,e 使得x = m * 2^e
|
||||
local function frexp( x )
|
||||
local m, e = math.frexp( x )
|
||||
return m .. ' * 2^' .. e
|
||||
end
|
||||
calcPlugin['frexp'] = frexp
|
||||
|
||||
-- 返回 x * 2^y
|
||||
local function ldexp( x, y ) return math.ldexp( x, y ) end
|
||||
calcPlugin['ldexp'] = ldexp
|
||||
|
||||
-- 返回 e^x
|
||||
local function exp( x ) return math.exp( x ) end
|
||||
calcPlugin['exp'] = exp
|
||||
|
||||
-- 返回x的平方根 e.g. sqrt(x) = x^0.5
|
||||
local function sqrt( x ) return math.sqrt( x ) end
|
||||
calcPlugin['sqrt'] = sqrt
|
||||
|
||||
-- y为底x的对数, 使用换底公式实现
|
||||
local function log( y, x )
|
||||
-- 不能为负数或0
|
||||
if x <= 0 or y <= 0 then return nil end
|
||||
|
||||
return math.log( x ) / math.log( y )
|
||||
end
|
||||
calcPlugin['log'] = log
|
||||
|
||||
-- e为底x的对数
|
||||
local function loge( x )
|
||||
-- 不能为负数或0
|
||||
if x <= 0 then return nil end
|
||||
|
||||
return math.log( x )
|
||||
end
|
||||
calcPlugin['loge'] = loge
|
||||
|
||||
-- 10为底x的对数
|
||||
local function log10( x )
|
||||
-- 不能为负数或0
|
||||
if x <= 0 then return nil end
|
||||
|
||||
return math.log10( x )
|
||||
end
|
||||
calcPlugin['log10'] = log10
|
||||
|
||||
-- 平均值
|
||||
local function avg( ... )
|
||||
local data = { ... }
|
||||
local n = select( '#', ... )
|
||||
-- 样本数量不能为0
|
||||
if n == 0 then return nil end
|
||||
|
||||
-- 计算总和
|
||||
local sum = 0
|
||||
for _, value in ipairs( data ) do sum = sum + value end
|
||||
|
||||
return sum / n
|
||||
end
|
||||
calcPlugin['avg'] = avg
|
||||
|
||||
-- 方差
|
||||
local function variance( ... )
|
||||
local data = { ... }
|
||||
local n = select( '#', ... )
|
||||
-- 样本数量不能为0
|
||||
if n == 0 then return nil end
|
||||
|
||||
-- 计算均值
|
||||
local sum = 0
|
||||
for _, value in ipairs( data ) do sum = sum + value end
|
||||
local mean = sum / n
|
||||
|
||||
-- 计算方差
|
||||
local sum_squared_diff = 0
|
||||
for _, value in ipairs( data ) do sum_squared_diff = sum_squared_diff + (value - mean) ^ 2 end
|
||||
|
||||
return sum_squared_diff / n
|
||||
end
|
||||
calcPlugin['var'] = variance
|
||||
|
||||
-- 阶乘
|
||||
local function factorial( x )
|
||||
-- 不能为负数
|
||||
if x < 0 then return nil end
|
||||
if x == 0 or x == 1 then return 1 end
|
||||
|
||||
local result = 1
|
||||
for i = 1, x do result = result * i end
|
||||
|
||||
return result
|
||||
end
|
||||
calcPlugin['fact'] = factorial
|
||||
|
||||
-- 实现阶乘计算(!)
|
||||
local function replaceToFactorial( str )
|
||||
-- 替换[0-9]!字符为fact([0-9])以实现阶乘
|
||||
return str:gsub( '([0-9]+)!', 'fact(%1)' )
|
||||
end
|
||||
|
||||
-- 简单计算器
|
||||
function calc.func( input, seg, env )
|
||||
if not seg:has_tag( 'calculator' ) or input == '' then return end
|
||||
-- 提取算式
|
||||
local express = truncateFromStart( input, env.prefix )
|
||||
if express == '' then return end -- 防止用户写错了正则表达式造成错误
|
||||
local code = replaceToFactorial( express )
|
||||
local success, result = pcall( load( 'return ' .. code, 'calculate', 't', calcPlugin ) )
|
||||
if success and result and (type( result ) == 'string' or type( result ) == 'number') and #tostring( result ) > 0 then
|
||||
yield_calc_cand( seg, result, '', express, env.show_prefix )
|
||||
yield_calc_cand( seg, express .. '=' .. result, '', express, env.show_prefix )
|
||||
else
|
||||
yield_calc_cand( seg, express, '解析失败', express, env.show_prefix )
|
||||
yield_calc_cand( seg, code, '入参', express, env.show_prefix )
|
||||
end
|
||||
end
|
||||
|
||||
return calc
|
||||
251
lua/calculator.lua
Normal file
251
lua/calculator.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
-- author: https://github.com/ChaosAlphard
|
||||
-- 说明 https://github.com/gaboolic/rime-shuangpin-fuzhuma/pull/41
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
local config = env.engine.schema.config
|
||||
env.name_space = env.name_space:gsub('^*', '')
|
||||
M.prefix = config:get_string(env.name_space .. '/trigger') or 'V'
|
||||
end
|
||||
|
||||
local function startsWith(str, start)
|
||||
return string.sub(str, 1, string.len(start)) == start
|
||||
end
|
||||
|
||||
local function truncateFromStart(str, truncateStr)
|
||||
return string.sub(str, string.len(truncateStr) + 1)
|
||||
end
|
||||
|
||||
-- 函数表
|
||||
local calcPlugin = {
|
||||
-- e, exp(1) = e^1 = e
|
||||
e = math.exp(1),
|
||||
-- π
|
||||
pi = math.pi
|
||||
}
|
||||
|
||||
-- random([m [,n ]]) 返回m-n之间的随机数, n为空则返回1-m之间, 都为空则返回0-1之间的小数
|
||||
local function random(...)
|
||||
return math.random(...)
|
||||
end
|
||||
-- 注册到函数表中
|
||||
calcPlugin["rdm"] = random
|
||||
|
||||
-- 正弦
|
||||
local function sin(x)
|
||||
return math.sin(x)
|
||||
end
|
||||
calcPlugin["sin"] = sin
|
||||
|
||||
-- 双曲正弦
|
||||
local function sinh(x)
|
||||
return math.sinh(x)
|
||||
end
|
||||
calcPlugin["sinh"] = sinh
|
||||
|
||||
-- 反正弦
|
||||
local function asin(x)
|
||||
return math.asin(x)
|
||||
end
|
||||
calcPlugin["asin"] = asin
|
||||
|
||||
-- 余弦
|
||||
local function cos(x)
|
||||
return math.cos(x)
|
||||
end
|
||||
calcPlugin["cos"] = cos
|
||||
|
||||
-- 双曲余弦
|
||||
local function cosh(x)
|
||||
return math.cosh(x)
|
||||
end
|
||||
calcPlugin["cosh"] = cosh
|
||||
|
||||
-- 反余弦
|
||||
local function acos(x)
|
||||
return math.acos(x)
|
||||
end
|
||||
calcPlugin["acos"] = acos
|
||||
|
||||
-- 正切
|
||||
local function tan(x)
|
||||
return math.tan(x)
|
||||
end
|
||||
calcPlugin["tan"] = tan
|
||||
|
||||
-- 双曲正切
|
||||
local function tanh(x)
|
||||
return math.tanh(x)
|
||||
end
|
||||
calcPlugin["tanh"] = tanh
|
||||
|
||||
-- 反正切
|
||||
local function atan(x)
|
||||
return math.atan(x)
|
||||
end
|
||||
calcPlugin["atan"] = atan
|
||||
|
||||
-- 返回以弧度为单位的点(x,y)相对于x轴的逆时针角度。y是点的纵坐标,x是点的横坐标
|
||||
-- 返回范围从−π到π (以弧度为单位),其中负角度表示向下旋转,正角度表示向上旋转
|
||||
-- 它与传统的 math.atan(y/x) 函数相比,具有更好的数学定义,因为它能够正确处理边界情况(例如x=0)
|
||||
local function atan2(y, x)
|
||||
return math.atan2(y, x)
|
||||
end
|
||||
calcPlugin["atan2"] = atan2
|
||||
|
||||
-- 将角度从弧度转换为度 e.g. deg(π) = 180
|
||||
local function deg(x)
|
||||
return math.deg(x)
|
||||
end
|
||||
calcPlugin["deg"] = deg
|
||||
|
||||
-- 将角度从度转换为弧度 e.g. rad(180) = π
|
||||
local function rad(x)
|
||||
return math.rad(x)
|
||||
end
|
||||
calcPlugin["rad"] = rad
|
||||
|
||||
-- 返回两个值, 无法参与运算后续
|
||||
-- 返回m,e 使得x = m*2^e
|
||||
-- local function frexp(x)
|
||||
-- return math.frexp(x)
|
||||
-- end
|
||||
-- calcPlugin["frexp"] = frexp
|
||||
|
||||
-- 返回 x*2^y
|
||||
local function ldexp(x, y)
|
||||
return math.ldexp(x, y)
|
||||
end
|
||||
calcPlugin["ldexp"] = ldexp
|
||||
|
||||
-- 返回 e^x
|
||||
local function exp(x)
|
||||
return math.exp(x)
|
||||
end
|
||||
calcPlugin["exp"] = exp
|
||||
|
||||
-- 返回x的平方根 e.g. sqrt(x) = x^0.5
|
||||
local function sqrt(x)
|
||||
return math.sqrt(x)
|
||||
end
|
||||
calcPlugin["sqrt"] = sqrt
|
||||
|
||||
-- x为底的对数, log(10, 100) = log(100) / log(10) = 2
|
||||
local function log(x, y)
|
||||
-- 不能为负数或0
|
||||
if x <= 0 or y <= 0 then return nil end
|
||||
|
||||
return math.log(y) / math.log(x)
|
||||
end
|
||||
calcPlugin["log"] = log
|
||||
|
||||
-- 自然数e为底的对数
|
||||
local function loge(x)
|
||||
-- 不能为负数或0
|
||||
if x <= 0 then return nil end
|
||||
|
||||
return math.log(x)
|
||||
end
|
||||
calcPlugin["loge"] = loge
|
||||
|
||||
-- 10为底的对数
|
||||
local function log10(x)
|
||||
-- 不能为负数或0
|
||||
if x <= 0 then return nil end
|
||||
|
||||
return math.log10(x)
|
||||
end
|
||||
calcPlugin["log10"] = log10
|
||||
|
||||
-- 平均值
|
||||
local function avg(...)
|
||||
local data = {...}
|
||||
local n = select("#", ...)
|
||||
-- 样本数量不能为0
|
||||
if n == 0 then return nil end
|
||||
|
||||
-- 计算总和
|
||||
local sum = 0
|
||||
for _, value in ipairs(data) do
|
||||
sum = sum + value
|
||||
end
|
||||
|
||||
return sum / n
|
||||
end
|
||||
calcPlugin["avg"] = avg
|
||||
|
||||
-- 方差
|
||||
local function variance(...)
|
||||
local data = {...}
|
||||
local n = select("#", ...)
|
||||
-- 样本数量不能为0
|
||||
if n == 0 then return nil end
|
||||
|
||||
-- 计算均值
|
||||
local sum = 0
|
||||
for _, value in ipairs(data) do
|
||||
sum = sum + value
|
||||
end
|
||||
local mean = sum / n
|
||||
|
||||
-- 计算方差
|
||||
local sum_squared_diff = 0
|
||||
for _, value in ipairs(data) do
|
||||
sum_squared_diff = sum_squared_diff + (value - mean)^2
|
||||
end
|
||||
|
||||
return sum_squared_diff / n
|
||||
end
|
||||
calcPlugin["var"] = variance
|
||||
|
||||
-- 阶乘
|
||||
local function factorial(x)
|
||||
-- 不能为负数
|
||||
if x < 0 then return nil end
|
||||
if x == 0 or x == 1 then return 1 end
|
||||
|
||||
local result = 1
|
||||
for i = 1, x do
|
||||
result = result * i
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
calcPlugin["fact"] = factorial
|
||||
|
||||
-- 实现阶乘计算(!)
|
||||
local function replaceToFactorial(str)
|
||||
-- 替换[0-9]!字符为fact([0-9])以实现阶乘
|
||||
return str:gsub("([0-9]+)!", "fact(%1)")
|
||||
end
|
||||
|
||||
-- 简单计算器
|
||||
function M.func(input, seg, env)
|
||||
if not startsWith(input, M.prefix) then return end
|
||||
-- 提取算式
|
||||
local express = truncateFromStart(input, M.prefix)
|
||||
-- 算式长度 < 2 直接终止(没有计算意义)
|
||||
if (string.len(express) < 2) then return end
|
||||
-- pcall()的原因需要控制一下 . 符号的位置
|
||||
-- 现在不需要了
|
||||
-- if (string.match(express, "[^0-9]%.")) then
|
||||
-- yield(Candidate(input, seg.start, seg._end, express, "小数点不能在非数字字符后面"))
|
||||
-- return
|
||||
-- end
|
||||
local code = replaceToFactorial(express)
|
||||
|
||||
local success, result = pcall(load("return " .. code, "calculate", "t", calcPlugin))
|
||||
if success then
|
||||
yield(Candidate(input, seg.start, seg._end, result, ""))
|
||||
yield(Candidate(input, seg.start, seg._end, express .. "=" .. result, ""))
|
||||
else
|
||||
yield(Candidate(input, seg.start, seg._end, express, "解析失败"))
|
||||
yield(Candidate(input, seg.start, seg._end, code, "入参"))
|
||||
-- TODO: 错误信息记录到日志中
|
||||
-- print("express: " .. express)
|
||||
-- print("code: " .. code)
|
||||
-- print("result: " .. result)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
31
lua/cn_en_spacer.lua
Normal file
31
lua/cn_en_spacer.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
-- 中英混输词条自动空格
|
||||
-- 在 engine/filters 增加 - lua_filter@cn_en_spacer
|
||||
--
|
||||
-- 为中英混输词条(cn_en.dict.yaml)自动空格
|
||||
-- 示例:`VIP中P` → `VIP 中 P`
|
||||
--
|
||||
-- ChatGPT 写的
|
||||
|
||||
local function add_spaces(s)
|
||||
-- 在中文字符后和英文字符前插入空格
|
||||
s = s:gsub("([\228-\233][\128-\191]-)([%w%p])", "%1 %2")
|
||||
-- 在英文字符后和中文字符前插入空格
|
||||
s = s:gsub("([%w%p])([\228-\233][\128-\191]-)", "%1 %2")
|
||||
return s
|
||||
end
|
||||
|
||||
-- 是否同时包含中文和英文数字
|
||||
local function is_mixed_cn_en_num(s)
|
||||
return s:find("([\228-\233][\128-\191]-)") and s:find("[%a%d]")
|
||||
end
|
||||
|
||||
local function cn_en_spacer(input, env)
|
||||
for cand in input:iter() do
|
||||
if is_mixed_cn_en_num(cand.text) then
|
||||
cand = cand:to_shadow_candidate(cand.type, add_spaces(cand.text), cand.comment)
|
||||
end
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return cn_en_spacer
|
||||
11
lua/cold_word_drop/debug_checker.lua
Normal file
11
lua/cold_word_drop/debug_checker.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
-- 临时用的
|
||||
function debug_checker(input, env)
|
||||
for cand in input:iter() do
|
||||
yield(ShadowCandidate(
|
||||
cand,
|
||||
cand.type,
|
||||
cand.text,
|
||||
env.engine.context.input .. " - " .. env.engine.context:get_preedit().text .. " - " .. cand.preedit
|
||||
))
|
||||
end
|
||||
end
|
||||
92
lua/cold_word_drop/debugtool.lua
Normal file
92
lua/cold_word_drop/debugtool.lua
Normal file
@@ -0,0 +1,92 @@
|
||||
#! /usr/bin/env lua
|
||||
--
|
||||
-- debugtool.lua
|
||||
-- Copyright (C) 2021 Shewer Lu <shewer@gmail.com>
|
||||
--
|
||||
-- Distributed under terms of the MIT license.
|
||||
--
|
||||
-- puts(tag,...)
|
||||
-- DEBUG --> log.error
|
||||
-- WARN --> log.warning
|
||||
-- INFO --> log.info
|
||||
-- CONSOLE --> print
|
||||
--
|
||||
-- ex:
|
||||
-- test.lua
|
||||
--
|
||||
-- local puts = require 'tools/debugtool'
|
||||
-- --set tag D103 C102
|
||||
-- local D103= DEBUG .. "103"
|
||||
-- local C102= CONSOLE .. "102"
|
||||
-- local C103= nil
|
||||
--
|
||||
--
|
||||
-- puts(ERROR,__FILE__(),__LINE__(),__FUNC__(), 1, 2 , 3 )
|
||||
-- --> log.error( "error" .. tran_msg(...))
|
||||
--
|
||||
-- puts(DEBUG,__FILE__(),__LINE__(),__FUNC__(), 1, 2 , 3 )
|
||||
-- --> log.error( DEBUG .. tran_msg(...))
|
||||
--
|
||||
-- puts(D103,__FILE__(),__LINE__(),__FUNC__(), 1 2 3)
|
||||
-- --> log.error("trace103" .. tran_msg(...)
|
||||
--
|
||||
-- puts(C102,__FILE__(),__LINE__(),__FUNC__(), 1 2 3)
|
||||
-- --> print("console103" .. tran_msg(...)
|
||||
--
|
||||
-- puts(C103,__FILE__(),__LINE__(),__FUNC__(), 1 2 3)
|
||||
-- --> pass
|
||||
--
|
||||
--
|
||||
--
|
||||
-- puts(DEBUG,__FILE__(),__LINE__(),__FUNC__() , ...)
|
||||
-- puts(INFO,__FILE__(),__LINE__(),__FUNC__() , ...)
|
||||
--
|
||||
-- global variable
|
||||
function __FILE__(n)
|
||||
n = n or 2
|
||||
return debug.getinfo(n, 'S').source
|
||||
end
|
||||
|
||||
function __LINE__(n)
|
||||
n = n or 2
|
||||
return debug.getinfo(n, 'l').currentline
|
||||
end
|
||||
|
||||
function __FUNC__(n)
|
||||
n = n or 2
|
||||
return debug.getinfo(n, 'n').name
|
||||
end
|
||||
|
||||
INFO = "log"
|
||||
WARN = "warn"
|
||||
ERROR = "error"
|
||||
DEBUG = "trace"
|
||||
CONSOLE = "console"
|
||||
|
||||
|
||||
|
||||
|
||||
local function tran_msg(...)
|
||||
local msg = "\t"
|
||||
for i, k in next, { ... } do msg = msg .. ": " .. tostring(k) end
|
||||
return msg
|
||||
end
|
||||
local function puts(tag, ...)
|
||||
if type(tag) ~= "string" then return end
|
||||
|
||||
if INFO and tag:match("^" .. INFO) then
|
||||
(log and log.info or print)(tag .. tran_msg(...))
|
||||
elseif WARN and tag:match("^" .. WARN) then
|
||||
(log and log.warning or print)(tag .. tran_msg(...))
|
||||
elseif ERROR and tag:match("^" .. ERROR) then
|
||||
(log and log.error or print)(tag .. tran_msg(...))
|
||||
elseif DEBUG and tag:match("^" .. DEBUG) then
|
||||
(log and log.error or print)(tag .. tran_msg(...))
|
||||
elseif CONSOLE and tag:match("^" .. CONSOLE) then
|
||||
(print)(tag .. tran_msg(...))
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return puts
|
||||
4
lua/cold_word_drop/drop_words.lua
Normal file
4
lua/cold_word_drop/drop_words.lua
Normal file
@@ -0,0 +1,4 @@
|
||||
local drop_words =
|
||||
{ "示~例~",
|
||||
}
|
||||
return drop_words
|
||||
54
lua/cold_word_drop/filter.lua
Normal file
54
lua/cold_word_drop/filter.lua
Normal file
@@ -0,0 +1,54 @@
|
||||
local drop_list = require("cold_word_drop.drop_words")
|
||||
local hide_list = require("cold_word_drop.hide_words")
|
||||
local turndown_freq_list = require("cold_word_drop.turndown_freq_words")
|
||||
|
||||
local function filter(input, env)
|
||||
local idx = 3 -- 降频的词条放到第三个后面, 即第四位, 可在 yaml 里配置
|
||||
local i = 1
|
||||
local cands = {}
|
||||
local context = env.engine.context
|
||||
local preedit_code = context.input
|
||||
|
||||
for cand in input:iter() do
|
||||
local cpreedit_code = string.gsub(cand.preedit, ' ', '')
|
||||
if (i <= idx) then
|
||||
local tfl = turndown_freq_list[cand.text] or nil
|
||||
-- 前三个 候选项排除 要调整词频的词条, 要删的(实际假性删词, 彻底隐藏罢了) 和要隐藏的词条
|
||||
if not
|
||||
((tfl and table.find_index(tfl, cpreedit_code)) or
|
||||
table.find_index(drop_list, cand.text) or
|
||||
(hide_list[cand.text] and table.find_index(hide_list[cand.text], cpreedit_code))
|
||||
)
|
||||
then
|
||||
i = i + 1
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
yield(cand)
|
||||
else
|
||||
table.insert(cands, cand)
|
||||
end
|
||||
else
|
||||
table.insert(cands, cand)
|
||||
end
|
||||
if (#cands > 50) then
|
||||
break
|
||||
end
|
||||
end
|
||||
for _, cand in ipairs(cands) do
|
||||
local cpreedit_code = string.gsub(cand.preedit, ' ', '')
|
||||
if not
|
||||
-- 要删的 和要隐藏的词条不显示
|
||||
(
|
||||
table.find_index(drop_list, cand.text) or
|
||||
(hide_list[cand.text] and table.find_index(hide_list[cand.text], cpreedit_code))
|
||||
)
|
||||
then
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
for cand in input:iter() do
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return filter
|
||||
4
lua/cold_word_drop/hide_words.lua
Normal file
4
lua/cold_word_drop/hide_words.lua
Normal file
@@ -0,0 +1,4 @@
|
||||
local hide_words =
|
||||
{ ["示~例~"] = { "shil", "shili", },
|
||||
}
|
||||
return hide_words
|
||||
163
lua/cold_word_drop/metatable.lua
Normal file
163
lua/cold_word_drop/metatable.lua
Normal file
@@ -0,0 +1,163 @@
|
||||
-- create metatable
|
||||
orgtype = type
|
||||
|
||||
function type(obj)
|
||||
local _type = orgtype(obj)
|
||||
if "table" == _type and obj._cname then
|
||||
return obj._cname
|
||||
end
|
||||
return _type
|
||||
end
|
||||
|
||||
function metatable(...)
|
||||
if ... and type(...) == "table" then
|
||||
return setmetatable(..., { __index = table })
|
||||
else
|
||||
return setmetatable({ ... }, { __index = table })
|
||||
end
|
||||
end
|
||||
|
||||
-- chech metatble
|
||||
function metatable_chk(tab)
|
||||
if "table" == type(tab)
|
||||
then
|
||||
return (tab.each and tab) or metatable(tab)
|
||||
else
|
||||
return tab
|
||||
end
|
||||
end
|
||||
|
||||
table.eachi = function(tab, func)
|
||||
for i = 1, #tab do
|
||||
func(tab[i], i)
|
||||
end
|
||||
return tab
|
||||
end
|
||||
table.eacha = function(tab, func)
|
||||
for i, v in ipairs(tab) do
|
||||
func(v, i)
|
||||
end
|
||||
return tab
|
||||
end
|
||||
table.each = function(tab, func)
|
||||
for k, v in pairs(tab) do
|
||||
func(v, k)
|
||||
end
|
||||
return tab
|
||||
end
|
||||
table.find_index = function(tab, elm, ...)
|
||||
local _, i = table.find(tab, elm, ...)
|
||||
return i
|
||||
end
|
||||
table.find = function(tab, elm, func)
|
||||
for i, v in ipairs(tab) do
|
||||
if elm == v then
|
||||
return v, i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.find_with_func = function(tab, elm, ...)
|
||||
local i, v = table.find(tab, elm)
|
||||
end
|
||||
table.delete = function(tab, elm, ...)
|
||||
local index = table.find_index(tab, elm)
|
||||
return index and table.remove(tab, index)
|
||||
end
|
||||
|
||||
table.find_all = function(tab, elm, ...)
|
||||
local tmptab = setmetatable({}, { __index = table })
|
||||
local _func = (type(elm) == "function" and elm) or function(v, k, ...) return v == elm end
|
||||
for k, v in pairs(tab) do
|
||||
if _func(v, k, ...) then
|
||||
tmptab:insert(v)
|
||||
end
|
||||
end
|
||||
return tmptab
|
||||
end
|
||||
table.select = table.find_all
|
||||
|
||||
table.reduce = function(tab, func, arg)
|
||||
local new, old = arg, arg
|
||||
for i, v in ipairs(tab) do
|
||||
new, old = func(v, new)
|
||||
end
|
||||
return new, arg
|
||||
end
|
||||
|
||||
table.map = function(tab, func)
|
||||
local newtab = setmetatable({}, { __index = table })
|
||||
func = func or function(v, i) return v, i end
|
||||
for i, v in ipairs(tab) do
|
||||
newtab[i] = func(v, i)
|
||||
end
|
||||
return newtab
|
||||
end
|
||||
table.map_hash = function(tab, func) -- table to list of array { key, v}
|
||||
local newtab = setmetatable({}, { __index = table })
|
||||
func = func or function(k, v) return { k, v } end
|
||||
for k, v in pairs(tab) do
|
||||
newtab:insert(func(k, v))
|
||||
end
|
||||
return newtab
|
||||
end
|
||||
function table:push(elm)
|
||||
self:insert(elm)
|
||||
end
|
||||
|
||||
table.append = table.push
|
||||
function table:pop()
|
||||
return self:remove(#self)
|
||||
end
|
||||
|
||||
function table:shift()
|
||||
self:remove(1)
|
||||
end
|
||||
|
||||
function table:unshift(elm)
|
||||
self:insert(1, elm)
|
||||
end
|
||||
|
||||
function table.len(t)
|
||||
local leng = 0
|
||||
for k, v in pairs(t) do
|
||||
leng = leng + 1
|
||||
end
|
||||
return leng;
|
||||
end
|
||||
|
||||
-- table to string 序列化
|
||||
function table.serialize(obj)
|
||||
local serialize_str = ""
|
||||
local t = type(obj)
|
||||
if t == "number" then
|
||||
serialize_str = serialize_str .. obj
|
||||
elseif t == "boolean" then
|
||||
serialize_str = serialize_str .. tostring(obj)
|
||||
elseif t == "string" then
|
||||
serialize_str = serialize_str .. string.format("%q", obj)
|
||||
elseif t == "table" then
|
||||
serialize_str = serialize_str .. "{ "
|
||||
local record_sep = #obj < 4 and ", " or ",\n"
|
||||
local record_prefix = #obj < 4 and "" or "\t"
|
||||
for k, v in pairs(obj) do
|
||||
if type(k) == "number" then
|
||||
serialize_str = serialize_str .. record_prefix .. '"' .. v .. '"' .. record_sep
|
||||
else
|
||||
serialize_str = serialize_str .. "\t[" .. table.serialize(k) .. "] = " .. table.serialize(v) .. ",\n"
|
||||
end
|
||||
end
|
||||
-- local metatable = getmetatable(obj)
|
||||
-- if metatable ~= nil and type(metatable.__index) == "table" then
|
||||
-- for k, v in pairs(metatable.__index) do
|
||||
-- serialize_str = serialize_str .. "[" .. table.serialize(k) .. "]=" .. table.serialize(v) .. ",\n"
|
||||
-- end
|
||||
-- end
|
||||
serialize_str = serialize_str .. "}"
|
||||
elseif t == "nil" then
|
||||
return nil
|
||||
else
|
||||
error("can not serialize a " .. t .. " type.")
|
||||
end
|
||||
return serialize_str
|
||||
end
|
||||
151
lua/cold_word_drop/processor.lua
Normal file
151
lua/cold_word_drop/processor.lua
Normal file
@@ -0,0 +1,151 @@
|
||||
require('cold_word_drop.string')
|
||||
require("cold_word_drop.metatable")
|
||||
-- local puts = require("tools/debugtool")
|
||||
local drop_list = require("cold_word_drop.drop_words")
|
||||
local hide_list = require("cold_word_drop.hide_words")
|
||||
local turndown_freq_list = require("cold_word_drop.turndown_freq_words")
|
||||
local tbls = {
|
||||
['drop_list'] = drop_list,
|
||||
['hide_list'] = hide_list,
|
||||
['turndown_freq_list'] = turndown_freq_list
|
||||
}
|
||||
-- local cold_word_drop = {}
|
||||
|
||||
|
||||
local function get_record_filername(record_type)
|
||||
local user_distribute_name = rime_api:get_distribution_name()
|
||||
if user_distribute_name == '小狼毫' then
|
||||
return string.format("%s\\Rime\\lua\\cold_word_drop\\%s_words.lua", os.getenv("APPDATA"), record_type)
|
||||
end
|
||||
|
||||
local system = io.popen("uname -s"):read("*l")
|
||||
local filename = nil
|
||||
-- body
|
||||
if system == "Darwin" then
|
||||
filename = string.format("%s/Library/Rime/lua/cold_word_drop/%s_words.lua", os.getenv('HOME'), record_type)
|
||||
elseif system == "Linux" then
|
||||
filename = string.format("%s/%s/rime/lua/cold_word_drop/%s_words.lua",
|
||||
os.getenv('HOME'),
|
||||
(string.find(os.getenv('GTK_IM_MODULE'), 'fcitx') and '.local/share/fcitx5' or '.config/ibus'),
|
||||
record_type)
|
||||
end
|
||||
return filename
|
||||
end
|
||||
|
||||
local function write_word_to_file(record_type)
|
||||
-- local filename = string.format("%s/Library/Rime/lua/cold_word_drop/%s_words.lua", os.getenv('HOME'), record_type)
|
||||
local filename = get_record_filername(record_type)
|
||||
local record_header = string.format("local %s_words =\n", record_type)
|
||||
local record_tailer = string.format("\nreturn %s_words", record_type)
|
||||
local fd = assert(io.open(filename, "w")) --打开
|
||||
fd:setvbuf("line")
|
||||
fd:write(record_header) --写入文件头部
|
||||
-- df:flush() --刷新
|
||||
local x = string.format("%s_list", record_type)
|
||||
local record = table.serialize(tbls[x]) -- lua 的 table 对象 序列化为字符串
|
||||
fd:write(record) --写入 序列化的字符串
|
||||
fd:write(record_tailer) --写入文件尾部, 结束记录
|
||||
fd:close() --关闭
|
||||
end
|
||||
|
||||
local function check_encode_matched(cand_code, word, input_code_tbl, reversedb)
|
||||
if #cand_code < 1 and utf8.len(word) > 1 then -- 二字词以上的词条反查, 需要逐个字去反查
|
||||
local word_cand_code = string.split(word, "")
|
||||
for i, v in ipairs(word_cand_code) do
|
||||
-- 如有 `[` 引导的辅助码情况, 去掉引导符及之后的所有形码字符
|
||||
local char_code = string.gsub(reversedb:lookup(v), '%[%l%l', '')
|
||||
local _char_preedit_code = input_code_tbl[i] or " "
|
||||
-- 如有 `[` 引导的辅助码情况, 同上, 去掉之
|
||||
local char_preedit_code = string.gsub(_char_preedit_code, '%[%l+', '')
|
||||
if not string.match(char_code, char_preedit_code) then
|
||||
-- 输入编码串和词条反查结果不匹配(考虑到多音字, 开启了模糊音, 纠错音), 返回false, 表示隐藏这个词条
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 输入编码串和词条反查结果匹配, 返回true, 表示对这个词条降频
|
||||
return true
|
||||
end
|
||||
|
||||
local function append_word_to_droplist(ctx, action_type, reversedb)
|
||||
local word = ctx.word
|
||||
local input_code = ctx.code
|
||||
if action_type == 'drop' then
|
||||
table.insert(drop_list, word) -- 高亮选中的词条插入到 drop_list
|
||||
return true
|
||||
end
|
||||
local input_code_tbl = string.split(input_code, " ")
|
||||
local cand_code = reversedb:lookup(word) or "" -- 反查候选项文字编码
|
||||
-- 二字词 的匹配检查, 匹配返回true, 不匹配返回false
|
||||
local match_result = check_encode_matched(cand_code, word, input_code_tbl, reversedb)
|
||||
local ccand_code = string.gsub(cand_code, '%[%l%l', '')
|
||||
-- 如有 `[` 引导的辅助码情况, 去掉引导符及之后的所有形码字符
|
||||
local input_str = string.gsub(input_code, '%[%l+', '')
|
||||
local input_code_str = table.concat(input_code_tbl, '')
|
||||
-- 单字和二字词 的匹配检查, 如果匹配, 降频
|
||||
if string.match(ccand_code, input_str) or match_result then
|
||||
if turndown_freq_list[word] then
|
||||
table.insert(turndown_freq_list[word], input_code_str)
|
||||
else
|
||||
turndown_freq_list[word] = { input_code_str }
|
||||
end
|
||||
return 'turndown_freq'
|
||||
end
|
||||
|
||||
-- 单字和二字词 如果不匹配 就隐藏
|
||||
if not hide_list[word] then
|
||||
hide_list[word] = { input_code_str }
|
||||
return true
|
||||
else
|
||||
-- 隐藏的词条如果已经在 hide_list 中, 则将输入串追加到 值表中, 如: ['藏'] = {'chang', 'zhang'}
|
||||
if not table.find_index(hide_list[word], input_code_str) then
|
||||
table.insert(hide_list[word], input_code_str)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function processor(key, env)
|
||||
local engine = env.engine
|
||||
local config = engine.schema.config
|
||||
local context = engine.context
|
||||
-- local top_cand_text = context:get_commit_text()
|
||||
-- local preedit_code = context.input
|
||||
local preedit_code = context:get_script_text()
|
||||
local turndown_cand_key = config:get_string("key_binder/turn_down_cand") or "Control+j"
|
||||
local drop_cand_key = config:get_string("key_binder/drop_cand") or "Control+d"
|
||||
local action_map = {
|
||||
[turndown_cand_key] = 'hide',
|
||||
[drop_cand_key] = 'drop'
|
||||
}
|
||||
|
||||
-- local schema_id = config:get_string("schema/schema_id")
|
||||
local schema_id = config:get_string("translator/dictionary") -- 多方案共用字典取主方案名称
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local reversedb = ReverseLookup(schema_id)
|
||||
if key:repr() == turndown_cand_key or key:repr() == drop_cand_key then
|
||||
local cand = context:get_selected_candidate()
|
||||
local action_type = action_map[key:repr()]
|
||||
local ctx_map = {
|
||||
['word'] = cand.text,
|
||||
['code'] = preedit_code
|
||||
}
|
||||
local res = append_word_to_droplist(ctx_map, action_type, reversedb)
|
||||
|
||||
context:refresh_non_confirmed_composition() -- 刷新当前输入法候选菜单, 实现看到实时效果
|
||||
if type(res) == "boolean" then
|
||||
-- 期望被删的词和隐藏的词条写入文件(drop_words.lua, hide_words.lua)
|
||||
write_word_to_file(action_type)
|
||||
else
|
||||
-- 期望 要调整词频的词条写入 turndown_freq_words.lua 文件
|
||||
write_word_to_file(res)
|
||||
end
|
||||
return 1 -- kAccept
|
||||
end
|
||||
|
||||
return 2 -- kNoop, 不做任何操作, 交给下个组件处理
|
||||
end
|
||||
|
||||
return processor
|
||||
41
lua/cold_word_drop/string.lua
Normal file
41
lua/cold_word_drop/string.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
-- wrap utf8.sub(str,head_index, tail_index)
|
||||
-- wrap string.split(str,sp,sp1)
|
||||
-- string.utf8_len = utf8.len
|
||||
-- string.utf8_offset= utf8.offset
|
||||
-- string.utf8_sub= utf8.sub
|
||||
function string.split(str, sp, sp1)
|
||||
sp = type(sp) == "string" and sp or " "
|
||||
if #sp == 0 then
|
||||
sp = "([%z\1-\127\194-\244][\128-\191]*)"
|
||||
elseif #sp == 1 then
|
||||
sp = "[^" .. (sp == "%" and "%%" or sp) .. "]*"
|
||||
else
|
||||
sp1 = sp1 or "^"
|
||||
str = str:gsub(sp, sp1)
|
||||
sp = "[^" .. sp1 .. "]*"
|
||||
end
|
||||
|
||||
local tab = {}
|
||||
for v in str:gmatch(sp) do
|
||||
table.insert(tab, v)
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
function utf8.gsub(str, si, ei)
|
||||
local function index(ustr, i)
|
||||
return i >= 0 and (ustr:utf8_offset(i) or ustr:len() + 1)
|
||||
or (ustr:utf8_offset(i) or 1)
|
||||
end
|
||||
|
||||
local u_si = index(str, si)
|
||||
ei = ei or str:utf8_len()
|
||||
ei = ei >= 0 and ei + 1 or ei
|
||||
local u_ei = index(str, ei) - 1
|
||||
return str:sub(u_si, u_ei)
|
||||
end
|
||||
|
||||
string.utf8_len = utf8.len
|
||||
string.utf8_offset = utf8.offset
|
||||
string.utf8_sub = utf8.gsub
|
||||
return true
|
||||
4
lua/cold_word_drop/turndown_freq_words.lua
Normal file
4
lua/cold_word_drop/turndown_freq_words.lua
Normal file
@@ -0,0 +1,4 @@
|
||||
local turndown_freq_words =
|
||||
{ ["示~例~"] = { "shili", },
|
||||
}
|
||||
return turndown_freq_words
|
||||
188
lua/corrector.lua
Normal file
188
lua/corrector.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
--[[
|
||||
错音错字提示。
|
||||
示例:「给予」的正确读音是 ji yu,当用户输入 gei yu 时,在候选项的 comment 显示正确读音
|
||||
示例:「按耐」的正确写法是「按捺」,当用户输入「按耐」时,在候选项的 comment 显示正确写法
|
||||
|
||||
关闭此 Lua 时,同时需要关闭 translator/spelling_hints,否则 comment 里都是拼音
|
||||
|
||||
为了让这个 Lua 同时适配全拼与双拼,使用 `spelling_hints` 生成的 comment(全拼拼音)作为通用的判断条件。
|
||||
感谢大佬@[Shewer Lu](https://github.com/shewer)提供的思路。
|
||||
|
||||
容错词在 cn_dicts/others.dict.yaml 中,有新增建议可以提个 issue
|
||||
--]]
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
local config = env.engine.schema.config
|
||||
env.keep_comment = config:get_bool('translator/keep_comments')
|
||||
local delimiter = config:get_string('speller/delimiter')
|
||||
if delimiter and #delimiter > 0 and delimiter:sub(1,1) ~= ' ' then
|
||||
env.delimiter = delimiter:sub(1,1)
|
||||
end
|
||||
env.name_space = env.name_space:gsub('^*', '')
|
||||
M.style = config:get_string(env.name_space) or '{comment}'
|
||||
M.corrections = {
|
||||
-- 错音
|
||||
["hun dun"] = { text = "馄饨", comment = "hún tun" },
|
||||
["zhu jiao"] = { text = "主角", comment = "zhǔ jué" },
|
||||
["jiao se"] = { text = "角色", comment = "jué sè" },
|
||||
["chi pi sa"] = { text = "吃比萨", comment = "chī bǐ sà" },
|
||||
["pi sa bing"] = { text = "比萨饼", comment = "bǐ sà bǐng" },
|
||||
["shui fu"] = { text = "说服", comment = "shuō fú" },
|
||||
["dao hang"] = { text = "道行", comment = "dào heng" },
|
||||
["mo yang"] = { text = "模样", comment = "mú yàng" },
|
||||
["you mo you yang"] = { text = "有模有样", comment = "yǒu mú yǒu yàng" },
|
||||
["yi mo yi yang"] = { text = "一模一样", comment = "yī mú yī yàng" },
|
||||
["zhuang mo zuo yang"] = { text = "装模作样", comment = "zhuāng mú zuò yàng" },
|
||||
["ren mo gou yang"] = { text = "人模狗样", comment = "rén mú gǒu yàng" },
|
||||
["mo ban"] = { text = "模板", comment = "mú bǎn" },
|
||||
["a mi tuo fo"] = { text = "阿弥陀佛", comment = "ē mí tuó fó" },
|
||||
["na mo a mi tuo fo"] = { text = "南无阿弥陀佛", comment = "nā mó ē mí tuó fó" },
|
||||
["nan wu a mi tuo fo"] = { text = "南无阿弥陀佛", comment = "nā mó ē mí tuó fó" },
|
||||
["nan wu e mi tuo fo"] = { text = "南无阿弥陀佛", comment = "nā mó ē mí tuó fó" },
|
||||
["gei yu"] = { text = "给予", comment = "jǐ yǔ" },
|
||||
["bin lang"] = { text = "槟榔", comment = "bīng láng" },
|
||||
["zhang bai zhi"] = { text = "张柏芝", comment = "zhāng bó zhī" },
|
||||
["teng man"] = { text = "藤蔓", comment = "téng wàn" },
|
||||
["nong tang"] = { text = "弄堂", comment = "lòng táng" },
|
||||
["xin kuan ti pang"] = { text = "心宽体胖", comment = "xīn kuān tǐ pán" },
|
||||
["mai yuan"] = { text = "埋怨", comment = "mán yuàn" },
|
||||
["xu yu wei she"] = { text = "虚与委蛇", comment = "xū yǔ wēi yí" },
|
||||
["mu na"] = { text = "木讷", comment = "mù nè" },
|
||||
["du le le"] = { text = "独乐乐", comment = "dú yuè lè" },
|
||||
["zhong le le"] = { text = "众乐乐", comment = "zhòng yuè lè" },
|
||||
["xun ma"] = { text = "荨麻", comment = "qián má" },
|
||||
["qian ma zhen"] = { text = "荨麻疹", comment = "xún má zhěn" },
|
||||
["mo ju"] = { text = "模具", comment = "mú jù" },
|
||||
["cao zhi"] = { text = "草薙", comment = "cǎo tì" },
|
||||
["cao zhi jing"] = { text = "草薙京", comment = "cǎo tì jīng" },
|
||||
["cao zhi jian"] = { text = "草薙剑", comment = "cǎo tì jiàn" },
|
||||
["jia ping ao"] = { text = "贾平凹", comment = "jiǎ píng wā" },
|
||||
["xue fo lan"] = { text = "雪佛兰", comment = "xuě fú lán" },
|
||||
["qiang jin"] = { text = "强劲", comment = "qiáng jìng" },
|
||||
["tong ti"] = { text = "胴体", comment = "dòng tǐ" },
|
||||
["li neng kang ding"] = { text = "力能扛鼎", comment = "lì néng gāng dǐng" },
|
||||
["ya lv jiang"] = { text = "鸭绿江", comment = "yā lù jiāng" },
|
||||
["da fu bian bian"] = { text = "大腹便便", comment = "dà fù pián pián" },
|
||||
["ka bo zi"] = { text = "卡脖子", comment = "qiǎ bó zi" },
|
||||
["zhi sheng"] = { text = "吱声", comment = "zī shēng" },
|
||||
["chan he"] = { text = "掺和", comment = "chān huo" },
|
||||
["can huo"] = { text = "掺和", comment = "chān huo" },
|
||||
["can he"] = { text = "掺和", comment = "chān huo" },
|
||||
["cheng zhi"] = { text = "称职", comment = "chèn zhí" },
|
||||
["luo shi fen"] = { text = "螺蛳粉", comment = "luó sī fěn" },
|
||||
["tiao huan"] = { text = "调换", comment = "diào huàn" },
|
||||
["tai xing shan"] = { text = "太行山", comment = "tài háng shān" },
|
||||
["jie si di li"] = { text = "歇斯底里", comment = "xiē sī dǐ lǐ" },
|
||||
["fa xiao"] = { text = "发酵", comment = "fā jiào" },
|
||||
["xiao mu jun"] = { text = "酵母菌", comment = "jiào mǔ jūn" },
|
||||
["yin hong"] = { text = "殷红", comment = "yān hóng" },
|
||||
["nuan he"] = { text = "暖和", comment = "nuǎn huo" },
|
||||
["mo ling liang ke"] = { text = "模棱两可", comment = "mó léng liǎng kě" },
|
||||
["pan yang hu"] = { text = "鄱阳湖", comment = "pó yáng hú" },
|
||||
["bo jing"] = { text = "脖颈", comment = "bó gěng" },
|
||||
["bo jing er"] = { text = "脖颈儿", comment = "bó gěng er" },
|
||||
["niu pi xian"] = { text = "牛皮癣", comment = "niú pí xuǎn" },
|
||||
["hua ban xian"] = { text = "花斑癣", comment = "huā bān xuǎn" },
|
||||
["ti xian"] = { text = "体癣", comment = "tǐ xuǎn" },
|
||||
["gu xian"] = { text = "股癣", comment = "gǔ xuǎn" },
|
||||
["jiao xian"] = { text = "脚癣", comment = "jiǎo xuǎn" },
|
||||
["zu xian"] = { text = "足癣", comment = "zú xuǎn" },
|
||||
["jie zha"] = { text = "结扎", comment = "jié zā" },
|
||||
["hai shen wei"] = { text = "海参崴", comment = "hǎi shēn wǎi" },
|
||||
["hou pu"] = { text = "厚朴", comment = "hòu pò " },
|
||||
["da wan ma"] = { text = "大宛马", comment = "dà yuān mǎ" },
|
||||
["ci ya"] = { text = "龇牙", comment = "zī yá" },
|
||||
["ci zhe ya"] = { text = "龇着牙", comment = "zī zhe yá" },
|
||||
["ci ya lie zui"] = { text = "龇牙咧嘴", comment = "zī yá liě zuǐ" },
|
||||
["tou pi xue"] = { text = "头皮屑", comment = "tóu pí xiè" },
|
||||
["liu an shi"] = { text = "六安市", comment = "lù ān shì" },
|
||||
["liu an xian"] = { text = "六安县", comment = "lù ān xiàn" },
|
||||
["an hui sheng liu an shi"] = { text = "安徽省六安市", comment = "ān huī shěng lù ān shì" },
|
||||
["an hui liu an"] = { text = "安徽六安", comment = "ān huī lù ān" },
|
||||
["an hui liu an shi"] = { text = "安徽六安市", comment = "ān huī lù ān shì" },
|
||||
["nan jing liu he"] = { text = "南京六合", comment = "nán jīng lù hé" },
|
||||
["nan jing shi liu he"] = { text = "南京六合区", comment = "nán jīng lù hé qū" },
|
||||
["nan jing shi liu he qu"] = { text = "南京市六合区", comment = "nán jīng shì lù hé qū" },
|
||||
["nuo da"] = { text = "偌大", comment = "偌(ruò)大" },
|
||||
["yin jiu zhi ke"] = { text = "饮鸩止渴", comment = "饮鸩(zhèn)止渴" },
|
||||
["yin jiu jie ke"] = { text = "饮鸩解渴", comment = "饮鸩(zhèn)解渴" },
|
||||
["gong shang jiao zhi yu"] = { text = "宫商角徵羽", comment = "宫商角(jué)徵羽" },
|
||||
["shan qi deng"] = { text = "氙气灯", comment = "氙(xiān)气灯" },
|
||||
["shan qi da deng"] = { text = "氙气大灯", comment = "氙(xiān)气大灯" },
|
||||
["shan qi shou dian tong"] = { text = "氙气手电筒", comment = "氙(xiān)气手电筒" },
|
||||
["yin gai"] = { text = "应该", comment = "应(yīng)该" },
|
||||
["nian tie"] = { text = "粘贴", comment = "粘(zhān)贴" },
|
||||
["gao ju li"] = { text = "高句丽", comment = "高句(gōu)丽" },
|
||||
["jiao dou shi"] = { text = "角斗士", comment = "角(jué)斗士" },
|
||||
["suo sha mi"] = { text = "缩砂密", comment = "缩(sù)砂密" },
|
||||
["po ji pao"] = { text = "迫击炮", comment = "迫(pǎi)击炮" },
|
||||
["wen bo"] = { text = "榅桲", comment = "wēn po" },
|
||||
["bi ji"] = { text = "荸荠", comment = "bí qi" },
|
||||
["rou yi"] = { text = "柔荑", comment = "柔荑(tí)" },
|
||||
["rou yi hua xu"] = { text = "柔荑花序", comment = "柔荑(tí)花序" },
|
||||
["shou ru rou yi"] = { text = "手如柔荑", comment = "手如柔荑(tí)" },
|
||||
["wen ting jun"] = { text = "温庭筠", comment = "温庭筠(yún)" },
|
||||
["guan ka"] = { text = "关卡", comment = "guān qiǎ" },
|
||||
["san wei zhen huo"] = { text = "三昧真火", comment = "三昧(mèi)真火" },
|
||||
["qing ping zhi mo"] = { text = "青𬞟之末", comment = "青𬞟(pín)之末" },
|
||||
["qi yu qing ping zhi mo"] = { text = "起于青𬞟之末", comment = "起于青𬞟(pín)之末" },
|
||||
["feng qi yu qing ping zhi mo"] = { text = "风起于青𬞟之末", comment = "风起于青𬞟(pín)之末" },
|
||||
["you hui juan"] = { text = "优惠券", comment = "优惠券(quàn)" },
|
||||
["gong quan"] = { text = "拱券", comment = "gǒng xuàn" },
|
||||
["pu ru"] = { text = "哺乳", comment = "bǔ rǔ" },
|
||||
["nao zu zhong"] = { text = "脑卒中", comment = "nǎo cù zhòng" },
|
||||
["xie hu"] = { text = "潟湖", comment = "xì hú" },
|
||||
["guo pu"] = { text = "果脯", comment = "guǒ fǔ" },
|
||||
["rou pu"] = { text = "肉脯", comment = "ròu fǔ" },
|
||||
["bai qi tun"] = { text = "白𬶨豚", comment = "bái jì tún" },
|
||||
-- 错字
|
||||
["pu jie"] = { text = "扑街", comment = "仆街" },
|
||||
["pu gai"] = { text = "扑街", comment = "仆街" },
|
||||
["pu jie zai"] = { text = "扑街仔", comment = "仆街仔" },
|
||||
["pu gai zai"] = { text = "扑街仔", comment = "仆街仔" },
|
||||
["ceng jin"] = { text = "曾今", comment = "曾经" },
|
||||
["an nai"] = { text = "按耐", comment = "按捺(nà)" },
|
||||
["an nai bu zhu"] = { text = "按耐不住", comment = "按捺(nà)不住" },
|
||||
["bie jie"] = { text = "别介", comment = "别价(jie)" },
|
||||
["beng jie"] = { text = "甭介", comment = "甭价(jie)" },
|
||||
["xue mai pen zhang"] = { text = "血脉喷张", comment = "血脉贲(bēn)张 | 血脉偾(fèn)张" },
|
||||
["qi ke fu"] = { text = "契科夫", comment = "契诃(hē)夫" },
|
||||
["zhao cha"] = { text = "找茬", comment = "找碴" },
|
||||
["zhao cha er"] = { text = "找茬儿", comment = "找碴儿" },
|
||||
["da jia lai zhao cha"] = { text = "大家来找茬", comment = "大家来找碴" },
|
||||
["da jia lai zhao cha er"] = { text = "大家来找茬儿", comment = "大家来找碴儿" },
|
||||
["cou huo"] = { text = "凑活", comment = "凑合(he)" },
|
||||
["ju hui"] = { text = "钜惠", comment = "巨惠" },
|
||||
["mo xie zuo"] = { text = "魔蝎座", comment = "摩羯(jié)座" },
|
||||
["pi sa"] = { text = "披萨", comment = "比(bǐ)萨" },
|
||||
["geng quan"] = { text = "梗犬", comment = "㹴犬" },
|
||||
}
|
||||
end
|
||||
|
||||
function M.func(input, env)
|
||||
for cand in input:iter() do
|
||||
-- cand.comment 是目前输入的词汇的完整拼音
|
||||
local pinyin = cand.comment:match("^[(.-)]$")
|
||||
if pinyin and #pinyin > 0 then
|
||||
local correction_pinyin = pinyin
|
||||
if env.delimiter then
|
||||
correction_pinyin = correction_pinyin:gsub(env.delimiter,' ')
|
||||
end
|
||||
local c = M.corrections[correction_pinyin]
|
||||
if c and cand.text == c.text then
|
||||
cand:get_genuine().comment = string.gsub(M.style, "{comment}", c.comment)
|
||||
else
|
||||
if env.keep_comment then
|
||||
cand:get_genuine().comment = string.gsub(M.style, "{comment}", pinyin)
|
||||
else
|
||||
cand:get_genuine().comment = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
72
lua/date_translator.lua
Normal file
72
lua/date_translator.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
-- 日期时间,可在方案中配置触发关键字。
|
||||
|
||||
-- 提高权重的原因:因为在方案中设置了大于 1 的 initial_quality,导致 rq sj xq dt ts 产出的候选项在所有词语的最后。
|
||||
local function yield_cand(seg, text)
|
||||
local cand = Candidate('', seg.start, seg._end, text, '')
|
||||
cand.quality = 100
|
||||
yield(cand)
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
local config = env.engine.schema.config
|
||||
env.name_space = env.name_space:gsub('^*', '')
|
||||
M.date = config:get_string(env.name_space .. '/date') or 'rq'
|
||||
M.time = config:get_string(env.name_space .. '/time') or 'sj'
|
||||
M.week = config:get_string(env.name_space .. '/week') or 'xq'
|
||||
M.datetime = config:get_string(env.name_space .. '/datetime') or 'dt'
|
||||
M.timestamp = config:get_string(env.name_space .. '/timestamp') or 'ts'
|
||||
end
|
||||
|
||||
function M.func(input, seg, env)
|
||||
-- 日期
|
||||
if (input == M.date) then
|
||||
local current_time = os.time()
|
||||
yield_cand(seg, os.date('%Y-%m-%d', current_time))
|
||||
yield_cand(seg, os.date('%Y/%m/%d', current_time))
|
||||
yield_cand(seg, os.date('%Y.%m.%d', current_time))
|
||||
yield_cand(seg, os.date('%Y%m%d', current_time))
|
||||
yield_cand(seg, os.date('%Y年%m月%d日', current_time):gsub('年0', '年'):gsub('月0','月'))
|
||||
|
||||
-- 时间
|
||||
elseif (input == M.time) then
|
||||
local current_time = os.time()
|
||||
yield_cand(seg, os.date('%H:%M', current_time))
|
||||
yield_cand(seg, os.date('%H:%M:%S', current_time))
|
||||
|
||||
-- 星期
|
||||
elseif (input == M.week) then
|
||||
local current_time = os.time()
|
||||
local week_tab = {'日', '一', '二', '三', '四', '五', '六'}
|
||||
local text = week_tab[tonumber(os.date('%w', current_time) + 1)]
|
||||
yield_cand(seg, '星期' .. text)
|
||||
yield_cand(seg, '礼拜' .. text)
|
||||
yield_cand(seg, '周' .. text)
|
||||
|
||||
-- ISO 8601/RFC 3339 的时间格式 (固定东八区)(示例 2022-01-07T20:42:51+08:00)
|
||||
elseif (input == M.datetime) then
|
||||
local current_time = os.time()
|
||||
yield_cand(seg, os.date('%Y-%m-%dT%H:%M:%S+08:00', current_time))
|
||||
yield_cand(seg, os.date('%Y-%m-%d %H:%M:%S', current_time))
|
||||
yield_cand(seg, os.date('%Y%m%d%H%M%S', current_time))
|
||||
|
||||
-- 时间戳(十位数,到秒,示例 1650861664)
|
||||
elseif (input == M.timestamp) then
|
||||
local current_time = os.time()
|
||||
yield_cand(seg, string.format('%d', current_time))
|
||||
end
|
||||
|
||||
-- -- 显示内存
|
||||
-- local cand = Candidate("date", seg.start, seg._end, ("%.f"):format(collectgarbage('count')), "")
|
||||
-- cand.quality = 100
|
||||
-- yield(cand)
|
||||
-- if input == "xxx" then
|
||||
-- collectgarbage()
|
||||
-- local cand = Candidate("date", seg.start, seg._end, "collectgarbage()", "")
|
||||
-- cand.quality = 100
|
||||
-- yield(cand)
|
||||
-- end
|
||||
end
|
||||
|
||||
return M
|
||||
12
lua/debuger.lua
Normal file
12
lua/debuger.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
local function debuger(input, env)
|
||||
for cand in input:iter() do
|
||||
yield(ShadowCandidate(
|
||||
cand,
|
||||
cand.type,
|
||||
cand.text,
|
||||
env.engine.context.input .. " - " .. env.engine.context:get_preedit().text .. " - " .. cand.preedit
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
return debuger
|
||||
18
lua/en_spacer.lua
Normal file
18
lua/en_spacer.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
-- 英文词条上屏自动添加空格
|
||||
-- 在 engine/filters 的倒数第二个位置,增加 - lua_filter@en_spacer
|
||||
--
|
||||
-- 英文后,再输入英文单词(必须为候选项)自动添加空格
|
||||
local F = {}
|
||||
|
||||
function F.func( input, env )
|
||||
local latest_text = env.engine.context.commit_history:latest_text()
|
||||
for cand in input:iter() do
|
||||
if cand.text:match( '^[%a\']+[%a\']*$' ) and latest_text and #latest_text > 0 and
|
||||
latest_text:find( '^ ?[%a\']+[%a\']*$' ) then
|
||||
cand = cand:to_shadow_candidate( 'en_spacer', cand.text:gsub( '(%a+\'?%a*)', ' %1' ), cand.comment )
|
||||
end
|
||||
yield( cand )
|
||||
end
|
||||
end
|
||||
|
||||
return F
|
||||
11
lua/force_gc.lua
Normal file
11
lua/force_gc.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
-- 暴力 GC
|
||||
-- 详情 https://github.com/hchunhui/librime-lua/issues/307
|
||||
-- collectgarbage():默认调用,等同于 collectgarbage("collect"),触发完整的垃圾回收。
|
||||
-- collectgarbage("step"):执行垃圾回收的一小步。这个函数会返回一个布尔值,表示这一步是否完成了整个收集周期。
|
||||
-- 这样也不会导致卡顿,那就每次都调用一下吧,内存稳稳的
|
||||
local function force_gc()
|
||||
-- collectgarbage()
|
||||
collectgarbage("step")
|
||||
end
|
||||
|
||||
return force_gc
|
||||
32
lua/is_in_user_dict.lua
Normal file
32
lua/is_in_user_dict.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
-- 根据是否在用户词典,在结尾加上一个星号 *
|
||||
-- is_in_user_dict: true 输入过的内容
|
||||
-- is_in_user_dict: false 或不写 未输入过的内容
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
local config = env.engine.schema.config
|
||||
env.name_space = env.name_space:gsub('^*', '')
|
||||
M.is_in_user_dict = config:get_bool(env.name_space) or true
|
||||
end
|
||||
|
||||
function M.func(input, env)
|
||||
for cand in input:iter() do
|
||||
-- 用户词库,加上*号
|
||||
if cand.type == "user_phrase" then
|
||||
cand.comment = '*'
|
||||
end
|
||||
-- 用户置顶词
|
||||
-- if cand.type == "user_table" then
|
||||
-- cand.comment = cand.comment .. '⚡️'
|
||||
-- end
|
||||
|
||||
-- 整句联想,加上𑄗符号
|
||||
if cand.type == 'sentence' then
|
||||
cand.comment = '∞'
|
||||
end
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
52
lua/long_word_filter.lua
Normal file
52
lua/long_word_filter.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
-- 长词优先(提升「西安」「提案」「图案」「饥饿」等词汇的优先级)
|
||||
-- 感谢&参考于: https://github.com/tumuyan/rime-melt
|
||||
-- 不提升包含英文、数字的候选项
|
||||
-- 不提升包含 emoji、假名的候选项(通过将此 Lua 放到 simplifier@emoji 前面来实现)
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
-- 提升 count 个词语,插入到第 idx 个位置,默认 2、4。
|
||||
local config = env.engine.schema.config
|
||||
env.name_space = env.name_space:gsub("^*", "")
|
||||
M.count = config:get_int(env.name_space .. "/count") or 2
|
||||
M.idx = config:get_int(env.name_space .. "/idx") or 4
|
||||
end
|
||||
|
||||
function M.func(input)
|
||||
local l = {}
|
||||
local firstWordLength = 0 -- 记录第一个候选词的长度,提前的候选词至少要比第一个候选词长
|
||||
local done = 0 -- 记录筛选了多少个词条(只提升 count 个词的权重)
|
||||
local i = 1
|
||||
for cand in input:iter() do
|
||||
local leng = utf8.len(cand.text)
|
||||
-- 只以第一个候选项的长度作为参考
|
||||
if firstWordLength < 1 then
|
||||
firstWordLength = leng
|
||||
end
|
||||
-- 不处理 M.idx 之前的候选项
|
||||
if i < M.idx then
|
||||
i = i + 1
|
||||
yield(cand)
|
||||
-- 长词直接 yield,其余的放到 l 里
|
||||
elseif leng <= firstWordLength or cand.text:find("[%a%d]") then
|
||||
table.insert(l, cand)
|
||||
else
|
||||
yield(cand)
|
||||
done = done + 1
|
||||
end
|
||||
-- 找齐了或者 l 太大了,就不找了,一般前 50 个就够了
|
||||
if done == M.count or #l > 50 then
|
||||
break
|
||||
end
|
||||
end
|
||||
-- yield l 及后续的候选项
|
||||
for _, cand in ipairs(l) do
|
||||
yield(cand)
|
||||
end
|
||||
for cand in input:iter() do
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
689
lua/lunar.lua
Executable file
689
lua/lunar.lua
Executable file
@@ -0,0 +1,689 @@
|
||||
--[[
|
||||
Lua 阿拉伯数字转中文实现 https://blog.csdn.net/lp12345678910/article/details/121396243
|
||||
农历功能复制自 https://github.com/boomker/rime-fast-xhup
|
||||
--]]
|
||||
--
|
||||
-- 农历,可在方案中配置触发关键字。
|
||||
|
||||
-- 数字转中文:
|
||||
|
||||
local numerical_units = {
|
||||
"",
|
||||
"十",
|
||||
"百",
|
||||
"千",
|
||||
"万",
|
||||
"十",
|
||||
"百",
|
||||
"千",
|
||||
"亿",
|
||||
"十",
|
||||
"百",
|
||||
"千",
|
||||
"兆",
|
||||
"十",
|
||||
"百",
|
||||
"千",
|
||||
}
|
||||
|
||||
local numerical_names = {
|
||||
"零",
|
||||
"一",
|
||||
"二",
|
||||
"三",
|
||||
"四",
|
||||
"五",
|
||||
"六",
|
||||
"七",
|
||||
"八",
|
||||
"九",
|
||||
}
|
||||
|
||||
local function convert_arab_to_chinese(number)
|
||||
local n_number = tonumber(number)
|
||||
assert(n_number, "传入参数非正确number类型!")
|
||||
|
||||
-- 0 ~ 9
|
||||
if n_number < 10 then
|
||||
return numerical_names[n_number + 1]
|
||||
end
|
||||
-- 一十九 => 十九
|
||||
if n_number < 20 then
|
||||
local digit = string.sub(n_number, 2, 2)
|
||||
if digit == "0" then
|
||||
return "十"
|
||||
else
|
||||
return "十" .. numerical_names[digit + 1]
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
1. 最大输入9位
|
||||
超过9位,string的len加2位(因为有.0的两位)
|
||||
零 ~ 九亿九千九百九十九万九千九百九十九
|
||||
0 ~ 999999999
|
||||
2. 最大输入14位(超过14位会四舍五入)
|
||||
零 ~ 九十九兆九千九百九十九亿九千九百九十九万九千九百九十九万
|
||||
0 ~ 99999999999999
|
||||
--]]
|
||||
local len_max = 9
|
||||
local len_number = string.len(number)
|
||||
assert(
|
||||
len_number > 0 and len_number <= len_max,
|
||||
"传入参数位数" .. len_number .. "必须在(0, " .. len_max .. "]之间!"
|
||||
)
|
||||
|
||||
-- 01,数字转成表结构存储
|
||||
local numerical_tbl = {}
|
||||
for i = 1, len_number do
|
||||
numerical_tbl[i] = tonumber(string.sub(n_number, i, i))
|
||||
end
|
||||
|
||||
local pre_zero = false
|
||||
local result = ""
|
||||
for index, digit in ipairs(numerical_tbl) do
|
||||
local curr_unit = numerical_units[len_number - index + 1]
|
||||
local curr_name = numerical_names[digit + 1]
|
||||
if digit == 0 then
|
||||
if not pre_zero then
|
||||
result = result .. curr_name
|
||||
end
|
||||
pre_zero = true
|
||||
else
|
||||
result = result .. curr_name .. curr_unit
|
||||
pre_zero = false
|
||||
end
|
||||
end
|
||||
result = string.gsub(result, "零+$", "")
|
||||
return result
|
||||
end
|
||||
|
||||
-- 农历:
|
||||
|
||||
-- 天干名称
|
||||
local cTianGan = {
|
||||
"甲",
|
||||
"乙",
|
||||
"丙",
|
||||
"丁",
|
||||
"戊",
|
||||
"己",
|
||||
"庚",
|
||||
"辛",
|
||||
"壬",
|
||||
"癸",
|
||||
}
|
||||
|
||||
-- 地支名称
|
||||
local cDiZhi = {
|
||||
"子",
|
||||
"丑",
|
||||
"寅",
|
||||
"卯",
|
||||
"辰",
|
||||
"巳",
|
||||
"午",
|
||||
"未",
|
||||
"申",
|
||||
"酉",
|
||||
"戌",
|
||||
"亥",
|
||||
}
|
||||
|
||||
-- 属相名称
|
||||
local cShuXiang = {
|
||||
"鼠",
|
||||
"牛",
|
||||
"虎",
|
||||
"兔",
|
||||
"龙",
|
||||
"蛇",
|
||||
"马",
|
||||
"羊",
|
||||
"猴",
|
||||
"鸡",
|
||||
"狗",
|
||||
"猪",
|
||||
}
|
||||
|
||||
-- 农历日期名
|
||||
local cDayName = {
|
||||
"初一",
|
||||
"初二",
|
||||
"初三",
|
||||
"初四",
|
||||
"初五",
|
||||
"初六",
|
||||
"初七",
|
||||
"初八",
|
||||
"初九",
|
||||
"初十",
|
||||
"十一",
|
||||
"十二",
|
||||
"十三",
|
||||
"十四",
|
||||
"十五",
|
||||
"十六",
|
||||
"十七",
|
||||
"十八",
|
||||
"十九",
|
||||
"二十",
|
||||
"廿一",
|
||||
"廿二",
|
||||
"廿三",
|
||||
"廿四",
|
||||
"廿五",
|
||||
"廿六",
|
||||
"廿七",
|
||||
"廿八",
|
||||
"廿九",
|
||||
"三十",
|
||||
}
|
||||
|
||||
-- 农历月份名
|
||||
local cMonName = {
|
||||
"正月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"冬月",
|
||||
"腊月",
|
||||
}
|
||||
|
||||
-- 农历数据
|
||||
local wNongliData = {
|
||||
"AB500D2",
|
||||
"4BD0883",
|
||||
"4AE00DB",
|
||||
"A5700D0",
|
||||
"54D0581",
|
||||
"D2600D8",
|
||||
"D9500CC",
|
||||
"655147D",
|
||||
"56A00D5",
|
||||
"9AD00CA",
|
||||
"55D027A",
|
||||
"4AE00D2",
|
||||
"A5B0682",
|
||||
"A4D00DA",
|
||||
"D2500CE",
|
||||
"D25157E",
|
||||
"B5500D6",
|
||||
"56A00CC",
|
||||
"ADA027B",
|
||||
"95B00D3",
|
||||
"49717C9",
|
||||
"49B00DC",
|
||||
"A4B00D0",
|
||||
"B4B0580",
|
||||
"6A500D8",
|
||||
"6D400CD",
|
||||
"AB5147C",
|
||||
"2B600D5",
|
||||
"95700CA",
|
||||
"52F027B",
|
||||
"49700D2",
|
||||
"6560682",
|
||||
"D4A00D9",
|
||||
"EA500CE",
|
||||
"6A9157E",
|
||||
"5AD00D6",
|
||||
"2B600CC",
|
||||
"86E137C",
|
||||
"92E00D3",
|
||||
"C8D1783",
|
||||
"C9500DB",
|
||||
"D4A00D0",
|
||||
"D8A167F",
|
||||
"B5500D7",
|
||||
"56A00CD",
|
||||
"A5B147D",
|
||||
"25D00D5",
|
||||
"92D00CA",
|
||||
"D2B027A",
|
||||
"A9500D2",
|
||||
"B550781",
|
||||
"6CA00D9",
|
||||
"B5500CE",
|
||||
"535157F",
|
||||
"4DA00D6",
|
||||
"A5B00CB",
|
||||
"457037C",
|
||||
"52B00D4",
|
||||
"A9A0883",
|
||||
"E9500DA",
|
||||
"6AA00D0",
|
||||
"AEA0680",
|
||||
"AB500D7",
|
||||
"4B600CD",
|
||||
"AAE047D",
|
||||
"A5700D5",
|
||||
"52600CA",
|
||||
"F260379",
|
||||
"D9500D1",
|
||||
"5B50782",
|
||||
"56A00D9",
|
||||
"96D00CE",
|
||||
"4DD057F",
|
||||
"4AD00D7",
|
||||
"A4D00CB",
|
||||
"D4D047B",
|
||||
"D2500D3",
|
||||
"D550883",
|
||||
"B5400DA",
|
||||
"B6A00CF",
|
||||
"95A1680",
|
||||
"95B00D8",
|
||||
"49B00CD",
|
||||
"A97047D",
|
||||
"A4B00D5",
|
||||
"B270ACA",
|
||||
"6A500DC",
|
||||
"6D400D1",
|
||||
"AF40681",
|
||||
"AB600D9",
|
||||
"93700CE",
|
||||
"4AF057F",
|
||||
"49700D7",
|
||||
"64B00CC",
|
||||
"74A037B",
|
||||
"EA500D2",
|
||||
"6B50883",
|
||||
"5AC00DB",
|
||||
"AB600CF",
|
||||
"96D0580",
|
||||
"92E00D8",
|
||||
"C9600CD",
|
||||
"D95047C",
|
||||
"D4A00D4",
|
||||
"DA500C9",
|
||||
"755027A",
|
||||
"56A00D1",
|
||||
"ABB0781",
|
||||
"25D00DA",
|
||||
"92D00CF",
|
||||
"CAB057E",
|
||||
"A9500D6",
|
||||
"B4A00CB",
|
||||
"BAA047B",
|
||||
"AD500D2",
|
||||
"55D0983",
|
||||
"4BA00DB",
|
||||
"A5B00D0",
|
||||
"5171680",
|
||||
"52B00D8",
|
||||
"A9300CD",
|
||||
"795047D",
|
||||
"6AA00D4",
|
||||
"AD500C9",
|
||||
"5B5027A",
|
||||
"4B600D2",
|
||||
"96E0681",
|
||||
"A4E00D9",
|
||||
"D2600CE",
|
||||
"EA6057E",
|
||||
"D5300D5",
|
||||
"5AA00CB",
|
||||
"76A037B",
|
||||
"96D00D3",
|
||||
"4AB0B83",
|
||||
"4AD00DB",
|
||||
"A4D00D0",
|
||||
"D0B1680",
|
||||
"D2500D7",
|
||||
"D5200CC",
|
||||
"DD4057C",
|
||||
"B5A00D4",
|
||||
"56D00C9",
|
||||
"55B027A",
|
||||
"49B00D2",
|
||||
"A570782",
|
||||
"A4B00D9",
|
||||
"AA500CE",
|
||||
"B25157E",
|
||||
"6D200D6",
|
||||
"ADA00CA",
|
||||
"4B6137B",
|
||||
"93700D3",
|
||||
"49F08C9",
|
||||
"49700DB",
|
||||
"64B00D0",
|
||||
"68A1680",
|
||||
"EA500D7",
|
||||
"6AA00CC",
|
||||
"A6C147C",
|
||||
"AAE00D4",
|
||||
"92E00CA",
|
||||
"D2E0379",
|
||||
"C9600D1",
|
||||
"D550781",
|
||||
"D4A00D9",
|
||||
"DA400CD",
|
||||
"5D5057E",
|
||||
"56A00D6",
|
||||
"A6C00CB",
|
||||
"55D047B",
|
||||
"52D00D3",
|
||||
"A9B0883",
|
||||
"A9500DB",
|
||||
"B4A00CF",
|
||||
"B6A067F",
|
||||
"AD500D7",
|
||||
"55A00CD",
|
||||
"ABA047C",
|
||||
"A5A00D4",
|
||||
"52B00CA",
|
||||
"B27037A",
|
||||
"69300D1",
|
||||
"7330781",
|
||||
"6AA00D9",
|
||||
"AD500CE",
|
||||
"4B5157E",
|
||||
"4B600D6",
|
||||
"A5700CB",
|
||||
"54E047C",
|
||||
"D1600D2",
|
||||
"E960882",
|
||||
"D5200DA",
|
||||
"DAA00CF",
|
||||
"6AA167F",
|
||||
"56D00D7",
|
||||
"4AE00CD",
|
||||
"A9D047D",
|
||||
"A2D00D4",
|
||||
"D1500C9",
|
||||
"F250279",
|
||||
"D5200D1",
|
||||
}
|
||||
|
||||
-- 十进制转二进制
|
||||
local function Dec2bin(n)
|
||||
local t, t1
|
||||
local tables = {}
|
||||
t = tonumber(n)
|
||||
while math.floor(t / 2) >= 1 do
|
||||
t1 = t and math.fmod(t, 2)
|
||||
if t1 > 0 then
|
||||
if #tables > 0 then
|
||||
table.insert(tables, 1, 1)
|
||||
else
|
||||
tables[1] = 1
|
||||
end
|
||||
else
|
||||
if #tables > 0 then
|
||||
table.insert(tables, 1, 0)
|
||||
else
|
||||
tables[1] = 0
|
||||
end
|
||||
end
|
||||
t = math.floor(t / 2)
|
||||
if t == 1 then
|
||||
if #tables > 0 then
|
||||
table.insert(tables, 1, 1)
|
||||
else
|
||||
tables[1] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return string.gsub(table.concat(tables), "^[0]+", "")
|
||||
end
|
||||
|
||||
-- 2/10/16进制互转
|
||||
local function Atoi(x, inPuttype, outputtype)
|
||||
local r
|
||||
if tonumber(inPuttype) == 2 then
|
||||
if tonumber(outputtype) == 10 then -- 2进制-->10进制
|
||||
r = tonumber(tostring(x), 2)
|
||||
-- elseif tonumber(outputtype) == 16 then -- 2进制-->16进制
|
||||
-- r = bin2hex(tostring(x))
|
||||
end
|
||||
elseif tonumber(inPuttype) == 10 then
|
||||
if tonumber(outputtype) == 2 then -- 10进制-->2进制
|
||||
r = Dec2bin(tonumber(x))
|
||||
elseif tonumber(outputtype) == 16 then -- 10进制-->16进制
|
||||
r = string.format("%x", x)
|
||||
end
|
||||
elseif tonumber(inPuttype) == 16 then
|
||||
if tonumber(outputtype) == 2 then -- 16进制-->2进制
|
||||
r = Dec2bin(tonumber(tostring(x), 16))
|
||||
elseif tonumber(outputtype) == 10 then -- 16进制-->10进制
|
||||
r = tonumber(tostring(x), 16)
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
-- 农历16进制数据分解
|
||||
local function Analyze(Data)
|
||||
local rtn1, rtn2, rtn3, rtn4
|
||||
rtn1 = Atoi(string.sub(Data, 1, 3), 16, 2)
|
||||
if string.len(rtn1) < 12 then
|
||||
rtn1 = "0" .. rtn1
|
||||
end
|
||||
rtn2 = string.sub(Data, 4, 4)
|
||||
rtn3 = Atoi(string.sub(Data, 5, 5), 16, 10)
|
||||
rtn4 = Atoi(string.sub(Data, -2, -1), 16, 10)
|
||||
if string.len(rtn4) == 3 then
|
||||
rtn4 = "0" .. Atoi(string.sub(Data, -2, -1), 16, 10)
|
||||
end
|
||||
-- string.gsub(rtn1, "^[0]*", "")
|
||||
return { rtn1, rtn2, rtn3, rtn4 }
|
||||
end
|
||||
|
||||
-- 年天数判断
|
||||
local function IsLeap(y)
|
||||
local year = tonumber(y)
|
||||
if not year then
|
||||
return nil
|
||||
end
|
||||
if math.fmod(year, 400) ~= 0 and math.fmod(year, 4) == 0 or math.fmod(year, 400) == 0 then
|
||||
return 366
|
||||
else
|
||||
return 365
|
||||
end
|
||||
end
|
||||
|
||||
-- 返回当年过了多少天
|
||||
local function leaveDate(y)
|
||||
local day, total
|
||||
total = 0
|
||||
if IsLeap(tonumber(string.sub(y, 1, 4))) > 365 then
|
||||
day = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
else
|
||||
day = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
end
|
||||
if tonumber(string.sub(y, 5, 6)) > 1 then
|
||||
for i = 1, tonumber(string.sub(y, 5, 6)) - 1 do
|
||||
total = total + day[i]
|
||||
end
|
||||
total = total + tonumber(string.sub(y, 7, 8))
|
||||
else
|
||||
return tonumber(string.sub(y, 7, 8))
|
||||
end
|
||||
return tonumber(total)
|
||||
end
|
||||
|
||||
-- 计算日期差,两个8位数日期之间相隔的天数,date2>date1
|
||||
local function diffDate(date1, date2)
|
||||
local n, total
|
||||
total = 0
|
||||
date1 = tostring(date1)
|
||||
date2 = tostring(date2)
|
||||
if tonumber(date2) > tonumber(date1) then
|
||||
n = tonumber(string.sub(date2, 1, 4)) - tonumber(string.sub(date1, 1, 4))
|
||||
if n > 1 then
|
||||
for i = 1, n - 1 do
|
||||
total = total + IsLeap(tonumber(string.sub(date1, 1, 4)) + i)
|
||||
end
|
||||
total = total
|
||||
+ leaveDate(tonumber(string.sub(date2, 1, 8)))
|
||||
+ IsLeap(tonumber(string.sub(date1, 1, 4)))
|
||||
- leaveDate(tonumber(string.sub(date1, 1, 8)))
|
||||
elseif n == 1 then
|
||||
total = IsLeap(tonumber(string.sub(date1, 1, 4)))
|
||||
- leaveDate(tonumber(string.sub(date1, 1, 8)))
|
||||
+ leaveDate(tonumber(string.sub(date2, 1, 8)))
|
||||
else
|
||||
total = leaveDate(tonumber(string.sub(date2, 1, 8))) - leaveDate(tonumber(string.sub(date1, 1, 8)))
|
||||
-- print(date1 .. "-" .. date2)
|
||||
end
|
||||
elseif tonumber(date2) == tonumber(date1) then
|
||||
return 0
|
||||
else
|
||||
return -1
|
||||
end
|
||||
return total
|
||||
end
|
||||
|
||||
-- 公历转农历,支持转化范围公元1900-2100年
|
||||
-- 公历日期 Gregorian:格式 YYYYMMDD
|
||||
-- <返回值>农历日期 中文 天干地支属相
|
||||
local function Date2LunarDate(Gregorian)
|
||||
Gregorian = tostring(Gregorian)
|
||||
local Year, Month, Day, Pos, Data0, Data1, MonthInfo, LeapInfo, Leap, Newyear, LYear, thisMonthInfo
|
||||
Year = tonumber(Gregorian.sub(Gregorian, 1, 4))
|
||||
Month = tonumber(Gregorian.sub(Gregorian, 5, 6))
|
||||
Day = tonumber(Gregorian.sub(Gregorian, 7, 8))
|
||||
LunarDate3 = Year .. "年" .. Month .."月".. Day .. "日"
|
||||
if Year > 2100 or Year < 1899 or Month > 12 or Month < 1 or Day < 1 or Day > 31 or string.len(Gregorian) < 8 then
|
||||
-- 2024.07.27 这个不能判断不存在的日期,例如 02.31 04.30 等,会显示农历,但不存在 by Mirtle
|
||||
return "无效日期", "无效日期"
|
||||
end
|
||||
|
||||
-- 获取两百年内的农历数据
|
||||
Pos = Year - 1900 + 2
|
||||
Data0 = wNongliData[Pos - 1]
|
||||
Data1 = wNongliData[Pos]
|
||||
-- 判断农历年份
|
||||
local tb1 = Analyze(Data1)
|
||||
MonthInfo = tb1[1]
|
||||
LeapInfo = tb1[2]
|
||||
Leap = tb1[3]
|
||||
Newyear = tb1[4]
|
||||
local Date1 = Year .. Newyear
|
||||
local Date2 = Gregorian
|
||||
local Date3 = diffDate(Date1, Date2) -- 和当年农历新年相差的天数
|
||||
if Date3 < 0 then
|
||||
-- print(Data0 .. "-2")
|
||||
tb1 = Analyze(Data0)
|
||||
Year = Year - 1
|
||||
MonthInfo = tb1[1]
|
||||
LeapInfo = tb1[2]
|
||||
Leap = tb1[3]
|
||||
Newyear = tb1[4]
|
||||
Date1 = Year .. Newyear
|
||||
Date2 = Gregorian
|
||||
Date3 = diffDate(Date1, Date2)
|
||||
-- print(Date2 .. "--" .. Date1 .. "--" .. Date3)
|
||||
end
|
||||
|
||||
Date3 = Date3 + 1
|
||||
LYear = Year -- 农历年份,就是上面计算后的值
|
||||
if Leap > 0 then -- 有闰月
|
||||
thisMonthInfo = string.sub(MonthInfo, 1, tonumber(Leap)) .. LeapInfo .. string.sub(MonthInfo, Leap + 1)
|
||||
else
|
||||
thisMonthInfo = MonthInfo
|
||||
end
|
||||
|
||||
local thisMonth, thisDays, LMonth, LDay, Isleap, LunarDate, LunarDate2, LunarYear, LunarMonth
|
||||
for i = 1, 13 do
|
||||
thisMonth = string.sub(thisMonthInfo, i, i)
|
||||
thisDays = 29 + thisMonth
|
||||
if Date3 > thisDays then
|
||||
Date3 = Date3 - thisDays
|
||||
else
|
||||
if Leap > 0 then
|
||||
if Leap >= i then
|
||||
LMonth = i
|
||||
Isleap = 0
|
||||
else
|
||||
LMonth = i - 1
|
||||
if i - Leap == 1 then
|
||||
Isleap = 1
|
||||
else
|
||||
Isleap = 0
|
||||
end
|
||||
end
|
||||
else
|
||||
LMonth = i
|
||||
Isleap = 0
|
||||
end
|
||||
LDay = math.floor(Date3)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if Isleap > 0 then
|
||||
LunarMonth = "闰" .. cMonName[LMonth]
|
||||
else
|
||||
LunarMonth = cMonName[LMonth]
|
||||
end
|
||||
|
||||
local _nis = tostring(LYear)
|
||||
local _LunarYears = ""
|
||||
for i = 1, _nis:len() do
|
||||
local _ni_digit = tonumber(_nis:sub(i, i))
|
||||
_LunarYears = _LunarYears .. convert_arab_to_chinese(_ni_digit)
|
||||
end
|
||||
|
||||
LunarYear = string.gsub(_LunarYears, "零", "〇")
|
||||
LunarDate = cTianGan[math.fmod(LYear - 4, 10) + 1]
|
||||
.. cDiZhi[math.fmod(LYear - 4, 12) + 1]
|
||||
.. "年("
|
||||
.. cShuXiang[math.fmod(LYear - 4, 12) + 1]
|
||||
.. ")"
|
||||
.. LunarMonth
|
||||
.. cDayName[LDay]
|
||||
|
||||
LunarDate2 = LunarYear .. "年" .. LunarMonth .. cDayName[LDay]
|
||||
|
||||
|
||||
return LunarDate, LunarDate2, LunarDate3
|
||||
end
|
||||
|
||||
-- 农历
|
||||
-- 从 lunar: nl 获取农历触发关键字(双拼默认为 lunar)
|
||||
-- 从 recognizer/patterns/gregorian_to_lunar 获取第 2 个字符作为公历转农历的触发前缀,默认为 N
|
||||
local function translator(input, seg, env)
|
||||
env.lunar_key_word = env.lunar_key_word or
|
||||
(env.engine.schema.config:get_string(env.name_space:gsub('^*', '')) or 'nl')
|
||||
env.gregorian_to_lunar = env.gregorian_to_lunar or
|
||||
(env.engine.schema.config:get_string('recognizer/patterns/gregorian_to_lunar'):sub(2, 2) or 'N')
|
||||
if input == env.lunar_key_word then
|
||||
local date1, date2,date3 = Date2LunarDate(os.date("%Y%m%d"))
|
||||
local lunar_ymd = (Candidate("", seg.start, seg._end, date2, ""))
|
||||
lunar_ymd.quality = 999
|
||||
yield(lunar_ymd)
|
||||
local lunar_date = Candidate("", seg.start, seg._end, date1, "")
|
||||
lunar_date.quality = 999
|
||||
yield(lunar_date)
|
||||
local date = Candidate("", seg.start, seg._end, date3, "")
|
||||
date.quality = 999
|
||||
yield(date)
|
||||
elseif env.gregorian_to_lunar ~= '' and input:sub(1, 1) == env.gregorian_to_lunar then
|
||||
local date1, date2, date3 = Date2LunarDate(input:sub(2))
|
||||
local lunar_ymd = (Candidate("", seg.start, seg._end, date2, ""))
|
||||
lunar_ymd.quality = 999
|
||||
yield(lunar_ymd)
|
||||
local lunar_date = Candidate("", seg.start, seg._end, date1, "")
|
||||
lunar_date.quality = 999
|
||||
yield(lunar_date)
|
||||
local date = Candidate("", seg.start, seg._end, date3, "")
|
||||
date.quality = 999
|
||||
yield(date)
|
||||
end
|
||||
end
|
||||
|
||||
local function yield_cand(seg, text)
|
||||
local cand = Candidate('', seg.start, seg._end, text, '')
|
||||
cand.quality = 1000000
|
||||
yield(cand)
|
||||
end
|
||||
|
||||
return translator
|
||||
163
lua/number_translator.lua
Normal file
163
lua/number_translator.lua
Normal file
@@ -0,0 +1,163 @@
|
||||
-- 来源 https://github.com/yanhuacuo/98wubi-tables > http://98wb.ysepan.com/
|
||||
-- 数字、金额大写
|
||||
-- 触发前缀默认为 recognizer/patterns/number 的第 2 个字符,即 R
|
||||
|
||||
local function splitNumPart(str)
|
||||
local part = {}
|
||||
part.int, part.dot, part.dec = string.match(str, "^(%d*)(%.?)(%d*)")
|
||||
return part
|
||||
end
|
||||
|
||||
local function GetPreciseDecimal(nNum, n)
|
||||
if type(nNum) ~= "number" then nNum = tonumber(nNum) end
|
||||
n = n or 0;
|
||||
n = math.floor(n)
|
||||
if n < 0 then n = 0 end
|
||||
local nDecimal = 10 ^ n
|
||||
local nTemp = math.floor(nNum * nDecimal);
|
||||
local nRet = nTemp / nDecimal;
|
||||
return nRet;
|
||||
end
|
||||
|
||||
local function decimal_func(str, posMap, valMap)
|
||||
local dec
|
||||
posMap = posMap or { [1] = "角", [2] = "分", [3] = "厘", [4] = "毫" }
|
||||
valMap = valMap or { [0] = "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }
|
||||
if #str > 4 then dec = string.sub(tostring(str), 1, 4) else dec = tostring(str) end
|
||||
dec = string.gsub(dec, "0+$", "")
|
||||
|
||||
if dec == "" then return "整" end
|
||||
|
||||
local result = ""
|
||||
for pos = 1, #dec do
|
||||
local val = tonumber(string.sub(dec, pos, pos))
|
||||
if val ~= 0 then result = result .. valMap[val] .. posMap[pos] else result = result .. valMap[val] end
|
||||
end
|
||||
result = result:gsub(valMap[0] .. valMap[0], valMap[0])
|
||||
return result:gsub(valMap[0] .. valMap[0], valMap[0])
|
||||
end
|
||||
|
||||
-- 把数字串按千分位四位数分割,进行转换为中文
|
||||
local function formatNum(num, t)
|
||||
local digitUnit, wordFigure
|
||||
local result = ""
|
||||
num = tostring(num)
|
||||
if tonumber(t) < 1 then digitUnit = { "", "十", "百", "千" } else digitUnit = { "", "拾", "佰", "仟" } end
|
||||
if tonumber(t) < 1 then
|
||||
wordFigure = { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" }
|
||||
else
|
||||
wordFigure = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }
|
||||
end
|
||||
if string.len(num) > 4 or tonumber(num) == 0 then return wordFigure[1] end
|
||||
local lens = string.len(num)
|
||||
for i = 1, lens do
|
||||
local n = wordFigure[tonumber(string.sub(num, -i, -i)) + 1]
|
||||
if n ~= wordFigure[1] then result = n .. digitUnit[i] .. result else result = n .. result end
|
||||
end
|
||||
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
|
||||
result = result:gsub(wordFigure[1] .. "$", "")
|
||||
result = result:gsub(wordFigure[1] .. "$", "")
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- 数值转换为中文
|
||||
local function number2cnChar(num, flag, digitUnit, wordFigure) --flag=0中文小写反之为大写
|
||||
local result = ""
|
||||
|
||||
if tonumber(flag) < 1 then
|
||||
digitUnit = digitUnit or { [1] = "万", [2] = "亿" }
|
||||
wordFigure = wordFigure or { [1] = "〇", [2] = "一", [3] = "十", [4] = "元" }
|
||||
else
|
||||
digitUnit = digitUnit or { [1] = "万", [2] = "亿" }
|
||||
wordFigure = wordFigure or { [1] = "零", [2] = "壹", [3] = "拾", [4] = "元" }
|
||||
end
|
||||
local lens = string.len(num)
|
||||
if lens < 5 then
|
||||
result = formatNum(num, flag)
|
||||
elseif lens < 9 then
|
||||
result = formatNum(string.sub(num, 1, -5), flag) .. digitUnit[1] .. formatNum(string.sub(num, -4, -1), flag)
|
||||
elseif lens < 13 then
|
||||
result = formatNum(string.sub(num, 1, -9), flag) ..
|
||||
digitUnit[2] ..
|
||||
formatNum(string.sub(num, -8, -5), flag) .. digitUnit[1] .. formatNum(string.sub(num, -4, -1), flag)
|
||||
else
|
||||
result = ""
|
||||
end
|
||||
|
||||
result = result:gsub("^" .. wordFigure[1], "")
|
||||
result = result:gsub(wordFigure[1] .. digitUnit[1], "")
|
||||
result = result:gsub(wordFigure[1] .. digitUnit[2], "")
|
||||
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
|
||||
result = result:gsub(wordFigure[1] .. "$", "")
|
||||
if lens > 4 then result = result:gsub("^" .. wordFigure[2] .. wordFigure[3], wordFigure[3]) end
|
||||
if result ~= "" then result = result .. wordFigure[4] else result = "数值超限!" end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function number2zh(num, t)
|
||||
local result, wordFigure
|
||||
result = ""
|
||||
if tonumber(t) < 1 then
|
||||
wordFigure = { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" }
|
||||
else
|
||||
wordFigure = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }
|
||||
end
|
||||
if tostring(num) == nil then return "" end
|
||||
for pos = 1, string.len(num) do
|
||||
result = result .. wordFigure[tonumber(string.sub(num, pos, pos) + 1)]
|
||||
end
|
||||
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
|
||||
return result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
|
||||
end
|
||||
|
||||
local function number_translatorFunc(num)
|
||||
local numberPart = splitNumPart(num)
|
||||
local result = {}
|
||||
if numberPart.dot ~= "" then
|
||||
table.insert(result,
|
||||
{ number2cnChar(numberPart.int, 0, { "万", "亿" }, { "〇", "一", "十", "点" }) .. number2zh(numberPart.dec, 0),
|
||||
"〔数字小写〕" })
|
||||
table.insert(result,
|
||||
{ number2cnChar(numberPart.int, 1, { "萬", "億" }, { "〇", "一", "十", "点" }) .. number2zh(numberPart.dec, 1),
|
||||
"〔数字大写〕" })
|
||||
else
|
||||
table.insert(result, { number2cnChar(numberPart.int, 0, { "万", "亿" }, { "〇", "一", "十", "" }), "〔数字小写〕" })
|
||||
table.insert(result, { number2cnChar(numberPart.int, 1, { "萬", "億" }, { "零", "壹", "拾", "" }), "〔数字大写〕" })
|
||||
end
|
||||
table.insert(result,
|
||||
{ number2cnChar(numberPart.int, 0) ..
|
||||
decimal_func(numberPart.dec, { [1] = "角", [2] = "分", [3] = "厘", [4] = "毫" },
|
||||
{ [0] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" }), "〔金额小写〕" })
|
||||
|
||||
local number2cnCharInt = number2cnChar(numberPart.int, 1)
|
||||
local number2cnCharDec = decimal_func(numberPart.dec, { [1] = "角", [2] = "分", [3] = "厘", [4] = "毫" }, { [0] = "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" })
|
||||
if string.len(numberPart.int) > 4 and number2cnCharInt:find('^拾[壹贰叁肆伍陆柒捌玖]?') and number2cnCharInt:find('[万亿]') then -- 简易地规避 utf8 匹配问题
|
||||
local number2cnCharInt_var = number2cnCharInt:gsub('^拾', '壹拾')
|
||||
table.insert(result, { number2cnCharInt_var .. number2cnCharDec , "〔金额大写〕"})
|
||||
-- 会计书写要求 https://github.com/iDvel/rime-ice/issues/989
|
||||
else
|
||||
table.insert(result, { number2cnCharInt .. number2cnCharDec , "〔金额大写〕"})
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function number_translator(input, seg, env)
|
||||
-- 获取 recognizer/patterns/number 的第 2 个字符作为触发前缀
|
||||
env.number_keyword = env.number_keyword or
|
||||
env.engine.schema.config:get_string('recognizer/patterns/number'):sub(2, 2)
|
||||
local str, num, numberPart
|
||||
if env.number_keyword ~= '' and input:sub(1, 1) == env.number_keyword then
|
||||
str = string.gsub(input, "^(%a+)", "")
|
||||
numberPart = number_translatorFunc(str)
|
||||
if str and #str > 0 and #numberPart > 0 then
|
||||
for i = 1, #numberPart do
|
||||
yield(Candidate(input, seg.start, seg._end, numberPart[i][1], numberPart[i][2]))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- print(#number_translatorFunc(3355.433))
|
||||
return number_translator
|
||||
238
lua/pin_cand_filter.lua
Normal file
238
lua/pin_cand_filter.lua
Normal file
@@ -0,0 +1,238 @@
|
||||
-- 置顶候选项
|
||||
--[[
|
||||
《说明书》
|
||||
|
||||
符合左边的编码(preedit)时,按顺序置顶右边的候选项。只是提升已有候选项的顺序,没有自创编码的功能。
|
||||
脚本对比的是去掉空格的 cand.preedit,配置里写空格可以生成额外的编码,参考示例。
|
||||
|
||||
cand.preedit 是经过 translator/preedit_format 转换后的编码
|
||||
⚠️ 注意方案的 preedit_format 设定,如果 v 显示为 ü,那么左边也要写 ü
|
||||
⚠️ 双拼:显示为全拼拼写就要写全拼,如 'shuang pin',显示为双拼拼写就要写双拼,如 'ul pb'
|
||||
|
||||
格式:编码<Tab>字词1<Space>字词2……
|
||||
按照 YAML 语法,加不加引号都行,也可以这么写 pin_cand_filter: [l 了, 'de 的', "ni hao 你好"]
|
||||
|
||||
示例:
|
||||
- 'le 了' # 输入 le 时,置顶「了」
|
||||
- 'ta 他 她 它' # 可以置顶多个字,按顺序排列
|
||||
- 'l 了 啦' # 支持单编码,输入 l 时,置顶「了、啦」
|
||||
- 'l 了 > 啦' # 右边的字词如果包含空格,用 > 分割也行(大于号左右必须有空格)
|
||||
- 'ta 啊' # ❌ 编码不会产生的字词,不会生效且影响查找效率。自创编码的字词句可以写到 custom_phrase 中。
|
||||
- 'hao 好 👌' # ❌ 不要写 emoji
|
||||
|
||||
### 简拼
|
||||
支持简拼,简拼加不加空格都行。但需要方案开启简拼,雾凇全拼是默认开启的,双拼默认没开启
|
||||
- s m 什么
|
||||
- wsm 为什么
|
||||
|
||||
### 空格的作用:
|
||||
- nihao 你好
|
||||
无空格,生成原样;
|
||||
生成 nihao,输入 nihao 时首位是「你好」,但输入 nih 时首位可能是「你会 你还」等其他词语。
|
||||
|
||||
- ni hao 你好
|
||||
包含空格,额外生成最后一个空格后的拼音的首字母简码;
|
||||
生成 nihao nih ,现在输入 nih 时首位也会是「你好」。
|
||||
|
||||
- bu hao chi 不好吃
|
||||
包含空格且结尾以 zh ch sh 开头,再额外生成最后一个空格后的拼音的 zh ch sh 简码;
|
||||
生成 buhaochi buhaoc buhaoch
|
||||
|
||||
### 优先级:
|
||||
- da zhuang 大专
|
||||
- da zhong 大众
|
||||
上面两行,会额外生成 'da z' 'da zh' 的置顶,前两个候选项是「大专、大众」,先写的排在前面
|
||||
|
||||
- da z 打字
|
||||
如果明确定义了简码形式,则完全使用简码形式
|
||||
此时输入 daz 首位为「打字」,输入 dazh 首位仍为「大专、大众」
|
||||
--]]
|
||||
|
||||
local function find_index(list, str)
|
||||
for i, v in ipairs(list) do
|
||||
if v == str then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
env.name_space = env.name_space:gsub("^*", "")
|
||||
|
||||
if env.pin_cands ~= nil then return end
|
||||
|
||||
local list = env.engine.schema.config:get_list(env.name_space)
|
||||
if not list or list.size == 0 then return end
|
||||
|
||||
-- 如果定义了 'da zhuan' 或 'da zhong' ,会自动生成 'daz' 和 'dazh' 的键。
|
||||
-- 然而,如果明确定义了 'da z' 或 'da zh',则会优先使用这些明确自定义的简码,用 set 来做判断。
|
||||
local set = {}
|
||||
for i = 0, list.size - 1 do
|
||||
local preedit, texts = list:get_value_at(i).value:match("([^\t]+)\t(.+)")
|
||||
if #preedit > 0 and #texts > 0 then
|
||||
set[preedit:gsub(" ", "")] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- 遍历要置顶的候选项列表,将其转换为 table 存储到 env.pin_cands
|
||||
-- 'l 了 啦' → env.pin_cands["l"] = {"了", "啦"}
|
||||
-- 'ta 他 她 它' → env.pin_cands["ta"] = {"他", "她", "它"}
|
||||
--
|
||||
-- 无空格的键,如 `nihao 你好` → env.pin_cands["nihao"] = {"你好"}
|
||||
--
|
||||
-- 包含空格的的键,同时生成简码的拼写(最后一个空格后的首字母),如:
|
||||
-- 'ni hao 你好 拟好' → env.pin_cands["nihao"] = {"你好", "拟好"}
|
||||
-- → env.pin_cands["nih"] = {"你好", "拟好"}
|
||||
--
|
||||
-- 如果最后一个空格后以 zh ch sh 开头,额外再生成 zh, ch, sh 的拼写,如:
|
||||
-- 'zhi chi 支持' → env.pin_cands["zhichi"] = {"支持"}
|
||||
-- → env.pin_cands["zhic"] = {"支持"}
|
||||
-- → env.pin_cands["zhich"] = {"支持"}
|
||||
--
|
||||
-- 如果同时定义了 'da zhuan 大专' 'da zhong 大众',会生成:
|
||||
-- env.pin_cands["dazhuan"] = {"大专"}
|
||||
-- env.pin_cands["dazhong"] = {"大众"}
|
||||
-- env.pin_cands["daz"] = {"大专", "大众"} -- 先写的排在前面
|
||||
-- env.pin_cands["dazh"] = {"大专", "大众"} -- 先写的排在前面
|
||||
--
|
||||
-- 如果同时定义了 'da zhuan 大专' 'da zhong 大众' 且明确定义了简码形式 'da z 打字',会生成:
|
||||
-- env.pin_cands["dazhuan"] = {"大专"}
|
||||
-- env.pin_cands["dazhong"] = {"大众"}
|
||||
-- env.pin_cands["daz"] = {"打字"} -- 明确定义的优先级更高
|
||||
-- env.pin_cands["dazh"] = {"大专", "大众"} -- 没明确定义的,仍然按上面的方式,先写的排在前面
|
||||
|
||||
env.pin_cands = {}
|
||||
for i = 0, list.size - 1 do
|
||||
local preedit, texts = list:get_value_at(i).value:match("([^\t]+)\t(.+)")
|
||||
if #preedit > 0 and #texts > 0 then
|
||||
-- 按照 " > " 或 " " 分割词汇
|
||||
local delimiter = "\0"
|
||||
if texts:find(" > ") then
|
||||
texts = texts:gsub(" > ", delimiter)
|
||||
else
|
||||
texts = texts:gsub(" ", delimiter)
|
||||
end
|
||||
|
||||
-- 按照键生成完整的拼写
|
||||
local preedit_no_spaces = preedit:gsub(" ", "")
|
||||
env.pin_cands[preedit_no_spaces] = {}
|
||||
for text in texts:gmatch("[^" .. delimiter .. "]+") do
|
||||
table.insert(env.pin_cands[preedit_no_spaces], text)
|
||||
end
|
||||
|
||||
-- 额外处理包含空格的 preedit,增加最后一个拼音的首字母和 zh, ch, sh 的简码
|
||||
if preedit:find(" ") then
|
||||
local preceding_part, last_part = preedit:match("^(.+)%s(%S+)$")
|
||||
local p1, p2 = "", ""
|
||||
-- p1 生成最后一个拼音的首字母简码拼写(最后一个空格后的首字母),如 ni hao 生成 nih
|
||||
p1 = preceding_part:gsub(" ", "") .. last_part:sub(1, 1)
|
||||
-- p2 生成最后一个拼音的 zh, ch, sh 的简码拼写(最后一个空格后以 zh ch sh 开头),如 zhi chi 生成 zhich
|
||||
if last_part:match("^[zcs]h") then
|
||||
p2 = preceding_part:gsub(" ", "") .. last_part:sub(1, 2)
|
||||
end
|
||||
for _, p in ipairs({ p1, p2 }) do
|
||||
-- 只在没有明确定义此简码时才生成,已有的追加,没有的直接赋值
|
||||
if p ~= "" and not set[p] then
|
||||
if env.pin_cands[p] ~= nil then
|
||||
for text in texts:gmatch("[^" .. delimiter .. "]+") do
|
||||
table.insert(env.pin_cands[p], text)
|
||||
end
|
||||
else
|
||||
env.pin_cands[p] = env.pin_cands[preedit_no_spaces]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.func(input, env)
|
||||
-- 当前输入框的 preedit,未经过方案 translator/preedit_format 转换
|
||||
-- 输入 nihaoshij 则为 nihaoshij,选择了「你好」后变成 你好shij
|
||||
local full_preedit = env.engine.context:get_preedit().text
|
||||
-- 非汉字部分的 preedit,如 shij
|
||||
local letter_only_preedit = string.gsub(full_preedit, "[^a-zA-Z]", "")
|
||||
|
||||
if env.pin_cands == nil or next(env.pin_cands) == nil or #letter_only_preedit == 0 then
|
||||
for cand in input:iter() do yield(cand) end
|
||||
return
|
||||
end
|
||||
|
||||
--[[
|
||||
full_preedit 与候选项的情况
|
||||
hao 好、号、毫 ... 哈、蛤、铪
|
||||
你hao 好、号、毫 ... 哈、蛤、铪
|
||||
haobu 好不、毫不 ... 好、号、毫 ... 哈、蛤、铪
|
||||
你haobu 好不、毫不 ... 好、号、毫 ... 哈、蛤、铪
|
||||
简化为 letter_only_preedit 与候选项的情况
|
||||
hao 好、号、毫 ... 哈、蛤、铪
|
||||
haobu 好不、毫不 ... 好、号、毫 ... 哈、蛤、铪
|
||||
|
||||
在循环中随着候选项的变化,cand.preedit 也跟着变化:
|
||||
| letter_only_preedit | cand.preedit |
|
||||
|---------------------|-----------------------------|
|
||||
| dian | dian ... di |
|
||||
| ha | ha |
|
||||
| hao | hao ... ha |
|
||||
| haobu | hao bu ... hao ... ha |
|
||||
--]]
|
||||
|
||||
-- 用 pined 和 others 调整顺序,找齐后先遍历 pined 再遍历 others
|
||||
local pined = {} -- 提升的候选项
|
||||
local others = {} -- 其余候选项
|
||||
local pined_count = 0
|
||||
|
||||
for cand in input:iter() do
|
||||
local preedit = cand.preedit:gsub(" ", "") -- 对比去掉空格的 cand.preedit
|
||||
local texts = env.pin_cands[preedit]
|
||||
|
||||
if texts == nil then
|
||||
-- 当前候选项无须排序,直接 yield 并结束循环
|
||||
-- 当前候选项正在排序,例如要置顶某个 `hao`,但从 `hao` 查到 `ha` 了还没找齐,不能直接 yield,要先输出 pined 和 others 中的 `hao`
|
||||
if letter_only_preedit == preedit then
|
||||
yield(cand)
|
||||
else
|
||||
table.insert(others, cand)
|
||||
end
|
||||
break
|
||||
else
|
||||
-- 给 pined 几个空字符串占位元素,后面直接 pined[idx] = cand 确保 pined 与 texts 顺序一致
|
||||
if #pined < #texts then
|
||||
for _ = 1, #texts do
|
||||
table.insert(pined, "")
|
||||
end
|
||||
end
|
||||
-- 要置顶的放到 pined 中,其余的放到 others
|
||||
local idx = find_index(texts, cand.text)
|
||||
if idx ~= 0 then
|
||||
pined[idx] = cand
|
||||
pined_count = pined_count + 1
|
||||
else
|
||||
table.insert(others, cand)
|
||||
end
|
||||
-- 找齐了或查询超过 100 个就不找了(如果要提升的候选项不在前 100 则不会被提升)
|
||||
if pined_count == #texts or #others > 100 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- yield pined others 及后续的候选项
|
||||
for _, cand in ipairs(pined) do
|
||||
if cand ~= "" then
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
for _, cand in ipairs(others) do
|
||||
yield(cand)
|
||||
end
|
||||
for cand in input:iter() do
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
114
lua/reduce_english_filter.lua
Normal file
114
lua/reduce_english_filter.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
-- 降低部分英语单词在候选项的位置,可在方案中配置要降低的模式和单词
|
||||
-- https://dvel.me/posts/make-rime-en-better/#短单词置顶的问题
|
||||
-- 感谢大佬 @[Shewer Lu](https://github.com/shewer) 指点
|
||||
-- Mintimate 修改:
|
||||
-- 1. 在不设置 mode 情况下,调整为默认全降模式(原本为 none 模式);
|
||||
-- 2. all 会合并默认全降内容和自定义内容。
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init(env)
|
||||
local config = env.engine.schema.config
|
||||
env.name_space = env.name_space:gsub("^*", "")
|
||||
|
||||
-- 要降低到的位置
|
||||
M.idx = config:get_int(env.name_space .. "/idx")
|
||||
|
||||
-- 所有 3~4 位长度、前 2~3 位是完整拼音、最后一位是声母的单词
|
||||
local all = { "aid", "aim", "air", "and", "ann", "ant", "any", "bad", "bag", "bail", "bait", "bam", "ban", "band",
|
||||
"bang", "bank", "bans", "bar", "bat", "bay", "bend", "benq", "bent", "benz", "bib", "bid", "bien", "big", "bin",
|
||||
"bind", "bit", "biz", "bob", "boc", "bop", "bos", "bot", "bow", "box", "boy", "bud", "buf", "bug", "bus",
|
||||
"but", "buy", "cab", "cad", "cain", "cam", "can", "cans", "cant", "cap", "car", "cat", "cef", "cen",
|
||||
"cent", "chad", "chan", "chap", "char", "chat", "chef", "chen", "cher", "chew", "chic", "chin", "chip", "chit",
|
||||
"coup", "cum", "cunt", "cup", "cur", "cut", "dab", "dad", "dag", "dal", "dam", "day", "def", "del", "den",
|
||||
"dent", "deny", "der", "dew", "dial", "did", "died", "dies", "diet", "dig", "dim", "din", "dip", "dir", "dis",
|
||||
"dit", "diy", "doug", "dub", "dug", "dun", "dunn", "don", "end", "err", "fab", "fan", "fans", "faq", "far", "fat",
|
||||
"fax", "fob", "fog", "for", "foul", "four", "fox", "fun", "fur", "gag", "gail", "gain", "gal", "gam", "gan",
|
||||
"gang", "gank", "gaol", "gap", "gas", "gay", "ged", "gel", "gem", "gen", "ger", "get", "guam", "guid", "gum",
|
||||
"gun", "guns", "gus", "gut", "guy", "had", "hail", "hair", "ham", "han", "hand", "hang", "hank", "hans", "has",
|
||||
"hat", "hay", "heil", "heir", "hem", "hen", "hep", "her", "hex", "hey", "hour", "hub", "hud", "hug", "huh",
|
||||
"hum", "hung", "hunk", "hunt", "hut", "jim", "jug", "junk", "kat", "kent", "key", "lab", "lad", "lag", "laid",
|
||||
"lam", "lan", "land", "lang", "laos", "lap", "lat", "law", "lax", "lay", "led", "leg", "len", "let", "lex",
|
||||
"liam", "liar", "lib", "lid", "lied", "lien", "lies", "ling", "link", "linn", "lip", "lit", "liz", "lob", "log",
|
||||
"lol", "lot", "loud", "low", "lug", "lund", "lung", "lux", "mac", "mad", "mag", "maid", "mail", "main", "man",
|
||||
"mann", "many", "map", "mar", "mat", "max", "may", "med", "mel", "men", "mend", "mens", "ment", "met", "mic",
|
||||
"mid", "mil", "min", "mind", "ming", "mins", "mint", "mit", "mix", "mob", "moc", "mod", "mom", "mop", "mos",
|
||||
"mot", "mud", "mug", "mum", "nad", "nail", "nan", "nap", "nas", "nat", "nay", "neil", "net", "new", "nib", "nil",
|
||||
"nip", "noun", "nous", "nun", "nut", "nvm", "our", "out", "pac", "pad", "paid", "pail", "pain", "pair", "pak", "pal",
|
||||
"pam", "pan", "pans", "pant", "pap", "par", "pat", "paw", "pax", "pay", "pens", "pic", "pier", "pies", "pig",
|
||||
"pin", "ping", "pink", "pins", "pint", "pit", "pix", "pod", "pop", "por", "pos", "pot", "pour", "pow", "pub",
|
||||
"put", "rand", "rang", "rank", "rant", "red", "rent", "rep", "res", "ret", "rex", "rib", "rid", "rig", "rim",
|
||||
"rip", "rub", "rug", "ruin", "rum", "run", "runc", "runs", "sac", "sad", "said", "sail", "sal", "sam", "san",
|
||||
"sand", "sang", "sans", "sap", "sat", "saw", "sax", "say", "sec", "send", "sent", "set", "sew", "sex", "sham",
|
||||
"shaw", "shed", "shin", "ship", "shit", "shut", "sig", "sim", "sin", "sip", "sir", "sis", "sit", "six", "soul",
|
||||
"soup", "sour", "sub", "suit", "sum", "sun", "sung", "suns", "sup", "sur", "sus", "tab", "tad", "tag", "tail",
|
||||
"taj", "tan", "tang", "tank", "tap", "tar", "tax", "tec", "ted", "tel", "ten", "ter", "tex", "tic", "tied",
|
||||
"tier", "ties", "tim", "tin", "tip", "tit", "tour", "tout", "tum", "wag", "wait", "wail", "wan", "wand", "womens",
|
||||
"want", "wap", "war", "was", "wax", "way", "weir", "went", "won", "wow", "yan", "yang", "yen", "yep", "yes",
|
||||
"yet", "yin", "your", "yum", "zen", "zip",
|
||||
-- 后面是 zh ch sh 的
|
||||
"bach", "bash", "bench", "bush", "cash", "couch", "dash", "dish", "hash", "hush", "lash", "loch", "lunch",
|
||||
"lush", "mesh", "much", "nash", "pinch", "pouch", "push", "ranch", "rich", "rush", "such", "tech", "touch",
|
||||
"wash", "zach",
|
||||
-- 其他
|
||||
"eg",
|
||||
"my", "mt", "dj", "as", "js", "cs", "ak", "ps", "cd", "cn", "hk", "bt", "pk", "ml"
|
||||
}
|
||||
M.all = {}
|
||||
for _, v in ipairs(all) do
|
||||
M.all[v] = true
|
||||
end
|
||||
|
||||
-- 自定义
|
||||
M.words = {}
|
||||
local list = config:get_list(env.name_space .. "/words")
|
||||
local listSize = list and list.size or 0
|
||||
for i = 0, listSize - 1 do
|
||||
local word = list:get_value_at(i).value
|
||||
M.words[word] = true
|
||||
end
|
||||
|
||||
-- 模式
|
||||
local mode = config:get_string(env.name_space .. "/mode")
|
||||
if mode == "custom" then
|
||||
M.map = M.words
|
||||
elseif mode == "none" then
|
||||
M.map = {}
|
||||
else -- 默认 mode 为 all 且合并 M.all 和 words
|
||||
for key in pairs(M.words) do
|
||||
M.all[key] = true
|
||||
end
|
||||
M.map = M.all
|
||||
end
|
||||
end
|
||||
|
||||
function M.func(input, env)
|
||||
-- filter start
|
||||
local code = env.engine.context.input
|
||||
if M.map[code] then
|
||||
local pending_cands = {}
|
||||
local index = 0
|
||||
for cand in input:iter() do
|
||||
index = index + 1
|
||||
-- 找到要降低的英文词,加入 pending_cands
|
||||
if cand.preedit:find(" ") or not cand.text:match("[a-zA-Z]") or cand.type == "user_table" then
|
||||
yield(cand)
|
||||
else
|
||||
table.insert(pending_cands, cand)
|
||||
end
|
||||
if index >= M.idx + #pending_cands - 1 then
|
||||
for _, cand in ipairs(pending_cands) do
|
||||
yield(cand)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- yield other
|
||||
for cand in input:iter() do
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
311
lua/search.lua
Executable file
311
lua/search.lua
Executable file
@@ -0,0 +1,311 @@
|
||||
-- 辅码,https://github.com/mirtlecn/rime-radical-pinyin/blob/master/search.lua.md
|
||||
--
|
||||
-- Copyright (C) [Mirtle](https://github.com/mirtlecn)
|
||||
-- License: CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
-- 使用说明:<https://github.com/mirtlecn/rime-radical-pinyin/blob/master/search.lua.md>
|
||||
-- 处理 lua 中的特殊字符用于匹配
|
||||
local function alt_lua_punc( s )
|
||||
if s then
|
||||
return s:gsub( '([%.%+%-%*%?%[%]%^%$%(%)%%])', '%%%1' )
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end
|
||||
|
||||
-- 获取指定字符在文本中的位置
|
||||
local function get_pos( text, char )
|
||||
local pos = {}
|
||||
if text:find( char ) then
|
||||
local tmp = text
|
||||
for i = 1, utf8.len( tmp ) do
|
||||
local first_char = tmp:sub( 1, utf8.offset( tmp, 2 ) - 1 )
|
||||
if first_char == char then pos[i] = true end
|
||||
tmp = tmp:gsub( '^' .. first_char, '' )
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
-- 此函数用于手动写入用户词库,目前仅对双拼有效
|
||||
local function update_dict_entry( s, code, mem, proj )
|
||||
if #s == 0 or utf8.len( s ) == #s or (#code % 2 ~= 0) then
|
||||
log.info( '[search.lua]: Ignored' .. s )
|
||||
return 0
|
||||
end
|
||||
local e = DictEntry()
|
||||
s = s:gsub( '^%s+', '' ):gsub( '%s+$', '' )
|
||||
e.text = s
|
||||
|
||||
local pos = {}
|
||||
if s:find( '·' ) and (utf8.len( s ) > 1) then pos = get_pos( s, '·' ) end
|
||||
|
||||
local custom_code = {}
|
||||
local loop = 1
|
||||
for i = 1, #code, 2 do
|
||||
local code_convert = code:sub( i, i + 1 )
|
||||
local p = proj:apply( code_convert, true )
|
||||
if p and #p > 0 then code_convert = p end
|
||||
if code_convert == 'dian' and pos[loop] then
|
||||
-- Ignored
|
||||
else
|
||||
table.insert( custom_code, code_convert )
|
||||
end
|
||||
loop = loop + 1
|
||||
end
|
||||
|
||||
e.custom_code = table.concat( custom_code, ' ' ) .. ' '
|
||||
if mem.start_session then mem:start_session() end -- new on librime 2024.05
|
||||
mem:update_userdict( e, 1, '' )
|
||||
if mem.finish_session then mem:finish_session() end -- new on librime 2024.05
|
||||
end
|
||||
|
||||
-- 通过 schema 的方式查询(以辅码查字,然后对比候选,慢,但能够匹配到算法转换过的码)
|
||||
-- 查询方案中的匹配项,并返回字表
|
||||
local function dict_init( search_string, mem, search_limit, code_projection )
|
||||
local dict_table = {}
|
||||
if code_projection then
|
||||
-- old librime(<= 2023.06) do not return original string when apply failed
|
||||
local p = code_projection:apply( search_string, true )
|
||||
if p and #p > 0 then search_string = p end
|
||||
end
|
||||
if mem:dict_lookup( search_string, true, search_limit ) then
|
||||
for entry in mem:iter_dict() do dict_table[entry.text] = true end
|
||||
end
|
||||
return dict_table
|
||||
end
|
||||
|
||||
-- 匹配候选
|
||||
local function dict_match( table, text )
|
||||
if table[text] == true then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
-- 通过 reverse db 查询(以字查码,然后比对辅码是否相同,快,但只能匹配未经算法转换的码)
|
||||
local function reverse_lookup( code_projection, db_table, wildcard, text, s, global_match )
|
||||
if wildcard then s = s:gsub( wildcard, '.*' ) end
|
||||
if code_projection then
|
||||
-- old librime do not return original string when apply failed
|
||||
local p = code_projection:apply( s, true )
|
||||
if p and #p > 0 then s = p end
|
||||
end
|
||||
-- log.error(s)
|
||||
for _, db in ipairs( db_table ) do
|
||||
local code = db:lookup( text )
|
||||
if code and #code > 0 then
|
||||
for part in code:gmatch( '%S+' ) do
|
||||
if global_match then
|
||||
if part:find( s ) then return true end
|
||||
else
|
||||
if part:find( '^' .. s ) then return true end -- an error pointing at this line. do not know why. so I'll keep an eye.
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- 处理单字优先
|
||||
local function handle_long_cand( if_single_char_first, cand, long_word_cands )
|
||||
if if_single_char_first and utf8.len( cand.text ) > 1 then
|
||||
table.insert( long_word_cands, cand )
|
||||
else
|
||||
yield( cand )
|
||||
end
|
||||
end
|
||||
|
||||
local f = {}
|
||||
|
||||
function f.init( env )
|
||||
local config = env.engine.schema.config
|
||||
local ns = 'search'
|
||||
env.if_schema_lookup = false
|
||||
env.if_reverse_lookup = false
|
||||
|
||||
-- 配置:仅限 script_translator 引擎
|
||||
-- local engine = config:get_list( 'engine/translators' )
|
||||
-- local engine_table = {}
|
||||
-- for i = 0, engine.size - 1 do engine_table[engine:get_value_at( i ).value] = true end
|
||||
-- if not engine_table['script_translator'] then
|
||||
-- log.error( '[search.lua]: script_translator not found in engine/translators, search.lua will not work' )
|
||||
-- return
|
||||
-- end
|
||||
|
||||
-- 配置:辅码查字方法
|
||||
-- --
|
||||
-- 当在 engine 出直接指定了 namespace 则使用该 namespace 进行 schema 匹配
|
||||
-- 当在 search_in_cand 节点下指定了 schema 和 db 则进行相应匹配
|
||||
-- 当该节点下 schema 为 0 或者 false,或者不存在时,不进行相应匹配
|
||||
-- --
|
||||
local schema_name = config:get_string( ns .. '/schema' )
|
||||
if not env.name_space:find( '^%*' ) then schema_name = env.name_space end
|
||||
if not schema_name or schema_name == 'false' or schema_name == '0' or #schema_name == 0 then goto checkdb end
|
||||
env.search = Memory( env.engine, Schema( schema_name ) )
|
||||
if schema_name and env.search then
|
||||
env.if_schema_lookup = true
|
||||
env.search_limit = config:get_int( ns .. '/schema_search_limit' ) or 1000
|
||||
end
|
||||
|
||||
::checkdb::
|
||||
|
||||
local db = config:get_list( ns .. '/db' )
|
||||
if db and db.size > 0 then
|
||||
env.wildcard = alt_lua_punc( config:get_string( ns .. '/wildcard' ) ) or '*'
|
||||
env.db_table = {}
|
||||
for i = 0, db.size - 1 do table.insert( env.db_table, ReverseLookup( db:get_value_at( i ).value ) ) end
|
||||
env.if_reverse_lookup = true
|
||||
end
|
||||
if not env.if_reverse_lookup and not env.if_schema_lookup then return end
|
||||
|
||||
-- 配置:辅码转换规则
|
||||
-- --
|
||||
-- 例如:- xlit/ABCD/1234/ 就可以用 ABCD 来输入 1234(地球拼音音调)
|
||||
local fuma_format = config:get_list( ns .. '/fuma_format' )
|
||||
if fuma_format and fuma_format.size > 0 then
|
||||
env.code_projection = Projection()
|
||||
env.code_projection:load( fuma_format )
|
||||
else
|
||||
env.code_projection = nil
|
||||
end
|
||||
|
||||
-- 配置:是否显示不符合辅码的候选
|
||||
env.show_other_cands = config:get_bool( ns .. '/show_other_cands' )
|
||||
-- 配置:辅码引导符号,默认为反引号 `
|
||||
local search_key = config:get_string( 'key_binder/search' ) or config:get_string( ns .. '/key' ) or '`'
|
||||
env.search_key_alt = alt_lua_punc( search_key )
|
||||
local code_pattern = config:get_string( ns .. '/code_pattern' ) or '[a-z;]'
|
||||
|
||||
-- 配置:seg tag
|
||||
local tag = config:get_list( ns .. '/tags' )
|
||||
if tag and tag.size > 0 then
|
||||
env.tag = {}
|
||||
for i = 0, tag.size - 1 do table.insert( env.tag, tag:get_value_at( i ).value ) end
|
||||
else
|
||||
env.tag = { 'abc' }
|
||||
end
|
||||
|
||||
-- 配置:手动写入用户词库
|
||||
local rules = config:get_list( ns .. '/input2code_format' )
|
||||
if rules and rules.size > 0 then
|
||||
env.projection = Projection()
|
||||
env.projection:load( rules )
|
||||
env.mem = Memory( env.engine, env.engine.schema )
|
||||
end
|
||||
|
||||
-- 推入输入历史,并手动(如果设定了按键到编码的转换规则)写入用户词库
|
||||
env.commit_notifier = env.engine.context.commit_notifier:connect(
|
||||
function( ctx )
|
||||
if env.have_select_commit and env.commit_code then
|
||||
local commit_text = ctx:get_commit_text()
|
||||
if env.mem then
|
||||
update_dict_entry( commit_text, env.commit_code, env.mem, env.projection )
|
||||
end
|
||||
ctx.commit_history:push( 'search.lua', commit_text )
|
||||
env.have_select_commit = false
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
-- 接管选词逻辑,是词组则始终保留引导码,否则直接上屏
|
||||
env.notifier = env.engine.context.select_notifier:connect(
|
||||
function( ctx )
|
||||
local input = ctx.input
|
||||
local code = input:match( '^(.-)' .. env.search_key_alt )
|
||||
if (not code or #code == 0) then return end
|
||||
|
||||
local preedit = ctx:get_preedit()
|
||||
local no_search_string = ctx.input:match( '^(.-)' .. env.search_key_alt )
|
||||
local edit = preedit.text:match( '^(.-)' .. env.search_key_alt )
|
||||
env.have_select_commit = true
|
||||
|
||||
if edit and edit:match( code_pattern ) then
|
||||
ctx.input = no_search_string .. search_key
|
||||
else
|
||||
ctx.input = no_search_string
|
||||
env.commit_code = no_search_string
|
||||
ctx:commit()
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function f.func( input, env )
|
||||
-- 当且仅当当输入码中含有辅码引导符号,并有有辅码存在,进入匹配逻辑
|
||||
local code, fuma = env.engine.context.input:match( '^(.-)' .. env.search_key_alt .. '(.+)$' )
|
||||
if (not code or #code == 0) or (not fuma or #fuma == 0) or (not env.if_reverse_lookup and not env.if_schema_lookup) then
|
||||
for cand in input:iter() do yield( cand ) end
|
||||
return
|
||||
end
|
||||
|
||||
local if_single_char_first = env.engine.context:get_option( 'search_single_char' )
|
||||
local dict_table
|
||||
local fuma_2
|
||||
local other_cand = {}
|
||||
local long_word_cands = {}
|
||||
if env.if_schema_lookup then dict_table = dict_init( fuma, env.search, env.search_limit, env.code_projection ) end
|
||||
|
||||
if fuma:find( env.search_key_alt ) then fuma, fuma_2 = fuma:match( '^(.-)' .. env.search_key_alt .. '(.*)$' ) end
|
||||
|
||||
for cand in input:iter() do
|
||||
if cand.type == 'sentence' then goto skip end
|
||||
|
||||
local cand_text = cand.text
|
||||
local text = cand_text
|
||||
local text_2 = nil
|
||||
|
||||
-- 当候选多于一个字,则取第一个匹配
|
||||
if utf8.len( cand_text ) and utf8.len( cand_text ) > 1 then
|
||||
text = cand_text:sub( 1, utf8.offset( cand_text, 2 ) - 1 )
|
||||
local cand_text_2 = cand_text:gsub( '^' .. text, '' )
|
||||
text_2 = cand_text_2:sub( 1, utf8.offset( cand_text_2, 2 ) - 1 )
|
||||
end
|
||||
|
||||
if fuma_2 and #fuma_2 > 0 and env.if_reverse_lookup and not env.if_schema_lookup then
|
||||
if -- 第一个辅码匹配第一个字,第二个辅码正则匹配第一个字**或者**匹配第二个字
|
||||
reverse_lookup( env.code_projection, env.db_table, env.wildcard, text, fuma ) and
|
||||
((text_2 and reverse_lookup( env.code_projection, env.db_table, env.wildcard, text_2, fuma_2 )) or
|
||||
reverse_lookup( env.code_projection, env.db_table, env.wildcard, text, fuma_2, true )) then
|
||||
handle_long_cand( if_single_char_first, cand, long_word_cands )
|
||||
else
|
||||
table.insert( other_cand, cand )
|
||||
end
|
||||
else
|
||||
if -- 用辅码匹配第一个字
|
||||
(env.if_reverse_lookup and reverse_lookup( env.code_projection, env.db_table, env.wildcard, text, fuma )) or
|
||||
(env.if_schema_lookup and dict_match( dict_table, text )) then
|
||||
handle_long_cand( if_single_char_first, cand, long_word_cands )
|
||||
else
|
||||
table.insert( other_cand, cand )
|
||||
end
|
||||
end
|
||||
::skip::
|
||||
end
|
||||
|
||||
-- 上屏其余的候选
|
||||
for i, cand in ipairs( long_word_cands ) do yield( cand ) end
|
||||
if env.show_other_cands then for i, cand in ipairs( other_cand ) do yield( cand ) end end
|
||||
end
|
||||
|
||||
function f.tags_match( seg, env )
|
||||
for i, v in ipairs( env.tag ) do if seg.tags[v] then return true end end
|
||||
return false
|
||||
end
|
||||
|
||||
function f.fini( env )
|
||||
if env.if_reverse_lookup or env.if_schema_lookup then
|
||||
env.notifier:disconnect()
|
||||
env.commit_notifier:disconnect()
|
||||
if env.mem and env.mem.disconnect then env.mem:disconnect() end
|
||||
if env.search and env.search.disconnect then env.search:disconnect() end
|
||||
if env.mem or env.search or env.db_table then
|
||||
env.db_table = nil
|
||||
env.mem = nil
|
||||
env.search = nil
|
||||
collectgarbage( 'collect' )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return f
|
||||
50
lua/select_character.lua
Normal file
50
lua/select_character.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
-- 以词定字
|
||||
-- 原脚本 https://github.com/BlindingDark/rime-lua-select-character
|
||||
-- 删除了默认按键 [ ],和方括号翻页冲突,需要在 key_binder 下指定才能生效
|
||||
-- 20230526195910 不再错误地获取commit_text,而是直接获取get_selected_candidate().text
|
||||
-- 20240128141207 重写:将读取设置移动到 init 方法中;简化中文取字方法;预先判断候选存在与否,无候选取 input
|
||||
-- 20240508111725 当候选字数为 1 时,快捷键使该字上屏
|
||||
|
||||
local select = {}
|
||||
|
||||
function select.init(env)
|
||||
local config = env.engine.schema.config
|
||||
env.first_key = config:get_string('key_binder/select_first_character')
|
||||
env.last_key = config:get_string('key_binder/select_last_character')
|
||||
end
|
||||
|
||||
function select.func(key, env)
|
||||
local engine = env.engine
|
||||
local context = env.engine.context
|
||||
|
||||
if
|
||||
not key:release()
|
||||
and (context:is_composing() or context:has_menu())
|
||||
and (env.first_key or env.last_key)
|
||||
then
|
||||
local text = context.input
|
||||
if context:get_selected_candidate() then
|
||||
text = context:get_selected_candidate().text
|
||||
end
|
||||
if utf8.len(text) > 1 then
|
||||
if (key:repr() == env.first_key) then
|
||||
engine:commit_text(text:sub(1, utf8.offset(text, 2) - 1))
|
||||
context:clear()
|
||||
return 1
|
||||
elseif (key:repr() == env.last_key) then
|
||||
engine:commit_text(text:sub(utf8.offset(text, -1)))
|
||||
context:clear()
|
||||
return 1
|
||||
end
|
||||
else
|
||||
if key:repr() == env.first_key or key:repr() == env.last_key then
|
||||
engine:commit_text(text)
|
||||
context:clear()
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return 2
|
||||
end
|
||||
|
||||
return select
|
||||
18
lua/t9_preedit.lua
Normal file
18
lua/t9_preedit.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
-- 九宫格,将输入框的数字转为对应的拼音或英文,iRime 用,Hamster 不需要。
|
||||
-- 在 engine/filters 增加 - lua_filter@t9_preedit
|
||||
--
|
||||
-- 九宫格专用,iRime 用,仓输入法不用
|
||||
-- 拼写规则通过 xlit 转写: xlit/abcdefghijklmnopqrstuvwxyz/22233344455566677778889999/
|
||||
-- 然后通过此 Lua 将输入框的数字转为对应的拼音或英文
|
||||
local function t9_preedit(input, env)
|
||||
for cand in input:iter() do
|
||||
if (string.find(cand.text, "%w+") ~= nil) then
|
||||
cand:get_genuine().preedit = cand.text
|
||||
else
|
||||
cand:get_genuine().preedit = cand.comment
|
||||
end
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
|
||||
return t9_preedit
|
||||
36
lua/unicode.lua
Normal file
36
lua/unicode.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
-- Unicode
|
||||
-- 复制自: https://github.com/shewer/librime-lua-script/blob/main/lua/component/unicode.lua
|
||||
-- 示例:输入 U62fc 得到「拼」
|
||||
-- 触发前缀默认为 recognizer/patterns/unicode 的第 2 个字符,即 U
|
||||
-- 2024.02.26: 限定编码最大值
|
||||
-- 2024.06.01: 部分变量初始化,条件语句调整。
|
||||
|
||||
local path = 'recognizer/patterns/unicode'
|
||||
local function unicode(input, seg, env)
|
||||
if not seg:has_tag("unicode") or input == '' then return end
|
||||
-- 获取 recognizer/patterns/unicode 的第 2 个字符作为触发前缀
|
||||
-- config:get_string(path) 可能取得 nil 造成error
|
||||
if not env.unicode_keyword then
|
||||
local pattern = env.engine.schema.config:get_string(path) or "UU"
|
||||
env.unicode_keyword = pattern:sub(2,2)
|
||||
end
|
||||
|
||||
local ucodestr = input:match(env.unicode_keyword .. "(%x+)")
|
||||
if ucodestr and #ucodestr > 1 then
|
||||
local code = tonumber(ucodestr, 16)
|
||||
if code > 0x10FFFF then
|
||||
yield(Candidate("unicode", seg.start, seg._end, "数值超限!", ""))
|
||||
return
|
||||
end
|
||||
local text = utf8.char(code)
|
||||
yield(Candidate("unicode", seg.start, seg._end, text, string.format("U%x", code)))
|
||||
if code < 0x10000 then
|
||||
for i = 0, 15 do
|
||||
local text = utf8.char(code * 16 + i)
|
||||
yield(Candidate("unicode", seg.start, seg._end, text, string.format("U%x~%x", code, i)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return unicode
|
||||
32
lua/v_filter.lua
Normal file
32
lua/v_filter.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
-- v 模式,单个字符优先
|
||||
-- 因为设置了英文翻译器的 initial_quality 大于 1,导致输入「va」时,候选项是「van vain …… ā á ǎ à」
|
||||
-- 把候选项应改为「ā á ǎ à …… van vain」,让单个字符的排在前面
|
||||
-- 感谢改进 @[t123yh](https://github.com/t123yh) @[Shewer Lu](https://github.com/shewer)
|
||||
local function v_filter(input, env)
|
||||
local code = env.engine.context.input -- 当前编码
|
||||
env.v_spec_arr = env.v_spec_arr or Set({ "0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "Vs." })
|
||||
-- 仅当当前输入以 v 开头,并且编码长度为 2,才进行处理
|
||||
if (string.len(code) == 2 and string.find(code, "^v")) then
|
||||
local l = {}
|
||||
for cand in input:iter() do
|
||||
-- 特殊情况处理
|
||||
if (env.v_spec_arr[cand.text]) then
|
||||
yield(cand)
|
||||
-- 候选项为单个字符的,提到前面来。
|
||||
elseif (utf8.len(cand.text) == 1) then
|
||||
yield(cand)
|
||||
else
|
||||
table.insert(l, cand)
|
||||
end
|
||||
end
|
||||
for _, cand in ipairs(l) do
|
||||
yield(cand)
|
||||
end
|
||||
else
|
||||
for cand in input:iter() do
|
||||
yield(cand)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return v_filter
|
||||
Reference in New Issue
Block a user