@singapore-editor/minimap 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/assets/minimap.worker-i4S59IOV.js +1616 -0
- package/dist/assets/minimap.worker-i4S59IOV.js.map +1 -0
- package/dist/color.d.ts +11 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +83 -0
- package/dist/color.js.map +1 -0
- package/dist/decorationMerge.d.ts +10 -0
- package/dist/decorationMerge.d.ts.map +1 -0
- package/dist/decorationMerge.js +65 -0
- package/dist/decorationMerge.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/layout.d.ts +43 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +137 -0
- package/dist/layout.js.map +1 -0
- package/dist/minimap.worker.d.ts +2 -0
- package/dist/minimap.worker.d.ts.map +1 -0
- package/dist/minimapCharRenderer.d.ts +13 -0
- package/dist/minimapCharRenderer.d.ts.map +1 -0
- package/dist/minimapCharRendererFactory.d.ts +14 -0
- package/dist/minimapCharRendererFactory.d.ts.map +1 -0
- package/dist/minimapCharSheet.d.ts +15 -0
- package/dist/minimapCharSheet.d.ts.map +1 -0
- package/dist/minimapCharSheet.js +24 -0
- package/dist/minimapCharSheet.js.map +1 -0
- package/dist/options.d.ts +3 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +65 -0
- package/dist/options.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +415 -0
- package/dist/plugin.js.map +1 -0
- package/dist/raster.d.ts +10 -0
- package/dist/raster.d.ts.map +1 -0
- package/dist/renderer.d.ts +58 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/sectionHeaders.d.ts +13 -0
- package/dist/sectionHeaders.d.ts.map +1 -0
- package/dist/style.css +97 -0
- package/dist/types.d.ts +211 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/viewportGeometry.d.ts +28 -0
- package/dist/viewportGeometry.d.ts.map +1 -0
- package/dist/viewportGeometry.js +22 -0
- package/dist/viewportGeometry.js.map +1 -0
- package/dist/workerClient.d.ts +131 -0
- package/dist/workerClient.d.ts.map +1 -0
- package/dist/workerClient.js +1337 -0
- package/dist/workerClient.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,1337 @@
|
|
|
1
|
+
import { computeFrameLayout, computeRenderLayout, visibleDocumentLineRange } from "./layout.js";
|
|
2
|
+
import { RGBA_BLACK, RGBA_WHITE, parseCssColor, transparent } from "./color.js";
|
|
3
|
+
import { createError } from "@singapore-editor/core/logging/evlog";
|
|
4
|
+
import { EditorSecondaryViewScheduler, createEditorSecondaryViewProjection } from "@singapore-editor/core/secondary-views";
|
|
5
|
+
//#region src/workerClient.ts
|
|
6
|
+
var MINIMAP_UPDATE_QUIET_DELAY_MS = 120;
|
|
7
|
+
var MINIMAP_UPDATE_MAX_DELAY_MS = 300;
|
|
8
|
+
var MINIMAP_FRAME_FLUSH_KEY = "minimap.flush.frame";
|
|
9
|
+
var MINIMAP_QUIET_FLUSH_KEY = "minimap.flush.quiet";
|
|
10
|
+
var MINIMAP_RENDER_KEY = "minimap.render";
|
|
11
|
+
var MinimapWorkerOwner = class {
|
|
12
|
+
options;
|
|
13
|
+
worker = null;
|
|
14
|
+
lifecycle = "ready";
|
|
15
|
+
postedRequests = 0;
|
|
16
|
+
disposalAcknowledged = false;
|
|
17
|
+
lastError = null;
|
|
18
|
+
disposalPromise = null;
|
|
19
|
+
resolveDisposal = null;
|
|
20
|
+
rejectDisposal = null;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.worker = this.createWorker();
|
|
24
|
+
}
|
|
25
|
+
inspect() {
|
|
26
|
+
return {
|
|
27
|
+
lifecycle: this.lifecycle,
|
|
28
|
+
postedRequests: this.postedRequests,
|
|
29
|
+
disposalAcknowledged: this.disposalAcknowledged,
|
|
30
|
+
lastError: this.lastError?.message ?? null
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
post(request, transfer) {
|
|
34
|
+
const handle = this.worker;
|
|
35
|
+
if (!this.canPost(handle)) return false;
|
|
36
|
+
this.postedRequests += 1;
|
|
37
|
+
try {
|
|
38
|
+
this.postToWorker(handle, request, transfer);
|
|
39
|
+
return true;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
this.fail(workerRequestError(error));
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
dispose() {
|
|
46
|
+
if (this.lifecycle === "disposed") return Promise.resolve();
|
|
47
|
+
if (this.disposalPromise) return this.disposalPromise;
|
|
48
|
+
if (!this.worker) {
|
|
49
|
+
this.finishDisposal();
|
|
50
|
+
return Promise.resolve();
|
|
51
|
+
}
|
|
52
|
+
this.lifecycle = "disposing";
|
|
53
|
+
this.disposalPromise = new Promise((resolve, reject) => {
|
|
54
|
+
this.resolveDisposal = resolve;
|
|
55
|
+
this.rejectDisposal = reject;
|
|
56
|
+
});
|
|
57
|
+
if (!this.post({ type: "dispose" })) this.rejectDisposal?.(this.lastError ?? workerDisposedError());
|
|
58
|
+
return this.disposalPromise;
|
|
59
|
+
}
|
|
60
|
+
createWorker() {
|
|
61
|
+
const handle = this.options.workerFactory?.() ?? new Worker(new URL("./assets/minimap.worker-i4S59IOV.js", import.meta.url), { type: "module" });
|
|
62
|
+
handle.onmessage = this.handleWorkerMessage;
|
|
63
|
+
handle.onerror = this.handleWorkerError;
|
|
64
|
+
return handle;
|
|
65
|
+
}
|
|
66
|
+
canPost(handle) {
|
|
67
|
+
if (!handle) return false;
|
|
68
|
+
if (this.lifecycle === "disposed") return false;
|
|
69
|
+
return this.lifecycle !== "crashed";
|
|
70
|
+
}
|
|
71
|
+
postToWorker(handle, request, transfer) {
|
|
72
|
+
if (transfer) {
|
|
73
|
+
handle.postMessage(request, transfer);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
handle.postMessage(request);
|
|
77
|
+
}
|
|
78
|
+
handleWorkerMessage = (event) => {
|
|
79
|
+
const response = event.data;
|
|
80
|
+
if (response.type === "disposed") {
|
|
81
|
+
this.disposalAcknowledged = true;
|
|
82
|
+
this.finishDisposal();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (response.type === "error") {
|
|
86
|
+
this.recordError(createWorkerResponseError(response));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.options.onMessage(response);
|
|
90
|
+
};
|
|
91
|
+
handleWorkerError = (event) => {
|
|
92
|
+
this.fail(createNativeWorkerError(event));
|
|
93
|
+
};
|
|
94
|
+
recordError(error) {
|
|
95
|
+
this.lastError = error;
|
|
96
|
+
this.options.onError?.(error);
|
|
97
|
+
}
|
|
98
|
+
fail(error) {
|
|
99
|
+
this.lastError = error;
|
|
100
|
+
this.lifecycle = "crashed";
|
|
101
|
+
this.terminateWorker();
|
|
102
|
+
this.rejectDisposal?.(error);
|
|
103
|
+
this.clearDisposalHandlers();
|
|
104
|
+
this.options.onError?.(error);
|
|
105
|
+
}
|
|
106
|
+
finishDisposal() {
|
|
107
|
+
this.lifecycle = "disposed";
|
|
108
|
+
this.terminateWorker();
|
|
109
|
+
this.resolveDisposal?.();
|
|
110
|
+
this.clearDisposalHandlers();
|
|
111
|
+
}
|
|
112
|
+
terminateWorker() {
|
|
113
|
+
this.worker?.terminate();
|
|
114
|
+
this.worker = null;
|
|
115
|
+
}
|
|
116
|
+
clearDisposalHandlers() {
|
|
117
|
+
this.resolveDisposal = null;
|
|
118
|
+
this.rejectDisposal = null;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var MinimapWorkerClient = class {
|
|
122
|
+
host;
|
|
123
|
+
options;
|
|
124
|
+
workerOwner;
|
|
125
|
+
colorResolver;
|
|
126
|
+
scheduler = new EditorSecondaryViewScheduler();
|
|
127
|
+
onLayoutWidth;
|
|
128
|
+
reservedLane;
|
|
129
|
+
externalDecorations;
|
|
130
|
+
pendingUpdate = null;
|
|
131
|
+
pendingUpdateReady = false;
|
|
132
|
+
pendingRender = false;
|
|
133
|
+
activeRenderToken = 0;
|
|
134
|
+
renderInFlight = false;
|
|
135
|
+
latestBaseStyles = null;
|
|
136
|
+
latestBaseStylesSignature = "";
|
|
137
|
+
latestLayoutSignature = "";
|
|
138
|
+
latestThemeSignature = "";
|
|
139
|
+
latestSnapshot;
|
|
140
|
+
latestViewport;
|
|
141
|
+
postedViewport = null;
|
|
142
|
+
latestFullDocumentSnapshot = null;
|
|
143
|
+
workerDocumentState = null;
|
|
144
|
+
latestTokenSource;
|
|
145
|
+
disposed = false;
|
|
146
|
+
constructor(options) {
|
|
147
|
+
this.host = options.host;
|
|
148
|
+
this.options = options.options;
|
|
149
|
+
this.onLayoutWidth = options.onLayoutWidth;
|
|
150
|
+
this.reservedLane = options.reservedLane;
|
|
151
|
+
this.externalDecorations = options.decorations;
|
|
152
|
+
this.latestSnapshot = options.snapshot;
|
|
153
|
+
this.latestViewport = options.snapshot.viewport;
|
|
154
|
+
this.latestTokenSource = options.snapshot.tokens;
|
|
155
|
+
this.colorResolver = new ColorResolver(options.host.colorScope);
|
|
156
|
+
this.workerOwner = new MinimapWorkerOwner({
|
|
157
|
+
onError: this.handleWorkerError,
|
|
158
|
+
onMessage: this.handleWorkerMessage
|
|
159
|
+
});
|
|
160
|
+
this.init(options.snapshot);
|
|
161
|
+
}
|
|
162
|
+
inspectWorker() {
|
|
163
|
+
return this.workerOwner.inspect();
|
|
164
|
+
}
|
|
165
|
+
update(snapshot, kind, change) {
|
|
166
|
+
if (this.disposed) return;
|
|
167
|
+
if (this.shouldSkipDocumentUpdate(snapshot, kind)) {
|
|
168
|
+
this.latestSnapshot = snapshot;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const previousSnapshot = this.latestSnapshot;
|
|
172
|
+
this.latestSnapshot = snapshot;
|
|
173
|
+
if (kind === "viewport") {
|
|
174
|
+
this.latestViewport = snapshot.viewport;
|
|
175
|
+
const layoutUpdated = this.postLayoutIfNeeded(snapshot);
|
|
176
|
+
this.updateViewport(snapshot.viewport);
|
|
177
|
+
if (layoutUpdated) this.requestRender();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const update = createPendingUpdate(snapshot, kind, change, previousSnapshot);
|
|
181
|
+
this.latestViewport = snapshot.viewport;
|
|
182
|
+
this.applyImmediateViewport();
|
|
183
|
+
this.queueUpdate(update);
|
|
184
|
+
}
|
|
185
|
+
queueUpdate(update) {
|
|
186
|
+
this.pendingUpdate = mergePendingUpdate(this.pendingUpdate, update);
|
|
187
|
+
recordMinimapPerformanceDiagnostic("minimap.updateClassification", () => pendingUpdateDiagnostics(update));
|
|
188
|
+
if (!this.renderInFlight) this.scheduleFlush();
|
|
189
|
+
}
|
|
190
|
+
updateViewport(viewport) {
|
|
191
|
+
if (this.disposed) return;
|
|
192
|
+
this.latestViewport = viewport;
|
|
193
|
+
this.applyImmediateViewport();
|
|
194
|
+
const next = this.viewport(this.latestSnapshot);
|
|
195
|
+
if (sameViewport(this.postedViewport, next)) return;
|
|
196
|
+
this.postedViewport = next;
|
|
197
|
+
this.post({
|
|
198
|
+
type: "updateViewport",
|
|
199
|
+
viewport: next
|
|
200
|
+
});
|
|
201
|
+
this.requestRender();
|
|
202
|
+
}
|
|
203
|
+
frameLayout() {
|
|
204
|
+
const viewport = this.viewport(this.latestSnapshot);
|
|
205
|
+
const metrics = this.metrics(this.latestSnapshot);
|
|
206
|
+
const renderLayout = computeRenderLayout({
|
|
207
|
+
minimap: this.options,
|
|
208
|
+
metrics,
|
|
209
|
+
viewport,
|
|
210
|
+
lineCount: this.latestSnapshot.lineCount
|
|
211
|
+
});
|
|
212
|
+
return computeFrameLayout({
|
|
213
|
+
renderLayout,
|
|
214
|
+
metrics,
|
|
215
|
+
viewport,
|
|
216
|
+
lineCount: this.latestSnapshot.lineCount,
|
|
217
|
+
realLineCount: this.latestSnapshot.lineCount,
|
|
218
|
+
previous: null
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
setExternalDecorations(decorations) {
|
|
222
|
+
if (this.disposed) return;
|
|
223
|
+
this.externalDecorations = decorations;
|
|
224
|
+
this.queueUpdate(createPendingUpdate(this.latestSnapshot, "decorations", null, this.latestSnapshot));
|
|
225
|
+
}
|
|
226
|
+
dispose() {
|
|
227
|
+
if (this.disposed) return;
|
|
228
|
+
this.disposed = true;
|
|
229
|
+
this.cancelScheduledFlush();
|
|
230
|
+
this.scheduler.dispose();
|
|
231
|
+
this.workerOwner.dispose().catch(() => void 0);
|
|
232
|
+
this.colorResolver.dispose();
|
|
233
|
+
}
|
|
234
|
+
init(snapshot) {
|
|
235
|
+
const mainCanvas = this.host.mainCanvas.transferControlToOffscreen();
|
|
236
|
+
const decorationsCanvas = this.host.decorationsCanvas.transferControlToOffscreen();
|
|
237
|
+
const baseStyles = this.baseStyles();
|
|
238
|
+
this.latestBaseStyles = baseStyles;
|
|
239
|
+
this.latestBaseStylesSignature = baseStylesSignature(baseStyles);
|
|
240
|
+
this.latestThemeSignature = themeSignature(snapshot);
|
|
241
|
+
const request = {
|
|
242
|
+
type: "init",
|
|
243
|
+
options: this.options,
|
|
244
|
+
baseStyles,
|
|
245
|
+
mainCanvas,
|
|
246
|
+
decorationsCanvas
|
|
247
|
+
};
|
|
248
|
+
this.post(request, [mainCanvas, decorationsCanvas]);
|
|
249
|
+
this.post({
|
|
250
|
+
type: "openDocument",
|
|
251
|
+
document: this.trackedDocumentPayload(snapshot)
|
|
252
|
+
});
|
|
253
|
+
this.latestFullDocumentSnapshot = snapshot;
|
|
254
|
+
this.postedViewport = this.viewport(snapshot);
|
|
255
|
+
this.post({
|
|
256
|
+
type: "updateLayout",
|
|
257
|
+
metrics: this.metrics(snapshot),
|
|
258
|
+
viewport: this.postedViewport
|
|
259
|
+
});
|
|
260
|
+
this.latestLayoutSignature = layoutSignature(snapshot, this.minimapHeight(snapshot));
|
|
261
|
+
this.postRender(snapshot);
|
|
262
|
+
}
|
|
263
|
+
scheduleFlush() {
|
|
264
|
+
const pending = this.pendingUpdate;
|
|
265
|
+
if (!pending) return;
|
|
266
|
+
if (this.pendingUpdateReady) {
|
|
267
|
+
this.scheduleFrameFlush();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (shouldDeferMinimapUpdate(pending)) {
|
|
271
|
+
this.scheduleDeferredFlush();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
this.scheduleFrameFlush();
|
|
275
|
+
}
|
|
276
|
+
scheduleFrameFlush() {
|
|
277
|
+
this.scheduler.schedule({
|
|
278
|
+
key: MINIMAP_FRAME_FLUSH_KEY,
|
|
279
|
+
taskClass: "visible-render",
|
|
280
|
+
priority: "high",
|
|
281
|
+
tags: {
|
|
282
|
+
configuration: "frame",
|
|
283
|
+
version: this.latestSnapshot.textVersion
|
|
284
|
+
},
|
|
285
|
+
run: () => this.flushPendingUpdate()
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
scheduleDeferredFlush() {
|
|
289
|
+
this.cancelScheduledFrame();
|
|
290
|
+
this.scheduler.schedule({
|
|
291
|
+
key: MINIMAP_QUIET_FLUSH_KEY,
|
|
292
|
+
taskClass: "background-derived",
|
|
293
|
+
priority: "low",
|
|
294
|
+
delayMs: MINIMAP_UPDATE_QUIET_DELAY_MS,
|
|
295
|
+
maxDelayMs: MINIMAP_UPDATE_MAX_DELAY_MS,
|
|
296
|
+
tags: {
|
|
297
|
+
configuration: "quiet",
|
|
298
|
+
version: this.latestSnapshot.textVersion
|
|
299
|
+
},
|
|
300
|
+
run: this.flushDeferredUpdate
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
flushDeferredUpdate = () => {
|
|
304
|
+
this.cancelDeferredFlush();
|
|
305
|
+
this.pendingUpdateReady = true;
|
|
306
|
+
this.scheduleFrameFlush();
|
|
307
|
+
};
|
|
308
|
+
flushPendingUpdate() {
|
|
309
|
+
if (this.disposed) return;
|
|
310
|
+
if (this.renderInFlight) return;
|
|
311
|
+
const pending = this.pendingUpdate;
|
|
312
|
+
if (!pending) return;
|
|
313
|
+
measureMinimapPerformance("minimap.flushPendingUpdate", () => this.flushPendingUpdateNow(pending), () => pendingUpdateDiagnostics(pending));
|
|
314
|
+
}
|
|
315
|
+
flushPendingUpdateNow(pending) {
|
|
316
|
+
this.pendingUpdate = null;
|
|
317
|
+
this.pendingUpdateReady = false;
|
|
318
|
+
measureMinimapPerformance("minimap.postUpdate", () => this.postUpdate(pending), () => pendingUpdateDiagnostics(pending));
|
|
319
|
+
const layoutUpdated = this.postLayoutIfNeeded(pending.snapshot);
|
|
320
|
+
this.postViewportIfNeeded(pending.snapshot, pending.syncViewport, layoutUpdated);
|
|
321
|
+
this.postRender(pending.snapshot);
|
|
322
|
+
}
|
|
323
|
+
postLayoutIfNeeded(snapshot) {
|
|
324
|
+
const signature = layoutSignature(snapshot, this.minimapHeight(snapshot));
|
|
325
|
+
if (signature === this.latestLayoutSignature) return false;
|
|
326
|
+
this.latestLayoutSignature = signature;
|
|
327
|
+
this.postedViewport = this.viewport(snapshot);
|
|
328
|
+
this.post({
|
|
329
|
+
type: "updateLayout",
|
|
330
|
+
metrics: this.metrics(snapshot),
|
|
331
|
+
viewport: this.postedViewport
|
|
332
|
+
});
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
postViewportIfNeeded(snapshot, syncViewport, layoutUpdated) {
|
|
336
|
+
if (layoutUpdated) return;
|
|
337
|
+
if (!syncViewport) return;
|
|
338
|
+
this.postedViewport = this.viewport(snapshot);
|
|
339
|
+
this.post({
|
|
340
|
+
type: "updateViewport",
|
|
341
|
+
viewport: this.postedViewport
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
postUpdate(update) {
|
|
345
|
+
const snapshot = update.snapshot;
|
|
346
|
+
let tokenColorsInvalidated = false;
|
|
347
|
+
if (update.syncBaseStyles) {
|
|
348
|
+
tokenColorsInvalidated = this.refreshThemeColorCache(snapshot);
|
|
349
|
+
tokenColorsInvalidated = this.syncBaseStyles() || tokenColorsInvalidated;
|
|
350
|
+
}
|
|
351
|
+
if (update.replaceDocument) {
|
|
352
|
+
this.post({
|
|
353
|
+
type: "replaceDocument",
|
|
354
|
+
document: this.trackedDocumentPayload(snapshot)
|
|
355
|
+
});
|
|
356
|
+
this.latestFullDocumentSnapshot = snapshot;
|
|
357
|
+
this.latestTokenSource = snapshot.tokens;
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (update.edits.length > 0) {
|
|
361
|
+
this.latestFullDocumentSnapshot = null;
|
|
362
|
+
this.postEditUpdate(update);
|
|
363
|
+
this.latestTokenSource = update.tokenSourceAfterEdits;
|
|
364
|
+
}
|
|
365
|
+
if (update.syncTokens) this.postTokenUpdate(snapshot, tokenColorsInvalidated);
|
|
366
|
+
if (update.syncSelection && update.edits.length === 0) this.post({
|
|
367
|
+
type: "updateSelection",
|
|
368
|
+
selections: selections(snapshot.selections)
|
|
369
|
+
});
|
|
370
|
+
if (update.syncExternalDecorations) this.post({
|
|
371
|
+
type: "updateExternalDecorations",
|
|
372
|
+
decorations: this.externalDecorations
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
postEditUpdate(update) {
|
|
376
|
+
const document = this.documentEditPayload(update, this.workerDocumentState);
|
|
377
|
+
const patch = document.summaryPatch;
|
|
378
|
+
if (this.workerDocumentState) this.workerDocumentState = {
|
|
379
|
+
textLength: patch.textLength,
|
|
380
|
+
lineCount: this.workerDocumentState.lineCount - patch.deleteCount + patch.lines.length
|
|
381
|
+
};
|
|
382
|
+
if (update.edits.length === 1) {
|
|
383
|
+
this.post({
|
|
384
|
+
type: "applyEdit",
|
|
385
|
+
edit: update.edits[0],
|
|
386
|
+
document
|
|
387
|
+
});
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
this.post({
|
|
391
|
+
type: "applyEdits",
|
|
392
|
+
edits: update.edits,
|
|
393
|
+
document
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
trackedDocumentPayload(snapshot) {
|
|
397
|
+
const document = this.documentPayload(snapshot);
|
|
398
|
+
this.workerDocumentState = {
|
|
399
|
+
textLength: document.textLength,
|
|
400
|
+
lineCount: document.lines.length
|
|
401
|
+
};
|
|
402
|
+
return document;
|
|
403
|
+
}
|
|
404
|
+
postTokenUpdate(snapshot, forceFullUpdate) {
|
|
405
|
+
const sourceTokens = this.latestTokenSource;
|
|
406
|
+
if (forceFullUpdate || !sourceTokens) {
|
|
407
|
+
this.postFullTokenUpdate(snapshot);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const patch = this.tokenPatch(sourceTokens, snapshot.tokens);
|
|
411
|
+
this.latestTokenSource = snapshot.tokens;
|
|
412
|
+
if (patch.deleteCount === 0 && patch.tokens.length === 0) return;
|
|
413
|
+
this.post({
|
|
414
|
+
type: "updateTokenRange",
|
|
415
|
+
patch
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
postFullTokenUpdate(snapshot) {
|
|
419
|
+
this.post({
|
|
420
|
+
type: "updateTokens",
|
|
421
|
+
tokens: this.tokens(snapshot.tokens)
|
|
422
|
+
});
|
|
423
|
+
this.latestTokenSource = snapshot.tokens;
|
|
424
|
+
}
|
|
425
|
+
tokenPatch(previous, next) {
|
|
426
|
+
const range = previous.changedRangeTo(next);
|
|
427
|
+
return {
|
|
428
|
+
start: range.start,
|
|
429
|
+
deleteCount: range.deleteCount,
|
|
430
|
+
tokens: this.tokens(next, range.start, range.insertEnd)
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
syncBaseStyles() {
|
|
434
|
+
const styles = this.baseStyles();
|
|
435
|
+
const signature = baseStylesSignature(styles);
|
|
436
|
+
if (signature === this.latestBaseStylesSignature) return false;
|
|
437
|
+
this.latestBaseStyles = styles;
|
|
438
|
+
this.latestBaseStylesSignature = signature;
|
|
439
|
+
this.colorResolver.clear();
|
|
440
|
+
this.post({
|
|
441
|
+
type: "updateBaseStyles",
|
|
442
|
+
baseStyles: styles
|
|
443
|
+
});
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
refreshThemeColorCache(snapshot) {
|
|
447
|
+
const signature = themeSignature(snapshot);
|
|
448
|
+
if (signature === this.latestThemeSignature) return false;
|
|
449
|
+
this.latestThemeSignature = signature;
|
|
450
|
+
this.colorResolver.clear();
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
shouldSkipDocumentUpdate(snapshot, kind) {
|
|
454
|
+
if (kind !== "document") return false;
|
|
455
|
+
const latest = this.latestFullDocumentSnapshot;
|
|
456
|
+
if (!latest) return false;
|
|
457
|
+
return latest === snapshot;
|
|
458
|
+
}
|
|
459
|
+
requestRender() {
|
|
460
|
+
if (this.renderInFlight) {
|
|
461
|
+
this.pendingRender = true;
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
this.postRender(this.latestSnapshot);
|
|
465
|
+
}
|
|
466
|
+
postRender(snapshot) {
|
|
467
|
+
this.pendingRender = false;
|
|
468
|
+
let renderToken = 0;
|
|
469
|
+
const handle = this.scheduler.schedule({
|
|
470
|
+
key: MINIMAP_RENDER_KEY,
|
|
471
|
+
taskClass: "visible-render",
|
|
472
|
+
priority: "high",
|
|
473
|
+
defer: true,
|
|
474
|
+
tags: {
|
|
475
|
+
configuration: "render",
|
|
476
|
+
snapshotVersion: snapshot.textVersion,
|
|
477
|
+
viewport: snapshot.viewport.visibleRange.start
|
|
478
|
+
},
|
|
479
|
+
run: (context) => this.postScheduledRender(snapshot, context.token),
|
|
480
|
+
cancel: () => this.cancelScheduledRender(renderToken)
|
|
481
|
+
});
|
|
482
|
+
renderToken = handle.token;
|
|
483
|
+
this.activeRenderToken = handle.token;
|
|
484
|
+
this.renderInFlight = true;
|
|
485
|
+
}
|
|
486
|
+
postScheduledRender(snapshot, token) {
|
|
487
|
+
if (token !== this.activeRenderToken) return;
|
|
488
|
+
this.pendingRender = false;
|
|
489
|
+
this.sizeCanvasElements(snapshot);
|
|
490
|
+
this.post({
|
|
491
|
+
type: "render",
|
|
492
|
+
sequence: token
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
cancelScheduledRender(token) {
|
|
496
|
+
if (token !== this.activeRenderToken) return;
|
|
497
|
+
this.activeRenderToken = 0;
|
|
498
|
+
this.renderInFlight = false;
|
|
499
|
+
}
|
|
500
|
+
applyImmediateViewport() {
|
|
501
|
+
const frame = this.frameLayout();
|
|
502
|
+
setStyleValue(this.host.slider, "display", frame.sliderNeeded ? "block" : "none");
|
|
503
|
+
setStyleValue(this.host.slider, "transform", `translate3d(0, ${frame.sliderTop}px, 0)`);
|
|
504
|
+
setStyleValue(this.host.slider, "height", `${frame.sliderHeight}px`);
|
|
505
|
+
setStyleValue(this.host.sliderHorizontal, "height", `${frame.sliderHeight}px`);
|
|
506
|
+
setClassName(this.host.shadow, shadowVisible(this.latestViewport) ? "editor-minimap-shadow editor-minimap-shadow-visible" : "editor-minimap-shadow editor-minimap-shadow-hidden");
|
|
507
|
+
}
|
|
508
|
+
documentPayload(snapshot) {
|
|
509
|
+
const projection = createEditorSecondaryViewProjection(snapshot);
|
|
510
|
+
let payload = null;
|
|
511
|
+
return measureMinimapPerformance("minimap.documentPayload", () => {
|
|
512
|
+
payload = {
|
|
513
|
+
...documentSummaryPayload(projection.text, this.options.maxColumn),
|
|
514
|
+
tokens: this.tokens(projection.syntaxColors.tokens),
|
|
515
|
+
selections: selections(projection.selections),
|
|
516
|
+
decorations: this.externalDecorations,
|
|
517
|
+
externalDecorations: this.externalDecorations
|
|
518
|
+
};
|
|
519
|
+
return payload;
|
|
520
|
+
}, () => documentPayloadDiagnostics(payload));
|
|
521
|
+
}
|
|
522
|
+
documentEditPayload(update, workerDocument) {
|
|
523
|
+
const snapshot = update.snapshot;
|
|
524
|
+
const projection = createEditorSecondaryViewProjection(snapshot);
|
|
525
|
+
let payload = null;
|
|
526
|
+
return measureMinimapPerformance("minimap.documentEditPayload", () => {
|
|
527
|
+
payload = {
|
|
528
|
+
selections: selections(projection.selections),
|
|
529
|
+
summaryPatch: documentSummaryPatchPayload(projection.text, previousDocumentSummary(update), update.edits, this.options.maxColumn, workerDocument)
|
|
530
|
+
};
|
|
531
|
+
return payload;
|
|
532
|
+
}, () => documentEditPayloadDiagnostics(payload));
|
|
533
|
+
}
|
|
534
|
+
tokens(tokens, from = 0, to = tokens.length) {
|
|
535
|
+
return measureMinimapPerformance("minimap.tokens", () => {
|
|
536
|
+
const foreground = this.latestBaseStyles?.foreground ?? this.baseStyles().foreground;
|
|
537
|
+
const colors = tokens.styles.map((style) => this.colorResolver.resolve(style.color, foreground));
|
|
538
|
+
const projected = [];
|
|
539
|
+
tokens.forEachInRange(from, to, (start, end, styleId) => {
|
|
540
|
+
projected.push({
|
|
541
|
+
start,
|
|
542
|
+
end,
|
|
543
|
+
color: colors[styleId]
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
return projected;
|
|
547
|
+
}, () => ({
|
|
548
|
+
inputTokens: tokens.length,
|
|
549
|
+
outputTokens: Math.max(0, to - from)
|
|
550
|
+
}));
|
|
551
|
+
}
|
|
552
|
+
metrics(snapshot) {
|
|
553
|
+
return {
|
|
554
|
+
rowHeight: snapshot.metrics.rowHeight,
|
|
555
|
+
characterWidth: snapshot.metrics.characterWidth,
|
|
556
|
+
devicePixelRatio: globalThis.devicePixelRatio || 1
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
viewport(snapshot) {
|
|
560
|
+
const snapshotViewport = this.latestViewport;
|
|
561
|
+
const fallbackClientHeight = snapshotViewport.clientHeight > 0 ? 0 : this.host.colorScope.clientHeight;
|
|
562
|
+
const fallbackClientWidth = snapshotViewport.clientWidth > 0 ? 0 : Math.max(0, this.host.colorScope.clientWidth - this.reservedLane());
|
|
563
|
+
const clientHeight = positiveOrFallback(snapshotViewport.clientHeight, fallbackClientHeight);
|
|
564
|
+
const clientWidth = positiveOrFallback(snapshotViewport.clientWidth, fallbackClientWidth);
|
|
565
|
+
const fallbackScrollHeight = snapshotViewport.scrollHeight > 0 ? 0 : this.host.colorScope.scrollHeight;
|
|
566
|
+
const fallbackScrollWidth = snapshotViewport.scrollWidth > 0 ? 0 : this.host.colorScope.scrollWidth;
|
|
567
|
+
const range = visibleDocumentLineRange(snapshot, snapshotViewport);
|
|
568
|
+
return {
|
|
569
|
+
scrollTop: snapshotViewport.scrollTop,
|
|
570
|
+
scrollRow: snapshotViewport.scrollRow,
|
|
571
|
+
scrollLeft: snapshotViewport.scrollLeft,
|
|
572
|
+
scrollHeight: Math.max(snapshotViewport.scrollHeight, fallbackScrollHeight, clientHeight),
|
|
573
|
+
scrollWidth: Math.max(snapshotViewport.scrollWidth, fallbackScrollWidth, clientWidth),
|
|
574
|
+
clientHeight,
|
|
575
|
+
clientWidth,
|
|
576
|
+
minimapHeight: this.minimapHeight(snapshot),
|
|
577
|
+
reservedWidth: Math.max(0, this.reservedLane()),
|
|
578
|
+
visibleStart: range.start,
|
|
579
|
+
visibleEnd: range.end
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
minimapHeight(snapshot) {
|
|
583
|
+
const height = Number.parseFloat(this.host.root.style.height);
|
|
584
|
+
if (Number.isFinite(height)) return Math.max(0, height);
|
|
585
|
+
if (snapshot.viewport.clientHeight > 0) return snapshot.viewport.clientHeight;
|
|
586
|
+
return this.host.colorScope.clientHeight;
|
|
587
|
+
}
|
|
588
|
+
baseStyles() {
|
|
589
|
+
const style = getComputedStyle(this.host.colorScope);
|
|
590
|
+
const foreground = this.colorResolver.resolve(style.color, RGBA_WHITE);
|
|
591
|
+
const background = this.colorResolver.resolve(style.backgroundColor, RGBA_BLACK);
|
|
592
|
+
return {
|
|
593
|
+
foreground,
|
|
594
|
+
background,
|
|
595
|
+
minimapBackground: transparent(this.colorResolver.resolve(style.getPropertyValue("--editor-minimap-background"), background), minimapBackgroundOpacity(style)),
|
|
596
|
+
foregroundOpacity: 255,
|
|
597
|
+
selection: this.colorResolver.resolve(style.getPropertyValue("--editor-minimap-selection-highlight"), {
|
|
598
|
+
r: 56,
|
|
599
|
+
g: 189,
|
|
600
|
+
b: 248,
|
|
601
|
+
a: 128
|
|
602
|
+
}),
|
|
603
|
+
slider: style.getPropertyValue("--editor-minimap-slider-background") || "rgba(121,121,121,.2)",
|
|
604
|
+
sliderHover: style.getPropertyValue("--editor-minimap-slider-hover-background") || "rgba(121,121,121,.35)",
|
|
605
|
+
sliderActive: style.getPropertyValue("--editor-minimap-slider-active-background") || "rgba(121,121,121,.5)",
|
|
606
|
+
fontFamily: style.fontFamily || "monospace"
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
sizeCanvasElements(snapshot) {
|
|
610
|
+
const height = `${this.minimapHeight(snapshot)}px`;
|
|
611
|
+
setStyleValue(this.host.mainCanvas, "height", height);
|
|
612
|
+
setStyleValue(this.host.decorationsCanvas, "height", height);
|
|
613
|
+
}
|
|
614
|
+
handleWorkerMessage = (response) => {
|
|
615
|
+
if (this.disposed) return;
|
|
616
|
+
if (response.type === "layout") {
|
|
617
|
+
this.applyLayout(response.layout.width, response.layout.canvasOuterWidth, response.layout.canvasOuterHeight);
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (response.type === "rendered") {
|
|
621
|
+
if (!this.isCurrentRenderResponse(response)) return;
|
|
622
|
+
this.scheduler.cancel(MINIMAP_RENDER_KEY);
|
|
623
|
+
this.renderInFlight = false;
|
|
624
|
+
this.activeRenderToken = 0;
|
|
625
|
+
if (this.pendingUpdate) this.scheduleFlush();
|
|
626
|
+
if (this.renderInFlight) return;
|
|
627
|
+
if (this.pendingRender) this.requestRender();
|
|
628
|
+
this.applyImmediateViewport();
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
applyLayout(width, canvasWidth, canvasHeight) {
|
|
633
|
+
this.onLayoutWidth(width);
|
|
634
|
+
setStyleValue(this.host.mainCanvas, "width", `${canvasWidth}px`);
|
|
635
|
+
setStyleValue(this.host.decorationsCanvas, "width", `${canvasWidth}px`);
|
|
636
|
+
setStyleValue(this.host.sliderHorizontal, "width", `${canvasWidth}px`);
|
|
637
|
+
setStyleValue(this.host.mainCanvas, "height", `${canvasHeight}px`);
|
|
638
|
+
setStyleValue(this.host.decorationsCanvas, "height", `${canvasHeight}px`);
|
|
639
|
+
}
|
|
640
|
+
handleWorkerError = (error) => {
|
|
641
|
+
console.warn(error.toString(), error);
|
|
642
|
+
};
|
|
643
|
+
post(request, transfer) {
|
|
644
|
+
measureMinimapPerformance("minimap.post", () => {
|
|
645
|
+
this.workerOwner.post(request, transfer);
|
|
646
|
+
}, () => requestDiagnostics(request));
|
|
647
|
+
}
|
|
648
|
+
cancelScheduledFlush() {
|
|
649
|
+
this.cancelScheduledFrame();
|
|
650
|
+
this.cancelDeferredFlush();
|
|
651
|
+
}
|
|
652
|
+
cancelScheduledFrame() {
|
|
653
|
+
this.scheduler.cancel(MINIMAP_FRAME_FLUSH_KEY);
|
|
654
|
+
}
|
|
655
|
+
cancelDeferredFlush() {
|
|
656
|
+
this.scheduler.cancel(MINIMAP_QUIET_FLUSH_KEY);
|
|
657
|
+
}
|
|
658
|
+
isCurrentRenderResponse(response) {
|
|
659
|
+
return response.sequence === this.activeRenderToken;
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
function canUseMinimapWorker() {
|
|
663
|
+
if (typeof Worker === "undefined") return false;
|
|
664
|
+
if (typeof OffscreenCanvas === "undefined") return false;
|
|
665
|
+
return typeof HTMLCanvasElement !== "undefined" && "transferControlToOffscreen" in HTMLCanvasElement.prototype;
|
|
666
|
+
}
|
|
667
|
+
function workerRequestError(error) {
|
|
668
|
+
if (error instanceof Error) return error;
|
|
669
|
+
return new Error(String(error));
|
|
670
|
+
}
|
|
671
|
+
function createWorkerResponseError(response) {
|
|
672
|
+
const workerMessage = nonEmptyString(response.message);
|
|
673
|
+
return createError({
|
|
674
|
+
code: "minimap.WORKER_REQUEST_FAILED",
|
|
675
|
+
message: messageWithDetail("Minimap worker request failed", workerMessage),
|
|
676
|
+
why: workerMessage ?? "The minimap worker reported an error without details.",
|
|
677
|
+
fix: "The editor keeps running; inspect the minimap worker request and renderer state if the minimap stops updating.",
|
|
678
|
+
internal: {
|
|
679
|
+
responseType: response.type,
|
|
680
|
+
sequence: response.sequence ?? null,
|
|
681
|
+
workerMessage: response.message
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
function createNativeWorkerError(event) {
|
|
686
|
+
const browserMessage = nonEmptyString(event.message);
|
|
687
|
+
return createError({
|
|
688
|
+
code: "minimap.WORKER_CRASHED",
|
|
689
|
+
message: messageWithDetail("Minimap worker crashed", browserMessage),
|
|
690
|
+
why: nativeWorkerFailureReason(browserMessage),
|
|
691
|
+
fix: "The editor keeps running without the minimap for this worker generation. Check the worker script request, CSP, MIME type, and browser worker support.",
|
|
692
|
+
cause: event.error instanceof Error ? event.error : void 0,
|
|
693
|
+
internal: workerErrorEventInternal(event)
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function nativeWorkerFailureReason(browserMessage) {
|
|
697
|
+
if (browserMessage) return `The browser reported: ${browserMessage}`;
|
|
698
|
+
return "The browser reported a native worker failure without an error message. This usually means the worker script failed to load or crashed before its own error handler ran.";
|
|
699
|
+
}
|
|
700
|
+
function workerErrorEventInternal(event) {
|
|
701
|
+
const error = event.error;
|
|
702
|
+
return {
|
|
703
|
+
browserMessage: nonEmptyString(event.message),
|
|
704
|
+
filename: nonEmptyString(event.filename),
|
|
705
|
+
lineNumber: positiveNumberOrNull(event.lineno),
|
|
706
|
+
columnNumber: positiveNumberOrNull(event.colno),
|
|
707
|
+
errorName: error instanceof Error ? error.name : null,
|
|
708
|
+
errorMessage: errorMessage(error),
|
|
709
|
+
errorStack: error instanceof Error ? error.stack : null,
|
|
710
|
+
rawErrorType: rawErrorType(error)
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function errorMessage(error) {
|
|
714
|
+
if (error instanceof Error) return error.message;
|
|
715
|
+
if (typeof error === "string") return error;
|
|
716
|
+
return null;
|
|
717
|
+
}
|
|
718
|
+
function rawErrorType(error) {
|
|
719
|
+
if (error === null || error === void 0) return null;
|
|
720
|
+
if (error instanceof Error) return error.name;
|
|
721
|
+
return Object.prototype.toString.call(error);
|
|
722
|
+
}
|
|
723
|
+
function messageWithDetail(summary, detail) {
|
|
724
|
+
if (!detail) return summary;
|
|
725
|
+
return `${summary}: ${detail}`;
|
|
726
|
+
}
|
|
727
|
+
function nonEmptyString(value) {
|
|
728
|
+
const trimmed = value?.trim() ?? "";
|
|
729
|
+
if (trimmed.length === 0) return null;
|
|
730
|
+
return trimmed;
|
|
731
|
+
}
|
|
732
|
+
function positiveNumberOrNull(value) {
|
|
733
|
+
if (value > 0) return value;
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
function workerDisposedError() {
|
|
737
|
+
return /* @__PURE__ */ new Error("Minimap worker is disposed");
|
|
738
|
+
}
|
|
739
|
+
function selections(selections) {
|
|
740
|
+
return selections.map((selection) => minimapSelection(selection));
|
|
741
|
+
}
|
|
742
|
+
function minimapSelection(selection) {
|
|
743
|
+
return {
|
|
744
|
+
startOffset: selection.startOffset,
|
|
745
|
+
endOffset: selection.endOffset
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
function arrayLineStarts(lineStarts) {
|
|
749
|
+
return {
|
|
750
|
+
length: lineStarts.length,
|
|
751
|
+
at: (index) => lineStarts[index],
|
|
752
|
+
indexForOffset: (offset) => arrayLineIndexForOffset(lineStarts, offset),
|
|
753
|
+
firstIndexAtOrAfter: (target) => arrayFirstLineStartAtOrAfter(lineStarts, target),
|
|
754
|
+
toArray: () => lineStarts
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function documentSummaryPayload(text, maxColumn) {
|
|
758
|
+
const textLength = text.length;
|
|
759
|
+
const lineStarts = text.lineStartsView.toArray();
|
|
760
|
+
return {
|
|
761
|
+
textLength,
|
|
762
|
+
lineStarts,
|
|
763
|
+
lines: lineStarts.map((startOffset, index) => lineSummaryFromSnapshot(text, startOffset, lineEndOffset(arrayLineStarts(lineStarts), index, textLength), maxColumn))
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function documentSummaryPatchPayload(text, previous, edits, maxColumn, workerDocument) {
|
|
767
|
+
const textLength = text.length;
|
|
768
|
+
const lineStarts = text.lineStartsView;
|
|
769
|
+
const range = documentSummaryPatchRange(previous, lineStarts, textLength, edits, workerDocument);
|
|
770
|
+
const lines = [];
|
|
771
|
+
for (let lineIndex = range.startLine; lineIndex < range.insertEndLine; lineIndex += 1) lines.push(lineSummaryFromSnapshot(text, lineStarts.at(lineIndex) ?? textLength, lineEndOffset(lineStarts, lineIndex, textLength), maxColumn));
|
|
772
|
+
return {
|
|
773
|
+
textLength,
|
|
774
|
+
startLine: range.startLine,
|
|
775
|
+
deleteCount: range.deleteCount,
|
|
776
|
+
lines
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
function lineSummaryFromSnapshot(text, startOffset, endOffset, maxColumn) {
|
|
780
|
+
const length = Math.max(0, endOffset - startOffset);
|
|
781
|
+
const clippedEnd = startOffset + Math.min(length, maxColumn);
|
|
782
|
+
return {
|
|
783
|
+
text: text.snapshot.readRange(startOffset, clippedEnd),
|
|
784
|
+
length
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function lineEndOffset(lineStarts, index, textLength) {
|
|
788
|
+
const startOffset = lineStarts.at(index) ?? textLength;
|
|
789
|
+
const nextStart = lineStarts.at(index + 1);
|
|
790
|
+
if (nextStart === void 0) return textLength;
|
|
791
|
+
return Math.max(startOffset, nextStart - 1);
|
|
792
|
+
}
|
|
793
|
+
function documentSummaryPatchRange(previous, nextLineStarts, nextTextLength, edits, workerDocument) {
|
|
794
|
+
const edited = editSummaryPatchRange(previous.lineStarts, nextLineStarts, edits);
|
|
795
|
+
if (edited && workerDocument && editsExplainTransition(workerDocument, nextLineStarts, nextTextLength, edits)) return normalizeSummaryPatchRange(edited, previous.lineStarts.length, nextLineStarts.length);
|
|
796
|
+
const changed = mergeSummaryPatchRanges(lineStartSummaryPatchRange(previous.lineStarts, previous.textLength, nextLineStarts, nextTextLength), edited);
|
|
797
|
+
if (!changed) return {
|
|
798
|
+
startLine: 0,
|
|
799
|
+
deleteCount: 0,
|
|
800
|
+
insertEndLine: 0
|
|
801
|
+
};
|
|
802
|
+
return normalizeSummaryPatchRange(changed, previous.lineStarts.length, nextLineStarts.length);
|
|
803
|
+
}
|
|
804
|
+
function editsExplainTransition(workerDocument, nextLineStarts, nextTextLength, edits) {
|
|
805
|
+
if (nextLineStarts.length !== workerDocument.lineCount) return false;
|
|
806
|
+
let textDelta = 0;
|
|
807
|
+
for (const edit of edits) {
|
|
808
|
+
if (edit.text.includes("\n")) return false;
|
|
809
|
+
textDelta += edit.text.length - (Math.max(edit.from, edit.to) - Math.min(edit.from, edit.to));
|
|
810
|
+
}
|
|
811
|
+
return workerDocument.textLength + textDelta === nextTextLength;
|
|
812
|
+
}
|
|
813
|
+
function arrayFirstLineStartAtOrAfter(lineStarts, target) {
|
|
814
|
+
let low = 0;
|
|
815
|
+
let high = lineStarts.length;
|
|
816
|
+
while (low < high) {
|
|
817
|
+
const middle = low + high >> 1;
|
|
818
|
+
if (lineStarts[middle] < target) low = middle + 1;
|
|
819
|
+
else high = middle;
|
|
820
|
+
}
|
|
821
|
+
return low;
|
|
822
|
+
}
|
|
823
|
+
function lineStartSummaryPatchRange(previousLineStarts, previousTextLength, nextLineStarts, nextTextLength) {
|
|
824
|
+
const prefix = commonLineSummaryPrefix(previousLineStarts, previousTextLength, nextLineStarts, nextTextLength);
|
|
825
|
+
const suffix = commonLineSummarySuffix(previousLineStarts, previousTextLength, nextLineStarts, nextTextLength, prefix);
|
|
826
|
+
if (prefix + suffix >= previousLineStarts.length && prefix + suffix >= nextLineStarts.length) return null;
|
|
827
|
+
return {
|
|
828
|
+
startLine: prefix,
|
|
829
|
+
previousEndLine: previousLineStarts.length - suffix,
|
|
830
|
+
nextEndLine: nextLineStarts.length - suffix
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
function commonLineSummaryPrefix(previousLineStarts, previousTextLength, nextLineStarts, nextTextLength) {
|
|
834
|
+
let count = 0;
|
|
835
|
+
const limit = Math.min(previousLineStarts.length, nextLineStarts.length);
|
|
836
|
+
while (count < limit && lineSummaryBoundariesMatch(previousLineStarts, previousTextLength, count, nextLineStarts, nextTextLength, count, 0)) count += 1;
|
|
837
|
+
return count;
|
|
838
|
+
}
|
|
839
|
+
function commonLineSummarySuffix(previousLineStarts, previousTextLength, nextLineStarts, nextTextLength, prefix) {
|
|
840
|
+
let count = 0;
|
|
841
|
+
const delta = nextTextLength - previousTextLength;
|
|
842
|
+
const previousLimit = previousLineStarts.length - prefix;
|
|
843
|
+
const nextLimit = nextLineStarts.length - prefix;
|
|
844
|
+
while (count < previousLimit && count < nextLimit) {
|
|
845
|
+
if (!lineSummaryBoundariesMatch(previousLineStarts, previousTextLength, previousLineStarts.length - count - 1, nextLineStarts, nextTextLength, nextLineStarts.length - count - 1, delta)) return count;
|
|
846
|
+
count += 1;
|
|
847
|
+
}
|
|
848
|
+
return count;
|
|
849
|
+
}
|
|
850
|
+
function lineSummaryBoundariesMatch(previousLineStarts, previousTextLength, previousIndex, nextLineStarts, nextTextLength, nextIndex, offsetDelta) {
|
|
851
|
+
const previousStart = previousLineStarts.at(previousIndex) ?? previousTextLength;
|
|
852
|
+
const nextStart = nextLineStarts.at(nextIndex) ?? nextTextLength;
|
|
853
|
+
if (previousStart + offsetDelta !== nextStart) return false;
|
|
854
|
+
return lineEndOffset(previousLineStarts, previousIndex, previousTextLength) + offsetDelta === lineEndOffset(nextLineStarts, nextIndex, nextTextLength);
|
|
855
|
+
}
|
|
856
|
+
function editSummaryPatchRange(previousLineStarts, nextLineStarts, edits) {
|
|
857
|
+
let startLine = Number.POSITIVE_INFINITY;
|
|
858
|
+
let previousEndLine = 0;
|
|
859
|
+
let nextEndLine = 0;
|
|
860
|
+
for (const edit of edits) {
|
|
861
|
+
if (editIsEmpty(edit)) continue;
|
|
862
|
+
const previousRange = previousLineRangeForEdit(previousLineStarts, nextLineStarts, edit);
|
|
863
|
+
const nextRange = lineRangeForEdit(nextLineStarts, edit.from, edit.from + edit.text.length);
|
|
864
|
+
startLine = Math.min(startLine, previousRange.startLine, nextRange.startLine);
|
|
865
|
+
previousEndLine = Math.max(previousEndLine, previousRange.endLine);
|
|
866
|
+
nextEndLine = Math.max(nextEndLine, nextRange.endLine);
|
|
867
|
+
}
|
|
868
|
+
if (startLine === Number.POSITIVE_INFINITY) return null;
|
|
869
|
+
return {
|
|
870
|
+
startLine,
|
|
871
|
+
previousEndLine,
|
|
872
|
+
nextEndLine
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
function editIsEmpty(edit) {
|
|
876
|
+
return edit.from === edit.to && edit.text.length === 0;
|
|
877
|
+
}
|
|
878
|
+
function previousLineRangeForEdit(previousLineStarts, nextLineStarts, edit) {
|
|
879
|
+
if (edit.from !== edit.to || edit.text.includes("\n")) return lineRangeForEdit(previousLineStarts, edit.from, edit.to);
|
|
880
|
+
const line = nextLineStarts.indexForOffset(edit.from);
|
|
881
|
+
return {
|
|
882
|
+
startLine: line,
|
|
883
|
+
endLine: line + 1
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function lineRangeForEdit(lineStarts, from, to) {
|
|
887
|
+
const startOffset = Math.min(from, to);
|
|
888
|
+
const endOffset = Math.max(from, to);
|
|
889
|
+
return {
|
|
890
|
+
startLine: lineStarts.indexForOffset(startOffset),
|
|
891
|
+
endLine: lineStarts.indexForOffset(endOffset) + 1
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
function mergeSummaryPatchRanges(left, right) {
|
|
895
|
+
if (!left) return right;
|
|
896
|
+
if (!right) return left;
|
|
897
|
+
return {
|
|
898
|
+
startLine: Math.min(left.startLine, right.startLine),
|
|
899
|
+
previousEndLine: Math.max(left.previousEndLine, right.previousEndLine),
|
|
900
|
+
nextEndLine: Math.max(left.nextEndLine, right.nextEndLine)
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
function normalizeSummaryPatchRange(range, previousLineCount, nextLineCount) {
|
|
904
|
+
const startLine = Math.min(Math.max(0, range.startLine), Math.max(previousLineCount, nextLineCount));
|
|
905
|
+
const previousEndLine = Math.min(Math.max(startLine, range.previousEndLine), previousLineCount);
|
|
906
|
+
const nextEndLine = Math.min(Math.max(startLine, range.nextEndLine), nextLineCount);
|
|
907
|
+
return {
|
|
908
|
+
startLine,
|
|
909
|
+
deleteCount: previousEndLine - startLine,
|
|
910
|
+
insertEndLine: nextEndLine
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
function incrementalTextEdits(change) {
|
|
914
|
+
if (!change || change.edits.length === 0) return null;
|
|
915
|
+
return sequentialTextEdits(change.edits.toSorted(compareTextEdits));
|
|
916
|
+
}
|
|
917
|
+
function sameViewport(previous, next) {
|
|
918
|
+
if (!previous) return false;
|
|
919
|
+
return previous.scrollTop === next.scrollTop && previous.scrollRow === next.scrollRow && previous.scrollLeft === next.scrollLeft && previous.scrollHeight === next.scrollHeight && previous.scrollWidth === next.scrollWidth && previous.clientHeight === next.clientHeight && previous.clientWidth === next.clientWidth && previous.minimapHeight === next.minimapHeight && previous.reservedWidth === next.reservedWidth && previous.visibleStart === next.visibleStart && previous.visibleEnd === next.visibleEnd;
|
|
920
|
+
}
|
|
921
|
+
function shadowVisible(viewport) {
|
|
922
|
+
return viewport.scrollLeft + viewport.clientWidth < viewport.scrollWidth;
|
|
923
|
+
}
|
|
924
|
+
function positiveOrFallback(value, fallback) {
|
|
925
|
+
if (value > 0) return value;
|
|
926
|
+
return Math.max(0, fallback);
|
|
927
|
+
}
|
|
928
|
+
function baseStylesSignature(styles) {
|
|
929
|
+
return JSON.stringify(styles);
|
|
930
|
+
}
|
|
931
|
+
function layoutSignature(snapshot, minimapHeight) {
|
|
932
|
+
return [
|
|
933
|
+
snapshot.metrics.rowHeight,
|
|
934
|
+
snapshot.metrics.characterWidth,
|
|
935
|
+
globalThis.devicePixelRatio || 1,
|
|
936
|
+
snapshot.viewport.clientHeight,
|
|
937
|
+
snapshot.viewport.clientWidth,
|
|
938
|
+
minimapHeight,
|
|
939
|
+
snapshot.lineCount
|
|
940
|
+
].join(":");
|
|
941
|
+
}
|
|
942
|
+
function createPendingUpdate(snapshot, kind, change, previousSnapshot) {
|
|
943
|
+
const base = basePendingUpdate(snapshot, kind);
|
|
944
|
+
if (kind === "content") return contentPendingUpdate(base, change, previousSnapshot);
|
|
945
|
+
if (kind === "document" || kind === "clear") return {
|
|
946
|
+
...base,
|
|
947
|
+
replaceDocument: true,
|
|
948
|
+
reason: kind
|
|
949
|
+
};
|
|
950
|
+
if (kind === "tokens") return {
|
|
951
|
+
...base,
|
|
952
|
+
syncTokens: true,
|
|
953
|
+
reason: "tokens"
|
|
954
|
+
};
|
|
955
|
+
if (kind === "selection") return {
|
|
956
|
+
...base,
|
|
957
|
+
syncSelection: true,
|
|
958
|
+
reason: "selection"
|
|
959
|
+
};
|
|
960
|
+
if (kind === "decorations") return {
|
|
961
|
+
...base,
|
|
962
|
+
syncExternalDecorations: true,
|
|
963
|
+
reason: "decorations"
|
|
964
|
+
};
|
|
965
|
+
return {
|
|
966
|
+
...base,
|
|
967
|
+
reason: kind
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function mergePendingUpdate(current, next) {
|
|
971
|
+
if (!current) return next;
|
|
972
|
+
if (current.replaceDocument || next.replaceDocument) return mergeReplacementUpdate(current, next);
|
|
973
|
+
const edits = current.edits.concat(next.edits);
|
|
974
|
+
const contentChangedAfterTokens = next.edits.length > 0;
|
|
975
|
+
return {
|
|
976
|
+
snapshot: next.snapshot,
|
|
977
|
+
replaceDocument: false,
|
|
978
|
+
edits,
|
|
979
|
+
previousDocumentSummary: current.previousDocumentSummary ?? next.previousDocumentSummary,
|
|
980
|
+
syncTokens: contentChangedAfterTokens ? next.syncTokens : current.syncTokens || next.syncTokens,
|
|
981
|
+
syncSelection: current.syncSelection || next.syncSelection,
|
|
982
|
+
syncExternalDecorations: current.syncExternalDecorations || next.syncExternalDecorations,
|
|
983
|
+
syncViewport: current.syncViewport || next.syncViewport,
|
|
984
|
+
syncBaseStyles: current.syncBaseStyles || next.syncBaseStyles,
|
|
985
|
+
tokenSourceAfterEdits: mergedTokenSourceAfterEdits(current, next),
|
|
986
|
+
reason: mergeReasons(current.reason, next.reason)
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
function mergeReplacementUpdate(current, next) {
|
|
990
|
+
return {
|
|
991
|
+
snapshot: next.snapshot,
|
|
992
|
+
replaceDocument: true,
|
|
993
|
+
edits: [],
|
|
994
|
+
previousDocumentSummary: null,
|
|
995
|
+
syncTokens: false,
|
|
996
|
+
syncSelection: false,
|
|
997
|
+
syncExternalDecorations: false,
|
|
998
|
+
syncViewport: current.syncViewport || next.syncViewport,
|
|
999
|
+
syncBaseStyles: current.syncBaseStyles || next.syncBaseStyles,
|
|
1000
|
+
tokenSourceAfterEdits: null,
|
|
1001
|
+
reason: mergeReasons(current.reason, next.reason)
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function mergedTokenSourceAfterEdits(current, next) {
|
|
1005
|
+
if (next.edits.length === 0) return current.tokenSourceAfterEdits;
|
|
1006
|
+
if (current.syncTokens) return null;
|
|
1007
|
+
return next.tokenSourceAfterEdits;
|
|
1008
|
+
}
|
|
1009
|
+
function shouldSyncBaseStyles(kind) {
|
|
1010
|
+
if (kind === "tokens") return true;
|
|
1011
|
+
if (kind === "document") return true;
|
|
1012
|
+
return kind === "clear";
|
|
1013
|
+
}
|
|
1014
|
+
function basePendingUpdate(snapshot, kind) {
|
|
1015
|
+
return {
|
|
1016
|
+
snapshot,
|
|
1017
|
+
replaceDocument: false,
|
|
1018
|
+
edits: [],
|
|
1019
|
+
previousDocumentSummary: null,
|
|
1020
|
+
syncTokens: false,
|
|
1021
|
+
syncSelection: false,
|
|
1022
|
+
syncExternalDecorations: false,
|
|
1023
|
+
syncViewport: shouldSyncViewport(kind),
|
|
1024
|
+
syncBaseStyles: shouldSyncBaseStyles(kind),
|
|
1025
|
+
tokenSourceAfterEdits: null,
|
|
1026
|
+
reason: "metadata"
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
function contentPendingUpdate(base, change, previousSnapshot) {
|
|
1030
|
+
const edits = incrementalTextEdits(change);
|
|
1031
|
+
if (!edits) return {
|
|
1032
|
+
...base,
|
|
1033
|
+
replaceDocument: true,
|
|
1034
|
+
reason: "content.replaceDocument"
|
|
1035
|
+
};
|
|
1036
|
+
return {
|
|
1037
|
+
...base,
|
|
1038
|
+
edits,
|
|
1039
|
+
previousDocumentSummary: snapshotSummaryBaseline(previousSnapshot),
|
|
1040
|
+
syncSelection: true,
|
|
1041
|
+
tokenSourceAfterEdits: tokenSourceAfterEdits(change, previousSnapshot, base.snapshot),
|
|
1042
|
+
reason: edits.length === 1 ? "content.edit" : "content.edits"
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
function previousDocumentSummary(update) {
|
|
1046
|
+
return update.previousDocumentSummary ?? snapshotSummaryBaseline(update.snapshot);
|
|
1047
|
+
}
|
|
1048
|
+
function snapshotSummaryBaseline(snapshot) {
|
|
1049
|
+
return {
|
|
1050
|
+
textLength: snapshot.textSnapshot.length,
|
|
1051
|
+
lineStarts: snapshot.lineStartsView
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
function shouldSyncViewport(kind) {
|
|
1055
|
+
if (kind === "content") return true;
|
|
1056
|
+
if (kind === "document") return true;
|
|
1057
|
+
if (kind === "clear") return true;
|
|
1058
|
+
if (kind === "viewport") return true;
|
|
1059
|
+
return kind === "layout";
|
|
1060
|
+
}
|
|
1061
|
+
function shouldDeferMinimapUpdate(update) {
|
|
1062
|
+
if (update.reason.includes("content")) return true;
|
|
1063
|
+
if (update.syncTokens) return true;
|
|
1064
|
+
return update.syncExternalDecorations;
|
|
1065
|
+
}
|
|
1066
|
+
function sequentialTextEdits(edits) {
|
|
1067
|
+
let delta = 0;
|
|
1068
|
+
return edits.map((edit) => {
|
|
1069
|
+
const from = edit.from + delta;
|
|
1070
|
+
const to = edit.to + delta;
|
|
1071
|
+
delta += edit.text.length - (edit.to - edit.from);
|
|
1072
|
+
return {
|
|
1073
|
+
from,
|
|
1074
|
+
to,
|
|
1075
|
+
text: edit.text
|
|
1076
|
+
};
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
function compareTextEdits(left, right) {
|
|
1080
|
+
return left.from - right.from || left.to - right.to;
|
|
1081
|
+
}
|
|
1082
|
+
function tokenSourceAfterEdits(change, previousSnapshot, nextSnapshot) {
|
|
1083
|
+
if (!change) return null;
|
|
1084
|
+
if (!editsPreserveLineStructure(change.edits, previousSnapshot.lineStartsView)) return null;
|
|
1085
|
+
return nextSnapshot.tokens;
|
|
1086
|
+
}
|
|
1087
|
+
function editsPreserveLineStructure(edits, lineStarts) {
|
|
1088
|
+
for (const edit of edits) {
|
|
1089
|
+
if (edit.text.includes("\n")) return false;
|
|
1090
|
+
if (!editRangeIsSingleLine(lineStarts, edit)) return false;
|
|
1091
|
+
}
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
function editRangeIsSingleLine(lineStarts, edit) {
|
|
1095
|
+
return lineStarts.indexForOffset(edit.from) === lineStarts.indexForOffset(edit.to);
|
|
1096
|
+
}
|
|
1097
|
+
function arrayLineIndexForOffset(lineStarts, offset) {
|
|
1098
|
+
let low = 0;
|
|
1099
|
+
let high = lineStarts.length - 1;
|
|
1100
|
+
const clamped = Math.max(0, offset);
|
|
1101
|
+
while (low <= high) {
|
|
1102
|
+
const middle = Math.floor((low + high) / 2);
|
|
1103
|
+
const start = lineStarts[middle] ?? 0;
|
|
1104
|
+
const next = lineStarts[middle + 1] ?? Number.POSITIVE_INFINITY;
|
|
1105
|
+
if (clamped < start) {
|
|
1106
|
+
high = middle - 1;
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1109
|
+
if (clamped >= next) {
|
|
1110
|
+
low = middle + 1;
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
return middle;
|
|
1114
|
+
}
|
|
1115
|
+
return Math.max(0, lineStarts.length - 1);
|
|
1116
|
+
}
|
|
1117
|
+
function mergeReasons(left, right) {
|
|
1118
|
+
if (left === right) return left;
|
|
1119
|
+
return `${left}+${right}`;
|
|
1120
|
+
}
|
|
1121
|
+
function measureMinimapPerformance(name, run, detail) {
|
|
1122
|
+
if (!minimapPerformanceDiagnosticsEnabled()) return run();
|
|
1123
|
+
const start = nowMs();
|
|
1124
|
+
try {
|
|
1125
|
+
return run();
|
|
1126
|
+
} finally {
|
|
1127
|
+
recordMinimapPerformanceDiagnostic(name, detail, nowMs() - start);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
function recordMinimapPerformanceDiagnostic(name, detail, durationMs) {
|
|
1131
|
+
const sink = minimapPerformanceDiagnosticSink();
|
|
1132
|
+
if (!sink) return;
|
|
1133
|
+
const diagnostic = createDiagnostic(name, detail, durationMs);
|
|
1134
|
+
if (typeof sink === "function") {
|
|
1135
|
+
sink(diagnostic);
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
sink.record?.(diagnostic);
|
|
1139
|
+
}
|
|
1140
|
+
function minimapPerformanceDiagnosticsEnabled() {
|
|
1141
|
+
const sink = minimapPerformanceDiagnosticGlobal().__EDITOR_PERFORMANCE_DIAGNOSTICS__;
|
|
1142
|
+
if (!sink) return false;
|
|
1143
|
+
if (typeof sink === "function") return true;
|
|
1144
|
+
return sink.enabled === true || typeof sink.record === "function";
|
|
1145
|
+
}
|
|
1146
|
+
function minimapPerformanceDiagnosticSink() {
|
|
1147
|
+
const sink = minimapPerformanceDiagnosticGlobal().__EDITOR_PERFORMANCE_DIAGNOSTICS__;
|
|
1148
|
+
if (!sink) return null;
|
|
1149
|
+
if (typeof sink === "function") return sink;
|
|
1150
|
+
if (sink.enabled !== true && typeof sink.record !== "function") return null;
|
|
1151
|
+
return sink;
|
|
1152
|
+
}
|
|
1153
|
+
function createDiagnostic(name, detail, durationMs) {
|
|
1154
|
+
const resolvedDetail = resolveDiagnosticDetail(detail);
|
|
1155
|
+
if (durationMs === void 0 && resolvedDetail === void 0) return { name };
|
|
1156
|
+
if (durationMs === void 0) return {
|
|
1157
|
+
name,
|
|
1158
|
+
detail: resolvedDetail
|
|
1159
|
+
};
|
|
1160
|
+
if (resolvedDetail === void 0) return {
|
|
1161
|
+
name,
|
|
1162
|
+
durationMs
|
|
1163
|
+
};
|
|
1164
|
+
return {
|
|
1165
|
+
name,
|
|
1166
|
+
durationMs,
|
|
1167
|
+
detail: resolvedDetail
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
function resolveDiagnosticDetail(detail) {
|
|
1171
|
+
if (typeof detail === "function") return detail();
|
|
1172
|
+
return detail;
|
|
1173
|
+
}
|
|
1174
|
+
function minimapPerformanceDiagnosticGlobal() {
|
|
1175
|
+
return globalThis;
|
|
1176
|
+
}
|
|
1177
|
+
function pendingUpdateDiagnostics(update) {
|
|
1178
|
+
return {
|
|
1179
|
+
editCount: update.edits.length,
|
|
1180
|
+
incremental: !update.replaceDocument,
|
|
1181
|
+
reason: update.reason,
|
|
1182
|
+
syncBaseStyles: update.syncBaseStyles,
|
|
1183
|
+
syncExternalDecorations: update.syncExternalDecorations,
|
|
1184
|
+
syncSelection: update.syncSelection,
|
|
1185
|
+
syncTokens: update.syncTokens,
|
|
1186
|
+
syncViewport: update.syncViewport,
|
|
1187
|
+
tokenSourceKnown: update.tokenSourceAfterEdits !== null || update.edits.length === 0,
|
|
1188
|
+
type: update.replaceDocument ? "replaceDocument" : "incremental"
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
function requestDiagnostics(request) {
|
|
1192
|
+
switch (request.type) {
|
|
1193
|
+
case "openDocument":
|
|
1194
|
+
case "replaceDocument": return {
|
|
1195
|
+
request: request.type,
|
|
1196
|
+
...documentPayloadDiagnostics(request.document)
|
|
1197
|
+
};
|
|
1198
|
+
case "applyEdit": return {
|
|
1199
|
+
request: request.type,
|
|
1200
|
+
editTextLength: request.edit.text.length,
|
|
1201
|
+
...documentEditPayloadDiagnostics(request.document)
|
|
1202
|
+
};
|
|
1203
|
+
case "applyEdits": return {
|
|
1204
|
+
request: request.type,
|
|
1205
|
+
editCount: request.edits.length,
|
|
1206
|
+
editTextLength: textLengthForEdits(request.edits),
|
|
1207
|
+
...documentEditPayloadDiagnostics(request.document)
|
|
1208
|
+
};
|
|
1209
|
+
case "updateTokens": return {
|
|
1210
|
+
request: request.type,
|
|
1211
|
+
tokens: request.tokens.length
|
|
1212
|
+
};
|
|
1213
|
+
case "updateTokenRange": return {
|
|
1214
|
+
request: request.type,
|
|
1215
|
+
deleteCount: request.patch.deleteCount,
|
|
1216
|
+
start: request.patch.start,
|
|
1217
|
+
tokens: request.patch.tokens.length
|
|
1218
|
+
};
|
|
1219
|
+
case "updateSelection": return {
|
|
1220
|
+
request: request.type,
|
|
1221
|
+
selections: request.selections.length
|
|
1222
|
+
};
|
|
1223
|
+
case "updateDecorations":
|
|
1224
|
+
case "updateExternalDecorations": return {
|
|
1225
|
+
request: request.type,
|
|
1226
|
+
decorations: request.decorations.length
|
|
1227
|
+
};
|
|
1228
|
+
default: return { request: "control" };
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
function documentPayloadDiagnostics(payload) {
|
|
1232
|
+
return {
|
|
1233
|
+
decorations: payload?.decorations.length ?? 0,
|
|
1234
|
+
externalDecorations: payload?.externalDecorations?.length ?? 0,
|
|
1235
|
+
lineSummaryTextLength: lineSummaryTextLength(payload?.lines ?? []),
|
|
1236
|
+
lineStarts: payload?.lineStarts.length ?? 0,
|
|
1237
|
+
lines: payload?.lines.length ?? 0,
|
|
1238
|
+
selections: payload?.selections.length ?? 0,
|
|
1239
|
+
textLength: payload?.textLength ?? 0,
|
|
1240
|
+
tokens: payload?.tokens.length ?? 0,
|
|
1241
|
+
type: "document"
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
function documentEditPayloadDiagnostics(payload) {
|
|
1245
|
+
const patch = payload?.summaryPatch;
|
|
1246
|
+
return {
|
|
1247
|
+
deleteCount: patch?.deleteCount ?? 0,
|
|
1248
|
+
lineSummaryTextLength: lineSummaryTextLength(patch?.lines ?? []),
|
|
1249
|
+
lineStarts: patch?.lineStarts?.length ?? 0,
|
|
1250
|
+
lines: patch?.lines.length ?? 0,
|
|
1251
|
+
selections: payload?.selections.length ?? 0,
|
|
1252
|
+
startLine: patch?.startLine ?? 0,
|
|
1253
|
+
textLength: patch?.textLength ?? 0,
|
|
1254
|
+
type: "edit"
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
function lineSummaryTextLength(lines) {
|
|
1258
|
+
let length = 0;
|
|
1259
|
+
for (const line of lines) length += line.text.length;
|
|
1260
|
+
return length;
|
|
1261
|
+
}
|
|
1262
|
+
function textLengthForEdits(edits) {
|
|
1263
|
+
let length = 0;
|
|
1264
|
+
for (const edit of edits) length += edit.text.length;
|
|
1265
|
+
return length;
|
|
1266
|
+
}
|
|
1267
|
+
function setStyleValue(element, property, value) {
|
|
1268
|
+
if (element.style[property] === value) return;
|
|
1269
|
+
element.style[property] = value;
|
|
1270
|
+
}
|
|
1271
|
+
function setClassName(element, className) {
|
|
1272
|
+
if (element.className === className) return;
|
|
1273
|
+
element.className = className;
|
|
1274
|
+
}
|
|
1275
|
+
function minimapBackgroundOpacity(style) {
|
|
1276
|
+
const value = Number.parseFloat(style.getPropertyValue("--editor-minimap-background-opacity"));
|
|
1277
|
+
if (!Number.isFinite(value)) return 1;
|
|
1278
|
+
return Math.min(1, Math.max(0, value));
|
|
1279
|
+
}
|
|
1280
|
+
function themeSignature(snapshot) {
|
|
1281
|
+
return JSON.stringify(snapshot.theme ?? null);
|
|
1282
|
+
}
|
|
1283
|
+
function nowMs() {
|
|
1284
|
+
return globalThis.performance?.now() ?? Date.now();
|
|
1285
|
+
}
|
|
1286
|
+
var ColorResolver = class {
|
|
1287
|
+
probe;
|
|
1288
|
+
canvasContext;
|
|
1289
|
+
cache = /* @__PURE__ */ new Map();
|
|
1290
|
+
constructor(root) {
|
|
1291
|
+
this.probe = root.ownerDocument.createElement("span");
|
|
1292
|
+
this.canvasContext = root.ownerDocument.createElement("canvas").getContext("2d", { willReadFrequently: true });
|
|
1293
|
+
this.probe.style.position = "absolute";
|
|
1294
|
+
this.probe.style.visibility = "hidden";
|
|
1295
|
+
this.probe.textContent = ".";
|
|
1296
|
+
root.appendChild(this.probe);
|
|
1297
|
+
}
|
|
1298
|
+
resolve(value, fallback) {
|
|
1299
|
+
if (!value) return fallback;
|
|
1300
|
+
const cached = this.cache.get(value);
|
|
1301
|
+
if (cached) return cached;
|
|
1302
|
+
this.probe.style.color = value;
|
|
1303
|
+
const resolved = this.resolveComputedColor(getComputedStyle(this.probe).color, fallback);
|
|
1304
|
+
this.cache.set(value, resolved);
|
|
1305
|
+
return resolved;
|
|
1306
|
+
}
|
|
1307
|
+
clear() {
|
|
1308
|
+
this.cache.clear();
|
|
1309
|
+
}
|
|
1310
|
+
dispose() {
|
|
1311
|
+
this.clear();
|
|
1312
|
+
this.probe.remove();
|
|
1313
|
+
}
|
|
1314
|
+
resolveComputedColor(value, fallback) {
|
|
1315
|
+
const canvasColor = this.canvasColor(value);
|
|
1316
|
+
if (canvasColor) return canvasColor;
|
|
1317
|
+
return parseCssColor(value, fallback);
|
|
1318
|
+
}
|
|
1319
|
+
canvasColor(value) {
|
|
1320
|
+
const context = this.canvasContext;
|
|
1321
|
+
if (!context) return null;
|
|
1322
|
+
context.clearRect(0, 0, 1, 1);
|
|
1323
|
+
context.fillStyle = value;
|
|
1324
|
+
context.fillRect(0, 0, 1, 1);
|
|
1325
|
+
const [r, g, b, a] = context.getImageData(0, 0, 1, 1).data;
|
|
1326
|
+
return {
|
|
1327
|
+
r: r ?? 0,
|
|
1328
|
+
g: g ?? 0,
|
|
1329
|
+
b: b ?? 0,
|
|
1330
|
+
a: a ?? 0
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
//#endregion
|
|
1335
|
+
export { MinimapWorkerClient, MinimapWorkerOwner, canUseMinimapWorker };
|
|
1336
|
+
|
|
1337
|
+
//# sourceMappingURL=workerClient.js.map
|