-
Notifications
You must be signed in to change notification settings - Fork 3
/
SourceFileChange.ts
116 lines (97 loc) · 4.62 KB
/
SourceFileChange.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import * as vscode from "vscode";
import { StringUtils } from "../../shared/utils/StringUtils";
import { SourceFilePositionShift } from "../source-files/SourceFilePosition";
export const enum SourceFileChangeKind {
Insertion = "Insertion",
Deletion = "Deletion",
Replacement = "Replacement"
}
export class SourceFileChange {
readonly event: vscode.TextDocumentContentChangeEvent;
readonly start: vscode.Position;
readonly end: vscode.Position;
readonly kind: SourceFileChangeKind;
// Note: be careful, the shift values may not make sense for every node!
// In particular, the column shift is only meaningful in a few particular cases.
readonly shift: SourceFilePositionShift;
// The size of a change represents how many characters have been affected by the change:
// - how many characters have been inserted; or
// - how many characters have been added/removed during a replacement; or
// - how many characters have been deleted.
readonly size: number;
constructor(event: vscode.TextDocumentContentChangeEvent) {
this.event = event;
this.start = event.range.start;
this.end = event.range.end;
this.kind = SourceFileChange.computeKindOf(event);
this.shift = SourceFileChange.computeShiftOf(event, this.kind);
this.size = SourceFileChange.computeSizeOf(event, this.kind);
// console.log("Source file change:", this);
}
private static computeKindOf(event: vscode.TextDocumentContentChangeEvent): SourceFileChangeKind {
if (event.text.length === 0) {
return SourceFileChangeKind.Deletion;
}
else if (event.rangeLength === 0) {
return SourceFileChangeKind.Insertion;
}
else {
return SourceFileChangeKind.Replacement;
}
}
// The line shift is given by the number of new lines minus the number of lines in the edited range.
private static computeLineShiftOf(event: vscode.TextDocumentContentChangeEvent): number {
return (event.text.match(/\n/g) || "").length // nb. lines added
- (event.range.end.line - event.range.start.line); // nb. lines removed/replaced
}
// The column shift depends on the kind of change this is, and possibly on some other properties of the change (such as the length of the last line of added text).
// It is only meaningful for
private static computeColumnShiftOf(
event: vscode.TextDocumentContentChangeEvent,
kind: SourceFileChangeKind
): number {
const start = event.range.start;
const end = event.range.end;
const nbLinesOfAddedText = StringUtils.countLinesOf(event.text);
const lengthOfLastLineOfAddedText = StringUtils.lastLineOf(event.text).length;
switch (kind) {
case SourceFileChangeKind.Insertion:
return nbLinesOfAddedText === 1
? lengthOfLastLineOfAddedText // if the node start is shifted on the same line
: lengthOfLastLineOfAddedText - start.character; // if the node start is moved to another line
case SourceFileChangeKind.Deletion:
return start.character - end.character;
case SourceFileChangeKind.Replacement:
return event.range.isSingleLine
? lengthOfLastLineOfAddedText - event.rangeLength // if the node start is shifted on the same line
: lengthOfLastLineOfAddedText - end.character; // if the node start is moved to another line
}
}
// The offset shift is given by the length of the new text minus the length of the edited range.
private static computeOffsetShiftOf(event: vscode.TextDocumentContentChangeEvent): number {
return event.text.length - event.rangeLength;
}
private static computeSizeOf(
event: vscode.TextDocumentContentChangeEvent,
kind: SourceFileChangeKind
): number {
switch (kind) {
case SourceFileChangeKind.Insertion:
return event.text.length;
case SourceFileChangeKind.Replacement:
return event.text.length - event.rangeLength;
case SourceFileChangeKind.Deletion:
return -event.rangeLength;
}
}
private static computeShiftOf(
event: vscode.TextDocumentContentChangeEvent,
kind: SourceFileChangeKind
): SourceFilePositionShift {
return {
lines: SourceFileChange.computeLineShiftOf(event),
columns: SourceFileChange.computeColumnShiftOf(event, kind),
offset: SourceFileChange.computeOffsetShiftOf(event)
};
}
}