mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 16:03:20 +00:00
fix(ime): stop re-sending input that follows a shortened commit
The recorded composition extent tracks the preedit, so for any conversion engine it overshoots the commit it produced. Used as a floor it made the strict variant of the pending-input read exclude nothing, and the character typed straight after a commit went to the pty twice. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -88,7 +88,7 @@ index 497afcf535f3eaca00889525a77e15eb633ccd96..96d499b34605f860608382114c3fbdc0
|
||||
|
||||
export interface IBrowser {
|
||||
diff --git a/src/browser/input/CompositionHelper.ts b/src/browser/input/CompositionHelper.ts
|
||||
index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..163a1d4a18dba60fe7e80245306fb8c31bf97247 100644
|
||||
index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..665f5f81c56fc59d3bcbf19239ff93cbaea01f88 100644
|
||||
--- a/src/browser/input/CompositionHelper.ts
|
||||
+++ b/src/browser/input/CompositionHelper.ts
|
||||
@@ -12,6 +12,28 @@ interface IPosition {
|
||||
@@ -486,7 +486,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..163a1d4a18dba60fe7e80245306fb8c3
|
||||
|
||||
// Since composition* events happen before the changes take place in the textarea on most
|
||||
// browsers, use a setTimeout with 0ms time to allow the native compositionend event to
|
||||
@@ -172,35 +413,277 @@ export class CompositionHelper {
|
||||
@@ -172,35 +413,282 @@ export class CompositionHelper {
|
||||
// - The last compositionupdate event's data property does not always accurately describe
|
||||
// the character, a counter example being Korean where an ending consonsant can move to
|
||||
// the following character if the following input is a vowel.
|
||||
@@ -626,9 +626,14 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..163a1d4a18dba60fe7e80245306fb8c3
|
||||
+ ? value.length - pending.suffix.length
|
||||
+ : value.length;
|
||||
+ const compositionLength = (pending.endData || pending.compositionData).length;
|
||||
+ // position.end recorded the *preedit* extent, which overshoots for every conversion
|
||||
+ // engine: "nihao" commits "你好". Once the commit length is known it is the extent, not
|
||||
+ // a floor, or this excludes nothing and the caller re-sends the text that followed.
|
||||
+ const observedEnd = includeFollowingInput
|
||||
+ ? suffixEnd
|
||||
+ : Math.max(pending.position.end, start + compositionLength);
|
||||
+ : compositionLength > 0
|
||||
+ ? start + compositionLength
|
||||
+ : pending.position.end;
|
||||
+ return value.substring(start, Math.max(start, Math.min(suffixEnd, observedEnd)));
|
||||
+ }
|
||||
+
|
||||
@@ -791,7 +796,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..163a1d4a18dba60fe7e80245306fb8c3
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,21 +697,39 @@ export class CompositionHelper {
|
||||
@@ -214,21 +702,39 @@ export class CompositionHelper {
|
||||
return;
|
||||
}
|
||||
const oldValue = this._textarea.value;
|
||||
@@ -835,7 +840,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..163a1d4a18dba60fe7e80245306fb8c3
|
||||
this._coreService.triggerDataEvent(newValue, true);
|
||||
}
|
||||
|
||||
@@ -278,7 +779,8 @@ export class CompositionHelper {
|
||||
@@ -278,7 +784,8 @@ export class CompositionHelper {
|
||||
}
|
||||
|
||||
if (!dontRecurse) {
|
||||
|
||||
Generated
+24
-24
@@ -19,7 +19,7 @@ patchedDependencies:
|
||||
hash: 6da7d7770b6427246f2a0d057d97da418040e498068b41d0c2d3c6b20bf49258
|
||||
path: config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch
|
||||
'@xterm/xterm@6.1.0-beta.287':
|
||||
hash: d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79
|
||||
hash: ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8
|
||||
path: config/patches/@xterm__xterm@6.1.0-beta.287.patch
|
||||
node-pty@1.1.0:
|
||||
hash: 8fc49f17011b6611a5b8c00e83a6f12e14e75aada2b0ef26dc5393f8376d20e8
|
||||
@@ -46,7 +46,7 @@ importers:
|
||||
version: 2.5.6
|
||||
'@xterm/addon-serialize':
|
||||
specifier: 0.15.0-beta.287
|
||||
version: 0.15.0-beta.287(patch_hash=81575700d58b62f9262d302aa4ae43b445a6273d579cd75dd6729c8883011ab9)(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.15.0-beta.287(patch_hash=81575700d58b62f9262d302aa4ae43b445a6273d579cd75dd6729c8883011ab9)(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/headless':
|
||||
specifier: 6.1.0-beta.287
|
||||
version: 6.1.0-beta.287
|
||||
@@ -206,25 +206,25 @@ importers:
|
||||
version: 5.2.0(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
|
||||
'@xterm/addon-fit':
|
||||
specifier: 0.12.0-beta.287
|
||||
version: 0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/addon-ligatures':
|
||||
specifier: 0.11.0-beta.287
|
||||
version: 0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/addon-search':
|
||||
specifier: 0.17.0-beta.287
|
||||
version: 0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/addon-unicode11':
|
||||
specifier: 0.10.0-beta.287
|
||||
version: 0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/addon-web-links':
|
||||
specifier: 0.13.0-beta.287
|
||||
version: 0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/addon-webgl':
|
||||
specifier: 0.20.0-beta.286
|
||||
version: 0.20.0-beta.286(patch_hash=6da7d7770b6427246f2a0d057d97da418040e498068b41d0c2d3c6b20bf49258)(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))
|
||||
version: 0.20.0-beta.286(patch_hash=6da7d7770b6427246f2a0d057d97da418040e498068b41d0c2d3c6b20bf49258)(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))
|
||||
'@xterm/xterm':
|
||||
specifier: 6.1.0-beta.287
|
||||
version: 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
version: 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
@@ -9579,39 +9579,39 @@ snapshots:
|
||||
|
||||
'@xmldom/xmldom@0.8.13': {}
|
||||
|
||||
'@xterm/addon-fit@0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-fit@0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
|
||||
'@xterm/addon-ligatures@0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-ligatures@0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
lru-cache: 11.5.1
|
||||
opentype.js: 2.0.0
|
||||
|
||||
'@xterm/addon-search@0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-search@0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
|
||||
'@xterm/addon-serialize@0.15.0-beta.287(patch_hash=81575700d58b62f9262d302aa4ae43b445a6273d579cd75dd6729c8883011ab9)(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-serialize@0.15.0-beta.287(patch_hash=81575700d58b62f9262d302aa4ae43b445a6273d579cd75dd6729c8883011ab9)(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
|
||||
'@xterm/addon-unicode11@0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-unicode11@0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
|
||||
'@xterm/addon-web-links@0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-web-links@0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
|
||||
'@xterm/addon-webgl@0.20.0-beta.286(patch_hash=6da7d7770b6427246f2a0d057d97da418040e498068b41d0c2d3c6b20bf49258)(@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79))':
|
||||
'@xterm/addon-webgl@0.20.0-beta.286(patch_hash=6da7d7770b6427246f2a0d057d97da418040e498068b41d0c2d3c6b20bf49258)(@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)
|
||||
|
||||
'@xterm/headless@6.1.0-beta.287': {}
|
||||
|
||||
'@xterm/xterm@6.1.0-beta.287(patch_hash=d396b2ad603c28a2ec1ffbee3cbd23addb86649773d8f0fd8797b85518866a79)': {}
|
||||
'@xterm/xterm@6.1.0-beta.287(patch_hash=ce1849dd5ba96d7c29b487945d7b5986fc0b998f66804b2daccbae670c63b2c8)': {}
|
||||
|
||||
abbrev@4.0.0: {}
|
||||
|
||||
|
||||
+21
@@ -281,6 +281,27 @@ describe('xterm IME composition de-duplication', () => {
|
||||
terminal.dispose()
|
||||
})
|
||||
|
||||
// The cases above commit exactly what they composed, so the recorded preedit extent and
|
||||
// the commit length always agree. Every conversion engine breaks that: the preedit is
|
||||
// Latin keystrokes and the commit is shorter.
|
||||
it.each([
|
||||
['nihao', '你好', '.'],
|
||||
['hiragana', 'ひらがな', 'a'],
|
||||
['gks', '한', '1']
|
||||
])('excludes input typed after %s commits the shorter %s', async (preedit, commit, following) => {
|
||||
const { emitted, terminal, textarea } = openTerminal()
|
||||
startComposition(textarea, preedit)
|
||||
await nextEventLoop()
|
||||
|
||||
dispatchCompositionEvent(textarea, 'compositionend', commit)
|
||||
textarea.value = `${commit}${following}`
|
||||
dispatchComposedInput(textarea, { data: following, inputType: 'insertText' })
|
||||
await nextEventLoop()
|
||||
|
||||
expect(emitted.join('')).toBe(`${commit}${following}`)
|
||||
terminal.dispose()
|
||||
})
|
||||
|
||||
it('emits repeated Korean insertText within one composition exactly twice', async () => {
|
||||
const { emitted, terminal, textarea } = openTerminal()
|
||||
startComposition(textarea, '가가')
|
||||
|
||||
Reference in New Issue
Block a user