Implement Unicode's grapheme cluster boundary rules

This commit is contained in:
Alexandru Dima 2019-11-27 11:23:09 +01:00
parent 453e750ca4
commit 3f1a2f690a
No known key found for this signature in database
GPG key ID: 6E58D7B045760DA0
5 changed files with 214 additions and 109 deletions

File diff suppressed because one or more lines are too long

View file

@ -492,4 +492,8 @@ suite('Strings', () => {
assertEncodeDecodeUTF8('🧝', [240, 159, 167, 157]);
});
test('getGraphemeBreakType', () => {
assert.equal(strings.getGraphemeBreakType(0xBC1), strings.GraphemeBreakType.SpacingMark);
});
});

View file

@ -523,12 +523,15 @@ export class CursorColumns {
if (codePoint === CharCode.Tab) {
result = CursorColumns.nextRenderTabStop(result, tabSize);
} else {
let graphemeBreakType = strings.getGraphemeBreakType(codePoint);
while (i < endOffset) {
const nextCodePoint = strings.getNextCodePoint(lineContent, endOffset, i);
if (!strings.isUnicodeMark(nextCodePoint)) {
const nextGraphemeBreakType = strings.getGraphemeBreakType(nextCodePoint);
if (strings.breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {
break;
}
i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);
graphemeBreakType = nextGraphemeBreakType;
}
if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {
result = result + 2;
@ -582,12 +585,15 @@ export class CursorColumns {
if (codePoint === CharCode.Tab) {
afterVisibleColumn = CursorColumns.nextRenderTabStop(beforeVisibleColumn, tabSize);
} else {
let graphemeBreakType = strings.getGraphemeBreakType(codePoint);
while (i < lineLength) {
const nextCodePoint = strings.getNextCodePoint(lineContent, lineLength, i);
if (!strings.isUnicodeMark(nextCodePoint)) {
const nextGraphemeBreakType = strings.getGraphemeBreakType(nextCodePoint);
if (strings.breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {
break;
}
i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);
graphemeBreakType = nextGraphemeBreakType;
}
if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {
afterVisibleColumn = beforeVisibleColumn + 2;

View file

@ -726,7 +726,7 @@ suite('Editor Controller - Cursor', () => {
});
});
test('combining marks', () => {
test('grapheme breaking', () => {
withTestCodeEditor([
'abcabc',
'ãããããã',

View file

@ -755,7 +755,7 @@ suite('Editor Model - TextModel', () => {
assert.deepEqual(actual, expected, `validateRange for ${input}, got ${actual}, expected ${expected}`);
}
test('combining marks', () => {
test('grapheme breaking', () => {
const m = TextModel.createFromString([
'abcabc',
'ãããããã',