Path: blob/main/src/vs/editor/browser/gpu/contentSegmenter.ts
3294 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { safeIntl } from '../../../base/common/date.js';6import type { GraphemeIterator } from '../../../base/common/strings.js';7import type { ViewLineRenderingData } from '../../common/viewModel.js';8import type { ViewLineOptions } from '../viewParts/viewLines/viewLineOptions.js';910export interface IContentSegmenter {11/**12* Gets the content segment at an index within the line data's contents. This will be undefined13* when the index should not be rendered, ie. when it's part of an earlier segment like the tail14* end of an emoji, or when the line is not that long.15* @param index The index within the line data's content string.16*/17getSegmentAtIndex(index: number): string | undefined;18getSegmentData(index: number): Intl.SegmentData | undefined;19}2021export function createContentSegmenter(lineData: ViewLineRenderingData, options: ViewLineOptions): IContentSegmenter {22if (lineData.isBasicASCII && options.useMonospaceOptimizations) {23return new AsciiContentSegmenter(lineData);24}25return new GraphemeContentSegmenter(lineData);26}2728class AsciiContentSegmenter implements IContentSegmenter {29private readonly _content: string;3031constructor(lineData: ViewLineRenderingData) {32this._content = lineData.content;33}3435getSegmentAtIndex(index: number): string {36return this._content[index];37}3839getSegmentData(index: number): Intl.SegmentData | undefined {40return undefined;41}42}4344/**45* This is a more modern version of {@link GraphemeIterator}, relying on browser APIs instead of a46* manual table approach.47*/48class GraphemeContentSegmenter implements IContentSegmenter {49private readonly _segments: (Intl.SegmentData | undefined)[] = [];5051constructor(lineData: ViewLineRenderingData) {52const content = lineData.content;53const segmenter = safeIntl.Segmenter(undefined, { granularity: 'grapheme' }).value;54const segmentedContent = Array.from(segmenter.segment(content));55let segmenterIndex = 0;5657for (let x = 0; x < content.length; x++) {58const segment = segmentedContent[segmenterIndex];5960// No more segments in the string (eg. an emoji is the last segment)61if (!segment) {62break;63}6465// The segment isn't renderable (eg. the tail end of an emoji)66if (segment.index !== x) {67this._segments.push(undefined);68continue;69}7071segmenterIndex++;72this._segments.push(segment);73}74}7576getSegmentAtIndex(index: number): string | undefined {77return this._segments[index]?.segment;78}7980getSegmentData(index: number): Intl.SegmentData | undefined {81return this._segments[index];82}83}848586