@lvce-editor/editor-worker 19.60.3 → 19.61.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 CHANGED
@@ -41,7 +41,7 @@ Install dependencies from the repository root:
41
41
  npm ci
42
42
  ```
43
43
 
44
- The root `postinstall` script bootstraps the packages with Lerna.
44
+ Installation does not modify the installed server assets.
45
45
 
46
46
  Start a development build and local test server:
47
47
 
@@ -49,7 +49,7 @@ Start a development build and local test server:
49
49
  npm run dev
50
50
  ```
51
51
 
52
- This starts the editor worker watch build and the Lvce Editor test server with `packages/e2e` as the test path.
52
+ This builds the local package, then starts the watch build and the Lvce Editor test server with `packages/e2e` as the test path. The server uses `--link` to load the generated `.tmp/dist` editor-worker package.
53
53
 
54
54
  ## Common Commands
55
55
 
@@ -61,7 +61,7 @@ Run these commands from the repository root unless noted otherwise.
61
61
  | `npm run build:watch` | Watches `packages/editor-worker/src/editorWorkerMain.ts` and rebuilds the worker with esbuild. |
62
62
  | `npm run build:static` | Exports a static test build into `.tmp/static`. Run `npm run build` first. |
63
63
  | `npm run dev` | Runs the watch build and local test server together. |
64
- | `npm test` | Runs package test scripts through Lerna. |
64
+ | `npm test` | Runs package test scripts through npm workspaces. |
65
65
  | `npm run type-check` | Runs TypeScript project references for all packages. |
66
66
  | `npm run lint` | Runs ESLint, Prettier checks, and Knip. |
67
67
  | `npm run format` | Formats the repository with Prettier. |
@@ -107,7 +107,7 @@ The worker listens for RPC messages, registers widget modules, initializes unhan
107
107
 
108
108
  Unit tests live in `packages/editor-worker/test` and are run by the editor-worker package's Jest setup.
109
109
 
110
- End-to-end tests live in `packages/e2e/src` and use fixture extensions from `packages/e2e/fixtures`. Before running e2e tests locally, install Chromium if needed:
110
+ End-to-end tests live in `packages/e2e/src` and use fixture extensions from `packages/e2e/fixtures`. Run `npm run build` from the repository root before launching either e2e suite: both server launchers link the local `.tmp/dist` package. Install Chromium if needed:
111
111
 
112
112
  ```sh
113
113
  cd packages/e2e
@@ -115,6 +115,8 @@ npx playwright install chromium
115
115
  npm run e2e:headless
116
116
  ```
117
117
 
118
+ The memory benchmark pins its Playwright version in `packages/build` to keep the browser runtime consistent with the memory limit. E2e tests use the browser version required by the test harness.
119
+
118
120
  ## CI and Releases
119
121
 
120
122
  Pull requests and pushes to `main` run on Ubuntu, macOS, and Windows. CI builds the worker, exports the static test build, runs unit tests, type checks, linting, e2e tests, and memory measurement.
@@ -669,6 +669,9 @@ const restoreExistingError = (error, currentStack) => {
669
669
  };
670
670
  const restoreMethodNotFoundError = (error, currentStack) => {
671
671
  const restoredError = new JsonRpcError(error.message);
672
+ Object.assign(restoredError, {
673
+ code: error.code
674
+ });
672
675
  const parentStack = getParentStack(error);
673
676
  setStack(restoredError, `${parentStack}${NewLine$1}${currentStack}`);
674
677
  return restoredError;
@@ -688,9 +691,13 @@ const applyDataProperties = (restoredError, error) => {
688
691
  // @ts-ignore
689
692
  restoredError.codeFrame = error.data.codeFrame;
690
693
  }
691
- if (error.data.code) {
694
+ if (typeof error.data.code === 'string' || typeof error.data.code === 'number') {
692
695
  // @ts-ignore
693
- restoredError.code = error.data.code;
696
+ Object.defineProperty(restoredError, 'code', {
697
+ configurable: true,
698
+ value: error.data.code,
699
+ writable: true
700
+ });
694
701
  }
695
702
  if (error.data.type) {
696
703
  // @ts-ignore
@@ -712,6 +719,13 @@ const applyDirectProperties = (restoredError, error) => {
712
719
  };
713
720
  const restoreMessageError = (error, _currentStack) => {
714
721
  const restoredError = constructError(error.message, error.type, error.name);
722
+ if (typeof error.code === 'string' || typeof error.code === 'number') {
723
+ Object.defineProperty(restoredError, 'code', {
724
+ configurable: true,
725
+ value: error.code,
726
+ writable: true
727
+ });
728
+ }
715
729
  if (error.data) {
716
730
  applyDataProperties(restoredError, error);
717
731
  } else {
@@ -790,7 +804,7 @@ const getErrorProperty = (error, prettyError) => {
790
804
  return {
791
805
  code: Custom,
792
806
  data: {
793
- code: prettyError.code,
807
+ code: prettyError.code ?? error?.code,
794
808
  codeFrame: prettyError.codeFrame,
795
809
  name: prettyError.name,
796
810
  stack: getStack(prettyError),
@@ -827,7 +841,12 @@ const getErrorResponseSimple = (id, error) => {
827
841
  return {
828
842
  error: {
829
843
  code: Custom,
830
- data: error,
844
+ data: error instanceof Error ? {
845
+ ...error,
846
+ code: 'code' in error ? error.code : undefined,
847
+ stack: error.stack,
848
+ type: error.name
849
+ } : error,
831
850
  // @ts-ignore
832
851
  message: error.message
833
852
  },
@@ -1262,7 +1281,7 @@ const CtrlCmd = 1 << 11 >>> 0;
1262
1281
  const Shift = 1 << 10 >>> 0;
1263
1282
  const Alt$1 = 1 << 9 >>> 0;
1264
1283
 
1265
- const Editor$1 = 3;
1284
+ const Editor$2 = 3;
1266
1285
  const SourceControl = 22;
1267
1286
 
1268
1287
  const Separator = 1;
@@ -1277,10 +1296,10 @@ const DragAndDropWorker = 3404;
1277
1296
  const EditorWorker = 99;
1278
1297
  const ErrorWorker = 3308;
1279
1298
  const ExtensionManagementWorker = 9006;
1280
- const IconThemeWorker = 7009;
1281
1299
  const MarkdownWorker = 300;
1282
1300
  const OpenerWorker = 4561;
1283
1301
  const RendererWorker = 1;
1302
+ const TextMeasurementWorker = 7011;
1284
1303
 
1285
1304
  const FocusSelector$1 = 'Viewlet.focusSelector';
1286
1305
  const SetCss$1 = 'Viewlet.setCss';
@@ -1396,7 +1415,7 @@ const openUrl = async (url, platform) => {
1396
1415
  const {
1397
1416
  invoke: invoke$d,
1398
1417
  set: set$b
1399
- } = create$a(IconThemeWorker);
1418
+ } = create$a(TextMeasurementWorker);
1400
1419
 
1401
1420
  const {
1402
1421
  invoke: invoke$c,
@@ -1412,7 +1431,7 @@ const showContextMenu2 = async (uid, menuId, x, y, args) => {
1412
1431
  };
1413
1432
  const sendMessagePortToDragAndDropWorker = async port => {
1414
1433
  const command = 'DragAndDrop.handleMessagePort';
1415
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToDragAndDropWorker', port, command);
1434
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToRendererProcess', port, command);
1416
1435
  };
1417
1436
  const sendMessagePortToOpenerWorker = async (port, rpcId) => {
1418
1437
  const command = 'HandleMessagePort.handleMessagePort';
@@ -5198,6 +5217,7 @@ const createEditor2 = (id, uri, x, y, width, height, platform, assetDir, _langua
5198
5217
  primarySelectionIndex: 0,
5199
5218
  problemsHighlightedRow: -1,
5200
5219
  redoStack: [],
5220
+ roundedSelection: false,
5201
5221
  rowHeight: 0,
5202
5222
  savedSelections: [],
5203
5223
  scrollBarHeight: 0,
@@ -5507,6 +5527,7 @@ const createEditor = async ({
5507
5527
  platform,
5508
5528
  primarySelectionIndex: 0,
5509
5529
  redoStack: [],
5530
+ roundedSelection: false,
5510
5531
  rowHeight,
5511
5532
  savedSelections,
5512
5533
  scrollBarHeight: 0,
@@ -5764,6 +5785,26 @@ const dispose$2 = uid => {
5764
5785
  pendingSaves.delete(uid);
5765
5786
  };
5766
5787
 
5788
+ const getOffset = (lines, rowIndex, columnIndex) => {
5789
+ let offset = columnIndex;
5790
+ for (let i = 0; i < rowIndex; i++) {
5791
+ offset += lines[i].length + 1;
5792
+ }
5793
+ return offset;
5794
+ };
5795
+ const getSelectedChars = editor => {
5796
+ const {
5797
+ lines,
5798
+ selections
5799
+ } = editor;
5800
+ let selectedChars = 0;
5801
+ for (let i = 0; i < selections.length; i += 4) {
5802
+ const startOffset = getOffset(lines, selections[i], selections[i + 1]);
5803
+ const endOffset = getOffset(lines, selections[i + 2], selections[i + 3]);
5804
+ selectedChars += Math.abs(endOffset - startOffset);
5805
+ }
5806
+ return selectedChars;
5807
+ };
5767
5808
  const getEditorStatus = editor => {
5768
5809
  const primarySelectionIndex = editor.primarySelectionIndex || 0;
5769
5810
  const rowIndex = editor.selections[primarySelectionIndex + 2] || 0;
@@ -5775,6 +5816,7 @@ const getEditorStatus = editor => {
5775
5816
  insertSpaces: editor.insertSpaces,
5776
5817
  languageId: editor.languageId,
5777
5818
  line: rowIndex + 1,
5819
+ selectedChars: getSelectedChars(editor),
5778
5820
  tabSize: editor.tabSize
5779
5821
  };
5780
5822
  };
@@ -7428,13 +7470,15 @@ const copyLineDown = editor => {
7428
7470
  start: position
7429
7471
  };
7430
7472
  });
7431
- const selectionChanges = new Uint32Array(uniqueRows.length * 4);
7432
- for (let i = 0; i < uniqueRows.length; i++) {
7433
- const rowIndex = uniqueRows[i] + i + 1;
7434
- selectionChanges[i * 4] = rowIndex;
7435
- selectionChanges[i * 4 + 1] = 0;
7436
- selectionChanges[i * 4 + 2] = rowIndex;
7437
- selectionChanges[i * 4 + 3] = 0;
7473
+ const rowOffsets = new Map(uniqueRows.map((row, index) => [row, index + 1]));
7474
+ const selectionChanges = new Uint32Array(selections.length);
7475
+ for (let i = 0; i < selections.length; i += 4) {
7476
+ const rowIndex = selections[i] + rowOffsets.get(selections[i]);
7477
+ const columnIndex = selections[i + 1];
7478
+ selectionChanges[i] = rowIndex;
7479
+ selectionChanges[i + 1] = columnIndex;
7480
+ selectionChanges[i + 2] = rowIndex;
7481
+ selectionChanges[i + 3] = columnIndex;
7438
7482
  }
7439
7483
  return scheduleDocumentAndCursorsSelections(editor, changes, selectionChanges);
7440
7484
  };
@@ -7746,17 +7790,18 @@ const cursorDocumentStart = editor => {
7746
7790
  return scheduleSelections(editor, newSelections);
7747
7791
  };
7748
7792
 
7749
- const moveSelectionDown = (selections, i, selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) => {
7750
- moveRangeToPosition$1(selections, i, selectionEndRow + 1, selectionEndColumn);
7793
+ const moveSelectionDown = (lastRow, selections, i, selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) => {
7794
+ moveRangeToPosition$1(selections, i, Math.min(selectionEndRow + 1, lastRow), selectionEndColumn);
7751
7795
  };
7752
- const getNewSelections$9 = selections => {
7753
- return map(selections, moveSelectionDown);
7796
+ const getNewSelections$9 = (selections, lastRow) => {
7797
+ return map(selections, moveSelectionDown.bind(null, lastRow));
7754
7798
  };
7755
7799
  const cursorDown = editor => {
7756
7800
  const {
7801
+ lines,
7757
7802
  selections
7758
7803
  } = editor;
7759
- const newSelections = getNewSelections$9(selections);
7804
+ const newSelections = getNewSelections$9(selections, Math.max(0, lines.length - 1));
7760
7805
  return scheduleSelections(editor, newSelections);
7761
7806
  };
7762
7807
 
@@ -7868,24 +7913,60 @@ const cutLine = async editor => {
7868
7913
  rows.push(startRowIndex);
7869
7914
  }
7870
7915
  }
7871
- const replaceRange$1 = new Uint32Array(rows.length * 4);
7872
- const selectionChanges = new Uint32Array(rows.length * 4);
7916
+ rows.sort((a, b) => a - b);
7917
+ const ranges = [];
7873
7918
  const cutLines = [];
7874
- for (let i = 0; i < rows.length; i++) {
7875
- const startRowIndex = rows[i];
7876
- const line = lines[startRowIndex];
7877
- const offset = i * 4;
7878
- replaceRange$1[offset] = startRowIndex;
7879
- replaceRange$1[offset + 1] = 0;
7880
- replaceRange$1[offset + 2] = startRowIndex;
7881
- replaceRange$1[offset + 3] = line.length;
7882
- selectionChanges[offset] = startRowIndex;
7883
- selectionChanges[offset + 1] = 0;
7884
- selectionChanges[offset + 2] = startRowIndex;
7885
- selectionChanges[offset + 3] = 0;
7919
+ const removedRows = [];
7920
+ for (const row of rows) {
7921
+ const line = lines[row];
7922
+ const range = [row, 0, row, line.length];
7923
+ if (line === '' && lines.length > 1) {
7924
+ if (row < lines.length - 1) {
7925
+ range[2] = row + 1;
7926
+ } else {
7927
+ range[0] = row - 1;
7928
+ range[1] = lines[row - 1].length;
7929
+ }
7930
+ removedRows.push(row);
7931
+ }
7932
+ const previous = ranges.at(-1);
7933
+ if (previous && (range[0] < previous[2] || range[0] === previous[2] && range[1] <= previous[3])) {
7934
+ if (row === lines.length - 1 && line === '' && previous[0] > 0 && lines[previous[0]] === '') {
7935
+ previous[0]--;
7936
+ previous[1] = lines[previous[0]].length;
7937
+ }
7938
+ previous[2] = range[2];
7939
+ previous[3] = range[3];
7940
+ } else {
7941
+ ranges.push(range);
7942
+ }
7886
7943
  cutLines.push(line);
7887
7944
  }
7945
+ const mergedRanges = [];
7946
+ for (const range of ranges) {
7947
+ const previous = mergedRanges.at(-1);
7948
+ if (previous && range[0] === previous[2] && range[1] <= previous[3]) {
7949
+ previous[2] = range[2];
7950
+ previous[3] = range[3];
7951
+ } else {
7952
+ mergedRanges.push(range);
7953
+ }
7954
+ }
7955
+ const replaceRange$1 = new Uint32Array(mergedRanges.flat());
7888
7956
  const changes = replaceRange(editor, replaceRange$1, [''], EditorCut);
7957
+ const deletedRowCount = changes.reduce((count, change) => count + change.end.rowIndex - change.start.rowIndex, 0);
7958
+ const lastRow = lines.length - deletedRowCount - 1;
7959
+ const selectionChanges = new Uint32Array(rows.length * 4);
7960
+ let removedBefore = 0;
7961
+ for (let i = 0; i < rows.length; i++) {
7962
+ const row = rows[i];
7963
+ while (removedBefore < removedRows.length && removedRows[removedBefore] < row) {
7964
+ removedBefore++;
7965
+ }
7966
+ const cursorRow = Math.min(row - removedBefore, lastRow);
7967
+ selectionChanges[i * 4] = cursorRow;
7968
+ selectionChanges[i * 4 + 2] = cursorRow;
7969
+ }
7889
7970
  await writeText(joinLines(cutLines));
7890
7971
  return scheduleDocumentAndCursorsSelections(editor, changes, selectionChanges);
7891
7972
  };
@@ -8791,14 +8872,14 @@ const handleClickAtPosition = async (editor, modifier, rowIndex, columnIndex) =>
8791
8872
  };
8792
8873
  };
8793
8874
 
8794
- const Editor = 3;
8875
+ const Editor$1 = 3;
8795
8876
 
8796
8877
  const handleContextMenu = async (editor, button, x, y) => {
8797
8878
  const {
8798
8879
  uid
8799
8880
  } = editor;
8800
- await showContextMenu2(uid, Editor, x, y, {
8801
- menuId: Editor
8881
+ await showContextMenu2(uid, Editor$1, x, y, {
8882
+ menuId: Editor$1
8802
8883
  });
8803
8884
  return editor;
8804
8885
  };
@@ -10520,10 +10601,7 @@ const getSelections$1 = editorUid => {
10520
10601
  };
10521
10602
  const setSelections$1 = async (editorUid, selections) => {
10522
10603
  const editor = getEditor$1(editorUid);
10523
- const newEditor = {
10524
- ...editor,
10525
- selections
10526
- };
10604
+ const newEditor = setSelections$2(editor, selections);
10527
10605
  await updateEditor(editorUid, editor, newEditor);
10528
10606
  };
10529
10607
 
@@ -12825,14 +12903,16 @@ const handleSashPointerUp = (state, eventX, eventY) => {
12825
12903
  return state;
12826
12904
  };
12827
12905
 
12828
- const CodeGeneratorInput$1 = 'CodeGeneratorInput';
12906
+ const CodeGeneratorInput$1 = 'CodeGeneratorInput InputBox';
12829
12907
  const CodeGeneratorMessage = 'CodeGeneratorMessage';
12830
- const CodeGeneratorWidget = 'CodeGeneratorWidget';
12908
+ const CodeGeneratorWidget = 'Viewlet CodeGeneratorWidget';
12831
12909
  const DiagnosticError = 'DiagnosticError';
12832
12910
  const DiagnosticWarning = 'DiagnosticWarning';
12833
12911
  const CompletionDetailCloseButton = 'CompletionDetailCloseButton';
12834
12912
  const CompletionDetailContent = 'CompletionDetailContent';
12835
12913
  const Diagnostic = 'Diagnostic';
12914
+ const Editor = 'Viewlet Editor';
12915
+ const EditorMessage = 'Viewlet EditorMessage EditorMessageText EditorOverlayMessage';
12836
12916
  const EditorCursor = 'EditorCursor';
12837
12917
  const EditorHoverDiagnosticOnly = 'EditorHoverDiagnosticOnly';
12838
12918
  const EditorLineDecoration = 'EditorLineDecoration';
@@ -12842,14 +12922,14 @@ const EditorSelection = 'EditorSelection';
12842
12922
  const HoverDisplayString = 'HoverDisplayString';
12843
12923
  const HoverDocumentation = 'HoverDocumentation';
12844
12924
  const HoverEditorRow = 'HoverEditorRow';
12845
- const HoverProblem = 'HoverProblem';
12925
+ const HoverProblem = 'HoverDisplayString HoverProblem';
12846
12926
  const HoverProblemDetail = 'HoverProblemDetail';
12847
12927
  const HoverProblemMessage = 'HoverProblemMessage';
12848
12928
  const IconClose = 'IconClose';
12849
- const InputBox = 'InputBox';
12850
12929
  const MaskIcon = 'MaskIcon';
12851
- const SelectionUnfocused = 'SelectionUnfocused';
12852
- const Viewlet = 'Viewlet';
12930
+ const SelectionUnfocused = 'EditorSelection SelectionUnfocused';
12931
+ const TextEditorErrorIcon = 'EditorTextIcon EditorTextIconError MaskIcon MaskIconError';
12932
+ const TextEditorError = 'Viewlet TextEditorError';
12853
12933
 
12854
12934
  const HandleBeforeInput = 1;
12855
12935
  const HandleBlur = 2;
@@ -13220,7 +13300,7 @@ const getHoverVirtualDom = (lineInfos, documentation, diagnostics) => {
13220
13300
  if (diagnostics && diagnostics.length > 0) {
13221
13301
  dom.push({
13222
13302
  childCount: diagnostics.length * 2,
13223
- className: mergeClassNames(HoverDisplayString, HoverProblem),
13303
+ className: HoverProblem,
13224
13304
  type: Div
13225
13305
  });
13226
13306
  for (const diagnostic of diagnostics) {
@@ -13395,7 +13475,7 @@ const executeViewletCommand$1 = async (commandMap, uid, commandId, ...args) => {
13395
13475
  throw new TypeError(`Viewlet command not found: ${commandId}`);
13396
13476
  }
13397
13477
  await fn(uid, ...args);
13398
- await invoke$c('Viewlet.requestRender', uid);
13478
+ await invoke$c('Viewlet.executeViewletCommand', uid, '__renderPending', false);
13399
13479
  };
13400
13480
 
13401
13481
  const executeWidgetCommand = async (editor, name, method, _uid, widgetId, ...params) => {
@@ -14061,7 +14141,7 @@ const getMenuEntries = () => {
14061
14141
  };
14062
14142
 
14063
14143
  const getMenuIds = () => {
14064
- return [Editor$1];
14144
+ return [Editor$2];
14065
14145
  };
14066
14146
 
14067
14147
  const getProblems = async () => {
@@ -14247,23 +14327,14 @@ const kFontSize = 'editor.fontSize';
14247
14327
  const kFontFamily = 'editor.fontFamily';
14248
14328
  const kLetterSpacing = 'editor.letterSpacing';
14249
14329
  const kTabSize = 'editor.tabSize';
14250
- const kInsertSpaces = 'editor.insertSpaces';
14251
14330
  const kLineNumbers = 'editor.lineNumbers';
14252
14331
  const kHighlightActiveLineNumber = 'editor.highlightActiveLineNumber';
14253
- const kFormatOnSave = 'editor.formatOnSave';
14254
- const kDiagnostics = 'editor.diagnostics';
14255
14332
  const kQuickSuggestions = 'editor.quickSuggestions';
14256
14333
  const kAutoClosingQuotes = 'editor.autoClosingQuotes';
14257
14334
  const kAutoClosingBrackets = 'editor.autoClosingBrackets';
14258
14335
  const kFontWeight = 'editor.fontWeight';
14259
- const kHover = 'editor.hover';
14260
14336
  const kMinimapEnabled = 'editor.minimap.enabled';
14261
14337
  const kMergeConflictActions = 'editor.mergeConflictActions';
14262
- const kBreadcrumbsEnabled = 'breadcrumbs.enabled';
14263
- const kDragAndDropEnabled = 'editor.dragAndDrop';
14264
- const getDragAndDropEnabled = async () => {
14265
- return (await get$3(kDragAndDropEnabled)) ?? true;
14266
- };
14267
14338
  const isAutoClosingBracketsEnabled = async () => {
14268
14339
  return Boolean(await get$3(kAutoClosingBrackets));
14269
14340
  };
@@ -14282,9 +14353,6 @@ const getRowHeight = async () => {
14282
14353
  const getFontSize = async () => {
14283
14354
  return (await get$3(kFontSize)) || 15; // TODO find out if it is possible to use all numeric values for settings for efficiency, maybe settings could be an array
14284
14355
  };
14285
- const getHoverEnabled = async () => {
14286
- return (await get$3(kHover)) ?? true;
14287
- };
14288
14356
  const getFontFamily = async () => {
14289
14357
  return (await get$3(kFontFamily)) || 'Fira Code';
14290
14358
  };
@@ -14297,9 +14365,6 @@ const getLetterSpacing = async () => {
14297
14365
  const getTabSize = async () => {
14298
14366
  return (await get$3(kTabSize)) || 2;
14299
14367
  };
14300
- const getInsertSpaces = async () => {
14301
- return (await get$3(kInsertSpaces)) ?? true;
14302
- };
14303
14368
  const getLineNumbers = async () => {
14304
14369
  return (await get$3(kLineNumbers)) ?? false;
14305
14370
  };
@@ -14309,12 +14374,6 @@ const getHighlightActiveLineNumber = async () => {
14309
14374
  const getCompletionTriggerCharacters = async () => {
14310
14375
  return ['.', '/'];
14311
14376
  };
14312
- const getFormatOnSave = async () => {
14313
- return (await get$3(kFormatOnSave)) ?? false;
14314
- };
14315
- const diagnosticsEnabled = async () => {
14316
- return (await get$3(kDiagnostics)) ?? false;
14317
- };
14318
14377
  const getFontWeight = async () => {
14319
14378
  return (await get$3(kFontWeight)) ?? 400;
14320
14379
  };
@@ -14324,24 +14383,22 @@ const getMinimapEnabled = async () => {
14324
14383
  const getMergeConflictActionsEnabled = async () => {
14325
14384
  return (await get$3(kMergeConflictActions)) ?? false;
14326
14385
  };
14327
- const getBreadcrumbsEnabled = async () => {
14328
- return (await get$3(kBreadcrumbsEnabled)) ?? false;
14329
- };
14330
14386
 
14331
14387
  const getEditorPreferences = async () => {
14332
- const [diagnosticsEnabled$1, fontFamily, fontSize, fontWeight, formatOnSave, hoverEnabled, isAutoClosingBracketsEnabled$1, isAutoClosingQuotesEnabled$1, isAutoClosingTagsEnabled$1, isQuickSuggestionsEnabled$1, lineNumbers, highlightActiveLineNumber, rowHeight, tabSize, letterSpacing, completionTriggerCharacters, minimapEnabled, mergeConflictActionsEnabled, breadcrumbsEnabled, insertSpaces, dragAndDropEnabled] = await Promise.all([diagnosticsEnabled(), getFontFamily(), getFontSize(), getFontWeight(), getFormatOnSave(), getHoverEnabled(), isAutoClosingBracketsEnabled(), isAutoClosingQuotesEnabled(), isAutoClosingTagsEnabled(), isQuickSuggestionsEnabled(), getLineNumbers(), getHighlightActiveLineNumber(), getRowHeight(), getTabSize(), getLetterSpacing(), getCompletionTriggerCharacters(), getMinimapEnabled(), getMergeConflictActionsEnabled(), getBreadcrumbsEnabled(), getInsertSpaces(), getDragAndDropEnabled()]);
14388
+ const [diagnosticsEnabled, fontFamily, fontSize, fontWeight, formatOnSave, hoverEnabled, isAutoClosingBracketsEnabled$1, isAutoClosingQuotesEnabled$1, isAutoClosingTagsEnabled$1, isQuickSuggestionsEnabled$1, lineNumbers, highlightActiveLineNumber, rowHeight, tabSize, letterSpacing, completionTriggerCharacters, minimapEnabled, mergeConflictActionsEnabled, breadcrumbsEnabled, insertSpaces, dragAndDropEnabled, roundedSelection, combineWhitespaceTokens] = await Promise.all([get$3('editor.diagnostics'), getFontFamily(), getFontSize(), getFontWeight(), get$3('editor.formatOnSave'), get$3('editor.hover'), isAutoClosingBracketsEnabled(), isAutoClosingQuotesEnabled(), isAutoClosingTagsEnabled(), isQuickSuggestionsEnabled(), getLineNumbers(), getHighlightActiveLineNumber(), getRowHeight(), getTabSize(), getLetterSpacing(), getCompletionTriggerCharacters(), getMinimapEnabled(), getMergeConflictActionsEnabled(), get$3('breadcrumbs.enabled'), get$3('editor.insertSpaces'), get$3('editor.dragAndDrop'), get$3('editor.roundedSelection'), get$3('editor.combineWhitespaceTokens')]);
14333
14389
  return {
14334
- breadcrumbsEnabled,
14390
+ breadcrumbsEnabled: breadcrumbsEnabled ?? false,
14391
+ combineWhitespaceTokens: combineWhitespaceTokens ?? true,
14335
14392
  completionTriggerCharacters,
14336
- diagnosticsEnabled: diagnosticsEnabled$1,
14337
- dragAndDropEnabled,
14393
+ diagnosticsEnabled: diagnosticsEnabled ?? false,
14394
+ dragAndDropEnabled: dragAndDropEnabled ?? true,
14338
14395
  fontFamily,
14339
14396
  fontSize,
14340
14397
  fontWeight,
14341
- formatOnSave,
14398
+ formatOnSave: formatOnSave ?? false,
14342
14399
  highlightActiveLineNumber,
14343
- hoverEnabled,
14344
- insertSpaces,
14400
+ hoverEnabled: hoverEnabled ?? true,
14401
+ insertSpaces: insertSpaces ?? true,
14345
14402
  isAutoClosingBracketsEnabled: isAutoClosingBracketsEnabled$1,
14346
14403
  isAutoClosingQuotesEnabled: isAutoClosingQuotesEnabled$1,
14347
14404
  isAutoClosingTagsEnabled: isAutoClosingTagsEnabled$1,
@@ -14350,6 +14407,7 @@ const getEditorPreferences = async () => {
14350
14407
  lineNumbers,
14351
14408
  mergeConflictActionsEnabled,
14352
14409
  minimapEnabled,
14410
+ roundedSelection: roundedSelection === true,
14353
14411
  rowHeight,
14354
14412
  tabSize
14355
14413
  };
@@ -14675,6 +14733,7 @@ const loadContent = async (state, savedState) => {
14675
14733
  } = state;
14676
14734
  const {
14677
14735
  breadcrumbsEnabled,
14736
+ combineWhitespaceTokens,
14678
14737
  completionTriggerCharacters,
14679
14738
  diagnosticsEnabled,
14680
14739
  dragAndDropEnabled,
@@ -14693,6 +14752,7 @@ const loadContent = async (state, savedState) => {
14693
14752
  lineNumbers,
14694
14753
  mergeConflictActionsEnabled,
14695
14754
  minimapEnabled,
14755
+ roundedSelection,
14696
14756
  rowHeight,
14697
14757
  tabSize
14698
14758
  } = await getEditorPreferences();
@@ -14710,6 +14770,7 @@ const loadContent = async (state, savedState) => {
14710
14770
  ...state,
14711
14771
  breadcrumbsEnabled,
14712
14772
  charWidth,
14773
+ combineWhitespaceTokens,
14713
14774
  completionTriggerCharacters,
14714
14775
  diagnosticsEnabled,
14715
14776
  dragAndDropEnabled,
@@ -14730,6 +14791,7 @@ const loadContent = async (state, savedState) => {
14730
14791
  loadError: '',
14731
14792
  mergeConflictActionsEnabled,
14732
14793
  minimapEnabled,
14794
+ roundedSelection,
14733
14795
  rowHeight,
14734
14796
  tabSize,
14735
14797
  tokenizerId: newTokenizerId
@@ -14939,6 +15001,10 @@ const getCss = (uid, rowHeight, scrollBarHeight, scrollBarTop, scrollBarWidth, s
14939
15001
  --ScrollBarWidth: ${scrollBarWidth}px;
14940
15002
  --ScrollBarLeft: ${scrollBarLeft}px;
14941
15003
  }
15004
+ ${editorSelector} .SelectionTopLeft { border-top-left-radius: 3px; }
15005
+ ${editorSelector} .SelectionTopRight { border-top-right-radius: 3px; }
15006
+ ${editorSelector} .SelectionBottomRight { border-bottom-right-radius: 3px; }
15007
+ ${editorSelector} .SelectionBottomLeft { border-bottom-left-radius: 3px; }
14942
15008
  ${editorSelector} .EditorLayers {
14943
15009
  height: calc(100% + var(--EditorRowHeight));
14944
15010
  translate: ${translate};
@@ -15089,6 +15155,22 @@ const Button = 'button';
15089
15155
  const Code = 'code';
15090
15156
  const TextBox = 'textbox';
15091
15157
 
15158
+ const combineWhitespaceTokens = tokens => {
15159
+ const combined = [];
15160
+ for (let i = 0; i < tokens.length; i += 2) {
15161
+ const tokenText = tokens[i];
15162
+ const tokenClass = tokens[i + 1];
15163
+ const previousClass = combined.at(-1);
15164
+ // Decorations add a class after the syntax class; preserve their exact ranges.
15165
+ if (previousClass && /^[ \t]+$/.test(tokenText) && !tokenClass.includes(' ', 6) && !previousClass.includes(' ', 6)) {
15166
+ combined[combined.length - 2] += tokenText;
15167
+ } else {
15168
+ combined.push(tokenText, tokens[i + 1]);
15169
+ }
15170
+ }
15171
+ return combined;
15172
+ };
15173
+
15092
15174
  const getPathname = uri => {
15093
15175
  return decodeURIComponent(URL.canParse(uri) ? new URL(uri).pathname : uri);
15094
15176
  };
@@ -15383,9 +15465,61 @@ const getEditorRowsVirtualDom = (textInfos, differences, lineNumbers = true, hig
15383
15465
  }, ...rowsDom];
15384
15466
  };
15385
15467
 
15386
- const getSelectionsVirtualDom = (selections, focused = true) => {
15468
+ const getSelectionCornerClasses = selections => {
15469
+ const edges = [new Map(), new Map()];
15470
+ for (let i = 0; i < selections.length; i += 4) {
15471
+ const [x, y, width, height] = selections.slice(i, i + 4);
15472
+ if (width <= 0 || height <= 0) {
15473
+ continue;
15474
+ }
15475
+ for (let side = 0; side < 2; side++) {
15476
+ const key = y + side * height;
15477
+ const row = edges[side].get(key) || [];
15478
+ row.push([x, x + width]);
15479
+ edges[side].set(key, row);
15480
+ }
15481
+ }
15482
+ // Prefix maxima make overlapping intervals searchable in logarithmic time.
15483
+ for (const rows of edges) {
15484
+ for (const row of rows.values()) {
15485
+ row.sort((a, b) => a[0] - b[0]);
15486
+ for (let i = 1; i < row.length; i++) {
15487
+ row[i][1] = Math.max(row[i][1], row[i - 1][1]);
15488
+ }
15489
+ }
15490
+ }
15491
+ const result = [];
15492
+ for (let i = 0; i < selections.length; i += 4) {
15493
+ const [x, y, width, height] = selections.slice(i, i + 4);
15494
+ let corners = '';
15495
+ if (width > 0 && height > 0) {
15496
+ for (const [vertical, horizontal] of [[0, 0], [0, 1], [1, 1], [1, 0]]) {
15497
+ const row = edges[1 - vertical].get(y + vertical * height) || [];
15498
+ const edge = x + horizontal * width;
15499
+ let low = 0;
15500
+ let high = row.length;
15501
+ while (low < high) {
15502
+ const mid = low + high >>> 1;
15503
+ if (horizontal ? row[mid][0] < edge : row[mid][0] <= edge) {
15504
+ low = mid + 1;
15505
+ } else {
15506
+ high = mid;
15507
+ }
15508
+ }
15509
+ if (!low || (horizontal ? row[low - 1][1] < edge : row[low - 1][1] <= edge)) {
15510
+ corners += ` Selection${vertical ? 'Bottom' : 'Top'}${horizontal ? 'Right' : 'Left'}`;
15511
+ }
15512
+ }
15513
+ }
15514
+ result.push(corners);
15515
+ }
15516
+ return result;
15517
+ };
15518
+
15519
+ const getSelectionsVirtualDom = (selections, focused = true, roundedSelection = false) => {
15520
+ const corners = roundedSelection ? getSelectionCornerClasses(selections.map(value => typeof value === 'number' ? value : Number(value.replace(/px$/, '')))) : [];
15387
15521
  const dom = [];
15388
- const className = focused ? EditorSelection : mergeClassNames(EditorSelection, SelectionUnfocused);
15522
+ const className = focused ? EditorSelection : SelectionUnfocused;
15389
15523
  for (let i = 0; i < selections.length; i += 4) {
15390
15524
  const x = selections[i];
15391
15525
  const y = selections[i + 1];
@@ -15393,7 +15527,7 @@ const getSelectionsVirtualDom = (selections, focused = true) => {
15393
15527
  const height = selections[i + 3];
15394
15528
  dom.push({
15395
15529
  childCount: 0,
15396
- className,
15530
+ className: className + (corners[i / 4] || ''),
15397
15531
  height,
15398
15532
  left: x,
15399
15533
  top: y,
@@ -15404,8 +15538,8 @@ const getSelectionsVirtualDom = (selections, focused = true) => {
15404
15538
  return dom;
15405
15539
  };
15406
15540
 
15407
- const getEditorSelectionsVirtualDom = (selectionInfos, focused = true) => {
15408
- const selectionsDom = getSelectionsVirtualDom(selectionInfos, focused);
15541
+ const getEditorSelectionsVirtualDom = (selectionInfos, focused = true, roundedSelection = false) => {
15542
+ const selectionsDom = getSelectionsVirtualDom(selectionInfos, focused, roundedSelection);
15409
15543
  return [{
15410
15544
  childCount: selectionInfos.length / 4,
15411
15545
  className: 'Selections',
@@ -15418,8 +15552,8 @@ const editorLayersNode = {
15418
15552
  className: 'EditorLayers',
15419
15553
  type: Div
15420
15554
  };
15421
- const getEditorLayersVirtualDom = (selectionInfos, textInfos, differences, lineNumbers = true, highlightedLine = -1, cursorInfos = [], diagnostics = [], visibleLineIndices = [], endOfLineDecorations = [], bracketMatchInfos = [], focused = true, visibleViewLineIndices = [], problemsHighlightedRow = -1) => {
15422
- return [editorLayersNode, ...getEditorSelectionsVirtualDom(selectionInfos, focused), ...getEditorRowsVirtualDom(textInfos, differences, lineNumbers, highlightedLine, visibleLineIndices, endOfLineDecorations, visibleViewLineIndices, problemsHighlightedRow), ...getEditorCursorsVirtualDom(cursorInfos), ...getEditorDiagnosticsVirtualDom(diagnostics, bracketMatchInfos)];
15555
+ const getEditorLayersVirtualDom = (selectionInfos, textInfos, differences, lineNumbers = true, highlightedLine = -1, cursorInfos = [], diagnostics = [], visibleLineIndices = [], endOfLineDecorations = [], bracketMatchInfos = [], focused = true, visibleViewLineIndices = [], problemsHighlightedRow = -1, roundedSelection = false) => {
15556
+ return [editorLayersNode, ...getEditorSelectionsVirtualDom(selectionInfos, focused, roundedSelection), ...getEditorRowsVirtualDom(textInfos, differences, lineNumbers, highlightedLine, visibleLineIndices, endOfLineDecorations, visibleViewLineIndices, problemsHighlightedRow), ...getEditorCursorsVirtualDom(cursorInfos), ...getEditorDiagnosticsVirtualDom(diagnostics, bracketMatchInfos)];
15423
15557
  };
15424
15558
 
15425
15559
  const getEditorScrollBarDiagnosticsVirtualDom = scrollBarDiagnostics => {
@@ -15485,13 +15619,14 @@ const getEditorContentVirtualDom = ({
15485
15619
  highlightedLine = -1,
15486
15620
  lineNumbers = true,
15487
15621
  problemsHighlightedRow = -1,
15622
+ roundedSelection = false,
15488
15623
  scrollBarDiagnostics = [],
15489
15624
  selectionInfos = [],
15490
15625
  textInfos,
15491
15626
  visibleLineIndices = [],
15492
15627
  visibleViewLineIndices = []
15493
15628
  }) => {
15494
- return [editorContentNode, ...getEditorInputVirtualDom(), ...getEditorLayersVirtualDom(selectionInfos, textInfos, differences, lineNumbers, highlightedLine, cursorInfos, diagnostics, visibleLineIndices, endOfLineDecorations, bracketMatchInfos, focused, visibleViewLineIndices, problemsHighlightedRow), ...getEditorScrollBarDiagnosticsVirtualDom(scrollBarDiagnostics), ...getScrollBarVirtualDom()];
15629
+ return [editorContentNode, ...getEditorInputVirtualDom(), ...getEditorLayersVirtualDom(selectionInfos, textInfos, differences, lineNumbers, highlightedLine, cursorInfos, diagnostics, visibleLineIndices, endOfLineDecorations, bracketMatchInfos, focused, visibleViewLineIndices, problemsHighlightedRow, roundedSelection), ...getEditorScrollBarDiagnosticsVirtualDom(scrollBarDiagnostics), ...getScrollBarVirtualDom()];
15495
15630
  };
15496
15631
 
15497
15632
  const getGutterInfoVirtualDom = (gutterInfo, activeLineNumber) => {
@@ -15608,7 +15743,7 @@ const getPrimaryCursorRowIndex = (selections, primarySelectionIndex = 0) => {
15608
15743
 
15609
15744
  const textEditorErrorIconNode = {
15610
15745
  childCount: 0,
15611
- className: mergeClassNames('EditorTextIcon', 'EditorTextIconError', 'MaskIcon', 'MaskIconError'),
15746
+ className: TextEditorErrorIcon,
15612
15747
  type: Div
15613
15748
  };
15614
15749
  const textEditorErrorMessageNode = {
@@ -15633,6 +15768,7 @@ const getEditorVirtualDom = ({
15633
15768
  bracketMatchInfos = [],
15634
15769
  breadcrumbsEnabled = false,
15635
15770
  breakPoints = [],
15771
+ combineWhitespaceTokens: combineWhitespaceTokens$1 = false,
15636
15772
  cursorInfos = [],
15637
15773
  diagnostics = [],
15638
15774
  differences,
@@ -15653,6 +15789,7 @@ const getEditorVirtualDom = ({
15653
15789
  minLineY = 0,
15654
15790
  primarySelectionIndex = 0,
15655
15791
  problemsHighlightedRow = -1,
15792
+ roundedSelection = false,
15656
15793
  scrollBarDiagnostics = [],
15657
15794
  selectionInfos = [],
15658
15795
  selections = new Uint32Array(),
@@ -15666,7 +15803,7 @@ const getEditorVirtualDom = ({
15666
15803
  if (loadError) {
15667
15804
  return [{
15668
15805
  childCount: 2,
15669
- className: mergeClassNames('Viewlet', 'TextEditorError'),
15806
+ className: TextEditorError,
15670
15807
  'data-uid': uid,
15671
15808
  role: Code,
15672
15809
  type: Div
@@ -15690,7 +15827,7 @@ const getEditorVirtualDom = ({
15690
15827
  }) : [];
15691
15828
  return [{
15692
15829
  childCount: (showGutter ? 2 : 1) + (minimapEnabled ? 1 : 0) + (breadcrumbsEnabled ? 1 : 0),
15693
- className: mergeClassNames('Viewlet', 'Editor'),
15830
+ className: Editor,
15694
15831
  'data-uid': uid,
15695
15832
  onContextMenu: HandleContextMenu,
15696
15833
  role: Code,
@@ -15705,9 +15842,10 @@ const getEditorVirtualDom = ({
15705
15842
  highlightedLine,
15706
15843
  lineNumbers,
15707
15844
  problemsHighlightedRow,
15845
+ roundedSelection,
15708
15846
  scrollBarDiagnostics,
15709
15847
  selectionInfos,
15710
- textInfos,
15848
+ textInfos: combineWhitespaceTokens$1 ? textInfos.map(combineWhitespaceTokens) : textInfos,
15711
15849
  visibleLineIndices: visibleLineIndices || [],
15712
15850
  visibleViewLineIndices
15713
15851
  }), ...minimapDom];
@@ -15924,10 +16062,10 @@ const renderSelections = {
15924
16062
  selectionInfos = []
15925
16063
  } = newState;
15926
16064
  const cursorsDom = getCursorsVirtualDom(cursorInfos);
15927
- const selectionsDom = getSelectionsVirtualDom(selectionInfos, newState.focused);
16065
+ const selectionsDom = getSelectionsVirtualDom(selectionInfos, newState.focused, newState.roundedSelection);
15928
16066
  return [/* method */'setSelections', cursorsDom, selectionsDom];
15929
16067
  },
15930
- isEqual: (oldState, newState) => oldState.cursorInfos === newState.cursorInfos && oldState.selectionInfos === newState.selectionInfos && oldState.focused === newState.focused
16068
+ isEqual: (oldState, newState) => oldState.cursorInfos === newState.cursorInfos && oldState.selectionInfos === newState.selectionInfos && oldState.focused === newState.focused && oldState.roundedSelection === newState.roundedSelection
15931
16069
  };
15932
16070
  const renderCss = {
15933
16071
  apply: renderCss$1,
@@ -16915,7 +17053,7 @@ const CodeGeneratorInput = 'CodeGeneratorInput';
16915
17053
 
16916
17054
  const codeGeneratorNode = {
16917
17055
  childCount: 2,
16918
- className: mergeClassNames(Viewlet, CodeGeneratorWidget),
17056
+ className: CodeGeneratorWidget,
16919
17057
  type: Div
16920
17058
  };
16921
17059
  const codeGeneratorMessageNode = {
@@ -16928,7 +17066,7 @@ const getCodeGeneratorVirtualDom = state => {
16928
17066
  const enterCode$1 = enterCode();
16929
17067
  return [codeGeneratorNode, {
16930
17068
  childCount: 0,
16931
- className: mergeClassNames(CodeGeneratorInput$1, InputBox),
17069
+ className: CodeGeneratorInput$1,
16932
17070
  name: CodeGeneratorInput,
16933
17071
  placeholder: enterCode$1,
16934
17072
  type: Input
@@ -17210,7 +17348,7 @@ const render = widget => {
17210
17348
  } = widget.newState;
17211
17349
  const dom = [{
17212
17350
  childCount: 1,
17213
- className: mergeClassNames('Viewlet', 'EditorMessage', 'EditorMessageText', 'EditorOverlayMessage'),
17351
+ className: EditorMessage,
17214
17352
  style: `left:${x}px;top:${y}px;`,
17215
17353
  type: Div
17216
17354
  }, text(message)];
@@ -1,4 +1,12 @@
1
1
  [
2
+ {
3
+ "category": "text-editor",
4
+ "description": "Combine space and tab tokens with the preceding token when rendering to reduce DOM nodes",
5
+ "heading": "Combine Whitespace Tokens",
6
+ "id": "editor.combineWhitespaceTokens",
7
+ "type": "boolean",
8
+ "value": true
9
+ },
2
10
  {
3
11
  "category": "text-editor",
4
12
  "description": "The font size of the editor",
@@ -887,7 +895,7 @@
887
895
  "heading": "Rounded Selection",
888
896
  "id": "editor.roundedSelection",
889
897
  "type": "boolean",
890
- "value": "true"
898
+ "value": "false"
891
899
  },
892
900
  {
893
901
  "category": "text-editor",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/editor-worker",
3
- "version": "19.60.3",
3
+ "version": "19.61.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git@github.com:lvce-editor/editor-worker.git"