fix length calculation of wide unicode chars

This commit is contained in:
Gerald
2021-02-22 16:06:57 +08:00
parent 187f072f43
commit 6f6378aaf2
2 changed files with 37 additions and 20 deletions
+29 -20
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { Terminal, IDisposable, ITerminalAddon, ISelectionPosition } from 'xterm';
import { Terminal, IBufferLine, IDisposable, ITerminalAddon, ISelectionPosition } from 'xterm';
export interface ISearchOptions {
regex?: boolean;
@@ -21,6 +21,7 @@ export interface ISearchResult {
term: string;
col: number;
row: number;
length: number;
}
const NON_WORD_CHARACTERS = ' ~!@#$%^&*()+`-=[]{}|\;:"\',./<>?';
@@ -324,34 +325,42 @@ export class SearchAddon implements ITerminalAddon {
}
const line = terminal.buffer.active.getLine(row);
let { length } = term;
if (line) {
for (let i = 0; i < resultIndex; i++) {
const cell = line.getCell(i);
if (!cell) {
break;
}
// Adjust the searchIndex to normalize emoji into single chars
const char = cell.getChars();
if (char.length > 1) {
resultIndex -= char.length - 1;
}
// Adjust the searchIndex for empty characters following wide unicode
// chars (eg. CJK)
const charWidth = cell.getWidth();
if (charWidth === 0) {
resultIndex++;
}
}
resultIndex = this._stringLengthToBufferSize(line, resultIndex);
length = this._stringLengthToBufferSize(line, length, resultIndex);
}
return {
term,
col: resultIndex,
row
row,
length
};
}
}
private _stringLengthToBufferSize(line: IBufferLine, length: number, start: number = 0): number {
for (let i = 0; i < length; i++) {
const cell = line.getCell(start + i);
if (!cell) {
break;
}
// Adjust the searchIndex to normalize emoji into single chars
const char = cell.getChars();
if (char.length > 1) {
length -= char.length - 1;
}
// Adjust the searchIndex for empty characters following wide unicode
// chars (eg. CJK)
const nextCell = line.getCell(start + i + 1);
if (nextCell && nextCell.getWidth() === 0) {
length++;
}
}
return length;
}
/**
* Translates a buffer line to a string, including subsequent lines if they are wraps.
* Wide characters will count as two columns in the resulting string. This
@@ -390,7 +399,7 @@ export class SearchAddon implements ITerminalAddon {
terminal.clearSelection();
return false;
}
terminal.select(result.col, result.row, result.term.length);
terminal.select(result.col, result.row, result.length);
// If it is not in the viewport then we scroll else it just gets selected
if (result.row >= (terminal.buffer.active.viewportY + terminal.rows) || result.row < terminal.buffer.active.viewportY) {
let scroll = result.row - terminal.buffer.active.viewportY;
@@ -106,6 +106,14 @@ describe('Search Tests', function(): void {
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'abc');
});
it('Search for result bounding with wide unicode chars', async () => {
await writeSync(page, '中文xxx');
assert.deepEqual(await page.evaluate(`window.search.findNext('中')`), true);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), '中');
assert.deepEqual(await page.evaluate(`window.search.findNext('xxx')`), true);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'xxx');
});
describe('Regression tests', () => {
describe('#2444 wrapped line content not being found', () => {
let fixture: string;