@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.
Files changed (56) hide show
  1. package/README.md +29 -0
  2. package/dist/assets/minimap.worker-i4S59IOV.js +1616 -0
  3. package/dist/assets/minimap.worker-i4S59IOV.js.map +1 -0
  4. package/dist/color.d.ts +11 -0
  5. package/dist/color.d.ts.map +1 -0
  6. package/dist/color.js +83 -0
  7. package/dist/color.js.map +1 -0
  8. package/dist/decorationMerge.d.ts +10 -0
  9. package/dist/decorationMerge.d.ts.map +1 -0
  10. package/dist/decorationMerge.js +65 -0
  11. package/dist/decorationMerge.js.map +1 -0
  12. package/dist/index.d.ts +4 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +3 -0
  15. package/dist/layout.d.ts +43 -0
  16. package/dist/layout.d.ts.map +1 -0
  17. package/dist/layout.js +137 -0
  18. package/dist/layout.js.map +1 -0
  19. package/dist/minimap.worker.d.ts +2 -0
  20. package/dist/minimap.worker.d.ts.map +1 -0
  21. package/dist/minimapCharRenderer.d.ts +13 -0
  22. package/dist/minimapCharRenderer.d.ts.map +1 -0
  23. package/dist/minimapCharRendererFactory.d.ts +14 -0
  24. package/dist/minimapCharRendererFactory.d.ts.map +1 -0
  25. package/dist/minimapCharSheet.d.ts +15 -0
  26. package/dist/minimapCharSheet.d.ts.map +1 -0
  27. package/dist/minimapCharSheet.js +24 -0
  28. package/dist/minimapCharSheet.js.map +1 -0
  29. package/dist/options.d.ts +3 -0
  30. package/dist/options.d.ts.map +1 -0
  31. package/dist/options.js +65 -0
  32. package/dist/options.js.map +1 -0
  33. package/dist/plugin.d.ts +4 -0
  34. package/dist/plugin.d.ts.map +1 -0
  35. package/dist/plugin.js +415 -0
  36. package/dist/plugin.js.map +1 -0
  37. package/dist/raster.d.ts +10 -0
  38. package/dist/raster.d.ts.map +1 -0
  39. package/dist/renderer.d.ts +58 -0
  40. package/dist/renderer.d.ts.map +1 -0
  41. package/dist/sectionHeaders.d.ts +13 -0
  42. package/dist/sectionHeaders.d.ts.map +1 -0
  43. package/dist/style.css +97 -0
  44. package/dist/types.d.ts +211 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +11 -0
  47. package/dist/types.js.map +1 -0
  48. package/dist/viewportGeometry.d.ts +28 -0
  49. package/dist/viewportGeometry.d.ts.map +1 -0
  50. package/dist/viewportGeometry.js +22 -0
  51. package/dist/viewportGeometry.js.map +1 -0
  52. package/dist/workerClient.d.ts +131 -0
  53. package/dist/workerClient.d.ts.map +1 -0
  54. package/dist/workerClient.js +1337 -0
  55. package/dist/workerClient.js.map +1 -0
  56. 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