@lvce-editor/editor-worker 19.72.5 → 19.72.6

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.
@@ -2463,77 +2463,132 @@ const getHorizontalVisibleRange = (line, deltaX, width, averageCharWidth, tabSiz
2463
2463
  start
2464
2464
  };
2465
2465
  };
2466
- const getHorizontalVisibleRangeMeasured = async (line, deltaX, width, averageCharWidth, tabSize, threshold, measureWidth) => {
2467
- const fallback = () => {
2468
- const range = getHorizontalVisibleRange(line, deltaX, width, averageCharWidth, tabSize, threshold);
2466
+ const getHorizontalVisibleRangesMeasured = async (requests, measureWidths) => {
2467
+ const fallback = request => {
2468
+ const range = getHorizontalVisibleRange(request.line, request.deltaX, request.width, request.averageCharWidth, request.tabSize, request.threshold);
2469
2469
  return {
2470
2470
  ...range,
2471
- difference: getHorizontalVisibleDifference(line, range.start, deltaX, averageCharWidth, tabSize)
2471
+ difference: getHorizontalVisibleDifference(request.line, range.start, request.deltaX, request.averageCharWidth, request.tabSize)
2472
2472
  };
2473
2473
  };
2474
- if (line.length <= threshold) {
2475
- return fallback();
2474
+ const results = requests.map(request => fallback(request));
2475
+ const boundariesByLine = [];
2476
+ const measurementsByLine = [];
2477
+ const cursors = [];
2478
+ for (let lineIndex = 0; lineIndex < requests.length; lineIndex++) {
2479
+ const request = requests[lineIndex];
2480
+ if (request.line.length <= request.threshold) {
2481
+ continue;
2482
+ }
2483
+ const segments = getSegments(request.line);
2484
+ const boundaries = [0, ...segments.map(({
2485
+ index,
2486
+ segment
2487
+ }) => index + segment.length)];
2488
+ boundariesByLine[lineIndex] = boundaries;
2489
+ measurementsByLine[lineIndex] = new Map([[0, 0]]);
2490
+ const scrollOffset = Math.max(0, Number.isFinite(request.deltaX) ? request.deltaX : 0);
2491
+ const viewportWidth = Number.isFinite(request.width) ? Math.max(0, request.width) : Infinity;
2492
+ cursors.push({
2493
+ high: boundaries.length,
2494
+ isStart: true,
2495
+ lineIndex,
2496
+ low: 0,
2497
+ target: scrollOffset
2498
+ });
2499
+ cursors.push({
2500
+ high: boundaries.length,
2501
+ isStart: false,
2502
+ lineIndex,
2503
+ low: 0,
2504
+ target: scrollOffset + viewportWidth
2505
+ });
2476
2506
  }
2477
- const scrollOffset = Math.max(0, Number.isFinite(deltaX) ? deltaX : 0);
2478
- const viewportWidth = Number.isFinite(width) ? Math.max(0, width) : Infinity;
2479
- const segments = getSegments(line);
2480
- const boundaries = [0, ...segments.map(({
2481
- index,
2482
- segment
2483
- }) => index + segment.length)];
2484
- const measurements = new Map([[0, 0]]);
2485
- const measureBoundary = async boundaryIndex => {
2486
- const cached = measurements.get(boundaryIndex);
2487
- if (cached !== undefined) {
2488
- return cached;
2489
- }
2490
- const prefix = line.slice(0, boundaries[boundaryIndex]).replaceAll('\t', () => ' '.repeat(tabSize));
2491
- const measured = await measureWidth(prefix);
2492
- measurements.set(boundaryIndex, measured);
2493
- return measured;
2494
- };
2495
- const findGreatestBoundaryAtMost = async target => {
2496
- let low = 0;
2497
- let high = boundaries.length;
2498
- while (low < high) {
2499
- const middle = Math.floor((low + high) / 2);
2500
- if ((await measureBoundary(middle)) <= target) {
2501
- low = middle + 1;
2502
- } else {
2503
- high = middle;
2507
+ try {
2508
+ const addPendingMeasurement = (cursor, pending) => {
2509
+ if (cursor.low >= cursor.high) {
2510
+ return;
2504
2511
  }
2505
- }
2506
- return Math.max(0, low - 1);
2507
- };
2508
- const findFirstBoundaryAtLeast = async target => {
2509
- let low = 0;
2510
- let high = boundaries.length;
2511
- while (low < high) {
2512
- const middle = Math.floor((low + high) / 2);
2513
- if ((await measureBoundary(middle)) < target) {
2514
- low = middle + 1;
2512
+ const boundaryIndex = Math.floor((cursor.low + cursor.high) / 2);
2513
+ if (measurementsByLine[cursor.lineIndex].has(boundaryIndex)) {
2514
+ return;
2515
+ }
2516
+ const request = requests[cursor.lineIndex];
2517
+ const prefix = request.line.slice(0, boundariesByLine[cursor.lineIndex][boundaryIndex]).replaceAll('\t', () => ' '.repeat(request.tabSize));
2518
+ pending.set(`${cursor.lineIndex}:${boundaryIndex}`, {
2519
+ boundaryIndex,
2520
+ lineIndex: cursor.lineIndex,
2521
+ text: prefix
2522
+ });
2523
+ };
2524
+ const updateCursor = cursor => {
2525
+ if (cursor.low >= cursor.high) {
2526
+ return;
2527
+ }
2528
+ const middle = Math.floor((cursor.low + cursor.high) / 2);
2529
+ const measured = measurementsByLine[cursor.lineIndex].get(middle);
2530
+ if (measured === undefined) {
2531
+ return;
2532
+ }
2533
+ if (cursor.isStart ? measured <= cursor.target : measured < cursor.target) {
2534
+ cursor.low = middle + 1;
2515
2535
  } else {
2516
- high = middle;
2536
+ cursor.high = middle;
2537
+ }
2538
+ };
2539
+ while (cursors.some(({
2540
+ high,
2541
+ low
2542
+ }) => low < high)) {
2543
+ const pending = new Map();
2544
+ for (const cursor of cursors) {
2545
+ addPendingMeasurement(cursor, pending);
2546
+ }
2547
+ if (pending.size > 0) {
2548
+ const entries = pending.values().toArray();
2549
+ const measuredWidths = await measureWidths(entries.map(({
2550
+ text
2551
+ }) => text));
2552
+ if (measuredWidths.length !== entries.length) {
2553
+ throw new Error('Text measurement returned an unexpected number of widths');
2554
+ }
2555
+ for (let i = 0; i < entries.length; i++) {
2556
+ const {
2557
+ boundaryIndex,
2558
+ lineIndex
2559
+ } = entries[i];
2560
+ measurementsByLine[lineIndex].set(boundaryIndex, measuredWidths[i]);
2561
+ }
2562
+ }
2563
+ for (const cursor of cursors) {
2564
+ updateCursor(cursor);
2517
2565
  }
2518
2566
  }
2519
- return Math.min(boundaries.length - 1, low);
2520
- };
2521
- try {
2522
- const startBoundary = await findGreatestBoundaryAtMost(scrollOffset);
2523
- const endBoundary = await findFirstBoundaryAtLeast(scrollOffset + viewportWidth);
2524
- const start = boundaries[startBoundary];
2525
- let end = boundaries[endBoundary];
2526
- if (end < line.length) {
2527
- end = boundaries[Math.min(boundaries.length - 1, endBoundary + 1)];
2567
+ for (let lineIndex = 0; lineIndex < boundariesByLine.length; lineIndex++) {
2568
+ const boundaries = boundariesByLine[lineIndex];
2569
+ if (!boundaries) {
2570
+ continue;
2571
+ }
2572
+ const request = requests[lineIndex];
2573
+ const lineCursors = cursors.filter(cursor => cursor.lineIndex === lineIndex);
2574
+ const startBoundary = Math.max(0, lineCursors[0].low - 1);
2575
+ const endBoundary = Math.min(boundaries.length - 1, lineCursors[1].low);
2576
+ const start = boundaries[startBoundary];
2577
+ let end = boundaries[endBoundary];
2578
+ if (end < request.line.length) {
2579
+ end = boundaries[Math.min(boundaries.length - 1, endBoundary + 1)];
2580
+ }
2581
+ const scrollOffset = Math.max(0, Number.isFinite(request.deltaX) ? request.deltaX : 0);
2582
+ results[lineIndex] = {
2583
+ difference: (measurementsByLine[lineIndex].get(startBoundary) ?? 0) - scrollOffset,
2584
+ end,
2585
+ start
2586
+ };
2528
2587
  }
2529
- return {
2530
- difference: (await measureBoundary(startBoundary)) - scrollOffset,
2531
- end,
2532
- start
2533
- };
2534
2588
  } catch {
2535
- return fallback();
2589
+ // Keep the existing approximate range fallback when worker measurement fails.
2536
2590
  }
2591
+ return results;
2537
2592
  };
2538
2593
  const getHorizontalVisibleDifference = (line, start, deltaX, averageCharWidth, tabSize) => {
2539
2594
  const charWidth = averageCharWidth > 0 ? averageCharWidth : 1;
@@ -2953,6 +3008,10 @@ const measureTextWidthSlow = async (text, fontWeight, fontSize, fontFamily, lett
2953
3008
  return width;
2954
3009
  };
2955
3010
 
3011
+ const measureTextWidthsSlow = async (texts, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
3012
+ return await invoke$e('TextMeasurement.measureTextWidths', texts, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
3013
+ };
3014
+
2956
3015
  const measureTextWidth = async (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2957
3016
  // TODO maybe have a property for the whole text document
2958
3017
  // whether the document is ASCII or not
@@ -2963,6 +3022,29 @@ const measureTextWidth = async (text, fontWeight, fontSize, fontFamily, letterSp
2963
3022
  }
2964
3023
  return await measureTextWidthSlow(text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
2965
3024
  };
3025
+ const measureTextWidths = async (texts, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
3026
+ const widths = Array.from({
3027
+ length: texts.length
3028
+ }, (_, index) => index);
3029
+ const slowTexts = [];
3030
+ const slowIndexes = [];
3031
+ for (let i = 0; i < texts.length; i++) {
3032
+ const text = texts[i];
3033
+ if (isMonoSpaceFont && isAscii(text)) {
3034
+ widths[i] = await measureTextWidthFast(text, charWidth);
3035
+ } else {
3036
+ slowTexts.push(text);
3037
+ slowIndexes.push(i);
3038
+ }
3039
+ }
3040
+ if (slowTexts.length > 0) {
3041
+ const slowWidths = await measureTextWidthsSlow(slowTexts, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
3042
+ for (let i = 0; i < slowWidths.length; i++) {
3043
+ widths[slowIndexes[i]] = slowWidths[i];
3044
+ }
3045
+ }
3046
+ return widths;
3047
+ };
2966
3048
 
2967
3049
  const Dot = '.';
2968
3050
  const DoubleQuote$1 = '"';
@@ -3487,10 +3569,18 @@ const getLineInfosViewport = async (editor, tokens, embeddedResults, minLineY, m
3487
3569
  const tokenMap = get$5(languageId);
3488
3570
  let offset = minLineOffset;
3489
3571
  const tabSize = editor.tabSize ?? 2;
3572
+ const measuredRanges = await getHorizontalVisibleRangesMeasured(lines.slice(minLineY, maxLineY).map(line => ({
3573
+ averageCharWidth,
3574
+ deltaX,
3575
+ line,
3576
+ tabSize,
3577
+ threshold: horizontalVirtualizationThreshold,
3578
+ width
3579
+ })), texts => measureTextWidths(texts, editor.fontWeight, editor.fontSize, editor.fontFamily, editor.letterSpacing, editor.isMonospaceFont, editor.charWidth));
3490
3580
  for (let i = minLineY; i < maxLineY; i++) {
3491
3581
  const line = lines[i];
3492
3582
  const normalize = shouldNormalizeText(line);
3493
- const measuredRange = await getHorizontalVisibleRangeMeasured(line, deltaX, width, averageCharWidth, tabSize, horizontalVirtualizationThreshold, text => measureTextWidth(text, editor.fontWeight, editor.fontSize, editor.fontFamily, editor.letterSpacing, editor.isMonospaceFont, editor.charWidth));
3583
+ const measuredRange = measuredRanges[i - minLineY];
3494
3584
 
3495
3585
  // Use decorations that were pre-computed (includes links and diagnostics)
3496
3586
  // Filter decorations to only include those for this line
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/editor-worker",
3
- "version": "19.72.5",
3
+ "version": "19.72.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git@github.com:lvce-editor/editor-worker.git"