Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/selection-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,29 @@ describe('SelectionManager', () => {
term.dispose();
});

test('getSelection does not insert spaces between wide (CJK) characters', async () => {
if (!container) return;

const term = await createIsolatedTerminal({ cols: 80, rows: 24 });
term.open(container);

// Three Korean wide characters — each occupies 2 terminal cells:
// leading cell {codepoint: ..., width: 2} + continuation cell
// {codepoint: 0, width: 0}. The fix ensures we skip continuation
// cells instead of treating them as empty cells (which would
// produce "안 녕 하" with stray spaces between glyphs).
term.write('안녕하\r\n');

const scrollbackLen = term.wasmTerm!.getScrollbackLength();
// Select the 6 cells covering all three wide chars
setSelectionAbsolute(term, 0, scrollbackLen, 5, scrollbackLen);

const selMgr = (term as any).selectionManager;
expect(selMgr.getSelection()).toBe('안녕하');

term.dispose();
});

test('getSelection extracts multi-line text', async () => {
if (!container) return;

Expand Down
10 changes: 9 additions & 1 deletion lib/selection-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,15 @@
if (char.trim()) {
lastNonEmpty = lineText.length;
}
} else {
} else if (!cell || cell.width !== 0) {

Check warning on line 186 in lib/selection-manager.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=diegosouzapw_ghostty-web&issues=AZ5UwVNWi-BUK6nuKRXo&open=AZ5UwVNWi-BUK6nuKRXo&pullRequest=9
// Only add a space for truly empty cells, NOT for wide-character
// continuation cells. Wide characters (CJK, fullwidth Latin, etc.)
// occupy 2 terminal cells:
// - First cell: codepoint set, width=2
// - Second cell: codepoint=0, width=0 (continuation marker)
// The first branch above handles the leading cell. We must skip
// the trailing continuation cell here, otherwise the copied text
// gets a stray space between every wide character.
lineText += ' ';
}
}
Expand Down