Skip to content

Commit e221ff8

Browse files
committed
fix(mixed): 顶码上屏首候选与 UI 候选框严格一致
HandleTopCode 改为复用 e.ConvertEx(UI 同款入口)取首候选,替代原先 委托 codetableEngine.ConvertEx + 手工 Shadow 重排的做法。 根因:码表子引擎 ConvertEx 末尾用 applyProtectTopN 把系统码表原始 top-N 回填到固定位置(保护五笔肌肉记忆),覆盖了 weight 排序;而 UI 的 convertMixed 路径在合并 boost 后重新按 weight 排序。两条路径首候选因此不同,导致顶码上屏 的词与候选框首选不一致。复用 e.ConvertEx 让顶码与 UI 走同一函数,自动对齐 boost / phrase tier / ProtectTopN / Shadow。
1 parent ed0d168 commit e221ff8

1 file changed

Lines changed: 20 additions & 24 deletions

File tree

  • wind_input/internal/engine/mixed

wind_input/internal/engine/mixed/mixed.go

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,10 @@ func (e *Engine) HandleEmptyCode(input string) (shouldClear bool, toEnglish bool
233233
// HandleTopCode 处理顶码
234234
// 混输模式下:先检查前 maxCodeLen 码是否构成合法拼音序列,
235235
// 若是则抑制顶码(用户可能在输入拼音,如 yans→yan+se=颜色);
236-
// 若不是合法拼音(如 rcqn)则走完整候选流水线后应用 Shadow 规则再取首选上屏
236+
// 若不是合法拼音(如 rcqn)则走与 UI 相同的转换路径取首选上屏
237237
//
238-
// 注意:不能直接委托 codetableEngine.HandleTopCode,因为码表子引擎在混输模式下
239-
// 设置了 SkipShadow=true,其 ConvertEx 会跳过 Phase 6,导致用户通过候选调整
240-
// 置顶的词条(Shadow pin)无法生效,顶码上屏的仍是原始首候选而非调整后首候选。
238+
// 关键:顶码上屏的首候选必须与用户看到的候选框首选严格一致,因此直接复用
239+
// e.ConvertEx(UI 同款入口),而非委托 codetableEngine 或手工重排。详见下方实现注释。
241240
func (e *Engine) HandleTopCode(input string) (commitText string, newInput string, shouldCommit bool) {
242241
if len(input) <= e.maxCodeLen {
243242
return "", input, false
@@ -266,31 +265,28 @@ func (e *Engine) HandleTopCode(input string) (commitText string, newInput string
266265
return "", input, false
267266
}
268267

269-
// 取前 N 码,获取全量候选(maxCandidates=0 不截断),再由本层应用 Shadow
268+
// 取前 N 码,走与 UI 展示完全相同的转换路径(e.ConvertEx),确保顶码上屏的
269+
// 首候选 == 用户输入该前缀时候选框看到的首候选。
270+
//
271+
// 不能直接用 codetableEngine.ConvertEx 的输出顺序:码表子引擎 ConvertEx 在最终
272+
// 排序后会用 applyProtectTopN 把"系统码表原始 top-N"回填到固定位置(保护五笔
273+
// 肌肉记忆),覆盖按 weight 的排序;而 UI 的 convertMixed 路径在合并 +10M boost
274+
// 后重新按 weight 排序,破坏了 ProtectTopN。两条路径首候选不同。手工补排也不行
275+
// (缺少 boost/phrase tier/拼音合并,edge case 仍会与 UI 漂移)。复用 e.ConvertEx
276+
// 让顶码与 UI 走同一函数,自动对齐 boost/tier/ProtectTopN/Shadow。
277+
//
278+
// prefix 长度恒等于 maxCodeLen,ConvertEx 分支必然落到 convertMixed(2~maxCodeLen
279+
// 码),即用户输入到第 maxCodeLen 码时候选框所展示的同一结果。
270280
prefix := input[:e.maxCodeLen]
271-
result := e.codetableEngine.ConvertEx(prefix, 0)
272-
e.logger.Debug("HandleTopCode", "prefix", prefix, "candidates", len(result.Candidates))
273-
274-
if len(result.Candidates) == 0 {
281+
convResult := e.ConvertEx(prefix, 0)
282+
if len(convResult.Candidates) == 0 {
275283
e.logger.Debug("HandleTopCode: no candidates found", "prefix", prefix)
276284
return "", input, false
277285
}
278286

279-
candidates := result.Candidates
280-
// 应用 Shadow 规则(置顶/删除),与 convertCodetableOnly 保持一致
281-
if e.dictManager != nil {
282-
if shadowLayer := e.dictManager.GetShadowProvider(); shadowLayer != nil {
283-
rules := shadowLayer.GetShadowRules(prefix)
284-
candidates = dict.ApplyShadowPins(candidates, rules)
285-
}
286-
}
287-
288-
if len(candidates) == 0 {
289-
return "", input, false
290-
}
291-
292-
e.logger.Debug("HandleTopCode commit", "commit", candidates[0].Text, "newInput", input[e.maxCodeLen:])
293-
return candidates[0].Text, input[e.maxCodeLen:], true
287+
commitText = convResult.Candidates[0].Text
288+
e.logger.Debug("HandleTopCode commit", "commit", commitText, "newInput", input[e.maxCodeLen:])
289+
return commitText, input[e.maxCodeLen:], true
294290
}
295291

296292
// isPossiblePinyinSequence 判断输入是否构成合法的拼音序列。

0 commit comments

Comments
 (0)