Path: blob/main/extensions/copilot/src/extension/prompts/node/inline/summarizedDocument/fragments.ts
13406 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 { Lazy } from '../../../../../util/vs/base/common/lazy';6import { StringEdit, StringReplacement } from '../../../../../util/vs/editor/common/core/edits/stringEdit';7import { OffsetRange } from '../../../../../util/vs/editor/common/core/ranges/offsetRange';8import { TextLength } from '../../../../../util/vs/editor/common/core/text/textLength';910export abstract class StringFragment {11abstract get length(): number;1213abstract get textLength(): TextLength;1415abstract get text(): string;1617toString() { return this.text; }1819toEditFromOriginal(originalLength: number): StringEdit {20const replacements: StringReplacement[] = [];21let lastOriginalIdx = 0;22let text = '';2324function emit(originalPos: number) {25if (lastOriginalIdx !== originalPos || text.length > 0) {26replacements.push(new StringReplacement(27new OffsetRange(lastOriginalIdx, originalPos),28text29));30text = '';31}32}3334function process(fragment: StringFragment) {35if (fragment instanceof ConcatenatedStringFragment) {36for (const f of fragment.fragments) {37process(f);38}39} else if (fragment instanceof LiteralStringFragment) {40text += fragment.text;41} else if (fragment instanceof OriginalStringFragment) {42emit(fragment.range.start);43lastOriginalIdx = fragment.range.endExclusive;44}45}4647process(this);48emit(originalLength);49return new StringEdit(replacements);50}51}5253export class LiteralStringFragment extends StringFragment {54constructor(55public readonly text: string56) {57super();58}5960get length(): number { return this.text.length; }6162private readonly _textLength = new Lazy(() => TextLength.ofText(this.text));6364get textLength() { return this._textLength.value; }65}6667export class OriginalStringFragment extends StringFragment {68constructor(69public readonly range: OffsetRange,70public readonly originalText: string71) {72super();73}7475get length(): number { return this.range.length; }7677get text(): string { return this.range.substring(this.originalText); }7879trimStart(): OriginalStringFragment {80const trimmed = this.text.trimStart();81if (trimmed.length === this.length) { return this; }82return new OriginalStringFragment(new OffsetRange(this.range.endExclusive - trimmed.length, this.range.endExclusive), this.originalText);83}8485trimEnd(): OriginalStringFragment {86const trimmed = this.text.trimEnd();87if (trimmed.length === this.length) { return this; }88return new OriginalStringFragment(new OffsetRange(this.range.start, this.range.start + trimmed.length), this.originalText);89}9091startsWith(str: string): boolean { return this.text.startsWith(str); }92endsWith(str: string): boolean { return this.text.endsWith(str); }9394tryJoin(other: OriginalStringFragment): OriginalStringFragment | null {95if (this.range.endExclusive === other.range.start) {96return new OriginalStringFragment(new OffsetRange(this.range.start, other.range.endExclusive), this.originalText);97}98return null;99}100101private readonly _textLength = new Lazy(() => TextLength.ofSubstr(this.originalText, this.range));102103get textLength() { return this._textLength.value; }104}105106export class ConcatenatedStringFragment extends StringFragment {107static from(result: StringFragment[]): StringFragment {108if (result.length === 0) {109return new LiteralStringFragment('');110}111if (result.length === 1) {112return result[0];113}114return new ConcatenatedStringFragment(result);115}116117readonly length = this.fragments.reduce((prev, cur) => prev + cur.length, 0);118119constructor(120public readonly fragments: readonly StringFragment[]121) {122super();123}124125get text(): string {126return this.fragments.map(f => f.text).join('');127}128129private readonly _textLength = new Lazy(() => TextLength.sum(this.fragments, f => f.textLength));130131get textLength() { return this._textLength.value; }132}133134export function pushFragment(fragments: StringFragment[], fragment: StringFragment): void {135if (fragment.length === 0) { return; }136const last = fragments[fragments.length - 1];137if (last && last instanceof OriginalStringFragment && fragment instanceof OriginalStringFragment) {138const joined = last.tryJoin(fragment);139if (joined) {140fragments[fragments.length - 1] = joined;141return;142}143}144fragments.push(fragment);145}146147148