mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-11 01:39:41 +02:00
fix(terminal): #541 landing fixes
A composition that ends in the same task as an Enter keydown was sent twice. The keydown settled the pending edit (sending the composed word and setting _dataAlreadySent), then xterm's own keydown finalized the composition synchronously through _finalizeComposition(false), which ignores _dataAlreadySent and sent the word again. settleEdit() now takes the keydown event and, while xterm has a composition in flight (_isSendingComposition), leaves the text to xterm for any key that makes it finalize synchronously. On 229, CapsLock and the modifiers xterm keeps the composition on its async path, which honours _dataAlreadySent, so the edit still applies there. The waiting timers are cleared before that early return, so a timer cannot fire after Enter's textarea clear and send a run of DELs. The guard sits in settleEdit(), not in applyEdit() as the bot proposed. In applyEdit() it would also silence the timer path, where xterm always finalizes asynchronously and skips _dataAlreadySent, so a non-composing character typed just before a composition (the x in xword) would be lost where master and the PR head both deliver it. Two unit tests pin it, both measured: one fails without the guard (the Enter keydown sends 'ab word' instead of 'ab '), and one fails with the guard moved into applyEdit() (the timer path sends 'ab ' instead of 'ab xword'; a 229 settle must also still send the edit). The xterm private-API guard test now also checks the bundle still ships _isSendingComposition, and names it in its failure message and comment. CLAUDE.md: the surviving #441 sentence said a keydown decides before xterm's 229 rescue has run and that Enter's clear makes the pending diff emit nothing. Neither holds any more (the edit diff is settled first, and master already sent one DEL there), so it now says the edit diff is settled first at that keydown. The PR's sentence notes the composition exception. The PR's own changeset is removed; its text goes into the single combined release changeset. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -180,7 +180,7 @@
|
||||
// It also has to happen BEFORE xterm handles THIS key: for Enter, xterm clears the textarea
|
||||
// in its own keydown, and a timer left pending would then diff the whole line against ''
|
||||
// and send one DEL per character ahead of the submitted line.
|
||||
settleEdit();
|
||||
settleEdit(event);
|
||||
flushPending();
|
||||
keydownSnapshot = canonicalCount;
|
||||
}
|
||||
@@ -266,7 +266,7 @@
|
||||
};
|
||||
|
||||
// Apply the pending edit NOW instead of on its timer (see handleKeyEvent).
|
||||
settleEdit = () => {
|
||||
settleEdit = (event) => {
|
||||
if (waiting.size === 0) return;
|
||||
for (const entry of waiting) {
|
||||
try {
|
||||
@@ -275,7 +275,16 @@
|
||||
// A broken timer host must not break input handling.
|
||||
}
|
||||
}
|
||||
// Cleared BEFORE the return below, on purpose: left pending, the timer would fire after
|
||||
// Enter clears the textarea and send one DEL per character ahead of the submitted line.
|
||||
waiting.clear();
|
||||
// A composition just ended and this key makes xterm finalize it SYNCHRONOUSLY, through
|
||||
// `_finalizeComposition(false)`, which ignores `_dataAlreadySent`: that text is xterm's, and
|
||||
// sending the edit too would deliver it twice. On 229, CapsLock and the modifiers xterm keeps
|
||||
// the composition on its async path, which honours `_dataAlreadySent`, so the edit still
|
||||
// applies there. Only this settle path is guarded: on the timer path xterm always finalizes
|
||||
// asynchronously, and skipping the edit there would drop a byte master delivers.
|
||||
if (helper._isSendingComposition && ![229, 20, 16, 17, 18].includes(event?.keyCode)) return;
|
||||
applyEdit();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user