diff.ts ×38

Frontier kind: Code frontier

unlabeled · c_8f465e0175aa

184 tests · 5928 LOC · 31 files · introduces 0 tests · 369 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
42 ranges369 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
857 ranges5928 lines · 31 files · Browse complete extent
All tests (intent)
184 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 369 introduced LOC across 42 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/base/common/diff/diff.ts 319 introduced LOC · 38 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- diff.ts
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 { DiffChange } from './diffChange.js';
7 > import { stringHash } from '../hash.js';
8 > import { Constants } from '../uint.js';
9 >
10 > export class StringDiffSequence implements ISequence {
11 >
12 > constructor(private source: string) { }
13 >
14 > getElements(): Int32Array | number[] | string[] {
15 const source = this.source;
16 const characters = new Int32Array(source.length);
20 return characters;
21 }
22 > } diff.ts
23 >
24 > export function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] {
25 return new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes;
26 }
27 > diff.ts
28 > export interface ISequence {
29 > getElements(): Int32Array | number[] | string[];
30 > getStrictElement?(index: number): string;
31 > }
32 >
33 > export interface IDiffChange {
34 > /**
35 > * The position of the first element in the original sequence which
36 > * this change affects.
37 > */
38 > originalStart: number;
39 >
40 > /**
41 > * The number of elements from the original sequence which were
42 > * affected.
43 > */
44 > originalLength: number;
45 >
46 > /**
47 > * The position of the first element in the modified sequence which
48 > * this change affects.
49 > */
50 > modifiedStart: number;
51 >
52 > /**
53 > * The number of elements from the modified sequence which were
54 > * affected (added).
55 > */
56 > modifiedLength: number;
57 > }
58 >
59 > export interface IContinueProcessingPredicate {
60 > (furthestOriginalIndex: number, matchLengthOfLongest: number): boolean;
61 > }
62 >
63 > export interface IDiffResult {
64 > quitEarly: boolean;
65 > changes: IDiffChange[];
66 > }
67 >
68 > //
69 > // The code below has been ported from a C# implementation in VS
70 > //
71 >
72 > class Debug {
73 >
74 > public static Assert(condition: boolean, message: string): void {
75 if (!condition) {
76 throw new Error(message);
77 }
78 }
79 > } diff.ts
80 >
81 > class MyArray {
82 > /**
83 > * Copies a range of elements from an Array starting at the specified source index and pastes
84 > * them to another Array starting at the specified destination index. The length and the indexes
85 > * are specified as 64-bit integers.
86 > * sourceArray:
87 > * The Array that contains the data to copy.
88 > * sourceIndex:
89 > * A 64-bit integer that represents the index in the sourceArray at which copying begins.
90 > * destinationArray:
91 > * The Array that receives the data.
92 > * destinationIndex:
93 > * A 64-bit integer that represents the index in the destinationArray at which storing begins.
94 > * length:
95 > * A 64-bit integer that represents the number of elements to copy.
96 > */
97 > public static Copy(sourceArray: unknown[], sourceIndex: number, destinationArray: unknown[], destinationIndex: number, length: number) {
98 for (let i = 0; i < length; i++) {
99 destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
100 }
101 }
102 > public static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) { diff.ts
103 for (let i = 0; i < length; i++) {
104 destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
105 }
106 }
107 > } diff.ts
108 >
109 > //*****************************************************************************
110 > // LcsDiff.cs
111 > //
112 > // An implementation of the difference algorithm described in
113 > // "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
114 > //
115 > // Copyright (C) 2008 Microsoft Corporation @minifier_do_not_preserve
116 > //*****************************************************************************
117 >
118 > // Our total memory usage for storing history is (worst-case):
119 > // 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int)
120 > // 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB
121 > const enum LocalConstants {
122 > MaxDifferencesHistory = 1447
123 > }
124 >
125 > /**
126 > * A utility class which helps to create the set of DiffChanges from
127 > * a difference operation. This class accepts original DiffElements and
128 > * modified DiffElements that are involved in a particular change. The
129 > * MarkNextChange() method can be called to mark the separation between
130 > * distinct changes. At the end, the Changes property can be called to retrieve
131 > * the constructed changes.
132 > */
133 > class DiffChangeHelper {
134 >
135 > private m_changes: DiffChange[];
136 > private m_originalStart: number;
137 > private m_modifiedStart: number;
138 > private m_originalCount: number;
139 > private m_modifiedCount: number;
140 >
141 > /**
142 > * Constructs a new DiffChangeHelper for the given DiffSequences.
143 > */
144 > constructor() {
145 this.m_changes = [];
146 this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;
149 this.m_modifiedCount = 0;
150 }
151 > diff.ts
152 > /**
153 > * Marks the beginning of the next change in the set of differences.
154 > */
155 > public MarkNextChange(): void {
156 // Only add to the list if there is something to add
157 if (this.m_originalCount > 0 || this.m_modifiedCount > 0) {
167 this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;
168 }
169 > diff.ts
170 > /**
171 > * Adds the original element at the given position to the elements
172 > * affected by the current change. The modified index gives context
173 > * to the change position with respect to the original sequence.
174 > * @param originalIndex The index of the original element to add.
175 > * @param modifiedIndex The index of the modified element that provides corresponding position in the modified sequence.
176 > */
177 > public AddOriginalElement(originalIndex: number, modifiedIndex: number) {
178 // The 'true' start index is the smallest of the ones we've seen
179 this.m_originalStart = Math.min(this.m_originalStart, originalIndex);
182 this.m_originalCount++;
183 }
184 > diff.ts
185 > /**
186 > * Adds the modified element at the given position to the elements
187 > * affected by the current change. The original index gives context
188 > * to the change position with respect to the modified sequence.
189 > * @param originalIndex The index of the original element that provides corresponding position in the original sequence.
190 > * @param modifiedIndex The index of the modified element to add.
191 > */
192 > public AddModifiedElement(originalIndex: number, modifiedIndex: number): void {
193 // The 'true' start index is the smallest of the ones we've seen
194 this.m_originalStart = Math.min(this.m_originalStart, originalIndex);
197 this.m_modifiedCount++;
198 }
199 > diff.ts
200 > /**
201 > * Retrieves all of the changes marked by the class.
202 > */
203 > public getChanges(): DiffChange[] {
204 if (this.m_originalCount > 0 || this.m_modifiedCount > 0) {
205 // Finish up on whatever is left
209 return this.m_changes;
210 }
211 > diff.ts
212 > /**
213 > * Retrieves all of the changes marked by the class in the reverse order
214 > */
215 > public getReverseChanges(): DiffChange[] {
216 if (this.m_originalCount > 0 || this.m_modifiedCount > 0) {
217 // Finish up on whatever is left
222 return this.m_changes;
223 }
224 > diff.ts
225 > }
226 >
227 > /**
228 > * An implementation of the difference algorithm described in
229 > * "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
230 > */
231 > export class LcsDiff {
232 >
233 > private readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null;
234 >
235 > private readonly _originalSequence: ISequence;
236 > private readonly _modifiedSequence: ISequence;
237 > private readonly _hasStrings: boolean;
238 > private readonly _originalStringElements: string[];
239 > private readonly _originalElementsOrHash: Int32Array;
240 > private readonly _modifiedStringElements: string[];
241 > private readonly _modifiedElementsOrHash: Int32Array;
242 >
243 > private m_forwardHistory: Int32Array[];
244 > private m_reverseHistory: Int32Array[];
245 >
246 > /**
247 > * Constructs the DiffFinder
248 > */
249 > constructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {
250 this.ContinueProcessingPredicate = continueProcessingPredicate;
251
265 this.m_reverseHistory = [];
266 }
267 > diff.ts
268 > private static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] {
269 return (arr.length > 0 && typeof arr[0] === 'string');
270 }
271 > diff.ts
272 > private static _getElements(sequence: ISequence): [string[], Int32Array, boolean] {
273 const elements = sequence.getElements();
274
287 return [[], new Int32Array(elements), false];
288 }
289 > diff.ts
290 > private ElementsAreEqual(originalIndex: number, newIndex: number): boolean {
291 if (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) {
292 return false;
294 return (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true);
295 }
296 > diff.ts
297 > private ElementsAreStrictEqual(originalIndex: number, newIndex: number): boolean {
298 if (!this.ElementsAreEqual(originalIndex, newIndex)) {
299 return false;
303 return (originalElement === modifiedElement);
304 }
305 > diff.ts
306 > private static _getStrictElement(sequence: ISequence, index: number): string | null {
307 if (typeof sequence.getStrictElement === 'function') {
308 return sequence.getStrictElement(index);
310 return null;
311 }
312 > diff.ts
313 > private OriginalElementsAreEqual(index1: number, index2: number): boolean {
314 if (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) {
315 return false;
317 return (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true);
318 }
319 > diff.ts
320 > private ModifiedElementsAreEqual(index1: number, index2: number): boolean {
321 if (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) {
322 return false;
324 return (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true);
325 }
326 > diff.ts
327 > public ComputeDiff(pretty: boolean): IDiffResult {
328 return this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty);
329 }
330 > diff.ts
331 > /**
332 > * Computes the differences between the original and modified input
333 > * sequences on the bounded range.
334 > * @returns An array of the differences between the two input sequences.
335 > */
336 > private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult {
337 const quitEarlyArr = [false];
338 let changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr);
350 };
351 }
352 > diff.ts
353 > /**
354 > * Private helper method which computes the differences on the bounded range
355 > * recursively.
356 > * @returns An array of the differences between the two input sequences.
357 > */
358 > private ComputeDiffRecursive(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, quitEarlyArr: boolean[]): DiffChange[] {
359 quitEarlyArr[0] = false;
360
439 ];
440 }
441 > diff.ts
442 > private WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number,
443 diagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number,
444 forwardPoints: Int32Array, reversePoints: Int32Array,
565 return this.ConcatenateChanges(forwardChanges, reverseChanges);
566 }
567 > diff.ts
568 > /**
569 > * Given the range to compute the diff on, this method finds the point:
570 > * (midOriginal, midModified)
571 > * that exists in the middle of the LCS of the two sequences and
572 > * is the point at which the LCS problem may be broken down recursively.
573 > * This method will try to keep the LCS trace in memory. If the LCS recursion
574 > * point is calculated and the full trace is available in memory, then this method
575 > * will return the change list.
576 > * @param originalStart The start bound of the original sequence range
577 > * @param originalEnd The end bound of the original sequence range
578 > * @param modifiedStart The start bound of the modified sequence range
579 > * @param modifiedEnd The end bound of the modified sequence range
580 > * @param midOriginal The middle point of the original sequence range
581 > * @param midModified The middle point of the modified sequence range
582 > * @returns The diff changes, if available, otherwise null
583 > */
584 > private ComputeRecursionPoint(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, midOriginalArr: number[], midModifiedArr: number[], quitEarlyArr: boolean[]) {
585 let originalIndex = 0, modifiedIndex = 0;
586 let diagonalForwardStart = 0, diagonalForwardEnd = 0;
817 );
818 }
819 > diff.ts
820 > /**
821 > * Shifts the given changes to provide a more intuitive diff.
822 > * While the first element in a diff matches the first element after the diff,
823 > * we shift the diff down.
824 > *
825 > * @param changes The list of changes to shift
826 > * @returns The shifted changes
827 > */
828 > private PrettifyChanges(changes: DiffChange[]): DiffChange[] {
829
830 // Shift all the changes down first
957 return changes;
958 }
959 > diff.ts
960 > private _findBetterContiguousSequence(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number, desiredLength: number): [number, number] | null {
961 if (originalLength < desiredLength || modifiedLength < desiredLength) {
962 return null;
982 return null;
983 }
984 > diff.ts
985 > private _contiguousSequenceScore(originalStart: number, modifiedStart: number, length: number): number {
986 let score = 0;
987 for (let l = 0; l < length; l++) {
993 return score;
994 }
995 > diff.ts
996 > private _OriginalIsBoundary(index: number): boolean {
997 if (index <= 0 || index >= this._originalElementsOrHash.length - 1) {
998 return true;
1000 return (this._hasStrings && /^\s*$/.test(this._originalStringElements[index]));
1001 }
1002 > diff.ts
1003 > private _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {
1004 if (this._OriginalIsBoundary(originalStart) || this._OriginalIsBoundary(originalStart - 1)) {
1005 return true;
1013 return false;
1014 }
1015 > diff.ts
1016 > private _ModifiedIsBoundary(index: number): boolean {
1017 if (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) {
1018 return true;
1020 return (this._hasStrings && /^\s*$/.test(this._modifiedStringElements[index]));
1021 }
1022 > diff.ts
1023 > private _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {
1024 if (this._ModifiedIsBoundary(modifiedStart) || this._ModifiedIsBoundary(modifiedStart - 1)) {
1025 return true;
1033 return false;
1034 }
1035 > diff.ts
1036 > private _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number {
1037 const originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);
1038 const modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);
1039 return (originalScore + modifiedScore);
1040 }
1041 > diff.ts
1042 > /**
1043 > * Concatenates the two input DiffChange lists and returns the resulting
1044 > * list.
1045 > * @param The left changes
1046 > * @param The right changes
1047 > * @returns The concatenated list
1048 > */
1049 > private ConcatenateChanges(left: DiffChange[], right: DiffChange[]): DiffChange[] {
1050 const mergedChangeArr: DiffChange[] = [];
1051
1071 }
1072 }
1073 > diff.ts
1074 > /**
1075 > * Returns true if the two changes overlap and can be merged into a single
1076 > * change
1077 > * @param left The left change
1078 > * @param right The right change
1079 > * @param mergedChange The merged change if the two overlap, null otherwise
1080 > * @returns True if the two changes overlap
1081 > */
1082 > private ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: Array<DiffChange | null>): boolean {
1083 Debug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change');
1084 Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');
1104 }
1105 }
1106 > diff.ts
1107 > /**
1108 > * Helper method used to clip a diagonal index to the range of valid
1109 > * diagonals. This also decides whether or not the diagonal index,
1110 > * if it exceeds the boundary, should be clipped to the boundary or clipped
1111 > * one inside the boundary depending on the Even/Odd status of the boundary
1112 > * and numDifferences.
1113 > * @param diagonal The index of the diagonal to clip.
1114 > * @param numDifferences The current number of differences being iterated upon.
1115 > * @param diagonalBaseIndex The base reference diagonal.
1116 > * @param numDiagonals The total number of diagonals.
1117 > * @returns The clipped diagonal index.
1118 > */
1119 > private ClipDiagonalBound(diagonal: number, numDifferences: number, diagonalBaseIndex: number, numDiagonals: number): number {
1120 if (diagonal >= 0 && diagonal < numDiagonals) {
1121 // Nothing to clip, its in range
1137 }
1138 }
1139 > } diff.ts
1140 >
1141 >
1142 > /**
1143 > * Precomputed equality array for character codes.
1144 > */
1145 > const precomputedEqualityArray = new Uint32Array(0x10000);
1146 >
1147 > /**
1148 > * Computes the Levenshtein distance for strings of length <= 32.
1149 > * @param firstString - The first string.
1150 > * @param secondString - The second string.
1151 > * @returns The Levenshtein distance.
1152 > */
1153 > const computeLevenshteinDistanceForShortStrings = (firstString: string, secondString: string): number => {
1154 const firstStringLength = firstString.length;
1155 const secondStringLength = secondString.length;
1191 return distance;
1192 };
1193 > diff.ts
1194 > /**
1195 > * Computes the Levenshtein distance for strings of length > 32.
1196 > * @param firstString - The first string.
1197 > * @param secondString - The second string.
1198 > * @returns The Levenshtein distance.
1199 > */
1200 function computeLevenshteinDistanceForLongStrings(firstString: string, secondString: string): number {
1201 const firstStringLength = firstString.length;
1293 return distance;
1294 }
1295 > diff.ts
1296 > /**
1297 > * Computes the Levenshtein distance between two strings.
1298 > * @param firstString - The first string.
1299 > * @param secondString - The second string.
1300 > * @returns The Levenshtein distance.
1301 > */
1302 > export function computeLevenshteinDistance(firstString: string, secondString: string): number {
1303 if (firstString.length < secondString.length) {
1304 const temp = secondString;
src/vs/base/common/diff/diffChange.ts 50 introduced LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- diffChange.ts
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 > /**
7 > * Represents information about a specific difference between two sequences.
8 > */
9 > export class DiffChange {
10 >
11 > /**
12 > * The position of the first element in the original sequence which
13 > * this change affects.
14 > */
15 > public originalStart: number;
16 >
17 > /**
18 > * The number of elements from the original sequence which were
19 > * affected.
20 > */
21 > public originalLength: number;
22 >
23 > /**
24 > * The position of the first element in the modified sequence which
25 > * this change affects.
26 > */
27 > public modifiedStart: number;
28 >
29 > /**
30 > * The number of elements from the modified sequence which were
31 > * affected (added).
32 > */
33 > public modifiedLength: number;
34 >
35 > /**
36 > * Constructs a new DiffChange with the given sequence information
37 > * and content.
38 > */
39 > constructor(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number) {
40 //Debug.Assert(originalLength > 0 || modifiedLength > 0, "originalLength and modifiedLength cannot both be <= 0");
41 this.originalStart = originalStart;
44 this.modifiedLength = modifiedLength;
45 }
47 > /**
48 > * The end point (exclusive) of the change in the original sequence.
49 > */
50 > public getOriginalEnd() {
51 return this.originalStart + this.originalLength;
52 }
54 > /**
55 > * The end point (exclusive) of the change in the modified sequence.
56 > */
57 > public getModifiedEnd() {
58 return this.modifiedStart + this.modifiedLength;
59 }
60 > } diffChange.ts