Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/inlineEdits/common/statelessNextEditProviders.ts
13400 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 { LineEdit, LineReplacement } from '../../../util/vs/editor/common/core/edits/lineEdit';
7
import { StringEdit } from '../../../util/vs/editor/common/core/edits/stringEdit';
8
import { StatelessNextEditDocument } from './statelessNextEditProvider';
9
10
export class IgnoreEmptyLineAndLeadingTrailingWhitespaceChanges {
11
public static filterEdit(resultDocument: StatelessNextEditDocument, singleEdits: readonly LineReplacement[]): readonly LineReplacement[] {
12
const filteredEdits = singleEdits.filter(e => !IgnoreEmptyLineAndLeadingTrailingWhitespaceChanges._isWhitespaceOnlyChange(e, resultDocument.documentAfterEditsLines));
13
return filteredEdits;
14
}
15
16
private static _isWhitespaceOnlyChange(edit: LineReplacement, baseLines: string[]): boolean {
17
const originalLines = edit.lineRange.toOffsetRange().slice(baseLines);
18
const newLines = edit.newLines;
19
20
const isRemoval = newLines.length === 0;
21
22
// is removing empty lines
23
if (isRemoval && originalLines.every(line => line.trim() === '')) {
24
return true;
25
}
26
27
// is adding empty lines
28
if (!isRemoval && newLines.every(line => line.trim() === '')) {
29
return true;
30
}
31
32
if (originalLines.length !== newLines.length) {
33
return false;
34
}
35
36
for (let i = 0; i < originalLines.length; i++) {
37
const originalLine = originalLines[i];
38
const newLine = newLines[i];
39
if (originalLine.trim() !== newLine.trim()) {
40
return false;
41
}
42
}
43
return true;
44
}
45
}
46
47
export class IgnoreWhitespaceOnlyChanges {
48
public static filterEdit(resultDocument: StatelessNextEditDocument, singleEdits: readonly LineReplacement[]): readonly LineReplacement[] {
49
return singleEdits.filter(e => !IgnoreWhitespaceOnlyChanges._isFormattingOnlyChange(resultDocument.documentAfterEditsLines, e));
50
}
51
52
/**
53
* @remarks public only for testing
54
*/
55
public static _isFormattingOnlyChange(baseLines: string[], singleEdit: LineReplacement): boolean {
56
const originalLines = singleEdit.lineRange.toOffsetRange().slice(baseLines).join('').replace(/\s/g, '');
57
const newLines = singleEdit.newLines.join('').replace(/\s/g, '');
58
return originalLines === newLines;
59
}
60
}
61
62
export function editWouldDeleteWhatWasJustInserted(activeDocument: StatelessNextEditDocument, lineEdit: LineEdit) {
63
let edit = lineEdit.toEdit(activeDocument.documentAfterEdits);
64
// ! important: reduce it to the minimal set of changes
65
edit = edit.normalizeOnSource(activeDocument.documentAfterEdits.value);
66
if (!editIsDeletion(edit)) {
67
return false;
68
}
69
// We are deleting something. Is it what was just inserted?
70
for (let i = activeDocument.recentEdits.edits.length - 1; i >= 0; i--) {
71
const recentEdit = activeDocument.recentEdits.edits[i];
72
const rebaseResult = edit.tryRebase(recentEdit);
73
if (!rebaseResult) {
74
// the edit we want to do cannot be rebased, which indicates that it would interfere with a recent edit
75
return true;
76
}
77
edit = rebaseResult;
78
}
79
return false;
80
}
81
export function editIsDeletion(edit: StringEdit): boolean {
82
const deletedChars = edit.replacements.reduce((acc, singleEdit) => acc + singleEdit.replaceRange.length, 0);
83
const insertedChars = edit.replacements.reduce((acc, singleEdit) => acc + singleEdit.newText.length, 0);
84
return insertedChars === 0 && deletedChars > 0;
85
}
86
87
export function editWouldDeleteWhatWasJustInserted2(activeDocument: StatelessNextEditDocument, lineEdit: LineEdit) {
88
let edit = lineEdit.toEdit(activeDocument.documentAfterEdits);
89
// ! important: reduce it to the minimal set of changes
90
edit = edit.normalizeOnSource(activeDocument.documentAfterEdits.value);
91
if (!editIsDeletion(edit)) {
92
return false;
93
}
94
95
let documentContents = activeDocument.documentAfterEdits.value;
96
97
for (let i = activeDocument.recentEdits.edits.length - 1; i >= 0; i--) {
98
const recentEdit = activeDocument.recentEdits.edits[i];
99
const recentEditInverse = recentEdit.inverse(documentContents);
100
101
if (recentEditInverse.equals(edit)) {
102
return true;
103
}
104
105
documentContents = recentEditInverse.apply(documentContents);
106
}
107
108
return false;
109
}
110
111