Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/editSurvivalTracking/common/editCollector.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 { CharCode } from '../../../util/vs/base/common/charCode';
7
import { StringEdit, StringReplacement } from '../../../util/vs/editor/common/core/edits/stringEdit';
8
import { OffsetRange } from '../../../util/vs/editor/common/core/ranges/offsetRange';
9
import * as vscodeTypes from '../../../vscodeTypes';
10
import { IDiffService } from '../../diff/common/diffService';
11
import { stringEditFromDiff } from '../../editing/common/edit';
12
import { OffsetLineColumnConverter } from '../../editing/common/offsetLineColumnConverter';
13
14
export interface IEditCollector {
15
initialText: string;
16
addEdits(edits: vscodeTypes.TextEdit[]): void;
17
getText(): string;
18
getEdits(): Promise<StringEdit>;
19
}
20
21
export class EditCollector implements IEditCollector {
22
private readonly _document: OffsetBasedTextDocument;
23
24
constructor(
25
public readonly initialText: string,
26
@IDiffService private readonly _diffService: IDiffService,
27
) {
28
this._document = new OffsetBasedTextDocument(initialText);
29
}
30
31
public addEdits(edits: vscodeTypes.TextEdit[]): void {
32
this._document.applyTextEdits(edits);
33
}
34
35
public getText(): string {
36
return this._document.getValue();
37
}
38
39
public async getEdits(): Promise<StringEdit> {
40
const newText = this.getText();
41
const edits = await stringEditFromDiff(this.initialText, newText, this._diffService);
42
return edits;
43
}
44
}
45
46
export class OffsetBasedTextDocument {
47
private _converter: OffsetLineColumnConverter | undefined = undefined;
48
private _value: string = '';
49
constructor(initialValue: string = '') {
50
this._value = initialValue;
51
}
52
53
getValue(): string {
54
return this._value;
55
}
56
57
applyTextEdits(edits: vscodeTypes.TextEdit[]) {
58
const offsetEdit = new StringEdit(edits.map(e => {
59
const start = this.positionToOffset(e.range.start);
60
const end = this.positionToOffset(e.range.end);
61
return new StringReplacement(new OffsetRange(start, end), e.newText);
62
}));
63
this.applyOffsetEdit(offsetEdit);
64
}
65
66
applyOffsetEdit(edit: StringEdit): void {
67
this._value = edit.apply(this._value);
68
this._converter = undefined;
69
}
70
71
positionToOffset(position: vscodeTypes.Position): number {
72
if (!this._converter) {
73
this._converter = new OffsetLineColumnConverter(this._value);
74
}
75
const line = position.line;
76
if (line < 0) {
77
return 0;
78
} else if (line >= this._converter.lines) {
79
return this._value.length;
80
}
81
const character = position.character;
82
const lineOffet = this._converter.lineOffset(line + 1);
83
if (character <= 0) {
84
return lineOffet;
85
}
86
let endLineOffest;
87
if (line + 1 < this._converter.lines) {
88
endLineOffest = this._converter.lineOffset(line + 2);
89
if (endLineOffest > lineOffet) {
90
const ch = this._value.charCodeAt(endLineOffest - 1);
91
if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) {
92
endLineOffest--;
93
}
94
if (ch === CharCode.LineFeed && endLineOffest > lineOffet && this._value.charCodeAt(endLineOffest - 1) === CharCode.CarriageReturn) {
95
endLineOffest--;
96
}
97
} else {
98
endLineOffest = lineOffet;
99
}
100
} else {
101
endLineOffest = this._value.length;
102
}
103
if (character > endLineOffest - lineOffet) {
104
return endLineOffest;
105
}
106
return lineOffet + character;
107
}
108
}
109
110