rime-ice icon indicating copy to clipboard operation
rime-ice copied to clipboard

以词定字长句输入支持

Open WantChane opened this issue 6 months ago • 3 comments

摘要

为以词定字功能提供长句输入支持,给出了一个粗糙的实现。

输入方案

小鹤双拼 double_pinyin_flypy

相关应用

Weasel 0.16.3

系统信息

Windows 11

详细说明

现在的以词定字功能不支持长句输入。

例如:目标输出“你好世(界)我爱你”,同时输入所有字符( ni hao shi jie wo ai ni ),我理想的情况下候选词和选定操作依次为“你好” -> 1 -> “世界” -> [ -> "我爱你" -> 1。

在rime-ice中,按下 [ 后会输出“世”,你好和 wo ai ni 全部被覆盖。

BlindingDark/rime-lua-select-character中,按下 [ 后会输出“你好世”。wo ai ni 会被覆盖。

个人觉得挺影响打字操作的,所以修改了一下WantChane/rime-ice

图片

但是感觉我的实现还有优化空间,比如说以词选字的时候,可以模仿数字符上屏的功能,数字上屏的时候并不会出现上述文字被覆盖的情况,以词选字只需要修改被上屏的字即可。在PR之前想看看大伙有没有思路,一起讨论一下。

自定义配置

-- 以词定字
-- 原脚本 https://github.com/BlindingDark/rime-lua-select-character
-- 可在 default.yaml → key_binder 下配置快捷键,默认为左右中括号 [ ]
-- 20230526195910 不再错误地获取commit_text,而是直接获取get_selected_candidate().text
-- 20240128141207 重写:将读取设置移动到 init 方法中;简化中文取字方法;预先判断候选存在与否,无候选取 input
-- 20240508111725 当候选字数为 1 时,快捷键使该字上屏
-- 20250515093039 以词定字支持长句输入

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 candidate = context.input
        if context:get_selected_candidate() then
            candidate = context:get_selected_candidate().text
        end
        if utf8.len(candidate) > 1 then
            local selected = ""
            if (key:repr() == env.first_key) then
                selected = candidate:sub(1, utf8.offset(candidate, 2) - 1)
            elseif (key:repr() == env.last_key) then
                selected = candidate:sub(utf8.offset(candidate, -1))
            else
                return 2
            end
            local committed = context:get_commit_text()
            local start_pos, end_pos = committed:find(candidate)
            if start_pos and end_pos then
                local part1 = committed:sub(1, end_pos):gsub(candidate, selected)
                local part2 = committed:sub(end_pos + 1)
                engine:commit_text(part1)
                context:clear()
                if part2 ~= "" then
                    context:push_input(part2)
                end
                return 1
            else
                return 2
            end
        else
            if key:repr() == env.first_key or key:repr() == env.last_key then
                engine:commit_text(candidate)
                context:clear()
                return 1
            end
        end
    end
    return 2
end

return select

WantChane avatar May 15 '25 02:05 WantChane

试了一下,非常好用,👍

netvolcano avatar May 15 '25 07:05 netvolcano

试了一下,非常好用,👍

你觉得当候选字数为 1 且还有未处理的输入时,以词定字该怎么处理?保留没有处理的部分比较好,还是舍弃掉比较好。

这个版本你也试试

-- 以词定字
-- 原脚本 https://github.com/BlindingDark/rime-lua-select-character
-- 可在 default.yaml → key_binder 下配置快捷键,默认为左右中括号 [ ]
-- 20230526195910 不再错误地获取commit_text,而是直接获取get_selected_candidate().text
-- 20240128141207 重写:将读取设置移动到 init 方法中;简化中文取字方法;预先判断候选存在与否,无候选取 input
-- 20240508111725 当候选字数为 1 时,快捷键使该字上屏
-- 20250515093039 以词定字支持长句输入
-- 20250516231523 当候选字数为 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 candidate = context.input
        if context:get_selected_candidate() then
            candidate = context:get_selected_candidate().text
        end
        local selected = ""
        if utf8.len(candidate) > 1 then
            if (key:repr() == env.first_key) then
                selected = candidate:sub(1, utf8.offset(candidate, 2) - 1)
            elseif (key:repr() == env.last_key) then
                selected = candidate:sub(utf8.offset(candidate, -1))
            else
                return 2
            end
        else
            if key:repr() == env.first_key or key:repr() == env.last_key then
                selected = candidate
            else
                return 2
            end
        end
        local committed = context:get_commit_text()
        local start_pos, end_pos = committed:find(candidate)
        if start_pos and end_pos then
            local part1 = committed:sub(1, end_pos):gsub(candidate, selected)
            local part2 = committed:sub(end_pos + 1)
            engine:commit_text(part1)
            context:clear()
            if part2 ~= "" then
                context:push_input(part2)
            end
            return 1
        else
            return 2
        end
    end
    return 2
end

return select

WantChane avatar May 16 '25 15:05 WantChane

修复了光标位置不在 input 末尾的情况下,导致光标右侧部分被清除的bug

https://github.com/WantChane/rime-ice/blob/2829984e37f0e64d66e4d432cb1fb8823e72a079/lua/select_character.lua#L9-L60

WantChane avatar May 24 '25 07:05 WantChane

ni hao shi jie wo ai ni

Image

shackleyu avatar Jul 05 '25 01:07 shackleyu

ni hao shi jie wo ai ni Image

请问你想表达什么?是不是没有看清我的例子?

WantChane avatar Jul 05 '25 14:07 WantChane