mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 16:03:45 +00:00
fix(terminal): keep IME caret visible at row edge
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..946a95d3b87d68f0f0324b5d74346d3f3ff3710c 100644
|
||||
index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..af918fdac462a77517d9755bea3cb73aed97bfc4 100644
|
||||
--- a/src/browser/input/CompositionHelper.ts
|
||||
+++ b/src/browser/input/CompositionHelper.ts
|
||||
@@ -3,8 +3,9 @@
|
||||
@@ -933,7 +933,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
this._dataAlreadySent = diff;
|
||||
|
||||
if (newValue.length > oldValue.length) {
|
||||
@@ -236,6 +831,130 @@ export class CompositionHelper {
|
||||
@@ -236,6 +831,133 @@ export class CompositionHelper {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -948,14 +948,14 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
+ this._resetCompositionView();
|
||||
+ return;
|
||||
+ }
|
||||
+ // Keep DOM order LTR; right alignment follows the insertion end for long compositions while
|
||||
+ // retaining the caret after the preedit.
|
||||
+ // Keep DOM order LTR so the insertion caret follows the preedit.
|
||||
+ const preeditText = `${data}`;
|
||||
+ this._compositionViewData = data;
|
||||
+ const doc = this._compositionView.ownerDocument;
|
||||
+ const preedit = doc.createElement('span');
|
||||
+ preedit.className = 'xterm-composition-preedit';
|
||||
+ // Underlined so the composing text stays distinguishable from the tail it pushed right.
|
||||
+ preedit.style.flexShrink = '0';
|
||||
+ preedit.style.textDecoration = 'underline';
|
||||
+ preedit.textContent = preeditText;
|
||||
+ const caret = doc.createElement('span');
|
||||
@@ -1024,6 +1024,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
+ caret.style.backgroundColor =
|
||||
+ this._themeService?.colors.cursor.css ?? theme?.cursor ?? theme?.foreground ?? '#FFF';
|
||||
+ caret.style.display = 'inline-block';
|
||||
+ caret.style.flexShrink = '0';
|
||||
+ caret.style.height = cellHeight + 'px';
|
||||
+ caret.style.marginLeft = -width + 'px';
|
||||
+ caret.style.verticalAlign = 'top';
|
||||
@@ -1037,6 +1038,8 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
+ this._compositionRemainderMasked = false;
|
||||
+ this._compositionCaret = undefined;
|
||||
+ this._compositionViewData = '';
|
||||
+ this._compositionView.style.display = '';
|
||||
+ this._compositionView.style.justifyContent = '';
|
||||
+ this._compositionView.style.textAlign = '';
|
||||
+ }
|
||||
+
|
||||
@@ -1064,7 +1067,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
/**
|
||||
* Positions the composition view on top of the cursor and the textarea just below it (so the
|
||||
* IME helper dialog is positioned correctly).
|
||||
@@ -243,10 +962,24 @@ export class CompositionHelper {
|
||||
@@ -243,10 +965,24 @@ export class CompositionHelper {
|
||||
* necessary as the IME events across browsers are not consistently triggered.
|
||||
*/
|
||||
public updateCompositionElements(dontRecurse?: boolean): void {
|
||||
@@ -1090,7 +1093,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
if (this._bufferService.buffer.isCursorInViewport) {
|
||||
const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1);
|
||||
|
||||
@@ -265,10 +998,21 @@ export class CompositionHelper {
|
||||
@@ -265,10 +1001,23 @@ export class CompositionHelper {
|
||||
const maxWidth = this._bufferService.cols * this._renderService.dimensions.css.cell.width - cursorLeft;
|
||||
this._compositionView.style.maxWidth = maxWidth + 'px';
|
||||
this._compositionView.style.overflow = 'hidden';
|
||||
@@ -1098,10 +1101,12 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
- // Sync the textarea to the exact position of the composition view so the IME knows where the
|
||||
- // text is.
|
||||
- const compositionViewBounds = this._compositionView.getBoundingClientRect();
|
||||
+ // Keep DOM order as preedit, caret, tail. At the right edge, right alignment clips the start
|
||||
+ // of a long preedit while retaining its insertion caret, matching xterm's former rtl trick.
|
||||
+ // End-aligned flex keeps an over-wide trailing preedit's caret inside the screen.
|
||||
+ const hasRemainder = Boolean(this._compositionRemainder);
|
||||
+ this._compositionView.style.direction = 'ltr';
|
||||
+ this._compositionView.style.textAlign = this._compositionRemainder ? 'left' : 'right';
|
||||
+ this._compositionView.style.display = hasRemainder ? '' : 'flex';
|
||||
+ this._compositionView.style.justifyContent = hasRemainder ? '' : 'flex-end';
|
||||
+ this._compositionView.style.textAlign = hasRemainder ? 'left' : '';
|
||||
+ // Themed rather than the stock #000/#FFF, so the pushed tail reads as ordinary terminal text
|
||||
+ // and light themes keep contrast.
|
||||
+ this._compositionView.style.background = this._opaqueViewBackground();
|
||||
@@ -1116,7 +1121,7 @@ index c9ec396ab66cb966d49aa63bed09cdf9cd6c4246..946a95d3b87d68f0f0324b5d74346d3f
|
||||
this._textarea.style.left = cursorLeft + 'px';
|
||||
this._textarea.style.top = cursorTop + 'px';
|
||||
// Ensure the text area is at least 1x1, otherwise certain IMEs may break
|
||||
@@ -278,7 +1022,8 @@ export class CompositionHelper {
|
||||
@@ -278,7 +1027,8 @@ export class CompositionHelper {
|
||||
}
|
||||
|
||||
if (!dontRecurse) {
|
||||
|
||||
Generated
+24
-24
@@ -21,7 +21,7 @@ patchedDependencies:
|
||||
hash: 118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91
|
||||
path: config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch
|
||||
'@xterm/xterm@6.1.0-beta.287':
|
||||
hash: 8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68
|
||||
hash: 76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b
|
||||
path: config/patches/@xterm__xterm@6.1.0-beta.287.patch
|
||||
lint-staged@16.4.0:
|
||||
hash: 7333b3837f80a7fbd045964db6d76ba4fc118e49134bdbabb00585b6b7b60673
|
||||
@@ -51,7 +51,7 @@ importers:
|
||||
version: 2.5.6
|
||||
'@xterm/addon-serialize':
|
||||
specifier: 0.15.0-beta.287
|
||||
version: 0.15.0-beta.287(patch_hash=af3b156143ed2ee9903b753145b63dd4a2ee72cadd7ef333ab0f4d5d3ebfc32c)(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.15.0-beta.287(patch_hash=af3b156143ed2ee9903b753145b63dd4a2ee72cadd7ef333ab0f4d5d3ebfc32c)(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@xterm/headless':
|
||||
specifier: 6.1.0-beta.287
|
||||
version: 6.1.0-beta.287
|
||||
@@ -220,25 +220,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=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@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=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@xterm/addon-search':
|
||||
specifier: 0.17.0-beta.287
|
||||
version: 0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@xterm/addon-unicode11':
|
||||
specifier: 0.10.0-beta.287
|
||||
version: 0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@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=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@xterm/addon-webgl':
|
||||
specifier: 0.20.0-beta.286
|
||||
version: 0.20.0-beta.286(patch_hash=118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))
|
||||
version: 0.20.0-beta.286(patch_hash=118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))
|
||||
'@xterm/xterm':
|
||||
specifier: 6.1.0-beta.287
|
||||
version: 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
version: 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
@@ -9624,39 +9624,39 @@ snapshots:
|
||||
|
||||
'@xmldom/xmldom@0.8.13': {}
|
||||
|
||||
'@xterm/addon-fit@0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-fit@0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
|
||||
'@xterm/addon-ligatures@0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-ligatures@0.11.0-beta.287(patch_hash=47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920)(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
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=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-search@0.17.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
|
||||
'@xterm/addon-serialize@0.15.0-beta.287(patch_hash=af3b156143ed2ee9903b753145b63dd4a2ee72cadd7ef333ab0f4d5d3ebfc32c)(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-serialize@0.15.0-beta.287(patch_hash=af3b156143ed2ee9903b753145b63dd4a2ee72cadd7ef333ab0f4d5d3ebfc32c)(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
|
||||
'@xterm/addon-unicode11@0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-unicode11@0.10.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
|
||||
'@xterm/addon-web-links@0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-web-links@0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
|
||||
'@xterm/addon-webgl@0.20.0-beta.286(patch_hash=118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68))':
|
||||
'@xterm/addon-webgl@0.20.0-beta.286(patch_hash=118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)
|
||||
'@xterm/xterm': 6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)
|
||||
|
||||
'@xterm/headless@6.1.0-beta.287': {}
|
||||
|
||||
'@xterm/xterm@6.1.0-beta.287(patch_hash=8ed744c9ce7594ef00062494dc54c59abaf4c71bb892a268b4e109890b363c68)': {}
|
||||
'@xterm/xterm@6.1.0-beta.287(patch_hash=76a05b8d4afb40b6f39a428e6192f9dccc781b376928459331eb04a194f6842b)': {}
|
||||
|
||||
abbrev@4.0.0: {}
|
||||
|
||||
|
||||
+14
-2
@@ -183,6 +183,9 @@ describe('mid-line composition renders the covered row tail after the preedit',
|
||||
expect(remainder!.textContent).toBe('하세요')
|
||||
// Start-anchored so the preedit stays put and the pushed tail clips at the right edge.
|
||||
expect(rig.compositionView.style.direction).toBe('ltr')
|
||||
expect(rig.compositionView.style.display).toBe('')
|
||||
expect(rig.compositionView.style.justifyContent).toBe('')
|
||||
expect(rig.compositionView.style.textAlign).toBe('left')
|
||||
})
|
||||
|
||||
it('keeps the tail current as the preedit grows through the composition', async () => {
|
||||
@@ -231,7 +234,9 @@ describe('mid-line composition renders the covered row tail after the preedit',
|
||||
expect(Array.from(rig.compositionView.children)).toEqual([preedit, caret])
|
||||
expect(remainder).toBeNull()
|
||||
expect(stripMarks(rig.compositionView.textContent)).toBe('가')
|
||||
expect(rig.compositionView.style.textAlign).toBe('right')
|
||||
expect(rig.compositionView.style.display).toBe('flex')
|
||||
expect(rig.compositionView.style.justifyContent).toBe('flex-end')
|
||||
expect(rig.compositionView.style.textAlign).toBe('')
|
||||
})
|
||||
|
||||
it('keeps the themed insertion caret visible inside the final cell', async () => {
|
||||
@@ -244,7 +249,10 @@ describe('mid-line composition renders the covered row tail after the preedit',
|
||||
expect(rig.terminal.buffer.active.cursorX).toBe(79)
|
||||
expect(Array.from(rig.compositionView.children)).toEqual([preedit, caret])
|
||||
expect(rig.compositionView.style.maxWidth).toBe(`${CELL_WIDTH_PX}px`)
|
||||
expect(rig.compositionView.style.textAlign).toBe('right')
|
||||
expect(rig.compositionView.style.display).toBe('flex')
|
||||
expect(rig.compositionView.style.justifyContent).toBe('flex-end')
|
||||
expect(preedit!.style.flexShrink).toBe('0')
|
||||
expect(caret!.style.flexShrink).toBe('0')
|
||||
expect(caret!.style.width).toBe('2px')
|
||||
expect(caret!.style.marginLeft).toBe('-2px')
|
||||
expect([THEME.cursor, 'rgb(68, 85, 102)']).toContain(caret!.style.backgroundColor)
|
||||
@@ -276,6 +284,8 @@ describe('mid-line composition renders the covered row tail after the preedit',
|
||||
)
|
||||
expect(rig.compositionView.classList.contains('active')).toBe(false)
|
||||
expect(rig.compositionView.children).toHaveLength(0)
|
||||
expect(rig.compositionView.style.display).toBe('')
|
||||
expect(rig.compositionView.style.justifyContent).toBe('')
|
||||
|
||||
rig.composeUpdate('글')
|
||||
expect(rig.compositionView.classList.contains('active')).toBe(true)
|
||||
@@ -283,6 +293,8 @@ describe('mid-line composition renders the covered row tail after the preedit',
|
||||
rig.composeUpdate('')
|
||||
expect(rig.compositionView.classList.contains('active')).toBe(false)
|
||||
expect(rig.compositionView.children).toHaveLength(0)
|
||||
expect(rig.compositionView.style.display).toBe('')
|
||||
expect(rig.compositionView.style.justifyContent).toBe('')
|
||||
})
|
||||
|
||||
it('masks a dim Codex placeholder instead of repeating it after the preedit', async () => {
|
||||
|
||||
+5
-2
@@ -137,8 +137,11 @@ describe('#12729 — the block over a trailing Korean syllable is the preedit ov
|
||||
expect(rig.terminal.buffer.active.cursorX).toBe(6)
|
||||
expect(rig.compositionView.classList.contains('active')).toBe(true)
|
||||
expect(stripMarks(rig.compositionView.textContent)).toBe('라')
|
||||
// Nothing follows the cursor, so the overlay carries the preedit alone.
|
||||
expect(rig.compositionView.children).toHaveLength(0)
|
||||
// Nothing follows the cursor, so the overlay needs only the preedit and its caret.
|
||||
const preedit = rig.compositionView.querySelector('.xterm-composition-preedit')
|
||||
const caret = rig.compositionView.querySelector('.xterm-composition-caret')
|
||||
expect(Array.from(rig.compositionView.children)).toEqual([preedit, caret])
|
||||
expect(rig.compositionView.querySelector('.xterm-composition-remainder')).toBeNull()
|
||||
})
|
||||
|
||||
it('anchors the overlay to the cursor cell so the preedit continues the run', async () => {
|
||||
|
||||
@@ -24,6 +24,7 @@ export type MidlinePreeditOcclusionSample = {
|
||||
caretRect: { left: number; right: number; width: number; height: number } | null
|
||||
overlayActive: boolean
|
||||
cursorColumn: number
|
||||
terminalColumns: number
|
||||
/** Columns covered by the overlay, as `[first, last]`; null when it covers none. */
|
||||
coveredColumns: [number, number] | null
|
||||
cellWidth: number
|
||||
@@ -107,6 +108,7 @@ function readMidlinePreeditOcclusion(): MidlinePreeditOcclusionSample {
|
||||
: null,
|
||||
overlayActive: view.classList.contains('active'),
|
||||
cursorColumn,
|
||||
terminalColumns: terminal.cols,
|
||||
coveredColumns: first === null ? null : [first, last],
|
||||
cellWidth,
|
||||
overlayRect: {
|
||||
|
||||
@@ -60,13 +60,16 @@ test.describe('Terminal end-of-row Korean preedit cell span', () => {
|
||||
const arena = await openTerminalImePaneArena(orcaPage)
|
||||
let completed = false
|
||||
try {
|
||||
await writeToActiveTerminal(orcaPage, '\x1b[2J\x1b[H\x1b[80G')
|
||||
// CHA clamps past-the-edge columns, keeping this valid when the runner resizes the grid.
|
||||
await writeToActiveTerminal(orcaPage, '\x1b[2J\x1b[H\x1b[999G')
|
||||
await setImeComposition(arena.session, '가')
|
||||
|
||||
const sample = await sampleOpenComposition(orcaPage)
|
||||
const caret = sample.caretRect
|
||||
const screenRight = sample.screenRect.left + sample.screenRect.width
|
||||
expect(sample.cursorColumn, 'the cursor is not in the final column').toBe(79)
|
||||
expect(sample.cursorColumn, 'the cursor is not in the final column').toBe(
|
||||
sample.terminalColumns - 1
|
||||
)
|
||||
expect(caret, 'the active preedit has no caret element').not.toBeNull()
|
||||
expect(caret!.width, 'the preedit caret has zero width').toBeGreaterThan(0)
|
||||
expect(caret!.height, 'the preedit caret has zero height').toBeGreaterThan(0)
|
||||
|
||||
Reference in New Issue
Block a user