mirror of
https://github.com/d0zingcat/rime_wanxiang.git
synced 2026-05-13 15:10:03 +00:00
141 lines
4.6 KiB
Lua
141 lines
4.6 KiB
Lua
-- 欢迎使用万象拼音方案
|
||
-- @amzxyz
|
||
-- https://github.com/amzxyz/rime_wanxiang
|
||
-- 用来在声调辅助的时候当你输入 2 个数字的时候自动将声调替换为第二个数字,
|
||
-- 也就是说你发现输入错误声调你可以手动轮巡输入而不用回退删除直接输入下一个即可
|
||
-- 兼容小键盘输入中不回退
|
||
|
||
local wanxiang = require("wanxiang")
|
||
|
||
-- 将目标字符的连续段压缩为“最后一个字符”
|
||
local function compress_runs_keep_last(text)
|
||
local changed = false
|
||
local out = text:gsub('([7890])([7890]+)', function(_, tail)
|
||
changed = true
|
||
return tail:sub(-1)
|
||
end)
|
||
return out, changed
|
||
end
|
||
|
||
local function should_ignore(ctx)
|
||
return wanxiang.is_function_mode_active(ctx) or ctx.input == ""
|
||
end
|
||
|
||
-- 小键盘 keycode 判定(0xFFB0 ~ 0xFFB9)
|
||
local function is_kp_digit_keycode(kc)
|
||
return kc >= 0xFFB0 and kc <= 0xFFB9
|
||
end
|
||
|
||
---@class Env
|
||
---@field tone_state "idle"|"skip"|"compress"
|
||
---@field tone_fallback_update_connection Connection|nil
|
||
|
||
local P = {}
|
||
|
||
function P.init(env)
|
||
env.tone_state = "idle"
|
||
local config = env.engine.schema.config
|
||
env.lookup_key = config:get_string('wanxiang_lookup/key') or '`'
|
||
local ctx = env.engine and env.engine.context
|
||
if not ctx or not ctx.update_notifier then return end
|
||
|
||
env.tone_fallback_update_connection = ctx.update_notifier:connect(function(c)
|
||
if should_ignore(c) then
|
||
env.tone_state = "idle"
|
||
return
|
||
end
|
||
|
||
-- 只在当前按键对应的一次更新里消费 state
|
||
local state = env.tone_state or "idle"
|
||
env.tone_state = "idle" -- 立刻消费,避免“下一次才生效”
|
||
|
||
-- 小键盘数字:标记为 skip,本次直接不压缩
|
||
if state == "skip" then
|
||
return
|
||
end
|
||
|
||
-- 非压缩状态:直接不动
|
||
if state ~= "compress" then
|
||
return
|
||
end
|
||
|
||
-- 压缩逻辑
|
||
local input = c.input
|
||
local caret = (c.caret_pos ~= nil) and c.caret_pos or #input
|
||
if caret < 0 then caret = 0 end
|
||
if caret > #input then caret = #input end
|
||
|
||
-- 仅处理光标左侧;右侧保持不变
|
||
local left = (caret > 0) and input:sub(1, caret) or ""
|
||
local right = (caret < #input) and input:sub(caret + 1) or ""
|
||
|
||
local left_new, changed = compress_runs_keep_last(left)
|
||
if not changed then return end
|
||
|
||
-- 只改左侧,避免干扰右侧;并精确设置 caret_pos
|
||
if caret > 0 then c:pop_input(caret) end
|
||
if #left_new > 0 then c:push_input(left_new) end
|
||
if c.caret_pos ~= nil then c.caret_pos = #left_new end
|
||
-- 右侧 right 不需处理,Rime 会保持不变
|
||
end)
|
||
end
|
||
|
||
function P.fini(env)
|
||
if env.tone_fallback_update_connection then
|
||
env.tone_fallback_update_connection:disconnect()
|
||
env.tone_fallback_update_connection = nil
|
||
end
|
||
env.tone_state = "idle"
|
||
end
|
||
|
||
---@return ProcessResult
|
||
function P.func(key, env)
|
||
local ctx = env.engine.context
|
||
if should_ignore(ctx) then
|
||
env.tone_state = "idle"
|
||
return wanxiang.RIME_PROCESS_RESULTS.kNoop
|
||
end
|
||
|
||
-- 小键盘数字:标记这次按键为 skip,本轮 update_notifier 不压缩
|
||
local kc = key.keycode
|
||
if is_kp_digit_keycode(kc) then
|
||
env.tone_state = "skip"
|
||
return wanxiang.RIME_PROCESS_RESULTS.kNoop
|
||
end
|
||
|
||
-- 主键盘数字 0–9:标记为 compress
|
||
local r = key:repr() or ""
|
||
if r:match("^[0-9]$") then
|
||
local input = ctx.input or ""
|
||
local caret = (ctx.caret_pos ~= nil) and ctx.caret_pos or #input
|
||
if caret < 0 then caret = 0 end
|
||
if caret > #input then caret = #input end
|
||
local left = (caret > 0) and input:sub(1, caret) or ""
|
||
|
||
if left:find(env.lookup_key, 1, true) then
|
||
env.tone_state = "idle"
|
||
return wanxiang.RIME_PROCESS_RESULTS.kNoop
|
||
end
|
||
|
||
env.tone_state = "compress"
|
||
|
||
-- 这里用“预测压缩是否会发生”来决定要不要告诉 Rime “我处理了这个按键”
|
||
local input = ctx.input or ""
|
||
local caret = (ctx.caret_pos ~= nil) and ctx.caret_pos or #input
|
||
if caret < 0 then caret = 0 end
|
||
if caret > #input then caret = #input end
|
||
|
||
local left = (caret > 0) and input:sub(1, caret) or ""
|
||
local _, changed = compress_runs_keep_last(left)
|
||
|
||
return changed and wanxiang.RIME_PROCESS_RESULTS.kAccepted
|
||
or wanxiang.RIME_PROCESS_RESULTS.kNoop
|
||
end
|
||
|
||
-- 其它按键:不触发压缩,也不跳过
|
||
env.tone_state = "idle"
|
||
return wanxiang.RIME_PROCESS_RESULTS.kNoop
|
||
end
|
||
|
||
return P
|