Files
rime_wanxiang/lua/limit_repeated.lua
2026-01-21 17:43:36 +08:00

61 lines
2.0 KiB
Lua

-- 用于限制最大候选数量以及重复最大输入编码,防止卡顿性能异常
--@amzxyz
--https://github.com/amzxyz
local M = {}
local ACCEPT, PASS = 1, 2
local MAX_REPEAT = 8 -- 连续重复输入声母上限
local MAX_SEGMENTS = 40 -- 允许的最大“分段”数
local INITIALS = "[bpmfdtnlgkhjqxrzcsywiu]"
-- 计算末尾重复
local function tail_rep(s)
local last, n = s:sub(-1), 1
for i = #s - 1, 1, -1 do
if s:sub(i, i) == last then n = n + 1 else break end
end
return last, n
end
-- 在候选栏最后一个 segment 加提示
local function prompt(ctx, msg)
local comp = ctx.composition
if comp and not comp:empty() then comp:back().prompt = msg end
end
function M.func(key, env)
local ctx, kc = env.engine.context, key.keycode
-- 先拿到“上一轮”高亮候选的 preedit 及段数
local cand = ctx:get_selected_candidate()
local preedit = cand and (cand.preedit or cand:get_genuine().preedit) or ""
local segs = 1
for _ in preedit:gmatch("[%'%s]") do segs = segs + 1 end
-- 本次按键字符(只关心字母 / 分隔符)
local ch
if kc >= 0x61 and kc <= 0x7A then -- a~z
ch = string.char(kc)
elseif kc == 0x27 then -- '
ch = "'"
elseif kc == 0x20 then -- space
ch = " "
end
-- ① 连续声母限制:第 MAX_REPEAT 个同声母直接拦截
if ch and kc >= 0x61 and kc <= 0x7A then
local nxt = ctx.input .. ch
local last, rep_n = tail_rep(nxt)
if last:match(INITIALS) and rep_n > MAX_REPEAT then
prompt(ctx, " 〔已超最大重复声母〕")
return ACCEPT
end
end
-- ② 分段限制:第 MAX_SEGMENTS 段拦截
local segs_after = segs
if ch == "'" or ch == " " then segs_after = segs + 1 end
if segs_after >= MAX_SEGMENTS and kc >= 0x61 and kc <= 0x7A then
prompt(ctx, " 〔已超最大输入长度〕")
return ACCEPT
end
return PASS
end
return M