Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/editing/common/abstractText.ts
13401 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 { Lazy } from '../../../util/vs/base/common/lazy';
7
import { Position as CorePos } from '../../../util/vs/editor/common/core/position';
8
import { OffsetRange } from '../../../util/vs/editor/common/core/ranges/offsetRange';
9
import { PositionOffsetTransformer } from '../../../util/vs/editor/common/core/text/positionToOffset';
10
import { Range, Position as VSCodePos } from '../../../vscodeTypes';
11
import { TextDocumentSnapshot } from './textDocumentSnapshot';
12
13
/**
14
* Represents an immutable view of a string with line/column characteristics.
15
* Offers many methods to work with various data types (ranges, positions, offsets, ...).
16
*/
17
export abstract class AbstractDocument {
18
abstract getText(): string;
19
20
abstract getTextInOffsetRange(offsetRange: OffsetRange): string;
21
22
abstract getPositionAtOffset(offset: number): VSCodePos;
23
24
abstract getOffsetAtPosition(position: VSCodePos): number;
25
26
abstract getLineText(lineIndex: number): string;
27
28
abstract getLineLength(lineIndex: number): number;
29
30
abstract getLineCount(): number;
31
32
rangeToOffsetRange(range: Range): OffsetRange {
33
return new OffsetRange(this.getOffsetAtPosition(range.start), this.getOffsetAtPosition(range.end));
34
}
35
36
offsetRangeToRange(offsetRange: OffsetRange): Range {
37
return new Range(
38
this.getPositionAtOffset(offsetRange.start),
39
this.getPositionAtOffset(offsetRange.endExclusive),
40
);
41
}
42
43
abstract getPositionOffsetTransformer(): PositionOffsetTransformer;
44
45
get length() {
46
return this.getText().length;
47
}
48
}
49
50
export interface AbstractDocumentWithLanguageId extends AbstractDocument {
51
readonly languageId: string;
52
}
53
54
export class VsCodeTextDocument extends AbstractDocument implements AbstractDocumentWithLanguageId {
55
public readonly uri = this.document.uri;
56
57
public readonly languageId = this.document.languageId;
58
59
constructor(public readonly document: TextDocumentSnapshot) {
60
super();
61
}
62
63
getLineText(lineIndex: number): string {
64
return this.document.lineAt(lineIndex).text;
65
}
66
67
getLineLength(lineIndex: number): number {
68
return this.document.lineAt(lineIndex).text.length;
69
}
70
71
getLineCount(): number {
72
return this.document.lineCount;
73
}
74
75
getText(): string {
76
return this.document.getText();
77
}
78
79
getTextInOffsetRange(offsetRange: OffsetRange): string {
80
return offsetRange.substring(this.document.getText());
81
}
82
83
getPositionAtOffset(offset: number): VSCodePos {
84
return this.document.positionAt(offset);
85
}
86
87
getOffsetAtPosition(position: VSCodePos): number {
88
return this.document.offsetAt(position);
89
}
90
91
private readonly _transformer = new Lazy(() => new PositionOffsetTransformer(this.document.getText()));
92
93
override getPositionOffsetTransformer() {
94
return this._transformer.value;
95
}
96
}
97
98
export class StringTextDocument extends AbstractDocument {
99
private readonly _transformer = new PositionOffsetTransformer(this.value);
100
101
constructor(
102
public readonly value: string,
103
) {
104
super();
105
}
106
107
override getText(): string {
108
return this.value;
109
}
110
111
getLineText(lineIndex: number): string {
112
const startOffset = this._transformer.getOffset(new CorePos(lineIndex + 1, 1));
113
const endOffset = startOffset + this.getLineLength(lineIndex);
114
return this.value.substring(startOffset, endOffset);
115
}
116
117
getLineLength(lineIndex: number): number {
118
return this._transformer.getLineLength(lineIndex + 1);
119
}
120
121
getLineCount(): number {
122
return this._transformer.textLength.lineCount + 1;
123
}
124
125
override getTextInOffsetRange(offsetRange: OffsetRange): string {
126
return offsetRange.substring(this.value);
127
}
128
129
override getPositionAtOffset(offset: number): VSCodePos {
130
return corePositionToVSCodePosition(this._transformer.getPosition(offset));
131
}
132
133
override getOffsetAtPosition(position: VSCodePos): number {
134
position = this._validatePosition(position);
135
return this._transformer.getOffset(vsCodePositionToCorePosition(position));
136
}
137
138
private _validatePosition(position: VSCodePos): VSCodePos {
139
if (position.line < 0) {
140
return new VSCodePos(0, 0);
141
}
142
const lineCount = this._transformer.textLength.lineCount + 1;
143
if (position.line >= lineCount) {
144
const lineLength = this._transformer.getLineLength(lineCount);
145
return new VSCodePos(lineCount - 1, lineLength);
146
}
147
if (position.character < 0) {
148
return new VSCodePos(position.line, 0);
149
}
150
const lineLength = this._transformer.getLineLength(position.line + 1);
151
if (position.character > lineLength) {
152
return new VSCodePos(position.line, lineLength);
153
}
154
return position;
155
}
156
157
override getPositionOffsetTransformer() {
158
return this._transformer;
159
}
160
}
161
162
export class StringTextDocumentWithLanguageId extends StringTextDocument implements AbstractDocumentWithLanguageId {
163
constructor(
164
value: string,
165
public readonly languageId: string,
166
) {
167
super(value);
168
}
169
}
170
171
function corePositionToVSCodePosition(position: CorePos): VSCodePos {
172
return new VSCodePos(position.lineNumber - 1, position.column - 1);
173
}
174
175
function vsCodePositionToCorePosition(position: VSCodePos): CorePos {
176
return new CorePos(position.line + 1, position.character + 1);
177
}
178
179