Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/inlineEdits/test/node/random.ts
13405 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 { numberComparator } from '../../../../util/vs/base/common/arrays';
7
import { BugIndicatingError } from '../../../../util/vs/base/common/errors';
8
import { StringEdit, StringReplacement } from '../../../../util/vs/editor/common/core/edits/stringEdit';
9
import { TextEdit, TextReplacement } from '../../../../util/vs/editor/common/core/edits/textEdit';
10
import { Position } from '../../../../util/vs/editor/common/core/position';
11
import { Range } from '../../../../util/vs/editor/common/core/range';
12
import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';
13
import { AbstractText } from '../../../../util/vs/editor/common/core/text/abstractText';
14
import { PositionOffsetTransformer } from '../../../../util/vs/editor/common/core/text/positionToOffset';
15
16
export abstract class Random {
17
public static readonly alphabetSmallLowercase = 'abcdefgh';
18
public static readonly alphabetSmallUppercase = 'ABCDEFGH';
19
public static readonly alphabetLowercase = 'abcdefghijklmnopqrstuvwxyz';
20
public static readonly alphabetUppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
21
public static readonly basicAlphabet: string = ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
22
public static readonly basicAlphabetMultiline: string = ' \n\n\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
23
24
public static create(seed: number): Random {
25
return new MersenneTwister(seed);
26
}
27
28
public stringGenerator(alphabet: string): IGenerator<string> {
29
return {
30
next: () => {
31
const characterIndex = this.nextIntRange(0, alphabet.length);
32
return alphabet.charAt(characterIndex);
33
}
34
};
35
}
36
37
public abstract nextIntRange(start: number, endExclusive: number): number;
38
39
public nextString(length: number, alphabet = this.stringGenerator(Random.basicAlphabet)): string {
40
let randomText: string = '';
41
for (let i = 0; i < length; i++) {
42
randomText += alphabet.next();
43
}
44
return randomText;
45
}
46
47
public nextMultiLineString(lineCount: number, lineLengthRange: OffsetRange, alphabet = this.stringGenerator(Random.basicAlphabet)): string {
48
const lines: string[] = [];
49
for (let i = 0; i < lineCount; i++) {
50
const lineLength = this.nextIntRange(lineLengthRange.start, lineLengthRange.endExclusive);
51
lines.push(this.nextString(lineLength, alphabet));
52
}
53
return lines.join('\n');
54
}
55
56
public nextConsecutiveOffsets(range: OffsetRange, count: number): number[] {
57
const offsets = OffsetRange.ofLength(count).map(() => this.nextIntRange(range.start, range.endExclusive));
58
offsets.sort(numberComparator);
59
return offsets;
60
}
61
62
public nextConsecutivePositions(source: AbstractText, count: number): Position[] {
63
const t = new PositionOffsetTransformer(source.getValue());
64
const offsets = this.nextConsecutiveOffsets(new OffsetRange(0, t.text.length), count);
65
return offsets.map(offset => t.getPosition(offset));
66
}
67
68
public nextRange(source: AbstractText): Range {
69
const [start, end] = this.nextConsecutivePositions(source, 2);
70
return Range.fromPositions(start, end);
71
}
72
73
public nextTextEdit(target: AbstractText, singleTextEditCount: number): TextEdit {
74
const singleTextEdits: TextReplacement[] = [];
75
76
const positions = this.nextConsecutivePositions(target, singleTextEditCount * 2);
77
78
for (let i = 0; i < singleTextEditCount; i++) {
79
const start = positions[i * 2];
80
const end = positions[i * 2 + 1];
81
const newText = this.nextString(end.column - start.column, this.stringGenerator(Random.basicAlphabetMultiline));
82
singleTextEdits.push(new TextReplacement(Range.fromPositions(start, end), newText));
83
}
84
85
return new TextEdit(singleTextEdits).normalize();
86
}
87
88
public nextOffsetEdit(target: string, singleTextEditCount: number, newTextAlphabet = Random.basicAlphabetMultiline): StringEdit {
89
const singleTextEdits: StringReplacement[] = [];
90
91
const positions = this.nextConsecutiveOffsets(new OffsetRange(0, target.length), singleTextEditCount * 2);
92
93
for (let i = 0; i < singleTextEditCount; i++) {
94
const start = positions[i * 2];
95
const end = positions[i * 2 + 1];
96
const range = new OffsetRange(start, end);
97
98
const newTextLen = this.nextIntRange(range.isEmpty ? 1 : 0, 10);
99
const newText = this.nextString(newTextLen, this.stringGenerator(newTextAlphabet));
100
singleTextEdits.push(new StringReplacement(range, newText));
101
}
102
103
return new StringEdit(singleTextEdits).normalize();
104
}
105
106
public nextSingleOffsetEdit(target: string, newTextAlphabet = Random.basicAlphabetMultiline): StringReplacement {
107
const edit = this.nextOffsetEdit(target, 1, newTextAlphabet);
108
return edit.replacements[0];
109
}
110
}
111
112
export function sequenceGenerator<T>(sequence: T[]): IGenerator<T> {
113
let index = 0;
114
return {
115
next: () => {
116
if (index >= sequence.length) {
117
throw new BugIndicatingError('End of sequence');
118
}
119
const element = sequence[index];
120
index++;
121
return element;
122
}
123
};
124
}
125
126
export interface IGenerator<T> {
127
next(): T;
128
}
129
130
class MersenneTwister extends Random {
131
private readonly mt = new Array(624);
132
private index = 0;
133
134
constructor(seed: number) {
135
super();
136
137
this.mt[0] = seed >>> 0;
138
for (let i = 1; i < 624; i++) {
139
const s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
140
this.mt[i] = (((((s & 0xffff0000) >>> 16) * 0x6c078965) << 16) + (s & 0x0000ffff) * 0x6c078965 + i) >>> 0;
141
}
142
}
143
144
private _nextInt() {
145
if (this.index === 0) {
146
this.generateNumbers();
147
}
148
149
let y = this.mt[this.index];
150
y = y ^ (y >>> 11);
151
y = y ^ ((y << 7) & 0x9d2c5680);
152
y = y ^ ((y << 15) & 0xefc60000);
153
y = y ^ (y >>> 18);
154
155
this.index = (this.index + 1) % 624;
156
157
return y >>> 0;
158
}
159
160
public nextIntRange(start: number, endExclusive: number) {
161
const range = endExclusive - start;
162
return Math.floor(this._nextInt() / (0x100000000 / range)) + start;
163
}
164
165
private generateNumbers() {
166
for (let i = 0; i < 624; i++) {
167
const y = (this.mt[i] & 0x80000000) + (this.mt[(i + 1) % 624] & 0x7fffffff);
168
this.mt[i] = this.mt[(i + 397) % 624] ^ (y >>> 1);
169
if ((y % 2) !== 0) {
170
this.mt[i] = this.mt[i] ^ 0x9908b0df;
171
}
172
}
173
}
174
}
175
176