Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/browser/gpu/contentSegmenter.ts
3294 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { safeIntl } from '../../../base/common/date.js';
7
import type { GraphemeIterator } from '../../../base/common/strings.js';
8
import type { ViewLineRenderingData } from '../../common/viewModel.js';
9
import type { ViewLineOptions } from '../viewParts/viewLines/viewLineOptions.js';
10
11
export interface IContentSegmenter {
12
/**
13
* Gets the content segment at an index within the line data's contents. This will be undefined
14
* when the index should not be rendered, ie. when it's part of an earlier segment like the tail
15
* end of an emoji, or when the line is not that long.
16
* @param index The index within the line data's content string.
17
*/
18
getSegmentAtIndex(index: number): string | undefined;
19
getSegmentData(index: number): Intl.SegmentData | undefined;
20
}
21
22
export function createContentSegmenter(lineData: ViewLineRenderingData, options: ViewLineOptions): IContentSegmenter {
23
if (lineData.isBasicASCII && options.useMonospaceOptimizations) {
24
return new AsciiContentSegmenter(lineData);
25
}
26
return new GraphemeContentSegmenter(lineData);
27
}
28
29
class AsciiContentSegmenter implements IContentSegmenter {
30
private readonly _content: string;
31
32
constructor(lineData: ViewLineRenderingData) {
33
this._content = lineData.content;
34
}
35
36
getSegmentAtIndex(index: number): string {
37
return this._content[index];
38
}
39
40
getSegmentData(index: number): Intl.SegmentData | undefined {
41
return undefined;
42
}
43
}
44
45
/**
46
* This is a more modern version of {@link GraphemeIterator}, relying on browser APIs instead of a
47
* manual table approach.
48
*/
49
class GraphemeContentSegmenter implements IContentSegmenter {
50
private readonly _segments: (Intl.SegmentData | undefined)[] = [];
51
52
constructor(lineData: ViewLineRenderingData) {
53
const content = lineData.content;
54
const segmenter = safeIntl.Segmenter(undefined, { granularity: 'grapheme' }).value;
55
const segmentedContent = Array.from(segmenter.segment(content));
56
let segmenterIndex = 0;
57
58
for (let x = 0; x < content.length; x++) {
59
const segment = segmentedContent[segmenterIndex];
60
61
// No more segments in the string (eg. an emoji is the last segment)
62
if (!segment) {
63
break;
64
}
65
66
// The segment isn't renderable (eg. the tail end of an emoji)
67
if (segment.index !== x) {
68
this._segments.push(undefined);
69
continue;
70
}
71
72
segmenterIndex++;
73
this._segments.push(segment);
74
}
75
}
76
77
getSegmentAtIndex(index: number): string | undefined {
78
return this._segments[index]?.segment;
79
}
80
81
getSegmentData(index: number): Intl.SegmentData | undefined {
82
return this._segments[index];
83
}
84
}
85
86