@lvce-editor/editor-worker 3.19.0 → 3.20.0

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 (2) hide show
  1. package/dist/editorWorkerMain.js +1836 -1755
  2. package/package.json +1 -1
@@ -1451,7 +1451,7 @@ const getErrorResponse = (message, error, preparePrettyError, logError) => {
1451
1451
  const errorProperty = getErrorProperty(error, prettyError);
1452
1452
  return create$1$1(message, errorProperty);
1453
1453
  };
1454
- const create$b = (message, result) => {
1454
+ const create$c = (message, result) => {
1455
1455
  return {
1456
1456
  jsonrpc: Two,
1457
1457
  id: message.id,
@@ -1460,7 +1460,7 @@ const create$b = (message, result) => {
1460
1460
  };
1461
1461
  const getSuccessResponse = (message, result) => {
1462
1462
  const resultProperty = result ?? null;
1463
- return create$b(message, resultProperty);
1463
+ return create$c(message, resultProperty);
1464
1464
  };
1465
1465
  const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
1466
1466
  try {
@@ -1660,7 +1660,7 @@ const waitForFirstMessage$1 = async port => {
1660
1660
  return event;
1661
1661
  };
1662
1662
 
1663
- const create$a = async () => {
1663
+ const create$b = async () => {
1664
1664
  const {
1665
1665
  port1,
1666
1666
  port2
@@ -1705,7 +1705,7 @@ const wrap$3 = port => {
1705
1705
 
1706
1706
  const IpcParentWithExtensionHostWorker = {
1707
1707
  __proto__: null,
1708
- create: create$a,
1708
+ create: create$b,
1709
1709
  wrap: wrap$3
1710
1710
  };
1711
1711
 
@@ -1713,7 +1713,7 @@ const sendMessagePortToSyntaxHighlightingWorker = async port => {
1713
1713
  await invokeAndTransfer('SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port, 'HandleMessagePort.handleMessagePort');
1714
1714
  };
1715
1715
 
1716
- const create$9 = async () => {
1716
+ const create$a = async () => {
1717
1717
  const {
1718
1718
  port1,
1719
1719
  port2
@@ -1758,7 +1758,7 @@ const wrap$1 = port => {
1758
1758
 
1759
1759
  const IpcParentWithSyntaxHighlightingWorker = {
1760
1760
  __proto__: null,
1761
- create: create$9,
1761
+ create: create$a,
1762
1762
  wrap: wrap$1
1763
1763
  };
1764
1764
 
@@ -1766,7 +1766,7 @@ const sendMessagePortToRendererProcess = async port => {
1766
1766
  await invokeAndTransfer('SendMessagePortToRendererProcess.sendMessagePortToRendererProcess', port, 'HandleMessagePort.handleMessagePort');
1767
1767
  };
1768
1768
 
1769
- const create$8 = async () => {
1769
+ const create$9 = async () => {
1770
1770
  const {
1771
1771
  port1,
1772
1772
  port2
@@ -1811,7 +1811,7 @@ const wrap = port => {
1811
1811
 
1812
1812
  const IpcParentWithRendererProcess = {
1813
1813
  __proto__: null,
1814
- create: create$8,
1814
+ create: create$9,
1815
1815
  wrap
1816
1816
  };
1817
1817
 
@@ -1828,7 +1828,7 @@ const getModule$1 = method => {
1828
1828
  }
1829
1829
  };
1830
1830
 
1831
- const create$7 = async ({
1831
+ const create$8 = async ({
1832
1832
  method,
1833
1833
  ...options
1834
1834
  }) => {
@@ -1846,7 +1846,7 @@ const create$7 = async ({
1846
1846
  const createRpc = method => {
1847
1847
  let _ipc;
1848
1848
  const listen = async () => {
1849
- const ipc = await create$7({
1849
+ const ipc = await create$8({
1850
1850
  method
1851
1851
  });
1852
1852
  handleIpc(ipc);
@@ -2122,7 +2122,7 @@ const getAccurateColumnIndexAscii = (line, guess, averageCharWidth, eventX, font
2122
2122
  const supported = () => {
2123
2123
  return 'Segmenter' in Intl;
2124
2124
  };
2125
- const create$6 = () => {
2125
+ const create$7 = () => {
2126
2126
  // @ts-ignore
2127
2127
  const segmenter = new Intl.Segmenter();
2128
2128
  return {
@@ -2160,7 +2160,7 @@ const create$6 = () => {
2160
2160
 
2161
2161
  // @ts-ignore
2162
2162
  const getAccurateColumnIndexUnicode = (line, guess, averageCharWidth, eventX, fontWeight, fontSize, fontFamily, letterSpacing) => {
2163
- const segmenter = create$6();
2163
+ const segmenter = create$7();
2164
2164
  const segments = segmenter.getSegments(line);
2165
2165
  const isMonospaceFont = false;
2166
2166
  const charWidth = 0;
@@ -2395,6 +2395,7 @@ const CompletionDetail$1 = 'completionDetail';
2395
2395
  const ColorPicker$1 = 'colorPicker';
2396
2396
  const Find = 'find';
2397
2397
  const Hover = 'hover';
2398
+ const SourceAction = 'sourceAction';
2398
2399
 
2399
2400
  const isCompletionWidget = widget => {
2400
2401
  return widget.id === Completion;
@@ -2465,12 +2466,12 @@ const addWidgetToEditor = async (widgetId, focusKey, editor, factory, newStateGe
2465
2466
  return newEditor;
2466
2467
  };
2467
2468
 
2468
- const create$5 = () => {
2469
+ const create$6 = () => {
2469
2470
  return Math.random();
2470
2471
  };
2471
2472
 
2472
- const create$4 = () => {
2473
- const completionUid = create$5();
2473
+ const create$5 = () => {
2474
+ const completionUid = create$6();
2474
2475
  const widget = {
2475
2476
  id: ColorPicker$1,
2476
2477
  oldState: {
@@ -2512,12 +2513,13 @@ const FocusFindWidgetCloseButton = 48;
2512
2513
  const FocusFindWidgetNextMatchButton = 49;
2513
2514
  const FocusFindWidgetPreviousMatchButton = 50;
2514
2515
  const FocusEditorHover = 51;
2516
+ const SourceActions = 52;
2515
2517
 
2516
2518
  const newStateGenerator$1 = state => {
2517
2519
  return loadContent$3(state);
2518
2520
  };
2519
2521
  const openColorPicker = async editor => {
2520
- return addWidgetToEditor(ColorPicker$1, ColorPicker, editor, create$4, newStateGenerator$1);
2522
+ return addWidgetToEditor(ColorPicker$1, ColorPicker, editor, create$5, newStateGenerator$1);
2521
2523
  };
2522
2524
 
2523
2525
  const state$6 = {
@@ -2814,7 +2816,7 @@ const characterLeft = (line, columnIndex) => {
2814
2816
  if (!supported()) {
2815
2817
  return 1;
2816
2818
  }
2817
- const segmenter = create$6();
2819
+ const segmenter = create$7();
2818
2820
  const last = segmenter.at(line, columnIndex - 1);
2819
2821
  return columnIndex - last.index;
2820
2822
  };
@@ -2825,7 +2827,7 @@ const characterRight = (line, columnIndex) => {
2825
2827
  if (!supported()) {
2826
2828
  return 1;
2827
2829
  }
2828
- const segmenter = create$6();
2830
+ const segmenter = create$7();
2829
2831
  const next = segmenter.at(line, columnIndex);
2830
2832
  return next.segment.length;
2831
2833
  };
@@ -3239,36 +3241,105 @@ const deleteWordLeft = editor => {
3239
3241
  return newEditor;
3240
3242
  };
3241
3243
 
3242
- const create$3 = () => {
3243
- const uid = create$5();
3244
- const widget = {
3245
- id: Hover,
3246
- oldState: {
3247
- uid: uid,
3248
- x: 0,
3249
- y: 0,
3250
- width: 0,
3251
- height: 0,
3252
- content: '',
3253
- diagnostics: [],
3254
- documentation: '',
3255
- editorUid: 0,
3256
- lineInfos: []
3257
- },
3258
- newState: {
3259
- uid: uid,
3260
- x: 0,
3261
- y: 0,
3262
- width: 0,
3263
- height: 0,
3264
- content: '',
3265
- diagnostics: [],
3266
- documentation: '',
3267
- editorUid: 0,
3268
- lineInfos: []
3244
+ const deleteWordPartLeft = editor => {
3245
+ const newEditor = editorDeleteHorizontalLeft(editor, wordPartLeft);
3246
+ return newEditor;
3247
+ };
3248
+
3249
+ const deleteWordPartRight = editor => {
3250
+ return editorDeleteHorizontalRight(editor, wordPartRight);
3251
+ };
3252
+
3253
+ const deleteWordRight = editor => {
3254
+ return editorDeleteHorizontalRight(editor, wordRight);
3255
+ };
3256
+
3257
+ const findAllReferences = async editor => {
3258
+ await invoke$3('SideBar.show', 'References', /* focus */true);
3259
+ return editor;
3260
+ };
3261
+
3262
+ // TODO format should be executed in parallel with saving
3263
+ // -> fast save, no need to wait for formatting
3264
+ // -> fast formatting, no need to wait for save
3265
+
3266
+ // TODO should format on save when closing/switching editor?
3267
+
3268
+ // TODO format with cursor
3269
+ // TODO should be in editor folder
3270
+
3271
+ const format$1 = async editor => {
3272
+ const edits = await invoke$3('Format.format', editor);
3273
+ return edits;
3274
+ };
3275
+
3276
+ const warn = (...args) => {
3277
+ console.warn(...args);
3278
+ };
3279
+ const error = (...args) => {
3280
+ console.error(...args);
3281
+ };
3282
+
3283
+ // @ts-ignore
3284
+ const getDocumentEdits = (editor, edits) => {
3285
+ const documentEdits = [];
3286
+ for (const edit of edits) {
3287
+ const start = positionAt(editor, edit.startOffset);
3288
+ const end = positionAt(editor, edit.endOffset);
3289
+ const deleted = getSelectionText(editor, {
3290
+ start,
3291
+ end
3292
+ });
3293
+ const documentEdit = {
3294
+ start,
3295
+ end,
3296
+ inserted: splitLines$2(edit.inserted),
3297
+ deleted,
3298
+ origin: Format
3299
+ };
3300
+ if (documentEdit.inserted.length === 0) {
3301
+ documentEdit.inserted = [''];
3269
3302
  }
3270
- };
3271
- return widget;
3303
+ documentEdits.push(documentEdit);
3304
+ }
3305
+ return documentEdits;
3306
+ };
3307
+
3308
+ // @ts-ignore
3309
+ const applyDocumentEdits = (editor, edits) => {
3310
+ if (!Array.isArray(edits)) {
3311
+ warn('something is wrong with format on save', edits);
3312
+ return editor;
3313
+ }
3314
+ if (edits.length === 0) {
3315
+ return editor;
3316
+ }
3317
+ const documentEdits = getDocumentEdits(editor, edits);
3318
+ return scheduleDocumentAndCursorsSelections(editor, documentEdits);
3319
+ };
3320
+
3321
+ const expectedErrorMessage = 'Failed to execute formatting provider: FormattingError:';
3322
+ const isFormattingError = error => {
3323
+ return error && error instanceof Error && error.message.startsWith(expectedErrorMessage);
3324
+ };
3325
+
3326
+ // TODO also format with cursor
3327
+ const format = async editor => {
3328
+ try {
3329
+ const edits = await format$1(editor);
3330
+ return applyDocumentEdits(editor, edits);
3331
+ } catch (error) {
3332
+ if (isFormattingError(error)) {
3333
+ console.error('Formatting Error:',
3334
+ // @ts-ignore
3335
+ error.message.slice(expectedErrorMessage.length));
3336
+ return editor;
3337
+ }
3338
+ console.error(error);
3339
+ const displayErrorMessage = `${error}`;
3340
+ await editorShowMessage(editor, 0, 0, displayErrorMessage, true);
3341
+ return editor;
3342
+ }
3272
3343
  };
3273
3344
 
3274
3345
  const RE_WORD_START$1 = /^[\w\-]+/;
@@ -3313,1774 +3384,1319 @@ const getWordBefore = (editor, rowIndex, columnIndex) => {
3313
3384
  return getWordBefore$1(line, columnIndex);
3314
3385
  };
3315
3386
 
3316
- const OnCompletion = 'onCompletion';
3317
- const OnHover = 'onHover';
3318
-
3319
- // TODO add tests for this
3320
- const activateByEvent = async event => {
3321
- await invoke$3('ExtensionHostManagement.activateByEvent', event);
3387
+ // @ts-ignore
3388
+ const getDefinition = async (editor, offset) => {
3389
+ const definition = await invoke$3('ExtensionHostDefinition.executeDefinitionProvider', editor, offset);
3390
+ return definition;
3322
3391
  };
3323
3392
 
3324
- const execute = async ({
3325
- editor,
3326
- args,
3327
- event,
3328
- method,
3329
- noProviderFoundMessage,
3330
- noProviderFoundResult = undefined
3331
- }) => {
3332
- const fullEvent = `${event}:${editor.languageId}`;
3333
- await activateByEvent(fullEvent);
3334
- const result = await invoke$2(method, editor.uid, ...args);
3335
- return result;
3393
+ const emptyObject = {};
3394
+ const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
3395
+ const i18nString = (key, placeholders = emptyObject) => {
3396
+ if (placeholders === emptyObject) {
3397
+ return key;
3398
+ }
3399
+ const replacer = (match, rest) => {
3400
+ return placeholders[rest];
3401
+ };
3402
+ return key.replaceAll(RE_PLACEHOLDER, replacer);
3336
3403
  };
3337
3404
 
3338
- const executeHoverProvider = (editor, offset) => {
3339
- object(editor);
3340
- number$1(offset);
3341
- return execute({
3342
- event: OnHover,
3343
- editor,
3344
- method: HoverExecute,
3345
- args: [offset],
3346
- noProviderFoundMessage: 'No hover provider found'
3347
- });
3405
+ const UiStrings$1 = {
3406
+ GoToDefinition: 'Go to Definition',
3407
+ NoDefinitionFound: 'No definition found',
3408
+ NoDefinitionFoundFor: "No definition found for '{PH1}'",
3409
+ NoTypeDefinitionFound: 'No type definition found',
3410
+ NoTypeDefinitionFoundFor: "No type definition found for '{PH1}'",
3411
+ NoResults: 'No Results',
3412
+ Replace: 'Replace',
3413
+ SourceAction: 'Source Action',
3414
+ OrganizeImports: 'Organize Imports',
3415
+ SortImports: 'Sort Imports'
3348
3416
  };
3349
-
3350
- const getHover = async (editor, offset) => {
3351
- object(editor);
3352
- number$1(offset);
3353
- // TODO invoke extension host worker directly
3354
- const hover = await executeHoverProvider(editor, offset);
3355
- return hover;
3417
+ const noDefinitionFound = () => {
3418
+ return i18nString(UiStrings$1.NoDefinitionFound);
3356
3419
  };
3357
-
3358
- let _ipc;
3359
- const listen$6 = async () => {
3360
- const ipc = await create$7({
3361
- method: RendererProcess
3420
+ const noDefinitionFoundFor = word => {
3421
+ return i18nString(UiStrings$1.NoDefinitionFoundFor, {
3422
+ PH1: word
3362
3423
  });
3363
- handleIpc(ipc);
3364
- _ipc = ipc;
3365
3424
  };
3366
- const invoke$1 = async (method, ...args) => {
3367
- return invoke$5(_ipc, method, ...args);
3425
+ const noTypeDefinitionFoundFor = word => {
3426
+ return i18nString(UiStrings$1.NoTypeDefinitionFoundFor, {
3427
+ PH1: word
3428
+ });
3368
3429
  };
3369
-
3370
- const measureTextBlockHeight = (text, fontFamily, fontSize, lineHeight, width) => {
3371
- return invoke$1('MeasureTextBlockHeight.measureTextBlockHeight', text, fontSize, fontFamily, lineHeight, width);
3430
+ const noTypeDefinitionFound = () => {
3431
+ return i18nString(UiStrings$1.NoTypeDefinitionFound);
3372
3432
  };
3373
-
3374
- const deepCopy = value => {
3375
- return structuredClone(value);
3433
+ const noResults$1 = () => {
3434
+ return i18nString(UiStrings$1.NoResults);
3376
3435
  };
3377
-
3378
- const getInitialLineState = initialLineState => {
3379
- return deepCopy(initialLineState);
3436
+ const organizeImports$1 = () => {
3437
+ return i18nString(UiStrings$1.OrganizeImports);
3380
3438
  };
3381
-
3382
- const getLineInfo$1 = (line, tokens, TokenMap) => {
3383
- const tokensLength = tokens.length;
3384
- let end = 0;
3385
- let start = 0;
3386
- const lineInfo = [];
3387
- for (let i = 0; i < tokensLength; i += 2) {
3388
- const tokenType = tokens[i];
3389
- const tokenLength = tokens[i + 1];
3390
- end += tokenLength;
3391
- const text = line.slice(start, end);
3392
- const className = `Token ${TokenMap[tokenType] || 'Unknown'}`;
3393
- const normalizedText = text;
3394
- lineInfo.push(normalizedText, className);
3395
- start = end;
3396
- }
3397
- return lineInfo;
3439
+ const sortImports = () => {
3440
+ return i18nString(UiStrings$1.SortImports);
3398
3441
  };
3399
3442
 
3400
- const state$5 = {
3401
- warned: []
3402
- };
3403
- const flattenTokensArray = tokens => {
3404
- const flattened = [];
3405
- for (const token of tokens) {
3406
- object(token);
3407
- flattened.push(token.type, token.length);
3408
- }
3409
- return flattened;
3410
- };
3411
- const warnDeprecatedArrayReturn = (languageId, fn) => {
3412
- if (state$5.warned.includes(fn)) {
3413
- return;
3414
- }
3415
- state$5.warned.push(fn);
3416
- console.warn(`tokenizers without hasArrayReturn=false are deprecated (language ${languageId})`);
3417
- };
3418
- const safeTokenizeLine = (languageId, tokenizeLine, line, lineStateAtStart, hasArrayReturn) => {
3443
+ // @ts-ignore
3444
+ const goTo = async ({
3445
+ editor,
3446
+ getLocation,
3447
+ getNoLocationFoundMessage,
3448
+ getErrorMessage,
3449
+ isNoProviderFoundError
3450
+ }) => {
3451
+ const {
3452
+ selections
3453
+ } = editor;
3454
+ const rowIndex = selections[0];
3455
+ const columnIndex = selections[1];
3419
3456
  try {
3420
- const lineState = tokenizeLine(line, lineStateAtStart);
3421
- if (!lineState || !lineState.tokens || !lineState.state) {
3422
- throw new Error('invalid tokenization result');
3457
+ const definition = await getLocation(editor, rowIndex, columnIndex);
3458
+ // TODO if editor is already disposed at this point, do nothing
3459
+ if (!definition) {
3460
+ // TODO show popup that no definition was found
3461
+ // TODO if there was an error, show popup that go to definition resulted in an error
3462
+ const info = getWordAt(editor, rowIndex, columnIndex);
3463
+ const message = getNoLocationFoundMessage(info);
3464
+ return editorShowMessage(editor, rowIndex, columnIndex, message, false);
3423
3465
  }
3424
- if (!hasArrayReturn) {
3425
- warnDeprecatedArrayReturn(languageId, tokenizeLine);
3426
- // workaround for old tokenizers
3427
- lineState.tokens = flattenTokensArray(lineState.tokens);
3466
+ if (typeof definition.uri !== 'string' || typeof definition.startOffset !== 'number' || typeof definition.endOffset !== 'number') {
3467
+ // Logger.warn('invalid definition result', definition)
3468
+ return editor;
3428
3469
  }
3429
- return lineState;
3430
- } catch (error) {
3431
- console.error(error);
3432
- return {
3433
- tokens: [/* type */0, /* length */line.length],
3434
- lineState: lineStateAtStart
3470
+ const uri = definition.uri;
3471
+ if (uri === editor.uri) {
3472
+ // TODO set cursor to the definition position
3473
+ const position = positionAt(editor, definition.startOffset);
3474
+ const selectionEdits = new Uint32Array([position.rowIndex, position.columnIndex, position.rowIndex, position.columnIndex]);
3475
+ return scheduleSelections(editor, selectionEdits);
3476
+ }
3477
+ // TODO if definition.file is not of type string, show a popup that definition.file must be of type string
3478
+ // TODO open file and scroll to that position and set cursor to that position
3479
+
3480
+ const context = {
3481
+ startRowIndex: definition.startRowIndex,
3482
+ startColumnIndex: definition.startColumnIndex,
3483
+ endRowIndex: definition.endRowIndex,
3484
+ endColumnIndex: definition.endColumnIndex
3435
3485
  };
3486
+ await invoke$3(/* Main.openUri */'Main.openUri', /* uri */uri, /* focus */true, context);
3487
+ return editor;
3488
+ } catch (error) {
3489
+ // TODO if editor is already disposed at this point, do nothing
3490
+ if (isNoProviderFoundError(error)) {
3491
+ const displayErrorMessage = getErrorMessage(error);
3492
+ await editorShowMessage(editor, rowIndex, columnIndex, displayErrorMessage, false);
3493
+ return editor;
3494
+ }
3495
+ // @ts-ignore
3496
+ // ErrorHandling.handleError(error, false)
3497
+ const displayErrorMessage = getErrorMessage(error);
3498
+ await editorShowMessage(editor, rowIndex, columnIndex, displayErrorMessage, true);
3499
+ return editor;
3436
3500
  }
3437
3501
  };
3438
3502
 
3439
- const getLineInfos = (lines, tokenizer, languageId) => {
3440
- const lineInfos = [];
3441
- const {
3442
- tokenizeLine,
3443
- initialLineState,
3444
- hasArrayReturn,
3445
- TokenMap
3446
- } = tokenizer;
3447
- let currentLineState = getInitialLineState(initialLineState);
3448
- for (const line of lines) {
3449
- const result = safeTokenizeLine(languageId, tokenizeLine, line, currentLineState, hasArrayReturn);
3450
- const {
3451
- tokens
3452
- } = result;
3453
- const lineInfo = getLineInfo$1(line, tokens, TokenMap);
3454
- lineInfos.push(lineInfo);
3455
- currentLineState = result;
3456
- }
3457
- return lineInfos;
3458
- };
3503
+ // TODO race condition, check that editor hasn't been closed in the meantime
3459
3504
 
3460
- /**
3461
- * @enum number
3462
- */
3463
- const State = {
3464
- TopLevelContent: 1
3505
+ // TODO in case of error should show message "Definition Error: Cannot ready Property x of undefined"
3506
+
3507
+ // TODO show some kind of message maybe ("No Definition found")
3508
+
3509
+ // TODO possible to do this with events/state machine instead of promises -> enables canceling operations / concurrent calls
3510
+
3511
+ // TODO there are still race conditions in this function:
3512
+ // - when open is called twice, previous dom nodes can either be reused or the previous dom nodes must be disposed
3513
+
3514
+ // @ts-ignore
3515
+ const getLocation$1 = async (editor, rowIndex, columnIndex) => {
3516
+ const offset = offsetAt(editor, rowIndex, columnIndex);
3517
+ const definition = await getDefinition(editor, offset);
3518
+ return definition;
3465
3519
  };
3466
3520
 
3467
- /**
3468
- * @enum number
3469
- */
3470
- const TokenType = {
3471
- Text: 1
3521
+ // @ts-ignore
3522
+ const getNoLocationFoundMessage$1 = info => {
3523
+ if (info.word) {
3524
+ return noDefinitionFoundFor(info.word);
3525
+ }
3526
+ return noDefinitionFound();
3472
3527
  };
3473
- const TokenMap = {
3474
- [TokenType.Text]: 'Text'
3528
+
3529
+ // @ts-ignore
3530
+ const getErrorMessage$3 = error => {
3531
+ // if (
3532
+ // error &&
3533
+ // error.message &&
3534
+ // error.message.startsWith('Failed to execute definition provider: ')
3535
+ // ) {
3536
+ // return error.message.replace('Failed to execute definition provider: ', '')
3537
+ // }
3538
+ return `${error}`;
3475
3539
  };
3476
- const initialLineState = {
3477
- state: State.TopLevelContent
3540
+
3541
+ // @ts-ignore
3542
+ const isNoProviderFoundError$1 = error => {
3543
+ return error &&
3544
+ // @ts-ignore
3545
+ error.message &&
3546
+ // @ts-ignore
3547
+ error.message.startsWith('Failed to execute definition provider: No definition provider found');
3478
3548
  };
3479
- const hasArrayReturn = true;
3480
- const tokenizeLine = (line, lineState) => {
3481
- return {
3482
- tokens: [TokenType.Text, line.length],
3483
- state: lineState.state
3484
- };
3549
+ const goToDefinition = editor => {
3550
+ return goTo({
3551
+ editor,
3552
+ getLocation: getLocation$1,
3553
+ getNoLocationFoundMessage: getNoLocationFoundMessage$1,
3554
+ getErrorMessage: getErrorMessage$3,
3555
+ isNoProviderFoundError: isNoProviderFoundError$1
3556
+ });
3485
3557
  };
3486
3558
 
3487
- const TokenizePlainText = {
3488
- __proto__: null,
3489
- State,
3490
- TokenMap,
3491
- TokenType,
3492
- hasArrayReturn,
3493
- initialLineState,
3494
- tokenizeLine
3559
+ const getNoLocationFoundMessage = info => {
3560
+ if (info.word) {
3561
+ return noTypeDefinitionFoundFor(info.word);
3562
+ }
3563
+ return noTypeDefinitionFound();
3495
3564
  };
3496
3565
 
3497
- const state$4 = {
3498
- tokenizers: Object.create(null),
3499
- tokenizePaths: Object.create(null),
3500
- listeners: [],
3501
- pending: Object.create(null),
3502
- /**
3503
- * @type {number[]}
3504
- */
3505
- connectedEditors: []
3566
+ const getTypeDefinition = async (editor, offset) => {
3567
+ const definition = await invoke$3('ExtensionHostTypeDefinition.executeTypeDefinitionProvider', editor, offset);
3568
+ return definition;
3506
3569
  };
3507
- const has = languageId => {
3508
- return languageId in state$4.tokenizers;
3570
+
3571
+ const getLocation = async (editor, rowIndex, columnIndex) => {
3572
+ const offset = offsetAt(editor, rowIndex, columnIndex);
3573
+ const definition = await getTypeDefinition(editor, offset);
3574
+ return definition;
3509
3575
  };
3510
- const set$4 = (languageId, tokenizer) => {
3511
- state$4.tokenizers[languageId] = tokenizer;
3576
+
3577
+ // @ts-ignore
3578
+ const getErrorMessage$2 = error => {
3579
+ // if (
3580
+ // error &&
3581
+ // error.message &&
3582
+ // error.message.startsWith('Failed to execute type definition provider: ')
3583
+ // ) {
3584
+ // return error.message.replace(
3585
+ // 'Failed to execute type definition provider: ',
3586
+ // ''
3587
+ // )
3588
+ // }
3589
+ return `${error}`;
3512
3590
  };
3513
- const get$4 = languageId => {
3514
- return state$4.tokenizers[languageId];
3591
+ const isNoProviderFoundError = error => {
3592
+ return error &&
3593
+ // @ts-ignore
3594
+ error.message &&
3595
+ // @ts-ignore
3596
+ error.message.startsWith('Failed to execute type definition provider: No type definition provider found');
3515
3597
  };
3516
- const isPending = languageId => {
3517
- return languageId in state$4.pending;
3598
+ const goToTypeDefinition = (editor, explicit = true) => {
3599
+ return goTo({
3600
+ editor,
3601
+ getLocation,
3602
+ getNoLocationFoundMessage: getNoLocationFoundMessage,
3603
+ isNoProviderFoundError,
3604
+ getErrorMessage: getErrorMessage$2
3605
+ });
3518
3606
  };
3519
3607
 
3520
- let enabled$1 = false;
3521
- const setEnabled$1 = value => {
3522
- enabled$1 = value;
3523
- };
3524
- const getEnabled$1 = () => {
3525
- return enabled$1;
3608
+ const Editor = 3;
3609
+
3610
+ const handleContextMenu = async (editor, button, x, y) => {
3611
+ await invoke$3(/* ContextMenu.show */'ContextMenu.show', /* x */x, /* y */y, /* id */Editor);
3612
+ return editor;
3526
3613
  };
3527
3614
 
3528
- const {
3529
- listen: listen$5,
3530
- invoke
3531
- } = createRpc(SyntaxHighlightingWorker);
3615
+ // @ts-ignore
3532
3616
 
3533
- const tokenMaps = Object.create(null);
3534
- const set$3 = (languageId, tokenMap) => {
3535
- tokenMaps[languageId] = tokenMap;
3617
+ // match all words, including umlauts, see https://stackoverflow.com/questions/5436824/matching-accented-characters-with-javascript-regexes/#answer-11550799
3618
+ const RE_WORD_START = /^[a-z\u00C0-\u017F\d]+/i;
3619
+ const RE_WORD_END = /[a-z\u00C0-\u017F\d]+$/i;
3620
+
3621
+ // @ts-ignore
3622
+ const getNewSelections$7 = (line, rowIndex, columnIndex) => {
3623
+ const before = line.slice(0, columnIndex);
3624
+ const after = line.slice(columnIndex);
3625
+ const beforeMatch = before.match(RE_WORD_END);
3626
+ const afterMatch = after.match(RE_WORD_START);
3627
+ const columnStart = columnIndex - (beforeMatch ? beforeMatch[0].length : 0);
3628
+ const columnEnd = columnIndex + (afterMatch ? afterMatch[0].length : 0);
3629
+ const newSelections = new Uint32Array([rowIndex, columnStart, rowIndex, columnEnd]);
3630
+ return newSelections;
3536
3631
  };
3537
- const get$3 = languageId => {
3538
- return tokenMaps[languageId] || {};
3632
+
3633
+ // @ts-ignore
3634
+ const selectWord = (editor, rowIndex, columnIndex) => {
3635
+ const line = getLine(editor, rowIndex);
3636
+ const newSelections = getNewSelections$7(line, rowIndex, columnIndex);
3637
+ return scheduleSelections(editor, newSelections);
3539
3638
  };
3540
3639
 
3541
- // TODO loadTokenizer should be invoked from renderer worker
3542
- const loadTokenizer = async (languageId, tokenizePath) => {
3543
- if (!tokenizePath) {
3544
- return;
3545
- }
3546
- if (getEnabled$1()) {
3547
- const tokenMap = await invoke('Tokenizer.load', languageId, tokenizePath);
3548
- set$3(languageId, tokenMap);
3549
- return;
3550
- }
3551
- try {
3552
- // TODO check that tokenizer is valid
3553
- // 1. tokenizeLine should be of type function
3554
- // 2. getTokenClass should be of type function
3555
- const tokenizer = await import(tokenizePath);
3556
- if (typeof tokenizer.tokenizeLine !== 'function') {
3557
- console.warn(`tokenizer.tokenizeLine should be a function in "${tokenizePath}"`);
3558
- return;
3559
- }
3560
- if (!tokenizer.TokenMap || typeof tokenizer.TokenMap !== 'object' || Array.isArray(tokenizer.TokenMap)) {
3561
- console.warn(`tokenizer.TokenMap should be an object in "${tokenizePath}"`);
3562
- return;
3563
- }
3564
- set$3(languageId, tokenizer.TokenMap);
3565
- set$4(languageId, tokenizer);
3566
- } catch (error) {
3567
- // TODO better error handling
3568
- console.error(error);
3569
- return;
3570
- }
3571
- };
3572
- const getTokenizer = languageId => {
3573
- if (has(languageId)) {
3574
- return get$4(languageId);
3575
- }
3576
- if (isPending(languageId)) {
3577
- return TokenizePlainText;
3578
- }
3579
- return TokenizePlainText;
3640
+ const handleDoubleClick = (editor, modifier, x, y) => {
3641
+ const position = at(editor, x, y);
3642
+ return selectWord(editor, position.rowIndex, position.columnIndex);
3580
3643
  };
3581
3644
 
3582
- const tokenizeCodeBlock = async (codeBlock, languageId, tokenizerPath) => {
3583
- await loadTokenizer(languageId, tokenizerPath);
3584
- const tokenizer = getTokenizer(languageId);
3585
- const lines = splitLines$2(codeBlock);
3586
- const lineInfos = getLineInfos(lines, tokenizer, languageId);
3587
- return lineInfos;
3645
+ const WhenExpressionEditorText = 12;
3646
+ const handleFocus = editor => {
3647
+ // TODO make change events functional,
3648
+ // when rendering, send focus changes to renderer worker
3649
+ invoke$3('Focus.setFocus', WhenExpressionEditorText);
3650
+ return editor;
3588
3651
  };
3589
3652
 
3590
- const getHoverPosition = (position, selections) => {
3591
- if (position) {
3592
- return position;
3653
+ const Single = 1;
3654
+ const Double = 2;
3655
+ const Triple = 3;
3656
+
3657
+ const state$5 = {
3658
+ position: {
3659
+ rowIndex: 0,
3660
+ columnIndex: 0
3593
3661
  }
3594
- const rowIndex = selections[0];
3595
- const columnIndex = selections[1];
3596
- return {
3597
- rowIndex,
3598
- columnIndex
3599
- };
3600
3662
  };
3601
- const getMatchingDiagnostics = (diagnostics, rowIndex, columnIndex) => {
3602
- const matching = [];
3603
- for (const diagnostic of diagnostics) {
3604
- if (diagnostic.rowIndex === rowIndex) {
3605
- matching.push(diagnostic);
3606
- }
3607
- }
3608
- return matching;
3663
+ const getPosition$1 = () => {
3664
+ return state$5.position;
3609
3665
  };
3610
- const fallbackDisplayStringLanguageId = 'typescript'; // TODO remove this
3611
3666
 
3612
- const hoverDocumentationFontSize = 15;
3613
- const hoverDocumentationFontFamily = 'Fira Code';
3614
- const hoverDocumentationLineHeight = '1.33333';
3615
- const hoverBorderLeft = 1;
3616
- const hoverBorderRight = 1;
3617
- const hoverPaddingLeft = 8;
3618
- const hoverPaddingRight = 8;
3619
- const hovverFullWidth = 400;
3620
- const hoverDocumentationWidth = hovverFullWidth - hoverPaddingLeft - hoverPaddingRight - hoverBorderLeft - hoverBorderRight;
3621
- const getHoverPositionXy = (editor, rowIndex, wordStart, documentationHeight) => {
3622
- const x$1 = x(editor, rowIndex, wordStart);
3623
- const y$1 = editor.height - y(editor, rowIndex) + editor.y + 40;
3624
- return {
3625
- x: x$1,
3626
- y: y$1
3627
- };
3667
+ // @ts-ignore
3668
+ const setPosition$1 = position => {
3669
+ state$5.position = position;
3628
3670
  };
3629
- const getEditorHoverInfo = async (editorUid, position) => {
3630
- number$1(editorUid);
3631
- const instance = get$7(editorUid);
3632
- const editor = instance.newState;
3633
- const {
3634
- selections
3635
- } = editor;
3671
+
3672
+ const Ctrl = 1;
3673
+ const Alt = 2;
3674
+
3675
+ // TODO first change cursor position, then run go to definition
3676
+ // cursor should appear at mousedown position immediately
3677
+ const handleSingleClickWithAlt = async (editor, position) => {
3636
3678
  const {
3637
3679
  rowIndex,
3638
3680
  columnIndex
3639
- } = getHoverPosition(position, selections);
3640
- const offset = offsetAt(editor, rowIndex, columnIndex);
3641
- const hover = await getHover(editor, offset);
3642
- if (!hover) {
3643
- return undefined;
3644
- }
3645
- const {
3646
- displayString,
3647
- documentation,
3648
- displayStringLanguageId
3649
- } = hover;
3650
- const tokenizerPath = '';
3651
- const lineInfos = await tokenizeCodeBlock(displayString, displayStringLanguageId || fallbackDisplayStringLanguageId, tokenizerPath);
3652
- const wordPart = await getWordBefore(editor, rowIndex, columnIndex);
3653
- const wordStart = columnIndex - wordPart.length;
3654
- await measureTextBlockHeight(documentation, hoverDocumentationFontFamily, hoverDocumentationFontSize, hoverDocumentationLineHeight, hoverDocumentationWidth);
3655
- const {
3656
- x,
3657
- y
3658
- } = getHoverPositionXy(editor, rowIndex, wordStart);
3659
- const diagnostics = editor.diagnostics || [];
3660
- const matchingDiagnostics = getMatchingDiagnostics(diagnostics, rowIndex);
3661
- return {
3662
- lineInfos,
3663
- documentation,
3664
- x,
3665
- y,
3666
- matchingDiagnostics
3681
+ } = position;
3682
+ const newEditor = {
3683
+ ...editor,
3684
+ selections: new Uint32Array([rowIndex, columnIndex, rowIndex, columnIndex])
3667
3685
  };
3686
+ // TODO rectangular selection with alt click,
3687
+ // but also go to definition with alt click
3688
+ const newEditor2 = await goToDefinition(newEditor);
3689
+ return newEditor2;
3668
3690
  };
3669
-
3670
- const loadHoverContent = async state => {
3671
- // TODO
3672
- const position = undefined;
3673
- const hoverInfo = await getEditorHoverInfo(state.editorUid, position);
3674
- if (!hoverInfo) {
3675
- return state;
3691
+ const handleSingleClickWithCtrl = async (editor, position) => {
3692
+ const selections = editor.selections;
3693
+ for (let i = 0; i < selections.length; i += 4) {
3694
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
3695
+ if (selectionStartRow === position.rowIndex && selectionStartColumn === position.columnIndex && selectionEndRow === position.rowIndex && selectionEndColumn === position.columnIndex) {
3696
+ // selection exists -> remove
3697
+ const newSelections = new Uint32Array(selections.length - 4);
3698
+ newSelections.set(selections.subarray(0, i), 0);
3699
+ newSelections.set(selections.subarray(i + 4), i);
3700
+ return scheduleSelections(editor, newSelections);
3701
+ }
3676
3702
  }
3677
- const {
3678
- lineInfos,
3679
- documentation,
3680
- x,
3681
- y,
3682
- matchingDiagnostics
3683
- } = hoverInfo;
3703
+ // TODO selection does not exist -> add
3704
+ // TODO insert in order
3705
+ const newSelections = new Uint32Array(selections.length + 4);
3706
+ newSelections.set(selections, 0);
3707
+ const insertIndex = selections.length;
3708
+ newSelections[insertIndex] = position.rowIndex;
3709
+ newSelections[insertIndex + 1] = position.columnIndex;
3710
+ newSelections[insertIndex + 2] = position.rowIndex;
3711
+ newSelections[insertIndex + 3] = position.columnIndex;
3712
+ return scheduleSelections(editor, newSelections);
3713
+ };
3714
+ const handleSingleClickDefault = (editor, position) => {
3715
+ setPosition$1(position);
3684
3716
  return {
3685
- ...state,
3686
- lineInfos,
3687
- documentation,
3688
- x,
3689
- y,
3690
- diagnostics: matchingDiagnostics
3717
+ ...editor,
3718
+ selections: new Uint32Array([position.rowIndex, position.columnIndex, position.rowIndex, position.columnIndex]),
3719
+ focused: true
3691
3720
  };
3692
3721
  };
3693
-
3694
- const newStateGenerator = state => {
3695
- return loadHoverContent(state);
3696
- };
3697
- const showHover2 = async editor => {
3698
- return addWidgetToEditor(Hover, FocusEditorHover, editor, create$3, newStateGenerator);
3722
+ const getFn = modifier => {
3723
+ switch (modifier) {
3724
+ case Alt:
3725
+ return handleSingleClickWithAlt;
3726
+ case Ctrl:
3727
+ return handleSingleClickWithCtrl;
3728
+ default:
3729
+ return handleSingleClickDefault;
3730
+ }
3699
3731
  };
3700
-
3701
- const deleteWordPartLeft = editor => {
3702
- const newEditor = editorDeleteHorizontalLeft(editor, wordPartLeft);
3732
+ const handleSingleClick = async (editor, modifier, x, y) => {
3733
+ object(editor);
3734
+ number$1(modifier);
3735
+ number$1(x);
3736
+ number$1(y);
3737
+ const position = at(editor, x, y);
3738
+ const fn = getFn(modifier);
3739
+ const newEditor = await fn(editor, position);
3740
+ // switch (newEditor.completionState) {
3741
+ // case EditorCompletionState.None:
3742
+ // case EditorCompletionState.Visible:
3743
+ // case EditorCompletionState.Loading:
3744
+ // return {
3745
+ // newState: newEditor,
3746
+ // commands: [],
3747
+ // }
3748
+ // default:
3749
+ // break
3750
+ // }
3703
3751
  return newEditor;
3704
3752
  };
3705
3753
 
3706
- const deleteWordPartRight = editor => {
3707
- return editorDeleteHorizontalRight(editor, wordPartRight);
3754
+ // @ts-ignore
3755
+
3756
+ // @ts-ignore
3757
+ const getNewSelections$6 = (line, rowIndex) => {
3758
+ // TODO handle virtual space when columnIndex is greater than line length
3759
+ return new Uint32Array([rowIndex, 0, rowIndex, line.length]);
3708
3760
  };
3709
3761
 
3710
- const deleteWordRight = editor => {
3711
- return editorDeleteHorizontalRight(editor, wordRight);
3762
+ // @ts-ignore
3763
+ const selectLine = editor => {
3764
+ const selections = editor.selections;
3765
+ const rowIndex = selections[editor.primarySelectionIndex];
3766
+ const line = getLine(editor, rowIndex);
3767
+ const newSelections = getNewSelections$6(line, rowIndex);
3768
+ return scheduleSelections(editor, newSelections);
3712
3769
  };
3713
3770
 
3714
- const findAllReferences = async editor => {
3715
- await invoke$3('SideBar.show', 'References', /* focus */true);
3716
- return editor;
3771
+ // TODO rowIndex and columnIndex should already be set because of singleClick which occurred before triple click
3772
+ // @ts-ignore
3773
+ const handleTripleClick = (editor, modifier, x, y) => {
3774
+ object(editor);
3775
+ number$1(x);
3776
+ number$1(y);
3777
+ return {
3778
+ newState: selectLine(editor),
3779
+ commands: []
3780
+ };
3717
3781
  };
3718
3782
 
3719
- // TODO format should be executed in parallel with saving
3720
- // -> fast save, no need to wait for formatting
3721
- // -> fast formatting, no need to wait for save
3722
-
3723
- // TODO should format on save when closing/switching editor?
3724
-
3725
- // TODO format with cursor
3726
- // TODO should be in editor folder
3727
-
3728
- const format$1 = async editor => {
3729
- const edits = await invoke$3('Format.format', editor);
3730
- return edits;
3783
+ const handleMouseDown = (state, modifier, x, y, detail) => {
3784
+ switch (detail) {
3785
+ case Single:
3786
+ return handleSingleClick(state, modifier, x, y);
3787
+ case Double:
3788
+ return handleDoubleClick(state, modifier, x, y);
3789
+ case Triple:
3790
+ return handleTripleClick(state, modifier, x, y);
3791
+ default:
3792
+ return state;
3793
+ }
3731
3794
  };
3732
3795
 
3733
- const warn = (...args) => {
3734
- console.warn(...args);
3796
+ const state$4 = {
3797
+ timeout: -1,
3798
+ x: 0,
3799
+ y: 0,
3800
+ editor: undefined
3735
3801
  };
3736
- const error = (...args) => {
3737
- console.error(...args);
3802
+ const get$4 = () => {
3803
+ return state$4;
3804
+ };
3805
+ const set$4 = (editor, timeout, x, y) => {
3806
+ state$4.editor = editor;
3807
+ state$4.timeout = timeout;
3808
+ state$4.x = x;
3809
+ state$4.y = y;
3738
3810
  };
3739
3811
 
3740
- // @ts-ignore
3741
- const getDocumentEdits = (editor, edits) => {
3742
- const documentEdits = [];
3743
- for (const edit of edits) {
3744
- const start = positionAt(editor, edit.startOffset);
3745
- const end = positionAt(editor, edit.endOffset);
3746
- const deleted = getSelectionText(editor, {
3747
- start,
3748
- end
3749
- });
3750
- const documentEdit = {
3751
- start,
3752
- end,
3753
- inserted: splitLines$2(edit.inserted),
3754
- deleted,
3755
- origin: Format
3756
- };
3757
- if (documentEdit.inserted.length === 0) {
3758
- documentEdit.inserted = [''];
3759
- }
3760
- documentEdits.push(documentEdit);
3761
- }
3762
- return documentEdits;
3812
+ const showHover$1 = async (editor, position) => {
3813
+ // TODO race condition
3814
+ // await Viewlet.closeWidget(ViewletModuleId.EditorHover)
3815
+ // await Viewlet.openWidget(ViewletModuleId.EditorHover, position)
3816
+ };
3817
+
3818
+ // TODO several things can happen:
3819
+ // 1. highlight link when alt key is pressed
3820
+ // 2. show hover info
3821
+ // 3. selection moves
3822
+ // 4. highlight go to definition
3823
+ // 5. show color picker
3824
+ // 6. show error info
3825
+
3826
+ const onHoverIdle = async () => {
3827
+ const {
3828
+ x,
3829
+ y,
3830
+ editor
3831
+ } = get$4();
3832
+ at(editor, x, y);
3833
+ await showHover$1();
3763
3834
  };
3835
+ const hoverDelay = 300;
3764
3836
 
3765
3837
  // @ts-ignore
3766
- const applyDocumentEdits = (editor, edits) => {
3767
- if (!Array.isArray(edits)) {
3768
- warn('something is wrong with format on save', edits);
3838
+ const handleMouseMove = (editor, x, y) => {
3839
+ if (!editor.hoverEnabled) {
3769
3840
  return editor;
3770
3841
  }
3771
- if (edits.length === 0) {
3772
- return editor;
3842
+ const oldState = get$4();
3843
+ if (oldState.timeout !== -1) {
3844
+ clearTimeout(oldState.timeout);
3773
3845
  }
3774
- const documentEdits = getDocumentEdits(editor, edits);
3775
- return scheduleDocumentAndCursorsSelections(editor, documentEdits);
3846
+ const timeout = setTimeout(onHoverIdle, hoverDelay);
3847
+ set$4(editor, timeout, x, y);
3848
+ return editor;
3776
3849
  };
3777
3850
 
3778
- const expectedErrorMessage = 'Failed to execute formatting provider: FormattingError:';
3779
- const isFormattingError = error => {
3780
- return error && error instanceof Error && error.message.startsWith(expectedErrorMessage);
3851
+ // @ts-ignore
3852
+ const getTokenIndex = (tokens, offset) => {
3853
+ let currentOffset = 0;
3854
+ for (let i = 0; i < tokens.length; i++) {
3855
+ const token = tokens[i];
3856
+ currentOffset += token.length;
3857
+ if (currentOffset >= offset) {
3858
+ return i;
3859
+ }
3860
+ }
3861
+ return -1;
3781
3862
  };
3782
3863
 
3783
- // TODO also format with cursor
3784
- const format = async editor => {
3864
+ // @ts-ignore
3865
+ const handleMouseMoveWithAltKey = async (editor, x, y) => {
3866
+ object(editor);
3867
+ number$1(x);
3868
+ number$1(y);
3869
+ const position = at(editor, x, y);
3870
+ const documentOffset = offsetAt(editor, position.rowIndex, position.columnIndex);
3785
3871
  try {
3786
- const edits = await format$1(editor);
3787
- return applyDocumentEdits(editor, edits);
3788
- } catch (error) {
3789
- if (isFormattingError(error)) {
3790
- console.error('Formatting Error:',
3791
- // @ts-ignore
3792
- error.message.slice(expectedErrorMessage.length));
3872
+ const definition = await getDefinition(editor, documentOffset);
3873
+ if (!definition) {
3793
3874
  return editor;
3794
3875
  }
3795
- console.error(error);
3796
- const displayErrorMessage = `${error}`;
3797
- await editorShowMessage(editor, 0, 0, displayErrorMessage, true);
3876
+
3877
+ // TODO make sure that editor is not disposed
3878
+
3879
+ const definitionStartPosition = positionAt(editor, definition.startOffset);
3880
+ const definitionEndPosition = positionAt(editor, definition.endOffset);
3881
+ // @ts-ignore
3882
+ const definitionRelativeStartX = definitionStartPosition.columnIndex;
3883
+ // @ts-ignore
3884
+ const definitionRelativeEndX = definitionEndPosition.columnIndex;
3885
+ // const definitionRelativeY = definitionStartPosition.rowIndex - editor.minLineY
3886
+
3887
+ const lineTokenMap = editor.lineCache[definitionStartPosition.rowIndex + 1];
3888
+ if (!lineTokenMap) {
3889
+ return editor;
3890
+ }
3891
+ const tokenIndex = getTokenIndex(lineTokenMap.tokens, definitionStartPosition.columnIndex);
3892
+ if (tokenIndex === -1) {
3893
+ return editor;
3894
+ }
3895
+ // .tokens
3896
+ // await RendererProcess.invoke(
3897
+ // /* Viewlet.invoke */ 'Viewlet.send',
3898
+ // /* id */ ViewletModuleId.EditorText,
3899
+ // /* method */ 'highlightAsLink',
3900
+ // /* relativeY */ definitionRelativeY,
3901
+ // /* tokenIndex */ tokenIndex,
3902
+ // )
3798
3903
  return editor;
3904
+ } catch (error) {
3905
+ // @ts-ignore
3906
+ if (error && error.message.startsWith('Failed to execute definition provider: No definition provider found')) {
3907
+ return editor;
3908
+ }
3909
+ throw error;
3799
3910
  }
3800
3911
  };
3801
3912
 
3913
+ // TODO adjust relative position
3802
3914
  // @ts-ignore
3803
- const getDefinition = async (editor, offset) => {
3804
- const definition = await invoke$3('ExtensionHostDefinition.executeDefinitionProvider', editor, offset);
3805
- return definition;
3915
+ const getSelectionFromNativeRange = (editor, range) => {
3916
+ return new Uint32Array([range.startRowIndex, range.startColumnIndex, range.endRowIndex, range.endColumnIndex]);
3806
3917
  };
3807
3918
 
3808
- const emptyObject = {};
3809
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
3810
- const i18nString = (key, placeholders = emptyObject) => {
3811
- if (placeholders === emptyObject) {
3812
- return key;
3813
- }
3814
- const replacer = (match, rest) => {
3815
- return placeholders[rest];
3919
+ // @ts-ignore
3920
+ const getChanges$4 = (editor, data, range) => {
3921
+ const selection = getSelectionFromNativeRange(editor, range);
3922
+ const selectionRange = {
3923
+ start: {
3924
+ rowIndex: selection[0],
3925
+ columnIndex: selection[1]
3926
+ },
3927
+ end: {
3928
+ rowIndex: selection[2],
3929
+ columnIndex: selection[3]
3930
+ }
3816
3931
  };
3817
- return key.replaceAll(RE_PLACEHOLDER, replacer);
3932
+ const changes = [{
3933
+ start: selectionRange.start,
3934
+ end: selectionRange.end,
3935
+ inserted: [data],
3936
+ deleted: getSelectionText(editor, selectionRange),
3937
+ origin: ContentEditableInput
3938
+ }];
3939
+ return changes;
3940
+ };
3941
+ const handleBeforeInputFromContentEditable = (editor, data, range) => {
3942
+ const changes = getChanges$4(editor, data, range);
3943
+ return scheduleDocumentAndCursorsSelections(editor, changes);
3818
3944
  };
3819
3945
 
3820
- const UiStrings$1 = {
3821
- GoToDefinition: 'Go to Definition',
3822
- NoDefinitionFound: 'No definition found',
3823
- NoDefinitionFoundFor: "No definition found for '{PH1}'",
3824
- NoTypeDefinitionFound: 'No type definition found',
3825
- NoTypeDefinitionFoundFor: "No type definition found for '{PH1}'",
3826
- NoResults: 'No Results',
3827
- Replace: 'Replace'
3946
+ // @ts-ignore
3947
+
3948
+ // @ts-ignore
3949
+ const editorHandleNativeSelectionChange = (editor, range) => {
3950
+ const selections = getSelectionFromNativeRange(editor, range);
3951
+ return scheduleSelections(editor, selections);
3828
3952
  };
3829
- const noDefinitionFound = () => {
3830
- return i18nString(UiStrings$1.NoDefinitionFound);
3953
+
3954
+ const state$3 = {
3955
+ /**
3956
+ * @type {any}
3957
+ */
3958
+ currentEditor: undefined,
3959
+ hasListener: false,
3960
+ position: {
3961
+ rowIndex: 0,
3962
+ columnIndex: 0
3963
+ }
3831
3964
  };
3832
- const noDefinitionFoundFor = word => {
3833
- return i18nString(UiStrings$1.NoDefinitionFoundFor, {
3834
- PH1: word
3835
- });
3965
+
3966
+ // @ts-ignore
3967
+ const setEditor = editor => {
3968
+ state$3.currentEditor = editor;
3969
+ state$3.hasListener = true;
3836
3970
  };
3837
- const noTypeDefinitionFoundFor = word => {
3838
- return i18nString(UiStrings$1.NoTypeDefinitionFoundFor, {
3839
- PH1: word
3840
- });
3971
+ const clearEditor = () => {
3972
+ state$3.currentEditor = undefined;
3973
+ state$3.hasListener = false;
3841
3974
  };
3842
- const noTypeDefinitionFound = () => {
3843
- return i18nString(UiStrings$1.NoTypeDefinitionFound);
3975
+
3976
+ // @ts-ignore
3977
+ const setPosition = position => {
3978
+ state$3.position = position;
3844
3979
  };
3845
- const noResults$1 = () => {
3846
- return i18nString(UiStrings$1.NoResults);
3980
+ const getEditor$1 = () => {
3981
+ return state$3.currentEditor;
3982
+ };
3983
+ const getPosition = () => {
3984
+ return state$3.position;
3985
+ };
3986
+ const hasListener = () => {
3987
+ return state$3.hasListener;
3847
3988
  };
3848
3989
 
3849
3990
  // @ts-ignore
3850
- const goTo = async ({
3851
- editor,
3852
- getLocation,
3853
- getNoLocationFoundMessage,
3854
- getErrorMessage,
3855
- isNoProviderFoundError
3856
- }) => {
3857
- const {
3858
- selections
3859
- } = editor;
3860
- const rowIndex = selections[0];
3861
- const columnIndex = selections[1];
3862
- try {
3863
- const definition = await getLocation(editor, rowIndex, columnIndex);
3864
- // TODO if editor is already disposed at this point, do nothing
3865
- if (!definition) {
3866
- // TODO show popup that no definition was found
3867
- // TODO if there was an error, show popup that go to definition resulted in an error
3868
- const info = getWordAt(editor, rowIndex, columnIndex);
3869
- const message = getNoLocationFoundMessage(info);
3870
- return editorShowMessage(editor, rowIndex, columnIndex, message, false);
3871
- }
3872
- if (typeof definition.uri !== 'string' || typeof definition.startOffset !== 'number' || typeof definition.endOffset !== 'number') {
3873
- // Logger.warn('invalid definition result', definition)
3874
- return editor;
3875
- }
3876
- const uri = definition.uri;
3877
- if (uri === editor.uri) {
3878
- // TODO set cursor to the definition position
3879
- const position = positionAt(editor, definition.startOffset);
3880
- const selectionEdits = new Uint32Array([position.rowIndex, position.columnIndex, position.rowIndex, position.columnIndex]);
3881
- return scheduleSelections(editor, selectionEdits);
3882
- }
3883
- // TODO if definition.file is not of type string, show a popup that definition.file must be of type string
3884
- // TODO open file and scroll to that position and set cursor to that position
3885
-
3886
- const context = {
3887
- startRowIndex: definition.startRowIndex,
3888
- startColumnIndex: definition.startColumnIndex,
3889
- endRowIndex: definition.endRowIndex,
3890
- endColumnIndex: definition.endColumnIndex
3891
- };
3892
- await invoke$3(/* Main.openUri */'Main.openUri', /* uri */uri, /* focus */true, context);
3893
- return editor;
3894
- } catch (error) {
3895
- // TODO if editor is already disposed at this point, do nothing
3896
- if (isNoProviderFoundError(error)) {
3897
- const displayErrorMessage = getErrorMessage(error);
3898
- await editorShowMessage(editor, rowIndex, columnIndex, displayErrorMessage, false);
3899
- return editor;
3900
- }
3901
- // @ts-ignore
3902
- // ErrorHandling.handleError(error, false)
3903
- const displayErrorMessage = getErrorMessage(error);
3904
- await editorShowMessage(editor, rowIndex, columnIndex, displayErrorMessage, true);
3905
- return editor;
3906
- }
3991
+ const handlePointerCaptureLost = editor => {
3992
+ clearEditor();
3993
+ return editor;
3907
3994
  };
3908
3995
 
3909
- // TODO race condition, check that editor hasn't been closed in the meantime
3910
-
3911
- // TODO in case of error should show message "Definition Error: Cannot ready Property x of undefined"
3912
-
3913
- // TODO show some kind of message maybe ("No Definition found")
3914
-
3915
- // TODO possible to do this with events/state machine instead of promises -> enables canceling operations / concurrent calls
3916
-
3917
- // TODO there are still race conditions in this function:
3918
- // - when open is called twice, previous dom nodes can either be reused or the previous dom nodes must be disposed
3996
+ // @ts-ignore
3919
3997
 
3920
3998
  // @ts-ignore
3921
- const getLocation$1 = async (editor, rowIndex, columnIndex) => {
3922
- const offset = offsetAt(editor, rowIndex, columnIndex);
3923
- const definition = await getDefinition(editor, offset);
3924
- return definition;
3999
+ const getNewPercent$1 = (size, scrollBarSize, relativeX) => {
4000
+ if (relativeX <= 0) {
4001
+ return 0;
4002
+ }
4003
+ // if (relativeY <= editor.scrollBarHeight / 2) {
4004
+ // console.log('clicked at top')
4005
+ // // clicked at top
4006
+ // return 0
4007
+ // }
4008
+ if (relativeX <= size - scrollBarSize / 2) {
4009
+ // clicked in middle
4010
+ return relativeX / (size - scrollBarSize);
4011
+ }
4012
+ // clicked at bottom
4013
+ return 1;
3925
4014
  };
3926
4015
 
3927
4016
  // @ts-ignore
3928
- const getNoLocationFoundMessage$1 = info => {
3929
- if (info.word) {
3930
- return noDefinitionFoundFor(info.word);
4017
+ const handleScrollBarHorizontalMove = (state, eventX) => {
4018
+ const {
4019
+ x,
4020
+ width,
4021
+ longestLineWidth,
4022
+ handleOffsetX
4023
+ } = state;
4024
+ const spaceRight = 20; // TODO make this configurable
4025
+ const normalizedEventX = clamp(eventX, x, x + width);
4026
+ if (width > longestLineWidth) {
4027
+ return {
4028
+ ...state,
4029
+ deltaX: 0,
4030
+ scrollBarWidth: 0
4031
+ };
3931
4032
  }
3932
- return noDefinitionFound();
4033
+ const relativeX = normalizedEventX - x - handleOffsetX;
4034
+ const scrollBarWidth = getScrollBarWidth(width, longestLineWidth);
4035
+ const finalDeltaX = longestLineWidth - width + spaceRight;
4036
+ const newPercent = getNewPercent$1(width, scrollBarWidth, relativeX);
4037
+ const clampedPercent = clamp(newPercent, 0, 1);
4038
+ const newDeltaX = clampedPercent * finalDeltaX;
4039
+ return {
4040
+ ...state,
4041
+ deltaX: newDeltaX
4042
+ };
3933
4043
  };
3934
4044
 
3935
4045
  // @ts-ignore
3936
- const getErrorMessage$3 = error => {
3937
- // if (
3938
- // error &&
3939
- // error.message &&
3940
- // error.message.startsWith('Failed to execute definition provider: ')
3941
- // ) {
3942
- // return error.message.replace('Failed to execute definition provider: ', '')
3943
- // }
3944
- return `${error}`;
3945
- };
4046
+
4047
+ // TODO duplicate code with vertical pointer down event listener
3946
4048
 
3947
4049
  // @ts-ignore
3948
- const isNoProviderFoundError$1 = error => {
3949
- return error &&
3950
- // @ts-ignore
3951
- error.message &&
4050
+ const handleScrollBarHorizontalPointerDown = (state, eventX) => {
3952
4051
  // @ts-ignore
3953
- error.message.startsWith('Failed to execute definition provider: No definition provider found');
3954
- };
3955
- const goToDefinition = editor => {
3956
- return goTo({
3957
- editor,
3958
- getLocation: getLocation$1,
3959
- getNoLocationFoundMessage: getNoLocationFoundMessage$1,
3960
- getErrorMessage: getErrorMessage$3,
3961
- isNoProviderFoundError: isNoProviderFoundError$1
3962
- });
3963
- };
3964
-
3965
- const getNoLocationFoundMessage = info => {
3966
- if (info.word) {
3967
- return noTypeDefinitionFoundFor(info.word);
4052
+ const {
4053
+ x,
4054
+ deltaX,
4055
+ width,
4056
+ finalDeltaY,
4057
+ height,
4058
+ scrollBarHeight,
4059
+ longestLineWidth
4060
+ } = state;
4061
+ const relativeX = eventX - x;
4062
+ const scrollBarWidth = getScrollBarWidth(width, longestLineWidth);
4063
+ const finalDeltaX = width - scrollBarWidth;
4064
+ const currentScrollBarX = getScrollBarOffset(deltaX, finalDeltaX, width, scrollBarWidth);
4065
+ const diff = relativeX - currentScrollBarX;
4066
+ if (diff >= 0 && diff < scrollBarWidth) {
4067
+ return {
4068
+ ...state,
4069
+ handleOffsetX: diff
4070
+ };
3968
4071
  }
3969
- return noTypeDefinitionFound();
3970
- };
3971
-
3972
- const getTypeDefinition = async (editor, offset) => {
3973
- const definition = await invoke$3('ExtensionHostTypeDefinition.executeTypeDefinitionProvider', editor, offset);
3974
- return definition;
4072
+ const {
4073
+ percent,
4074
+ handleOffset
4075
+ } = getNewDeltaPercent(width, scrollBarWidth, relativeX);
4076
+ const newDeltaX = percent * finalDeltaX;
4077
+ return {
4078
+ ...state,
4079
+ handleOffsetX: handleOffset,
4080
+ deltaX: newDeltaX
4081
+ };
3975
4082
  };
3976
4083
 
3977
- const getLocation = async (editor, rowIndex, columnIndex) => {
3978
- const offset = offsetAt(editor, rowIndex, columnIndex);
3979
- const definition = await getTypeDefinition(editor, offset);
3980
- return definition;
3981
- };
4084
+ // @ts-ignore
3982
4085
 
3983
4086
  // @ts-ignore
3984
- const getErrorMessage$2 = error => {
3985
- // if (
3986
- // error &&
3987
- // error.message &&
3988
- // error.message.startsWith('Failed to execute type definition provider: ')
3989
- // ) {
3990
- // return error.message.replace(
3991
- // 'Failed to execute type definition provider: ',
3992
- // ''
3993
- // )
4087
+ const getNewPercent = (state, relativeY) => {
4088
+ const {
4089
+ height,
4090
+ scrollBarHeight
4091
+ } = state;
4092
+ // if (relativeY <= editor.scrollBarHeight / 2) {
4093
+ // console.log('clicked at top')
4094
+ // // clicked at top
4095
+ // return 0
3994
4096
  // }
3995
- return `${error}`;
3996
- };
3997
- const isNoProviderFoundError = error => {
3998
- return error &&
3999
- // @ts-ignore
4000
- error.message &&
4001
- // @ts-ignore
4002
- error.message.startsWith('Failed to execute type definition provider: No type definition provider found');
4003
- };
4004
- const goToTypeDefinition = (editor, explicit = true) => {
4005
- return goTo({
4006
- editor,
4007
- getLocation,
4008
- getNoLocationFoundMessage: getNoLocationFoundMessage,
4009
- isNoProviderFoundError,
4010
- getErrorMessage: getErrorMessage$2
4011
- });
4097
+ if (relativeY <= height - scrollBarHeight / 2) {
4098
+ // clicked in middle
4099
+ return relativeY / (height - scrollBarHeight);
4100
+ }
4101
+ // clicked at bottom
4102
+ return 1;
4012
4103
  };
4013
4104
 
4014
- const Editor = 3;
4015
-
4016
- const handleContextMenu = async (editor, button, x, y) => {
4017
- await invoke$3(/* ContextMenu.show */'ContextMenu.show', /* x */x, /* y */y, /* id */Editor);
4018
- return editor;
4105
+ // @ts-ignore
4106
+ const handleScrollBarMove = (state, eventY) => {
4107
+ const {
4108
+ y,
4109
+ finalDeltaY,
4110
+ handleOffset
4111
+ } = state;
4112
+ const relativeY = eventY - y - handleOffset;
4113
+ const newPercent = getNewPercent(state, relativeY);
4114
+ const newDeltaY = newPercent * finalDeltaY;
4115
+ return setDeltaYFixedValue$1(state, newDeltaY);
4019
4116
  };
4117
+ const handleScrollBarVerticalPointerMove = handleScrollBarMove;
4020
4118
 
4021
4119
  // @ts-ignore
4022
4120
 
4023
- // match all words, including umlauts, see https://stackoverflow.com/questions/5436824/matching-accented-characters-with-javascript-regexes/#answer-11550799
4024
- const RE_WORD_START = /^[a-z\u00C0-\u017F\d]+/i;
4025
- const RE_WORD_END = /[a-z\u00C0-\u017F\d]+$/i;
4121
+ // TODO scrollbar position can be in interval [0, editor.height - editor.scrollBarHeight]
4122
+ // when clicked at y <= editor.scrollbarHeight/2, position is set to zero
4123
+ // when clicked at y >= editor.height - editor.scrollBarHeight/2, position is set to (editor.height - scrollBarHeight/2)
4124
+ // when clicked at y > editor.height - editor.scrollBarHeight/2, position scrollbar at (y - scrollbarHeight/2)
4125
+ // additionally, when clicked on scrollbar, scrollbar position shouldn't move
4026
4126
 
4027
4127
  // @ts-ignore
4028
- const getNewSelections$7 = (line, rowIndex, columnIndex) => {
4029
- const before = line.slice(0, columnIndex);
4030
- const after = line.slice(columnIndex);
4031
- const beforeMatch = before.match(RE_WORD_END);
4032
- const afterMatch = after.match(RE_WORD_START);
4033
- const columnStart = columnIndex - (beforeMatch ? beforeMatch[0].length : 0);
4034
- const columnEnd = columnIndex + (afterMatch ? afterMatch[0].length : 0);
4035
- const newSelections = new Uint32Array([rowIndex, columnStart, rowIndex, columnEnd]);
4036
- return newSelections;
4128
+ const handleScrollBarPointerDown = (state, eventY) => {
4129
+ const {
4130
+ y,
4131
+ deltaY,
4132
+ finalDeltaY,
4133
+ height,
4134
+ scrollBarHeight
4135
+ } = state;
4136
+ const relativeY = eventY - y;
4137
+ const currentScrollBarY = getScrollBarY(deltaY, finalDeltaY, height, scrollBarHeight);
4138
+ const diff = relativeY - currentScrollBarY;
4139
+ if (diff >= 0 && diff < scrollBarHeight) {
4140
+ return {
4141
+ ...state,
4142
+ handleOffset: diff
4143
+ };
4144
+ }
4145
+ const {
4146
+ percent,
4147
+ handleOffset
4148
+ } = getNewDeltaPercent(height, scrollBarHeight, relativeY);
4149
+ const newDeltaY = percent * finalDeltaY;
4150
+ return {
4151
+ ...setDeltaYFixedValue$1(state, newDeltaY),
4152
+ handleOffset
4153
+ };
4037
4154
  };
4038
4155
 
4039
- // @ts-ignore
4040
- const selectWord = (editor, rowIndex, columnIndex) => {
4041
- const line = getLine(editor, rowIndex);
4042
- const newSelections = getNewSelections$7(line, rowIndex, columnIndex);
4043
- return scheduleSelections(editor, newSelections);
4156
+ const state$2 = {
4157
+ touchOffsetY: 0,
4158
+ deltaY: 0
4044
4159
  };
4045
4160
 
4046
- const handleDoubleClick = (editor, modifier, x, y) => {
4047
- const position = at(editor, x, y);
4048
- return selectWord(editor, position.rowIndex, position.columnIndex);
4161
+ // @ts-ignore
4162
+ const handleTouchStart = (editor, touchEvent) => {
4163
+ if (touchEvent.touches.length === 0) {
4164
+ return;
4165
+ }
4166
+ const firstTouch = touchEvent.touches[0];
4167
+ state$2.touchOffsetY = firstTouch.y;
4168
+ state$2.deltaY = editor.deltaY;
4169
+ // const position = EditorPosition.at(editor, firstTouch.x, firstTouch.y)
4170
+ // EditorMoveSelection.state.position = position
4171
+ // state.date = Date.now()
4049
4172
  };
4050
4173
 
4051
- const WhenExpressionEditorText = 12;
4052
- const handleFocus = editor => {
4053
- // TODO make change events functional,
4054
- // when rendering, send focus changes to renderer worker
4055
- invoke$3('Focus.setFocus', WhenExpressionEditorText);
4056
- return editor;
4057
- };
4174
+ const LessThan = -1;
4175
+ const Equal = 0;
4176
+ const GreaterThan = 1;
4058
4177
 
4059
- const Single = 1;
4060
- const Double = 2;
4061
- const Triple = 3;
4178
+ // @ts-ignore
4062
4179
 
4063
- const state$3 = {
4064
- position: {
4065
- rowIndex: 0,
4066
- columnIndex: 0
4180
+ // @ts-ignore
4181
+ const compare = (positionA, positionB) => {
4182
+ if (positionA.rowIndex > positionB.rowIndex) {
4183
+ return GreaterThan;
4067
4184
  }
4068
- };
4069
- const getPosition$1 = () => {
4070
- return state$3.position;
4185
+ if (positionA.rowIndex === positionB.rowIndex) {
4186
+ if (positionA.columnIndex > positionB.columnIndex) {
4187
+ return GreaterThan;
4188
+ }
4189
+ if (positionA.columnIndex < positionB.columnIndex) {
4190
+ return LessThan;
4191
+ }
4192
+ return Equal;
4193
+ }
4194
+ return LessThan;
4071
4195
  };
4072
4196
 
4073
4197
  // @ts-ignore
4074
- const setPosition$1 = position => {
4075
- state$3.position = position;
4198
+ const editorMoveSelectionBackwards = (anchor, position) => {
4199
+ return new Uint32Array([anchor.rowIndex, anchor.columnIndex, position.rowIndex, position.columnIndex]);
4076
4200
  };
4077
4201
 
4078
- const Ctrl = 1;
4079
- const Alt = 2;
4080
-
4081
- // TODO first change cursor position, then run go to definition
4082
- // cursor should appear at mousedown position immediately
4083
- const handleSingleClickWithAlt = async (editor, position) => {
4084
- const {
4085
- rowIndex,
4086
- columnIndex
4087
- } = position;
4088
- const newEditor = {
4089
- ...editor,
4090
- selections: new Uint32Array([rowIndex, columnIndex, rowIndex, columnIndex])
4091
- };
4092
- // TODO rectangular selection with alt click,
4093
- // but also go to definition with alt click
4094
- const newEditor2 = await goToDefinition(newEditor);
4095
- return newEditor2;
4096
- };
4097
- const handleSingleClickWithCtrl = async (editor, position) => {
4098
- const selections = editor.selections;
4099
- for (let i = 0; i < selections.length; i += 4) {
4100
- const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
4101
- if (selectionStartRow === position.rowIndex && selectionStartColumn === position.columnIndex && selectionEndRow === position.rowIndex && selectionEndColumn === position.columnIndex) {
4102
- // selection exists -> remove
4103
- const newSelections = new Uint32Array(selections.length - 4);
4104
- newSelections.set(selections.subarray(0, i), 0);
4105
- newSelections.set(selections.subarray(i + 4), i);
4106
- return scheduleSelections(editor, newSelections);
4107
- }
4108
- }
4109
- // TODO selection does not exist -> add
4110
- // TODO insert in order
4111
- const newSelections = new Uint32Array(selections.length + 4);
4112
- newSelections.set(selections, 0);
4113
- const insertIndex = selections.length;
4114
- newSelections[insertIndex] = position.rowIndex;
4115
- newSelections[insertIndex + 1] = position.columnIndex;
4116
- newSelections[insertIndex + 2] = position.rowIndex;
4117
- newSelections[insertIndex + 3] = position.columnIndex;
4118
- return scheduleSelections(editor, newSelections);
4202
+ // @ts-ignore
4203
+ const editorMoveSelectionEqual = (anchor, position) => {
4204
+ return new Uint32Array([position.rowIndex, position.columnIndex, position.rowIndex, position.columnIndex]);
4119
4205
  };
4120
- const handleSingleClickDefault = (editor, position) => {
4121
- setPosition$1(position);
4122
- return {
4123
- ...editor,
4124
- selections: new Uint32Array([position.rowIndex, position.columnIndex, position.rowIndex, position.columnIndex]),
4125
- focused: true
4126
- };
4206
+
4207
+ // @ts-ignore
4208
+ const editorMoveSelectionForwards = (anchor, position) => {
4209
+ return new Uint32Array([anchor.rowIndex, anchor.columnIndex, position.rowIndex, position.columnIndex]);
4127
4210
  };
4128
- const getFn = modifier => {
4129
- switch (modifier) {
4130
- case Alt:
4131
- return handleSingleClickWithAlt;
4132
- case Ctrl:
4133
- return handleSingleClickWithCtrl;
4211
+
4212
+ // @ts-ignore
4213
+ const getNewSelections$5 = (anchor, position) => {
4214
+ switch (compare(position, anchor)) {
4215
+ case LessThan:
4216
+ return editorMoveSelectionBackwards(anchor, position);
4217
+ case Equal:
4218
+ return editorMoveSelectionEqual(anchor, position);
4219
+ case GreaterThan:
4220
+ return editorMoveSelectionForwards(anchor, position);
4134
4221
  default:
4135
- return handleSingleClickDefault;
4222
+ throw new Error('unexpected comparison result');
4136
4223
  }
4137
4224
  };
4138
- const handleSingleClick = async (editor, modifier, x, y) => {
4139
- object(editor);
4140
- number$1(modifier);
4141
- number$1(x);
4142
- number$1(y);
4143
- const position = at(editor, x, y);
4144
- const fn = getFn(modifier);
4145
- const newEditor = await fn(editor, position);
4146
- // switch (newEditor.completionState) {
4147
- // case EditorCompletionState.None:
4148
- // case EditorCompletionState.Visible:
4149
- // case EditorCompletionState.Loading:
4150
- // return {
4151
- // newState: newEditor,
4152
- // commands: [],
4153
- // }
4154
- // default:
4155
- // break
4156
- // }
4157
- return newEditor;
4225
+
4226
+ // @ts-ignore
4227
+ const editorMoveSelection = (editor, position) => {
4228
+ const anchor = getPosition$1();
4229
+ const newSelections = getNewSelections$5(anchor, position);
4230
+ // TODO if selection equals previous selection -> do nothing
4231
+ return scheduleSelections(editor, newSelections);
4158
4232
  };
4159
4233
 
4234
+ const LONG_TOUCH_THRESHOLD = 150;
4235
+
4160
4236
  // @ts-ignore
4237
+ const handleTouchEnd = (editor, touchEvent) => {
4238
+ if (touchEvent.changedTouches.length === 0) {
4239
+ return;
4240
+ }
4241
+ const firstTouch = touchEvent.changedTouches[0];
4242
+ const position = at(editor, firstTouch.x, firstTouch.y);
4243
+ // @ts-ignore
4244
+ if (undefined.position.rowIndex === position.rowIndex && undefined.position.columnIndex === position.columnIndex) {
4245
+ // @ts-ignore
4246
+ if (Date.now() - state$2.date > LONG_TOUCH_THRESHOLD) {
4247
+ selectWord(editor, position.rowIndex, position.columnIndex);
4248
+ } else {
4249
+ // @ts-ignore
4250
+ cursorSet(editor, position);
4251
+ }
4252
+ } else {
4253
+ console.log('different position');
4254
+ }
4255
+ };
4161
4256
 
4162
4257
  // @ts-ignore
4163
- const getNewSelections$6 = (line, rowIndex) => {
4164
- // TODO handle virtual space when columnIndex is greater than line length
4165
- return new Uint32Array([rowIndex, 0, rowIndex, line.length]);
4258
+ const setDeltaY = (editor, deltaY) => {
4259
+ return setDeltaY$1(editor, deltaY);
4166
4260
  };
4167
4261
 
4168
4262
  // @ts-ignore
4169
- const selectLine = editor => {
4170
- const selections = editor.selections;
4171
- const rowIndex = selections[editor.primarySelectionIndex];
4172
- const line = getLine(editor, rowIndex);
4173
- const newSelections = getNewSelections$6(line, rowIndex);
4174
- return scheduleSelections(editor, newSelections);
4263
+ const setDeltaYFixedValue = (editor, deltaY) => {
4264
+ return setDeltaYFixedValue$1(editor, deltaY);
4175
4265
  };
4176
4266
 
4177
- // TODO rowIndex and columnIndex should already be set because of singleClick which occurred before triple click
4178
4267
  // @ts-ignore
4179
- const handleTripleClick = (editor, modifier, x, y) => {
4180
- object(editor);
4181
- number$1(x);
4182
- number$1(y);
4268
+ const setDelta = (editor, deltaMode, eventDeltaX, eventDeltaY) => {
4269
+ number$1(deltaMode);
4270
+ number$1(eventDeltaX);
4271
+ number$1(eventDeltaY);
4272
+ // @ts-ignore
4273
+ const {
4274
+ deltaX,
4275
+ deltaY
4276
+ } = editor;
4277
+ if (eventDeltaX === 0) {
4278
+ return setDeltaY(editor, eventDeltaY);
4279
+ }
4280
+ const newDeltaX = clamp(deltaX + eventDeltaX, 0, Number.POSITIVE_INFINITY);
4183
4281
  return {
4184
- newState: selectLine(editor),
4185
- commands: []
4282
+ ...setDeltaY(editor, eventDeltaY),
4283
+ deltaX: newDeltaX
4186
4284
  };
4187
4285
  };
4188
4286
 
4189
- const handleMouseDown = (state, modifier, x, y, detail) => {
4190
- switch (detail) {
4191
- case Single:
4192
- return handleSingleClick(state, modifier, x, y);
4193
- case Double:
4194
- return handleDoubleClick(state, modifier, x, y);
4195
- case Triple:
4196
- return handleTripleClick(state, modifier, x, y);
4197
- default:
4198
- return state;
4199
- }
4200
- };
4201
-
4202
- const state$2 = {
4203
- timeout: -1,
4204
- x: 0,
4205
- y: 0,
4206
- editor: undefined
4207
- };
4208
- const get$2 = () => {
4209
- return state$2;
4210
- };
4211
- const set$2 = (editor, timeout, x, y) => {
4212
- state$2.editor = editor;
4213
- state$2.timeout = timeout;
4214
- state$2.x = x;
4215
- state$2.y = y;
4216
- };
4217
-
4218
- const showHover$1 = async (editor, position) => {
4219
- // TODO race condition
4220
- // await Viewlet.closeWidget(ViewletModuleId.EditorHover)
4221
- // await Viewlet.openWidget(ViewletModuleId.EditorHover, position)
4222
- };
4223
-
4224
- // TODO several things can happen:
4225
- // 1. highlight link when alt key is pressed
4226
- // 2. show hover info
4227
- // 3. selection moves
4228
- // 4. highlight go to definition
4229
- // 5. show color picker
4230
- // 6. show error info
4231
-
4232
- const onHoverIdle = async () => {
4233
- const {
4234
- x,
4235
- y,
4236
- editor
4237
- } = get$2();
4238
- at(editor, x, y);
4239
- await showHover$1();
4240
- };
4241
- const hoverDelay = 300;
4242
-
4243
4287
  // @ts-ignore
4244
- const handleMouseMove = (editor, x, y) => {
4245
- if (!editor.hoverEnabled) {
4246
- return editor;
4247
- }
4248
- const oldState = get$2();
4249
- if (oldState.timeout !== -1) {
4250
- clearTimeout(oldState.timeout);
4288
+ const handleTouchMove = (editor, touchEvent) => {
4289
+ if (touchEvent.touches.length === 0) {
4290
+ return;
4251
4291
  }
4252
- const timeout = setTimeout(onHoverIdle, hoverDelay);
4253
- set$2(editor, timeout, x, y);
4254
- return editor;
4292
+ const firstTouch = touchEvent.touches[0];
4293
+ const offsetY = state$2.deltaY + (state$2.touchOffsetY - firstTouch.y);
4294
+ setDeltaYFixedValue(editor, offsetY);
4255
4295
  };
4256
4296
 
4257
4297
  // @ts-ignore
4258
- const getTokenIndex = (tokens, offset) => {
4259
- let currentOffset = 0;
4260
- for (let i = 0; i < tokens.length; i++) {
4261
- const token = tokens[i];
4262
- currentOffset += token.length;
4263
- if (currentOffset >= offset) {
4264
- return i;
4298
+ const getChanges$3 = selections => {
4299
+ const changes = [];
4300
+ const rowsToIndentLess = [];
4301
+ for (let i = 0; i < selections.length; i += 4) {
4302
+ const selectionStartRow = selections[i];
4303
+ const selectionEndRow = selections[i + 2];
4304
+ for (let i = selectionStartRow; i <= selectionEndRow; i++) {
4305
+ rowsToIndentLess.push(i);
4265
4306
  }
4266
4307
  }
4267
- return -1;
4268
- };
4269
-
4270
- // @ts-ignore
4271
- const handleMouseMoveWithAltKey = async (editor, x, y) => {
4272
- object(editor);
4273
- number$1(x);
4274
- number$1(y);
4275
- const position = at(editor, x, y);
4276
- const documentOffset = offsetAt(editor, position.rowIndex, position.columnIndex);
4277
- try {
4278
- const definition = await getDefinition(editor, documentOffset);
4279
- if (!definition) {
4280
- return editor;
4281
- }
4282
-
4283
- // TODO make sure that editor is not disposed
4284
-
4285
- const definitionStartPosition = positionAt(editor, definition.startOffset);
4286
- const definitionEndPosition = positionAt(editor, definition.endOffset);
4287
- // @ts-ignore
4288
- const definitionRelativeStartX = definitionStartPosition.columnIndex;
4289
- // @ts-ignore
4290
- const definitionRelativeEndX = definitionEndPosition.columnIndex;
4291
- // const definitionRelativeY = definitionStartPosition.rowIndex - editor.minLineY
4292
-
4293
- const lineTokenMap = editor.lineCache[definitionStartPosition.rowIndex + 1];
4294
- if (!lineTokenMap) {
4295
- return editor;
4296
- }
4297
- const tokenIndex = getTokenIndex(lineTokenMap.tokens, definitionStartPosition.columnIndex);
4298
- if (tokenIndex === -1) {
4299
- return editor;
4300
- }
4301
- // .tokens
4302
- // await RendererProcess.invoke(
4303
- // /* Viewlet.invoke */ 'Viewlet.send',
4304
- // /* id */ ViewletModuleId.EditorText,
4305
- // /* method */ 'highlightAsLink',
4306
- // /* relativeY */ definitionRelativeY,
4307
- // /* tokenIndex */ tokenIndex,
4308
- // )
4309
- return editor;
4310
- } catch (error) {
4311
- // @ts-ignore
4312
- if (error && error.message.startsWith('Failed to execute definition provider: No definition provider found')) {
4313
- return editor;
4314
- }
4315
- throw error;
4308
+ for (const rowToIndent of rowsToIndentLess) {
4309
+ changes.push({
4310
+ start: {
4311
+ rowIndex: rowToIndent,
4312
+ columnIndex: 0
4313
+ },
4314
+ end: {
4315
+ rowIndex: rowToIndent,
4316
+ columnIndex: 2
4317
+ },
4318
+ inserted: [''],
4319
+ deleted: [' '],
4320
+ origin: IndentLess
4321
+ });
4316
4322
  }
4323
+ return changes;
4317
4324
  };
4318
4325
 
4319
- // TODO adjust relative position
4320
4326
  // @ts-ignore
4321
- const getSelectionFromNativeRange = (editor, range) => {
4322
- return new Uint32Array([range.startRowIndex, range.startColumnIndex, range.endRowIndex, range.endColumnIndex]);
4327
+ const indentLess = editor => {
4328
+ const selections = editor.selections;
4329
+ const changes = getChanges$3(selections);
4330
+ return scheduleDocumentAndCursorsSelections(editor, changes);
4323
4331
  };
4324
4332
 
4325
- // @ts-ignore
4326
- const getChanges$4 = (editor, data, range) => {
4327
- const selection = getSelectionFromNativeRange(editor, range);
4328
- const selectionRange = {
4329
- start: {
4330
- rowIndex: selection[0],
4331
- columnIndex: selection[1]
4332
- },
4333
- end: {
4334
- rowIndex: selection[2],
4335
- columnIndex: selection[3]
4333
+ const getChanges$2 = selections => {
4334
+ const rowsToIndent = [];
4335
+ for (let i = 0; i < selections.length; i += 4) {
4336
+ const selectionStartRow = selections[i];
4337
+ const selectionEndRow = selections[i + 2];
4338
+ for (let i = selectionStartRow; i <= selectionEndRow; i++) {
4339
+ rowsToIndent.push(i);
4336
4340
  }
4337
- };
4338
- const changes = [{
4339
- start: selectionRange.start,
4340
- end: selectionRange.end,
4341
- inserted: [data],
4342
- deleted: getSelectionText(editor, selectionRange),
4343
- origin: ContentEditableInput
4344
- }];
4341
+ }
4342
+ const changes = [];
4343
+ for (const rowToIndent of rowsToIndent) {
4344
+ changes.push({
4345
+ start: {
4346
+ rowIndex: rowToIndent,
4347
+ columnIndex: 0
4348
+ },
4349
+ end: {
4350
+ rowIndex: rowToIndent,
4351
+ columnIndex: 0
4352
+ },
4353
+ inserted: [' '],
4354
+ deleted: [''],
4355
+ origin: IndentMore
4356
+ });
4357
+ }
4345
4358
  return changes;
4346
4359
  };
4347
- const handleBeforeInputFromContentEditable = (editor, data, range) => {
4348
- const changes = getChanges$4(editor, data, range);
4360
+ const indentMore = editor => {
4361
+ const {
4362
+ selections
4363
+ } = editor;
4364
+ const changes = getChanges$2(selections);
4349
4365
  return scheduleDocumentAndCursorsSelections(editor, changes);
4350
4366
  };
4351
4367
 
4352
- // @ts-ignore
4353
-
4354
- // @ts-ignore
4355
- const editorHandleNativeSelectionChange = (editor, range) => {
4356
- const selections = getSelectionFromNativeRange(editor, range);
4357
- return scheduleSelections(editor, selections);
4368
+ const getLanguageConfiguration = editor => {
4369
+ return invoke$3('Languages.getLanguageConfiguration', {
4370
+ uri: editor.uri,
4371
+ languageId: editor.languageId
4372
+ });
4358
4373
  };
4359
4374
 
4360
- const state$1 = {
4361
- /**
4362
- * @type {any}
4363
- */
4364
- currentEditor: undefined,
4365
- hasListener: false,
4366
- position: {
4367
- rowIndex: 0,
4368
- columnIndex: 0
4375
+ const getIncreaseIndentRegex = languageConfiguration => {
4376
+ if (languageConfiguration && languageConfiguration.indentationRules && languageConfiguration.indentationRules.increaseIndentPattern && typeof languageConfiguration.indentationRules.increaseIndentPattern === 'string') {
4377
+ const regex = new RegExp(languageConfiguration.indentationRules.increaseIndentPattern);
4378
+ return regex;
4369
4379
  }
4380
+ return undefined;
4370
4381
  };
4371
-
4372
- // @ts-ignore
4373
- const setEditor = editor => {
4374
- state$1.currentEditor = editor;
4375
- state$1.hasListener = true;
4376
- };
4377
- const clearEditor = () => {
4378
- state$1.currentEditor = undefined;
4379
- state$1.hasListener = false;
4380
- };
4381
-
4382
- // @ts-ignore
4383
- const setPosition = position => {
4384
- state$1.position = position;
4385
- };
4386
- const getEditor$1 = () => {
4387
- return state$1.currentEditor;
4388
- };
4389
- const getPosition = () => {
4390
- return state$1.position;
4391
- };
4392
- const hasListener = () => {
4393
- return state$1.hasListener;
4394
- };
4395
-
4396
- // @ts-ignore
4397
- const handlePointerCaptureLost = editor => {
4398
- clearEditor();
4399
- return editor;
4400
- };
4401
-
4402
- // @ts-ignore
4403
-
4404
- // @ts-ignore
4405
- const getNewPercent$1 = (size, scrollBarSize, relativeX) => {
4406
- if (relativeX <= 0) {
4407
- return 0;
4408
- }
4409
- // if (relativeY <= editor.scrollBarHeight / 2) {
4410
- // console.log('clicked at top')
4411
- // // clicked at top
4412
- // return 0
4413
- // }
4414
- if (relativeX <= size - scrollBarSize / 2) {
4415
- // clicked in middle
4416
- return relativeX / (size - scrollBarSize);
4382
+ const shouldIncreaseIndent = (before, increaseIndentRegex) => {
4383
+ if (!increaseIndentRegex) {
4384
+ return false;
4417
4385
  }
4418
- // clicked at bottom
4419
- return 1;
4386
+ return increaseIndentRegex.test(before);
4420
4387
  };
4421
-
4422
- // @ts-ignore
4423
- const handleScrollBarHorizontalMove = (state, eventX) => {
4424
- const {
4425
- x,
4426
- width,
4427
- longestLineWidth,
4428
- handleOffsetX
4429
- } = state;
4430
- const spaceRight = 20; // TODO make this configurable
4431
- const normalizedEventX = clamp(eventX, x, x + width);
4432
- if (width > longestLineWidth) {
4433
- return {
4434
- ...state,
4435
- deltaX: 0,
4436
- scrollBarWidth: 0
4388
+ const getChanges$1 = (lines, selections, languageConfiguration) => {
4389
+ const changes = [];
4390
+ const selectionChanges = [];
4391
+ const increaseIndentRegex = getIncreaseIndentRegex(languageConfiguration);
4392
+ for (let i = 0; i < selections.length; i += 4) {
4393
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
4394
+ const start = {
4395
+ rowIndex: selectionStartRow,
4396
+ columnIndex: selectionStartColumn
4397
+ };
4398
+ const end = {
4399
+ rowIndex: selectionEndRow,
4400
+ columnIndex: selectionEndColumn
4401
+ };
4402
+ const range = {
4403
+ start,
4404
+ end
4437
4405
  };
4406
+ if (isEmpty(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn)) {
4407
+ const line = lines[selectionStartRow];
4408
+ const before = line.slice(0, selectionStartColumn);
4409
+ const indent = getIndent(before);
4410
+ if (shouldIncreaseIndent(before, increaseIndentRegex)) {
4411
+ changes.push({
4412
+ start: start,
4413
+ end: end,
4414
+ inserted: ['', indent + ' ', indent],
4415
+ deleted: getSelectionText({
4416
+ lines
4417
+ }, range),
4418
+ origin: InsertLineBreak
4419
+ });
4420
+ selectionChanges.push(selectionStartRow + 1, indent.length + 2, selectionStartRow + 1, indent.length + 2);
4421
+ } else {
4422
+ changes.push({
4423
+ start: start,
4424
+ end: end,
4425
+ inserted: ['', indent],
4426
+ deleted: getSelectionText({
4427
+ lines
4428
+ }, range),
4429
+ origin: InsertLineBreak
4430
+ });
4431
+ selectionChanges.push(selectionStartRow + 1, indent.length, selectionStartRow + 1, indent.length);
4432
+ }
4433
+ } else {
4434
+ changes.push({
4435
+ start: start,
4436
+ end: end,
4437
+ inserted: ['', ''],
4438
+ deleted: getSelectionText({
4439
+ lines
4440
+ }, range),
4441
+ origin: InsertLineBreak
4442
+ });
4443
+ selectionChanges.push(selectionStartRow + 1, 0, selectionStartRow + 1, 0);
4444
+ }
4438
4445
  }
4439
- const relativeX = normalizedEventX - x - handleOffsetX;
4440
- const scrollBarWidth = getScrollBarWidth(width, longestLineWidth);
4441
- const finalDeltaX = longestLineWidth - width + spaceRight;
4442
- const newPercent = getNewPercent$1(width, scrollBarWidth, relativeX);
4443
- const clampedPercent = clamp(newPercent, 0, 1);
4444
- const newDeltaX = clampedPercent * finalDeltaX;
4445
4446
  return {
4446
- ...state,
4447
- deltaX: newDeltaX
4447
+ changes,
4448
+ selectionChanges: new Uint32Array(selectionChanges)
4448
4449
  };
4449
4450
  };
4450
-
4451
- // @ts-ignore
4452
-
4453
- // TODO duplicate code with vertical pointer down event listener
4454
-
4455
- // @ts-ignore
4456
- const handleScrollBarHorizontalPointerDown = (state, eventX) => {
4457
- // @ts-ignore
4451
+ const insertLineBreak = async editor => {
4458
4452
  const {
4459
- x,
4460
- deltaX,
4461
- width,
4462
- finalDeltaY,
4463
- height,
4464
- scrollBarHeight,
4465
- longestLineWidth
4466
- } = state;
4467
- const relativeX = eventX - x;
4468
- const scrollBarWidth = getScrollBarWidth(width, longestLineWidth);
4469
- const finalDeltaX = width - scrollBarWidth;
4470
- const currentScrollBarX = getScrollBarOffset(deltaX, finalDeltaX, width, scrollBarWidth);
4471
- const diff = relativeX - currentScrollBarX;
4472
- if (diff >= 0 && diff < scrollBarWidth) {
4473
- return {
4474
- ...state,
4475
- handleOffsetX: diff
4476
- };
4477
- }
4453
+ lines,
4454
+ selections
4455
+ } = editor;
4456
+ const languageConfiguration = await getLanguageConfiguration(editor);
4478
4457
  const {
4479
- percent,
4480
- handleOffset
4481
- } = getNewDeltaPercent(width, scrollBarWidth, relativeX);
4482
- const newDeltaX = percent * finalDeltaX;
4483
- return {
4484
- ...state,
4485
- handleOffsetX: handleOffset,
4486
- deltaX: newDeltaX
4487
- };
4458
+ changes,
4459
+ selectionChanges
4460
+ } = getChanges$1(lines, selections, languageConfiguration);
4461
+ return scheduleDocumentAndCursorsSelections(editor, changes, selectionChanges);
4488
4462
  };
4489
4463
 
4490
4464
  // @ts-ignore
4491
4465
 
4492
4466
  // @ts-ignore
4493
- const getNewPercent = (state, relativeY) => {
4494
- const {
4495
- height,
4496
- scrollBarHeight
4497
- } = state;
4498
- // if (relativeY <= editor.scrollBarHeight / 2) {
4499
- // console.log('clicked at top')
4500
- // // clicked at top
4501
- // return 0
4502
- // }
4503
- if (relativeY <= height - scrollBarHeight / 2) {
4504
- // clicked in middle
4505
- return relativeY / (height - scrollBarHeight);
4467
+ const moveRectangleSelection = (editor, position) => {
4468
+ // @ts-ignore
4469
+ const anchor = undefined.position;
4470
+ const startRowIndex = anchor.rowIndex;
4471
+ const startColumnIndex = anchor.columnIndex;
4472
+ const endRowIndex = position.rowIndex;
4473
+ const endColumnIndex = position.columnIndex;
4474
+ const selectionEdits = [];
4475
+ for (let i = startRowIndex; i <= endRowIndex; i++) {
4476
+ selectionEdits.push({
4477
+ start: {
4478
+ rowIndex: i,
4479
+ columnIndex: startColumnIndex
4480
+ },
4481
+ end: {
4482
+ rowIndex: i,
4483
+ columnIndex: endColumnIndex
4484
+ }
4485
+ });
4506
4486
  }
4507
- // clicked at bottom
4508
- return 1;
4487
+ // @ts-ignore
4488
+ const cursorEdits = [selectionEdits.at(-1).end];
4489
+ // @ts-ignore
4490
+ undefined(editor, cursorEdits, selectionEdits);
4509
4491
  };
4510
4492
 
4511
4493
  // @ts-ignore
4512
- const handleScrollBarMove = (state, eventY) => {
4513
- const {
4514
- y,
4515
- finalDeltaY,
4516
- handleOffset
4517
- } = state;
4518
- const relativeY = eventY - y - handleOffset;
4519
- const newPercent = getNewPercent(state, relativeY);
4520
- const newDeltaY = newPercent * finalDeltaY;
4521
- return setDeltaYFixedValue$1(state, newDeltaY);
4494
+ const moveRectangleSelectionPx = (editor, x, y) => {
4495
+ const position = at(editor, x, y);
4496
+ moveRectangleSelection(editor, position);
4522
4497
  };
4523
- const handleScrollBarVerticalPointerMove = handleScrollBarMove;
4524
-
4525
- // @ts-ignore
4526
4498
 
4527
- // TODO scrollbar position can be in interval [0, editor.height - editor.scrollBarHeight]
4528
- // when clicked at y <= editor.scrollbarHeight/2, position is set to zero
4529
- // when clicked at y >= editor.height - editor.scrollBarHeight/2, position is set to (editor.height - scrollBarHeight/2)
4530
- // when clicked at y > editor.height - editor.scrollBarHeight/2, position scrollbar at (y - scrollbarHeight/2)
4531
- // additionally, when clicked on scrollbar, scrollbar position shouldn't move
4499
+ const requestAnimationFrame = fn => {
4500
+ globalThis.requestAnimationFrame(fn);
4501
+ };
4532
4502
 
4533
4503
  // @ts-ignore
4534
- const handleScrollBarPointerDown = (state, eventY) => {
4504
+ const getNewEditor$1 = (editor, position) => {
4535
4505
  const {
4536
- y,
4537
- deltaY,
4538
- finalDeltaY,
4539
- height,
4540
- scrollBarHeight
4541
- } = state;
4542
- const relativeY = eventY - y;
4543
- const currentScrollBarY = getScrollBarY(deltaY, finalDeltaY, height, scrollBarHeight);
4544
- const diff = relativeY - currentScrollBarY;
4545
- if (diff >= 0 && diff < scrollBarHeight) {
4506
+ minLineY,
4507
+ maxLineY,
4508
+ rowHeight
4509
+ } = editor;
4510
+ const diff = maxLineY - minLineY;
4511
+ if (position.rowIndex < minLineY) {
4512
+ const newMinLineY = position.rowIndex;
4513
+ const newMaxLineY = position.rowIndex + diff;
4514
+ const newDeltaY = position.rowIndex * rowHeight;
4515
+ const anchor = getPosition$1();
4516
+ const newSelections = new Uint32Array([position.rowIndex - 1, position.columnIndex, anchor.rowIndex, anchor.columnIndex]);
4546
4517
  return {
4547
- ...state,
4548
- handleOffset: diff
4518
+ ...editor,
4519
+ minLineY: newMinLineY,
4520
+ maxLineY: newMaxLineY,
4521
+ deltaY: newDeltaY,
4522
+ selections: newSelections
4549
4523
  };
4550
4524
  }
4551
- const {
4552
- percent,
4553
- handleOffset
4554
- } = getNewDeltaPercent(height, scrollBarHeight, relativeY);
4555
- const newDeltaY = percent * finalDeltaY;
4556
- return {
4557
- ...setDeltaYFixedValue$1(state, newDeltaY),
4558
- handleOffset
4559
- };
4560
- };
4561
-
4562
- const state = {
4563
- touchOffsetY: 0,
4564
- deltaY: 0
4525
+ if (position.rowIndex > maxLineY) {
4526
+ const diff = maxLineY - minLineY;
4527
+ const newMinLineY = position.rowIndex - diff;
4528
+ const newMaxLineY = position.rowIndex;
4529
+ const newDeltaY = newMinLineY * rowHeight;
4530
+ const anchor = getPosition$1();
4531
+ const newSelections = new Uint32Array([anchor.rowIndex, anchor.columnIndex, position.rowIndex + 1, position.columnIndex]);
4532
+ return {
4533
+ ...editor,
4534
+ minLineY: newMinLineY,
4535
+ maxLineY: newMaxLineY,
4536
+ deltaY: newDeltaY,
4537
+ selections: newSelections
4538
+ };
4539
+ }
4540
+ return editor;
4565
4541
  };
4566
-
4567
- // @ts-ignore
4568
- const handleTouchStart = (editor, touchEvent) => {
4569
- if (touchEvent.touches.length === 0) {
4542
+ const continueScrollingAndMovingSelection = async () => {
4543
+ const editor = getEditor$1();
4544
+ if (!editor) {
4570
4545
  return;
4571
4546
  }
4572
- const firstTouch = touchEvent.touches[0];
4573
- state.touchOffsetY = firstTouch.y;
4574
- state.deltaY = editor.deltaY;
4575
- // const position = EditorPosition.at(editor, firstTouch.x, firstTouch.y)
4576
- // EditorMoveSelection.state.position = position
4577
- // state.date = Date.now()
4578
- };
4579
-
4580
- const LessThan = -1;
4581
- const Equal = 0;
4582
- const GreaterThan = 1;
4583
-
4584
- // @ts-ignore
4585
-
4586
- // @ts-ignore
4587
- const compare = (positionA, positionB) => {
4588
- if (positionA.rowIndex > positionB.rowIndex) {
4589
- return GreaterThan;
4547
+ const position = getPosition();
4548
+ if (position.rowIndex === 0) {
4549
+ return;
4590
4550
  }
4591
- if (positionA.rowIndex === positionB.rowIndex) {
4592
- if (positionA.columnIndex > positionB.columnIndex) {
4593
- return GreaterThan;
4594
- }
4595
- if (positionA.columnIndex < positionB.columnIndex) {
4596
- return LessThan;
4597
- }
4598
- return Equal;
4551
+ const newEditor = getNewEditor$1(editor, position);
4552
+ if (editor === newEditor) {
4553
+ return;
4599
4554
  }
4600
- return LessThan;
4555
+ // await Viewlet.setState(ViewletModuleId.EditorText, newEditor)
4556
+ setEditor(newEditor);
4557
+ // @ts-ignore
4558
+ const delta = position.rowIndex < editor.minLineY ? -1 : 1;
4559
+ setPosition({
4560
+ rowIndex: position.rowIndex + delta,
4561
+ columnIndex: position.columnIndex
4562
+ });
4563
+ requestAnimationFrame(continueScrollingAndMovingSelection);
4564
+ // TODO get editor state
4565
+ // if editor is disposed, return and remove animation frame
4566
+ // on cursor up, remove animation frame
4567
+ //
4601
4568
  };
4602
4569
 
4603
4570
  // @ts-ignore
4604
- const editorMoveSelectionBackwards = (anchor, position) => {
4605
- return new Uint32Array([anchor.rowIndex, anchor.columnIndex, position.rowIndex, position.columnIndex]);
4571
+ const moveSelectionPx = (editor, x, y) => {
4572
+ object(editor);
4573
+ number$1(x);
4574
+ number$1(y);
4575
+ const position = at(editor, x, y);
4576
+ if (!hasListener() && (position.rowIndex < editor.minLineY || position.rowIndex > editor.maxLineY)) {
4577
+ requestAnimationFrame(continueScrollingAndMovingSelection);
4578
+ setEditor(editor);
4579
+ setPosition(position);
4580
+ }
4581
+ return editorMoveSelection(editor, position);
4606
4582
  };
4607
4583
 
4608
- // @ts-ignore
4609
- const editorMoveSelectionEqual = (anchor, position) => {
4610
- return new Uint32Array([position.rowIndex, position.columnIndex, position.rowIndex, position.columnIndex]);
4584
+ const create$4 = () => {
4585
+ const completionUid = create$6();
4586
+ const completionWidget = {
4587
+ id: Completion,
4588
+ oldState: {
4589
+ items: [],
4590
+ itemHeight: 20,
4591
+ maxHeight: 150,
4592
+ minLineY: 0,
4593
+ maxLineY: 0,
4594
+ uid: completionUid,
4595
+ focusedIndex: -1,
4596
+ x: 0,
4597
+ y: 0,
4598
+ width: 0,
4599
+ height: 0
4600
+ },
4601
+ newState: {
4602
+ items: [],
4603
+ itemHeight: 20,
4604
+ maxHeight: 150,
4605
+ minLineY: 0,
4606
+ maxLineY: 10,
4607
+ uid: completionUid,
4608
+ focusedIndex: -1,
4609
+ x: 0,
4610
+ y: 0,
4611
+ width: 0,
4612
+ height: 0
4613
+ }
4614
+ };
4615
+ return completionWidget;
4611
4616
  };
4612
4617
 
4613
- // @ts-ignore
4614
- const editorMoveSelectionForwards = (anchor, position) => {
4615
- return new Uint32Array([anchor.rowIndex, anchor.columnIndex, position.rowIndex, position.columnIndex]);
4616
- };
4618
+ const OnCompletion = 'onCompletion';
4619
+ const OnHover = 'onHover';
4617
4620
 
4618
- // @ts-ignore
4619
- const getNewSelections$5 = (anchor, position) => {
4620
- switch (compare(position, anchor)) {
4621
- case LessThan:
4622
- return editorMoveSelectionBackwards(anchor, position);
4623
- case Equal:
4624
- return editorMoveSelectionEqual(anchor, position);
4625
- case GreaterThan:
4626
- return editorMoveSelectionForwards(anchor, position);
4627
- default:
4628
- throw new Error('unexpected comparison result');
4629
- }
4621
+ // TODO add tests for this
4622
+ const activateByEvent = async event => {
4623
+ await invoke$3('ExtensionHostManagement.activateByEvent', event);
4630
4624
  };
4631
4625
 
4632
- // @ts-ignore
4633
- const editorMoveSelection = (editor, position) => {
4634
- const anchor = getPosition$1();
4635
- const newSelections = getNewSelections$5(anchor, position);
4636
- // TODO if selection equals previous selection -> do nothing
4637
- return scheduleSelections(editor, newSelections);
4626
+ const execute = async ({
4627
+ editor,
4628
+ args,
4629
+ event,
4630
+ method,
4631
+ noProviderFoundMessage,
4632
+ noProviderFoundResult = undefined
4633
+ }) => {
4634
+ const fullEvent = `${event}:${editor.languageId}`;
4635
+ await activateByEvent(fullEvent);
4636
+ const result = await invoke$2(method, editor.uid, ...args);
4637
+ return result;
4638
4638
  };
4639
4639
 
4640
- const LONG_TOUCH_THRESHOLD = 150;
4641
-
4642
- // @ts-ignore
4643
- const handleTouchEnd = (editor, touchEvent) => {
4644
- if (touchEvent.changedTouches.length === 0) {
4645
- return;
4646
- }
4647
- const firstTouch = touchEvent.changedTouches[0];
4648
- const position = at(editor, firstTouch.x, firstTouch.y);
4649
- // @ts-ignore
4650
- if (undefined.position.rowIndex === position.rowIndex && undefined.position.columnIndex === position.columnIndex) {
4651
- // @ts-ignore
4652
- if (Date.now() - state.date > LONG_TOUCH_THRESHOLD) {
4653
- selectWord(editor, position.rowIndex, position.columnIndex);
4654
- } else {
4655
- // @ts-ignore
4656
- cursorSet(editor, position);
4657
- }
4658
- } else {
4659
- console.log('different position');
4660
- }
4640
+ const combineResults = results => {
4641
+ return results[0] ?? [];
4661
4642
  };
4662
-
4663
- // @ts-ignore
4664
- const setDeltaY = (editor, deltaY) => {
4665
- return setDeltaY$1(editor, deltaY);
4643
+ const executeCompletionProvider = (editor, offset) => {
4644
+ return execute({
4645
+ editor,
4646
+ event: OnCompletion,
4647
+ method: CompletionExecute,
4648
+ args: [offset],
4649
+ noProviderFoundMessage: 'no completion provider found',
4650
+ noProviderFoundResult: [],
4651
+ combineResults
4652
+ });
4666
4653
  };
4667
-
4668
- // @ts-ignore
4669
- const setDeltaYFixedValue = (editor, deltaY) => {
4670
- return setDeltaYFixedValue$1(editor, deltaY);
4654
+ const combineResultsResolve = items => {
4655
+ return items[0] ?? undefined;
4656
+ };
4657
+ const executeResolveCompletionItem = (editor, offset, name, completionItem) => {
4658
+ return execute({
4659
+ editor,
4660
+ event: OnCompletion,
4661
+ method: CompletionResolveExecute,
4662
+ args: [offset, name, completionItem],
4663
+ noProviderFoundMessage: 'no completion provider found',
4664
+ noProviderFoundResult: [],
4665
+ combineResults: combineResultsResolve
4666
+ });
4671
4667
  };
4672
4668
 
4673
- // @ts-ignore
4674
- const setDelta = (editor, deltaMode, eventDeltaX, eventDeltaY) => {
4675
- number$1(deltaMode);
4676
- number$1(eventDeltaX);
4677
- number$1(eventDeltaY);
4678
- // @ts-ignore
4669
+ // TODO possible to do this with events/state machine instead of promises -> enables canceling operations / concurrent calls
4670
+ const getCompletions = async editor => {
4679
4671
  const {
4680
- deltaX,
4681
- deltaY
4672
+ selections
4682
4673
  } = editor;
4683
- if (eventDeltaX === 0) {
4684
- return setDeltaY(editor, eventDeltaY);
4685
- }
4686
- const newDeltaX = clamp(deltaX + eventDeltaX, 0, Number.POSITIVE_INFINITY);
4687
- return {
4688
- ...setDeltaY(editor, eventDeltaY),
4689
- deltaX: newDeltaX
4690
- };
4674
+ const rowIndex = selections[0];
4675
+ const columnIndex = selections[1];
4676
+ // Editor.sync(editor)
4677
+ const offset = await offsetAt(editor, rowIndex, columnIndex);
4678
+ const completions = await executeCompletionProvider(editor, offset);
4679
+ return completions;
4691
4680
  };
4692
4681
 
4693
- // @ts-ignore
4694
- const handleTouchMove = (editor, touchEvent) => {
4695
- if (touchEvent.touches.length === 0) {
4696
- return;
4682
+ // TODO don't send unnecessary parts of completion item like matches
4683
+ const resolveCompletion = async (editor, name, completionItem) => {
4684
+ try {
4685
+ object(editor);
4686
+ string(name);
4687
+ object(completionItem);
4688
+ const rowIndex = editor.selections[0];
4689
+ const columnIndex = editor.selections[1];
4690
+ const offset = await offsetAt(editor, rowIndex, columnIndex);
4691
+ // @ts-ignore
4692
+ const resolvedCompletionItem = await executeResolveCompletionItem(editor, offset, name, completionItem);
4693
+ return resolvedCompletionItem;
4694
+ } catch {
4695
+ return undefined;
4697
4696
  }
4698
- const firstTouch = touchEvent.touches[0];
4699
- const offsetY = state.deltaY + (state.touchOffsetY - firstTouch.y);
4700
- setDeltaYFixedValue(editor, offsetY);
4701
4697
  };
4702
4698
 
4703
- // @ts-ignore
4704
- const getChanges$3 = selections => {
4705
- const changes = [];
4706
- const rowsToIndentLess = [];
4707
- for (let i = 0; i < selections.length; i += 4) {
4708
- const selectionStartRow = selections[i];
4709
- const selectionEndRow = selections[i + 2];
4710
- for (let i = selectionStartRow; i <= selectionEndRow; i++) {
4711
- rowsToIndentLess.push(i);
4712
- }
4713
- }
4714
- for (const rowToIndent of rowsToIndentLess) {
4715
- changes.push({
4716
- start: {
4717
- rowIndex: rowToIndent,
4718
- columnIndex: 0
4719
- },
4720
- end: {
4721
- rowIndex: rowToIndent,
4722
- columnIndex: 2
4723
- },
4724
- inserted: [''],
4725
- deleted: [' '],
4726
- origin: IndentLess
4727
- });
4728
- }
4729
- return changes;
4730
- };
4731
-
4732
- // @ts-ignore
4733
- const indentLess = editor => {
4734
- const selections = editor.selections;
4735
- const changes = getChanges$3(selections);
4736
- return scheduleDocumentAndCursorsSelections(editor, changes);
4737
- };
4738
-
4739
- const getChanges$2 = selections => {
4740
- const rowsToIndent = [];
4741
- for (let i = 0; i < selections.length; i += 4) {
4742
- const selectionStartRow = selections[i];
4743
- const selectionEndRow = selections[i + 2];
4744
- for (let i = selectionStartRow; i <= selectionEndRow; i++) {
4745
- rowsToIndent.push(i);
4746
- }
4747
- }
4748
- const changes = [];
4749
- for (const rowToIndent of rowsToIndent) {
4750
- changes.push({
4751
- start: {
4752
- rowIndex: rowToIndent,
4753
- columnIndex: 0
4754
- },
4755
- end: {
4756
- rowIndex: rowToIndent,
4757
- columnIndex: 0
4758
- },
4759
- inserted: [' '],
4760
- deleted: [''],
4761
- origin: IndentMore
4762
- });
4763
- }
4764
- return changes;
4765
- };
4766
- const indentMore = editor => {
4767
- const {
4768
- selections
4769
- } = editor;
4770
- const changes = getChanges$2(selections);
4771
- return scheduleDocumentAndCursorsSelections(editor, changes);
4772
- };
4773
-
4774
- const getLanguageConfiguration = editor => {
4775
- return invoke$3('Languages.getLanguageConfiguration', {
4776
- uri: editor.uri,
4777
- languageId: editor.languageId
4778
- });
4779
- };
4780
-
4781
- const getIncreaseIndentRegex = languageConfiguration => {
4782
- if (languageConfiguration && languageConfiguration.indentationRules && languageConfiguration.indentationRules.increaseIndentPattern && typeof languageConfiguration.indentationRules.increaseIndentPattern === 'string') {
4783
- const regex = new RegExp(languageConfiguration.indentationRules.increaseIndentPattern);
4784
- return regex;
4785
- }
4786
- return undefined;
4787
- };
4788
- const shouldIncreaseIndent = (before, increaseIndentRegex) => {
4789
- if (!increaseIndentRegex) {
4790
- return false;
4791
- }
4792
- return increaseIndentRegex.test(before);
4793
- };
4794
- const getChanges$1 = (lines, selections, languageConfiguration) => {
4795
- const changes = [];
4796
- const selectionChanges = [];
4797
- const increaseIndentRegex = getIncreaseIndentRegex(languageConfiguration);
4798
- for (let i = 0; i < selections.length; i += 4) {
4799
- const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
4800
- const start = {
4801
- rowIndex: selectionStartRow,
4802
- columnIndex: selectionStartColumn
4803
- };
4804
- const end = {
4805
- rowIndex: selectionEndRow,
4806
- columnIndex: selectionEndColumn
4807
- };
4808
- const range = {
4809
- start,
4810
- end
4811
- };
4812
- if (isEmpty(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn)) {
4813
- const line = lines[selectionStartRow];
4814
- const before = line.slice(0, selectionStartColumn);
4815
- const indent = getIndent(before);
4816
- if (shouldIncreaseIndent(before, increaseIndentRegex)) {
4817
- changes.push({
4818
- start: start,
4819
- end: end,
4820
- inserted: ['', indent + ' ', indent],
4821
- deleted: getSelectionText({
4822
- lines
4823
- }, range),
4824
- origin: InsertLineBreak
4825
- });
4826
- selectionChanges.push(selectionStartRow + 1, indent.length + 2, selectionStartRow + 1, indent.length + 2);
4827
- } else {
4828
- changes.push({
4829
- start: start,
4830
- end: end,
4831
- inserted: ['', indent],
4832
- deleted: getSelectionText({
4833
- lines
4834
- }, range),
4835
- origin: InsertLineBreak
4836
- });
4837
- selectionChanges.push(selectionStartRow + 1, indent.length, selectionStartRow + 1, indent.length);
4838
- }
4839
- } else {
4840
- changes.push({
4841
- start: start,
4842
- end: end,
4843
- inserted: ['', ''],
4844
- deleted: getSelectionText({
4845
- lines
4846
- }, range),
4847
- origin: InsertLineBreak
4848
- });
4849
- selectionChanges.push(selectionStartRow + 1, 0, selectionStartRow + 1, 0);
4850
- }
4851
- }
4852
- return {
4853
- changes,
4854
- selectionChanges: new Uint32Array(selectionChanges)
4855
- };
4856
- };
4857
- const insertLineBreak = async editor => {
4858
- const {
4859
- lines,
4860
- selections
4861
- } = editor;
4862
- const languageConfiguration = await getLanguageConfiguration(editor);
4863
- const {
4864
- changes,
4865
- selectionChanges
4866
- } = getChanges$1(lines, selections, languageConfiguration);
4867
- return scheduleDocumentAndCursorsSelections(editor, changes, selectionChanges);
4868
- };
4869
-
4870
- // @ts-ignore
4871
-
4872
- // @ts-ignore
4873
- const moveRectangleSelection = (editor, position) => {
4874
- // @ts-ignore
4875
- const anchor = undefined.position;
4876
- const startRowIndex = anchor.rowIndex;
4877
- const startColumnIndex = anchor.columnIndex;
4878
- const endRowIndex = position.rowIndex;
4879
- const endColumnIndex = position.columnIndex;
4880
- const selectionEdits = [];
4881
- for (let i = startRowIndex; i <= endRowIndex; i++) {
4882
- selectionEdits.push({
4883
- start: {
4884
- rowIndex: i,
4885
- columnIndex: startColumnIndex
4886
- },
4887
- end: {
4888
- rowIndex: i,
4889
- columnIndex: endColumnIndex
4890
- }
4891
- });
4892
- }
4893
- // @ts-ignore
4894
- const cursorEdits = [selectionEdits.at(-1).end];
4895
- // @ts-ignore
4896
- undefined(editor, cursorEdits, selectionEdits);
4897
- };
4898
-
4899
- // @ts-ignore
4900
- const moveRectangleSelectionPx = (editor, x, y) => {
4901
- const position = at(editor, x, y);
4902
- moveRectangleSelection(editor, position);
4903
- };
4904
-
4905
- const requestAnimationFrame = fn => {
4906
- globalThis.requestAnimationFrame(fn);
4907
- };
4908
-
4909
- // @ts-ignore
4910
- const getNewEditor$1 = (editor, position) => {
4911
- const {
4912
- minLineY,
4913
- maxLineY,
4914
- rowHeight
4915
- } = editor;
4916
- const diff = maxLineY - minLineY;
4917
- if (position.rowIndex < minLineY) {
4918
- const newMinLineY = position.rowIndex;
4919
- const newMaxLineY = position.rowIndex + diff;
4920
- const newDeltaY = position.rowIndex * rowHeight;
4921
- const anchor = getPosition$1();
4922
- const newSelections = new Uint32Array([position.rowIndex - 1, position.columnIndex, anchor.rowIndex, anchor.columnIndex]);
4923
- return {
4924
- ...editor,
4925
- minLineY: newMinLineY,
4926
- maxLineY: newMaxLineY,
4927
- deltaY: newDeltaY,
4928
- selections: newSelections
4929
- };
4930
- }
4931
- if (position.rowIndex > maxLineY) {
4932
- const diff = maxLineY - minLineY;
4933
- const newMinLineY = position.rowIndex - diff;
4934
- const newMaxLineY = position.rowIndex;
4935
- const newDeltaY = newMinLineY * rowHeight;
4936
- const anchor = getPosition$1();
4937
- const newSelections = new Uint32Array([anchor.rowIndex, anchor.columnIndex, position.rowIndex + 1, position.columnIndex]);
4938
- return {
4939
- ...editor,
4940
- minLineY: newMinLineY,
4941
- maxLineY: newMaxLineY,
4942
- deltaY: newDeltaY,
4943
- selections: newSelections
4944
- };
4945
- }
4946
- return editor;
4947
- };
4948
- const continueScrollingAndMovingSelection = async () => {
4949
- const editor = getEditor$1();
4950
- if (!editor) {
4951
- return;
4952
- }
4953
- const position = getPosition();
4954
- if (position.rowIndex === 0) {
4955
- return;
4956
- }
4957
- const newEditor = getNewEditor$1(editor, position);
4958
- if (editor === newEditor) {
4959
- return;
4960
- }
4961
- // await Viewlet.setState(ViewletModuleId.EditorText, newEditor)
4962
- setEditor(newEditor);
4963
- // @ts-ignore
4964
- const delta = position.rowIndex < editor.minLineY ? -1 : 1;
4965
- setPosition({
4966
- rowIndex: position.rowIndex + delta,
4967
- columnIndex: position.columnIndex
4968
- });
4969
- requestAnimationFrame(continueScrollingAndMovingSelection);
4970
- // TODO get editor state
4971
- // if editor is disposed, return and remove animation frame
4972
- // on cursor up, remove animation frame
4973
- //
4974
- };
4975
-
4976
- // @ts-ignore
4977
- const moveSelectionPx = (editor, x, y) => {
4978
- object(editor);
4979
- number$1(x);
4980
- number$1(y);
4981
- const position = at(editor, x, y);
4982
- if (!hasListener() && (position.rowIndex < editor.minLineY || position.rowIndex > editor.maxLineY)) {
4983
- requestAnimationFrame(continueScrollingAndMovingSelection);
4984
- setEditor(editor);
4985
- setPosition(position);
4986
- }
4987
- return editorMoveSelection(editor, position);
4988
- };
4989
-
4990
- const create$2 = () => {
4991
- const completionUid = create$5();
4992
- const completionWidget = {
4993
- id: Completion,
4994
- oldState: {
4995
- items: [],
4996
- itemHeight: 20,
4997
- maxHeight: 150,
4998
- minLineY: 0,
4999
- maxLineY: 0,
5000
- uid: completionUid,
5001
- focusedIndex: -1,
5002
- x: 0,
5003
- y: 0,
5004
- width: 0,
5005
- height: 0
5006
- },
5007
- newState: {
5008
- items: [],
5009
- itemHeight: 20,
5010
- maxHeight: 150,
5011
- minLineY: 0,
5012
- maxLineY: 10,
5013
- uid: completionUid,
5014
- focusedIndex: -1,
5015
- x: 0,
5016
- y: 0,
5017
- width: 0,
5018
- height: 0
5019
- }
5020
- };
5021
- return completionWidget;
5022
- };
5023
-
5024
- const combineResults = results => {
5025
- return results[0] ?? [];
5026
- };
5027
- const executeCompletionProvider = (editor, offset) => {
5028
- return execute({
5029
- editor,
5030
- event: OnCompletion,
5031
- method: CompletionExecute,
5032
- args: [offset],
5033
- noProviderFoundMessage: 'no completion provider found',
5034
- noProviderFoundResult: [],
5035
- combineResults
5036
- });
5037
- };
5038
- const combineResultsResolve = items => {
5039
- return items[0] ?? undefined;
5040
- };
5041
- const executeResolveCompletionItem = (editor, offset, name, completionItem) => {
5042
- return execute({
5043
- editor,
5044
- event: OnCompletion,
5045
- method: CompletionResolveExecute,
5046
- args: [offset, name, completionItem],
5047
- noProviderFoundMessage: 'no completion provider found',
5048
- noProviderFoundResult: [],
5049
- combineResults: combineResultsResolve
5050
- });
5051
- };
5052
-
5053
- // TODO possible to do this with events/state machine instead of promises -> enables canceling operations / concurrent calls
5054
- const getCompletions = async editor => {
5055
- const {
5056
- selections
5057
- } = editor;
5058
- const rowIndex = selections[0];
5059
- const columnIndex = selections[1];
5060
- // Editor.sync(editor)
5061
- const offset = await offsetAt(editor, rowIndex, columnIndex);
5062
- const completions = await executeCompletionProvider(editor, offset);
5063
- return completions;
5064
- };
5065
-
5066
- // TODO don't send unnecessary parts of completion item like matches
5067
- const resolveCompletion = async (editor, name, completionItem) => {
5068
- try {
5069
- object(editor);
5070
- string(name);
5071
- object(completionItem);
5072
- const rowIndex = editor.selections[0];
5073
- const columnIndex = editor.selections[1];
5074
- const offset = await offsetAt(editor, rowIndex, columnIndex);
5075
- // @ts-ignore
5076
- const resolvedCompletionItem = await executeResolveCompletionItem(editor, offset, name, completionItem);
5077
- return resolvedCompletionItem;
5078
- } catch {
5079
- return undefined;
5080
- }
5081
- };
5082
-
5083
- const None$1 = 1;
4699
+ const None$1 = 1;
5084
4700
 
5085
4701
  const Diagonal = 1;
5086
4702
  const Left = 2;
@@ -5452,7 +5068,7 @@ const openCompletion = async editor => {
5452
5068
  if (hasWidget(widgets, Completion)) {
5453
5069
  return editor;
5454
5070
  }
5455
- const completionWidget = create$2();
5071
+ const completionWidget = create$4();
5456
5072
  const newWidgets = [...widgets, completionWidget];
5457
5073
  const newEditor = {
5458
5074
  ...editor,
@@ -5481,8 +5097,8 @@ const User = 1;
5481
5097
  const Script = 2;
5482
5098
  const Unknown$1 = 0;
5483
5099
 
5484
- const create$1 = () => {
5485
- const uid = create$5();
5100
+ const create$3 = () => {
5101
+ const uid = create$6();
5486
5102
  const widget = {
5487
5103
  id: Find,
5488
5104
  oldState: {
@@ -5879,7 +5495,7 @@ const openFind2 = async editor => {
5879
5495
  return latestState;
5880
5496
  };
5881
5497
  const fullFocus = true;
5882
- return addWidgetToEditor(Find, FindWidget, editor, create$1, newStateGenerator, fullFocus);
5498
+ return addWidgetToEditor(Find, FindWidget, editor, create$3, newStateGenerator, fullFocus);
5883
5499
  };
5884
5500
 
5885
5501
  const openFind = async state => {
@@ -6429,228 +6045,623 @@ const getSelectionEditsSingleLineWord = (lines, selections) => {
6429
6045
  };
6430
6046
  }
6431
6047
  }
6432
- return undefined;
6048
+ return undefined;
6049
+ };
6050
+ const getSelectNextOccurrenceResult = editor => {
6051
+ const lines = editor.lines;
6052
+ const selections = editor.selections;
6053
+ if (isEverySelectionEmpty(selections)) {
6054
+ const newSelections = new Uint32Array(selections.length);
6055
+ for (let i = 0; i < selections.length; i += 4) {
6056
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
6057
+ const wordMatch = getWordMatchAtPosition(lines, selectionStartRow, selectionStartColumn);
6058
+ if (wordMatch.start === wordMatch.end) {
6059
+ newSelections[i] = selectionStartRow;
6060
+ newSelections[i + 1] = selectionStartColumn;
6061
+ newSelections[i + 2] = selectionEndRow;
6062
+ newSelections[i + 3] = selectionEndColumn;
6063
+ } else {
6064
+ newSelections[i] = selectionStartRow;
6065
+ newSelections[i + 1] = wordMatch.start;
6066
+ newSelections[i + 2] = selectionStartRow;
6067
+ newSelections[i + 3] = wordMatch.end;
6068
+ }
6069
+ }
6070
+ return {
6071
+ selectionEdits: newSelections,
6072
+ revealRange: newSelections.length - 4 // TODO should be primary selection
6073
+ };
6074
+ }
6075
+ if (isEverySelectionSingleLine(editor.selections)) {
6076
+ return getSelectionEditsSingleLineWord(editor.lines, editor.selections);
6077
+ }
6078
+ return undefined;
6079
+ };
6080
+
6081
+ // TODO handle virtual space
6082
+
6083
+ // TODO editors behave differently when selecting next occurrence, for example:
6084
+
6085
+ // aaa
6086
+ // bbb 1
6087
+ // ccc
6088
+ // bbb 2
6089
+ // bbb 3
6090
+ // aaa
6091
+ // bbb 4
6092
+ // ccc
6093
+
6094
+ // when clicking first at position 4 and then position 2,
6095
+ // - vscode selects next position 3 and refuses to select position 1
6096
+ // - atom also selects next position 3 and refuses to select position 1
6097
+ // - WebStorm also selects next position 3 and refuses to select position 1
6098
+ // - brackets (codemirror) selects position 3 and then selects position 1
6099
+ // - sublime selects next position 1, then next position 3
6100
+
6101
+ const isRangeInViewPort = (minLineY, maxLineY, startRowIndex, endRowIndex) => {
6102
+ return startRowIndex >= minLineY && endRowIndex <= maxLineY;
6103
+ };
6104
+
6105
+ // TODO handle virtual space
6106
+ const selectNextOccurrence = editor => {
6107
+ const result = getSelectNextOccurrenceResult(editor);
6108
+ if (!result) {
6109
+ return editor;
6110
+ }
6111
+ const revealRange = result.revealRange;
6112
+ const selectionEdits = result.selectionEdits;
6113
+ const revealRangeStartRowIndex = selectionEdits[revealRange];
6114
+ const revealRangeEndRowIndex = selectionEdits[revealRange + 2];
6115
+ if (isRangeInViewPort(editor.minLineY, editor.maxLineY, revealRangeStartRowIndex, revealRangeEndRowIndex)) {
6116
+ return scheduleSelections(editor, selectionEdits);
6117
+ }
6118
+ // TODO what is this magic number 5?
6119
+ // const deltaY = (revealRangeStartRowIndex - 5) * editor.rowHeight
6120
+ return scheduleDocumentAndCursorsSelections(editor, [], selectionEdits);
6121
+ };
6122
+
6123
+ // @ts-ignore
6124
+ const selectPreviousOccurrence = editor => {
6125
+ return editor;
6126
+ };
6127
+
6128
+ // @ts-ignore
6129
+
6130
+ // @ts-ignore
6131
+ const getSelectUpChanges = (lines, selections) => {
6132
+ const newSelections = new Uint32Array(selections.length);
6133
+ for (let i = 0; i < selections.length; i += 4) {
6134
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
6135
+ newSelections[i] = Math.max(selectionStartRow - 1, 0);
6136
+ newSelections[i + 1] = selectionStartColumn;
6137
+ newSelections[i + 2] = selectionEndRow;
6138
+ newSelections[i + 3] = selectionEndColumn;
6139
+ }
6140
+ return newSelections;
6141
+ };
6142
+
6143
+ // @ts-ignore
6144
+ const selectUp = editor => {
6145
+ const {
6146
+ lines,
6147
+ selections
6148
+ } = editor;
6149
+ const newSelections = getSelectUpChanges(lines, selections);
6150
+ return scheduleSelections(editor, newSelections);
6151
+ };
6152
+
6153
+ // @ts-ignore
6154
+ const selectWordLeft = editor => {
6155
+ return editorSelectHorizontalLeft(editor, wordLeft);
6156
+ };
6157
+
6158
+ // @ts-ignore
6159
+ const selectWordRight = editor => {
6160
+ return editorSelectHorizontalRight(editor, wordRight);
6161
+ };
6162
+
6163
+ // import * as ExtensionHostSelection from '../ExtensionHost/ExtensionHostSelection.ts'
6164
+
6165
+ const getNewSelections = async (editor, selections) => {
6166
+ const newSelections = await invoke$3('ExtensionHostSelection.executeGrowSelection', editor, selections);
6167
+ if (newSelections.length === 0) {
6168
+ return selections;
6169
+ }
6170
+ return new Uint32Array(newSelections);
6171
+ };
6172
+ const selectionGrow = async editor => {
6173
+ const {
6174
+ selections
6175
+ } = editor;
6176
+ const newSelections = await getNewSelections(editor, selections);
6177
+ return scheduleSelections(editor, newSelections);
6178
+ };
6179
+
6180
+ const setDecorations = (editor, decorations, diagnostics) => {
6181
+ if (editor.decorations.length === 0 && decorations.length === 0) {
6182
+ return editor;
6183
+ }
6184
+ return {
6185
+ ...editor,
6186
+ decorations,
6187
+ diagnostics
6188
+ };
6189
+ };
6190
+
6191
+ /**
6192
+ * @enum number
6193
+ */
6194
+ const State = {
6195
+ TopLevelContent: 1
6196
+ };
6197
+
6198
+ /**
6199
+ * @enum number
6200
+ */
6201
+ const TokenType = {
6202
+ Text: 1
6203
+ };
6204
+ const TokenMap = {
6205
+ [TokenType.Text]: 'Text'
6206
+ };
6207
+ const initialLineState = {
6208
+ state: State.TopLevelContent
6209
+ };
6210
+ const hasArrayReturn = true;
6211
+ const tokenizeLine = (line, lineState) => {
6212
+ return {
6213
+ tokens: [TokenType.Text, line.length],
6214
+ state: lineState.state
6215
+ };
6216
+ };
6217
+
6218
+ const TokenizePlainText = {
6219
+ __proto__: null,
6220
+ State,
6221
+ TokenMap,
6222
+ TokenType,
6223
+ hasArrayReturn,
6224
+ initialLineState,
6225
+ tokenizeLine
6226
+ };
6227
+
6228
+ const state$1 = {
6229
+ tokenizers: Object.create(null),
6230
+ tokenizePaths: Object.create(null),
6231
+ listeners: [],
6232
+ pending: Object.create(null),
6233
+ /**
6234
+ * @type {number[]}
6235
+ */
6236
+ connectedEditors: []
6237
+ };
6238
+ const has = languageId => {
6239
+ return languageId in state$1.tokenizers;
6240
+ };
6241
+ const set$3 = (languageId, tokenizer) => {
6242
+ state$1.tokenizers[languageId] = tokenizer;
6243
+ };
6244
+ const get$3 = languageId => {
6245
+ return state$1.tokenizers[languageId];
6246
+ };
6247
+ const isPending = languageId => {
6248
+ return languageId in state$1.pending;
6249
+ };
6250
+
6251
+ let enabled$1 = false;
6252
+ const setEnabled$1 = value => {
6253
+ enabled$1 = value;
6254
+ };
6255
+ const getEnabled$1 = () => {
6256
+ return enabled$1;
6257
+ };
6258
+
6259
+ const {
6260
+ listen: listen$6,
6261
+ invoke: invoke$1
6262
+ } = createRpc(SyntaxHighlightingWorker);
6263
+
6264
+ const tokenMaps = Object.create(null);
6265
+ const set$2 = (languageId, tokenMap) => {
6266
+ tokenMaps[languageId] = tokenMap;
6267
+ };
6268
+ const get$2 = languageId => {
6269
+ return tokenMaps[languageId] || {};
6270
+ };
6271
+
6272
+ // TODO loadTokenizer should be invoked from renderer worker
6273
+ const loadTokenizer = async (languageId, tokenizePath) => {
6274
+ if (!tokenizePath) {
6275
+ return;
6276
+ }
6277
+ if (getEnabled$1()) {
6278
+ const tokenMap = await invoke$1('Tokenizer.load', languageId, tokenizePath);
6279
+ set$2(languageId, tokenMap);
6280
+ return;
6281
+ }
6282
+ try {
6283
+ // TODO check that tokenizer is valid
6284
+ // 1. tokenizeLine should be of type function
6285
+ // 2. getTokenClass should be of type function
6286
+ const tokenizer = await import(tokenizePath);
6287
+ if (typeof tokenizer.tokenizeLine !== 'function') {
6288
+ console.warn(`tokenizer.tokenizeLine should be a function in "${tokenizePath}"`);
6289
+ return;
6290
+ }
6291
+ if (!tokenizer.TokenMap || typeof tokenizer.TokenMap !== 'object' || Array.isArray(tokenizer.TokenMap)) {
6292
+ console.warn(`tokenizer.TokenMap should be an object in "${tokenizePath}"`);
6293
+ return;
6294
+ }
6295
+ set$2(languageId, tokenizer.TokenMap);
6296
+ set$3(languageId, tokenizer);
6297
+ } catch (error) {
6298
+ // TODO better error handling
6299
+ console.error(error);
6300
+ return;
6301
+ }
6302
+ };
6303
+ const getTokenizer = languageId => {
6304
+ if (has(languageId)) {
6305
+ return get$3(languageId);
6306
+ }
6307
+ if (isPending(languageId)) {
6308
+ return TokenizePlainText;
6309
+ }
6310
+ return TokenizePlainText;
6433
6311
  };
6434
- const getSelectNextOccurrenceResult = editor => {
6435
- const lines = editor.lines;
6436
- const selections = editor.selections;
6437
- if (isEverySelectionEmpty(selections)) {
6438
- const newSelections = new Uint32Array(selections.length);
6439
- for (let i = 0; i < selections.length; i += 4) {
6440
- const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
6441
- const wordMatch = getWordMatchAtPosition(lines, selectionStartRow, selectionStartColumn);
6442
- if (wordMatch.start === wordMatch.end) {
6443
- newSelections[i] = selectionStartRow;
6444
- newSelections[i + 1] = selectionStartColumn;
6445
- newSelections[i + 2] = selectionEndRow;
6446
- newSelections[i + 3] = selectionEndColumn;
6447
- } else {
6448
- newSelections[i] = selectionStartRow;
6449
- newSelections[i + 1] = wordMatch.start;
6450
- newSelections[i + 2] = selectionStartRow;
6451
- newSelections[i + 3] = wordMatch.end;
6452
- }
6453
- }
6312
+
6313
+ const tokenizers = Object.create(null);
6314
+ const set$1 = (id, value) => {
6315
+ tokenizers[id] = value;
6316
+ };
6317
+ const get$1 = id => {
6318
+ return tokenizers[id] || TokenizePlainText;
6319
+ };
6320
+
6321
+ // TODO add command to set language id
6322
+ // without needing to specify tokenizePath
6323
+ const setLanguageId = async (editor, languageId, tokenizePath) => {
6324
+ const {
6325
+ tokenizerId
6326
+ } = editor;
6327
+ // TODO move tokenizer to syntax highlighting worker
6328
+ // TODO only load tokenizer if not already loaded
6329
+ // if already loaded just set tokenizer and rerender text
6330
+ // TODO race condition
6331
+ await loadTokenizer(languageId, tokenizePath);
6332
+ const tokenizer = getTokenizer(languageId);
6333
+ const newTokenizerId = tokenizerId + 1;
6334
+ set$1(newTokenizerId, tokenizer);
6335
+ const latest = getEditor(editor.uid);
6336
+ if (!latest) {
6337
+ return editor;
6338
+ }
6339
+ // TODO don't update editor if tokenizer was already loaded
6340
+ // TODO update syntax highlighting
6341
+ // TODO get edits
6342
+
6343
+ return {
6344
+ ...latest,
6345
+ languageId,
6346
+ invalidStartIndex: 0,
6347
+ tokenizerId: newTokenizerId
6348
+ };
6349
+ };
6350
+
6351
+ const setSelections = (editor, selections) => {
6352
+ const {
6353
+ minLineY,
6354
+ maxLineY,
6355
+ rowHeight
6356
+ } = editor;
6357
+ const startRowIndex = selections[0];
6358
+ if (startRowIndex < minLineY) {
6359
+ const deltaY = startRowIndex * rowHeight;
6454
6360
  return {
6455
- selectionEdits: newSelections,
6456
- revealRange: newSelections.length - 4 // TODO should be primary selection
6361
+ ...editor,
6362
+ minLineY: startRowIndex,
6363
+ maxLineY: startRowIndex + 1,
6364
+ selections,
6365
+ deltaY
6457
6366
  };
6458
6367
  }
6459
- if (isEverySelectionSingleLine(editor.selections)) {
6460
- return getSelectionEditsSingleLineWord(editor.lines, editor.selections);
6368
+ if (startRowIndex > maxLineY) {
6369
+ const deltaY = startRowIndex * rowHeight;
6370
+ return {
6371
+ ...editor,
6372
+ minLineY: startRowIndex,
6373
+ maxLineY: startRowIndex + 1,
6374
+ selections,
6375
+ deltaY
6376
+ };
6461
6377
  }
6462
- return undefined;
6378
+ return {
6379
+ ...editor,
6380
+ selections
6381
+ };
6463
6382
  };
6464
6383
 
6465
- // TODO handle virtual space
6384
+ const EditorHover = 'EditorHover';
6385
+ const showHover = async state => {
6386
+ await invoke$3('Viewlet.openWidget', EditorHover);
6387
+ return state;
6388
+ };
6466
6389
 
6467
- // TODO editors behave differently when selecting next occurrence, for example:
6390
+ const create$2 = () => {
6391
+ const uid = create$6();
6392
+ const widget = {
6393
+ id: Hover,
6394
+ oldState: {
6395
+ uid: uid,
6396
+ x: 0,
6397
+ y: 0,
6398
+ width: 0,
6399
+ height: 0,
6400
+ content: '',
6401
+ diagnostics: [],
6402
+ documentation: '',
6403
+ editorUid: 0,
6404
+ lineInfos: []
6405
+ },
6406
+ newState: {
6407
+ uid: uid,
6408
+ x: 0,
6409
+ y: 0,
6410
+ width: 0,
6411
+ height: 0,
6412
+ content: '',
6413
+ diagnostics: [],
6414
+ documentation: '',
6415
+ editorUid: 0,
6416
+ lineInfos: []
6417
+ }
6418
+ };
6419
+ return widget;
6420
+ };
6468
6421
 
6469
- // aaa
6470
- // bbb 1
6471
- // ccc
6472
- // bbb 2
6473
- // bbb 3
6474
- // aaa
6475
- // bbb 4
6476
- // ccc
6422
+ const executeHoverProvider = (editor, offset) => {
6423
+ object(editor);
6424
+ number$1(offset);
6425
+ return execute({
6426
+ event: OnHover,
6427
+ editor,
6428
+ method: HoverExecute,
6429
+ args: [offset],
6430
+ noProviderFoundMessage: 'No hover provider found'
6431
+ });
6432
+ };
6477
6433
 
6478
- // when clicking first at position 4 and then position 2,
6479
- // - vscode selects next position 3 and refuses to select position 1
6480
- // - atom also selects next position 3 and refuses to select position 1
6481
- // - WebStorm also selects next position 3 and refuses to select position 1
6482
- // - brackets (codemirror) selects position 3 and then selects position 1
6483
- // - sublime selects next position 1, then next position 3
6434
+ const getHover = async (editor, offset) => {
6435
+ object(editor);
6436
+ number$1(offset);
6437
+ // TODO invoke extension host worker directly
6438
+ const hover = await executeHoverProvider(editor, offset);
6439
+ return hover;
6440
+ };
6484
6441
 
6485
- const isRangeInViewPort = (minLineY, maxLineY, startRowIndex, endRowIndex) => {
6486
- return startRowIndex >= minLineY && endRowIndex <= maxLineY;
6442
+ let _ipc;
6443
+ const listen$5 = async () => {
6444
+ const ipc = await create$8({
6445
+ method: RendererProcess
6446
+ });
6447
+ handleIpc(ipc);
6448
+ _ipc = ipc;
6449
+ };
6450
+ const invoke = async (method, ...args) => {
6451
+ return invoke$5(_ipc, method, ...args);
6487
6452
  };
6488
6453
 
6489
- // TODO handle virtual space
6490
- const selectNextOccurrence = editor => {
6491
- const result = getSelectNextOccurrenceResult(editor);
6492
- if (!result) {
6493
- return editor;
6494
- }
6495
- const revealRange = result.revealRange;
6496
- const selectionEdits = result.selectionEdits;
6497
- const revealRangeStartRowIndex = selectionEdits[revealRange];
6498
- const revealRangeEndRowIndex = selectionEdits[revealRange + 2];
6499
- if (isRangeInViewPort(editor.minLineY, editor.maxLineY, revealRangeStartRowIndex, revealRangeEndRowIndex)) {
6500
- return scheduleSelections(editor, selectionEdits);
6501
- }
6502
- // TODO what is this magic number 5?
6503
- // const deltaY = (revealRangeStartRowIndex - 5) * editor.rowHeight
6504
- return scheduleDocumentAndCursorsSelections(editor, [], selectionEdits);
6454
+ const measureTextBlockHeight = (text, fontFamily, fontSize, lineHeight, width) => {
6455
+ return invoke('MeasureTextBlockHeight.measureTextBlockHeight', text, fontSize, fontFamily, lineHeight, width);
6505
6456
  };
6506
6457
 
6507
- // @ts-ignore
6508
- const selectPreviousOccurrence = editor => {
6509
- return editor;
6458
+ const deepCopy = value => {
6459
+ return structuredClone(value);
6510
6460
  };
6511
6461
 
6512
- // @ts-ignore
6462
+ const getInitialLineState = initialLineState => {
6463
+ return deepCopy(initialLineState);
6464
+ };
6513
6465
 
6514
- // @ts-ignore
6515
- const getSelectUpChanges = (lines, selections) => {
6516
- const newSelections = new Uint32Array(selections.length);
6517
- for (let i = 0; i < selections.length; i += 4) {
6518
- const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
6519
- newSelections[i] = Math.max(selectionStartRow - 1, 0);
6520
- newSelections[i + 1] = selectionStartColumn;
6521
- newSelections[i + 2] = selectionEndRow;
6522
- newSelections[i + 3] = selectionEndColumn;
6466
+ const getLineInfo$1 = (line, tokens, TokenMap) => {
6467
+ const tokensLength = tokens.length;
6468
+ let end = 0;
6469
+ let start = 0;
6470
+ const lineInfo = [];
6471
+ for (let i = 0; i < tokensLength; i += 2) {
6472
+ const tokenType = tokens[i];
6473
+ const tokenLength = tokens[i + 1];
6474
+ end += tokenLength;
6475
+ const text = line.slice(start, end);
6476
+ const className = `Token ${TokenMap[tokenType] || 'Unknown'}`;
6477
+ const normalizedText = text;
6478
+ lineInfo.push(normalizedText, className);
6479
+ start = end;
6480
+ }
6481
+ return lineInfo;
6482
+ };
6483
+
6484
+ const state = {
6485
+ warned: []
6486
+ };
6487
+ const flattenTokensArray = tokens => {
6488
+ const flattened = [];
6489
+ for (const token of tokens) {
6490
+ object(token);
6491
+ flattened.push(token.type, token.length);
6492
+ }
6493
+ return flattened;
6494
+ };
6495
+ const warnDeprecatedArrayReturn = (languageId, fn) => {
6496
+ if (state.warned.includes(fn)) {
6497
+ return;
6498
+ }
6499
+ state.warned.push(fn);
6500
+ console.warn(`tokenizers without hasArrayReturn=false are deprecated (language ${languageId})`);
6501
+ };
6502
+ const safeTokenizeLine = (languageId, tokenizeLine, line, lineStateAtStart, hasArrayReturn) => {
6503
+ try {
6504
+ const lineState = tokenizeLine(line, lineStateAtStart);
6505
+ if (!lineState || !lineState.tokens || !lineState.state) {
6506
+ throw new Error('invalid tokenization result');
6507
+ }
6508
+ if (!hasArrayReturn) {
6509
+ warnDeprecatedArrayReturn(languageId, tokenizeLine);
6510
+ // workaround for old tokenizers
6511
+ lineState.tokens = flattenTokensArray(lineState.tokens);
6512
+ }
6513
+ return lineState;
6514
+ } catch (error) {
6515
+ console.error(error);
6516
+ return {
6517
+ tokens: [/* type */0, /* length */line.length],
6518
+ lineState: lineStateAtStart
6519
+ };
6523
6520
  }
6524
- return newSelections;
6525
6521
  };
6526
6522
 
6527
- // @ts-ignore
6528
- const selectUp = editor => {
6523
+ const getLineInfos = (lines, tokenizer, languageId) => {
6524
+ const lineInfos = [];
6529
6525
  const {
6530
- lines,
6531
- selections
6532
- } = editor;
6533
- const newSelections = getSelectUpChanges(lines, selections);
6534
- return scheduleSelections(editor, newSelections);
6535
- };
6536
-
6537
- // @ts-ignore
6538
- const selectWordLeft = editor => {
6539
- return editorSelectHorizontalLeft(editor, wordLeft);
6526
+ tokenizeLine,
6527
+ initialLineState,
6528
+ hasArrayReturn,
6529
+ TokenMap
6530
+ } = tokenizer;
6531
+ let currentLineState = getInitialLineState(initialLineState);
6532
+ for (const line of lines) {
6533
+ const result = safeTokenizeLine(languageId, tokenizeLine, line, currentLineState, hasArrayReturn);
6534
+ const {
6535
+ tokens
6536
+ } = result;
6537
+ const lineInfo = getLineInfo$1(line, tokens, TokenMap);
6538
+ lineInfos.push(lineInfo);
6539
+ currentLineState = result;
6540
+ }
6541
+ return lineInfos;
6540
6542
  };
6541
6543
 
6542
- // @ts-ignore
6543
- const selectWordRight = editor => {
6544
- return editorSelectHorizontalRight(editor, wordRight);
6544
+ const tokenizeCodeBlock = async (codeBlock, languageId, tokenizerPath) => {
6545
+ await loadTokenizer(languageId, tokenizerPath);
6546
+ const tokenizer = getTokenizer(languageId);
6547
+ const lines = splitLines$2(codeBlock);
6548
+ const lineInfos = getLineInfos(lines, tokenizer, languageId);
6549
+ return lineInfos;
6545
6550
  };
6546
6551
 
6547
- // import * as ExtensionHostSelection from '../ExtensionHost/ExtensionHostSelection.ts'
6548
-
6549
- const getNewSelections = async (editor, selections) => {
6550
- const newSelections = await invoke$3('ExtensionHostSelection.executeGrowSelection', editor, selections);
6551
- if (newSelections.length === 0) {
6552
- return selections;
6552
+ const getHoverPosition = (position, selections) => {
6553
+ if (position) {
6554
+ return position;
6553
6555
  }
6554
- return new Uint32Array(newSelections);
6556
+ const rowIndex = selections[0];
6557
+ const columnIndex = selections[1];
6558
+ return {
6559
+ rowIndex,
6560
+ columnIndex
6561
+ };
6555
6562
  };
6556
- const selectionGrow = async editor => {
6557
- const {
6558
- selections
6559
- } = editor;
6560
- const newSelections = await getNewSelections(editor, selections);
6561
- return scheduleSelections(editor, newSelections);
6563
+ const getMatchingDiagnostics = (diagnostics, rowIndex, columnIndex) => {
6564
+ const matching = [];
6565
+ for (const diagnostic of diagnostics) {
6566
+ if (diagnostic.rowIndex === rowIndex) {
6567
+ matching.push(diagnostic);
6568
+ }
6569
+ }
6570
+ return matching;
6562
6571
  };
6572
+ const fallbackDisplayStringLanguageId = 'typescript'; // TODO remove this
6563
6573
 
6564
- const setDecorations = (editor, decorations, diagnostics) => {
6565
- if (editor.decorations.length === 0 && decorations.length === 0) {
6566
- return editor;
6567
- }
6574
+ const hoverDocumentationFontSize = 15;
6575
+ const hoverDocumentationFontFamily = 'Fira Code';
6576
+ const hoverDocumentationLineHeight = '1.33333';
6577
+ const hoverBorderLeft = 1;
6578
+ const hoverBorderRight = 1;
6579
+ const hoverPaddingLeft = 8;
6580
+ const hoverPaddingRight = 8;
6581
+ const hovverFullWidth = 400;
6582
+ const hoverDocumentationWidth = hovverFullWidth - hoverPaddingLeft - hoverPaddingRight - hoverBorderLeft - hoverBorderRight;
6583
+ const getHoverPositionXy = (editor, rowIndex, wordStart, documentationHeight) => {
6584
+ const x$1 = x(editor, rowIndex, wordStart);
6585
+ const y$1 = editor.height - y(editor, rowIndex) + editor.y + 40;
6568
6586
  return {
6569
- ...editor,
6570
- decorations,
6571
- diagnostics
6587
+ x: x$1,
6588
+ y: y$1
6572
6589
  };
6573
6590
  };
6574
-
6575
- const tokenizers = Object.create(null);
6576
- const set$1 = (id, value) => {
6577
- tokenizers[id] = value;
6578
- };
6579
- const get$1 = id => {
6580
- return tokenizers[id] || TokenizePlainText;
6581
- };
6582
-
6583
- // TODO add command to set language id
6584
- // without needing to specify tokenizePath
6585
- const setLanguageId = async (editor, languageId, tokenizePath) => {
6591
+ const getEditorHoverInfo = async (editorUid, position) => {
6592
+ number$1(editorUid);
6593
+ const instance = get$7(editorUid);
6594
+ const editor = instance.newState;
6586
6595
  const {
6587
- tokenizerId
6596
+ selections
6588
6597
  } = editor;
6589
- // TODO move tokenizer to syntax highlighting worker
6590
- // TODO only load tokenizer if not already loaded
6591
- // if already loaded just set tokenizer and rerender text
6592
- // TODO race condition
6593
- await loadTokenizer(languageId, tokenizePath);
6594
- const tokenizer = getTokenizer(languageId);
6595
- const newTokenizerId = tokenizerId + 1;
6596
- set$1(newTokenizerId, tokenizer);
6597
- const latest = getEditor(editor.uid);
6598
- if (!latest) {
6599
- return editor;
6598
+ const {
6599
+ rowIndex,
6600
+ columnIndex
6601
+ } = getHoverPosition(position, selections);
6602
+ const offset = offsetAt(editor, rowIndex, columnIndex);
6603
+ const hover = await getHover(editor, offset);
6604
+ if (!hover) {
6605
+ return undefined;
6600
6606
  }
6601
- // TODO don't update editor if tokenizer was already loaded
6602
- // TODO update syntax highlighting
6603
- // TODO get edits
6604
-
6607
+ const {
6608
+ displayString,
6609
+ documentation,
6610
+ displayStringLanguageId
6611
+ } = hover;
6612
+ const tokenizerPath = '';
6613
+ const lineInfos = await tokenizeCodeBlock(displayString, displayStringLanguageId || fallbackDisplayStringLanguageId, tokenizerPath);
6614
+ const wordPart = await getWordBefore(editor, rowIndex, columnIndex);
6615
+ const wordStart = columnIndex - wordPart.length;
6616
+ await measureTextBlockHeight(documentation, hoverDocumentationFontFamily, hoverDocumentationFontSize, hoverDocumentationLineHeight, hoverDocumentationWidth);
6617
+ const {
6618
+ x,
6619
+ y
6620
+ } = getHoverPositionXy(editor, rowIndex, wordStart);
6621
+ const diagnostics = editor.diagnostics || [];
6622
+ const matchingDiagnostics = getMatchingDiagnostics(diagnostics, rowIndex);
6605
6623
  return {
6606
- ...latest,
6607
- languageId,
6608
- invalidStartIndex: 0,
6609
- tokenizerId: newTokenizerId
6624
+ lineInfos,
6625
+ documentation,
6626
+ x,
6627
+ y,
6628
+ matchingDiagnostics
6610
6629
  };
6611
6630
  };
6612
6631
 
6613
- const setSelections = (editor, selections) => {
6614
- const {
6615
- minLineY,
6616
- maxLineY,
6617
- rowHeight
6618
- } = editor;
6619
- const startRowIndex = selections[0];
6620
- if (startRowIndex < minLineY) {
6621
- const deltaY = startRowIndex * rowHeight;
6622
- return {
6623
- ...editor,
6624
- minLineY: startRowIndex,
6625
- maxLineY: startRowIndex + 1,
6626
- selections,
6627
- deltaY
6628
- };
6629
- }
6630
- if (startRowIndex > maxLineY) {
6631
- const deltaY = startRowIndex * rowHeight;
6632
- return {
6633
- ...editor,
6634
- minLineY: startRowIndex,
6635
- maxLineY: startRowIndex + 1,
6636
- selections,
6637
- deltaY
6638
- };
6632
+ const loadHoverContent = async state => {
6633
+ // TODO
6634
+ const position = undefined;
6635
+ const hoverInfo = await getEditorHoverInfo(state.editorUid, position);
6636
+ if (!hoverInfo) {
6637
+ return state;
6639
6638
  }
6639
+ const {
6640
+ lineInfos,
6641
+ documentation,
6642
+ x,
6643
+ y,
6644
+ matchingDiagnostics
6645
+ } = hoverInfo;
6640
6646
  return {
6641
- ...editor,
6642
- selections
6647
+ ...state,
6648
+ lineInfos,
6649
+ documentation,
6650
+ x,
6651
+ y,
6652
+ diagnostics: matchingDiagnostics
6643
6653
  };
6644
6654
  };
6645
6655
 
6646
- const EditorHover = 'EditorHover';
6647
- const showHover = async state => {
6648
- await invoke$3('Viewlet.openWidget', EditorHover);
6649
- return state;
6656
+ const newStateGenerator = state => {
6657
+ return loadHoverContent(state);
6658
+ };
6659
+ const showHover2 = async editor => {
6660
+ return addWidgetToEditor(Hover, FocusEditorHover, editor, create$2, newStateGenerator);
6650
6661
  };
6651
6662
 
6652
6663
  const EditorSourceActions = 'EditorSourceActions';
6653
- const showSourceActions = async editor => {
6664
+ const showSourceActions$1 = async editor => {
6654
6665
  // TODO
6655
6666
  // 1. hide hover, completions, color picker
6656
6667
  // 2. query source actions from extension host
@@ -6660,6 +6671,70 @@ const showSourceActions = async editor => {
6660
6671
  return editor;
6661
6672
  };
6662
6673
 
6674
+ const getEditorSourceActions = async () => {
6675
+ const sourceActions = [{
6676
+ name: organizeImports$1(),
6677
+ command: 'Editor.organizeImports'
6678
+ }, {
6679
+ name: sortImports(),
6680
+ command: 'Editor.sortImports'
6681
+ }];
6682
+ return sourceActions;
6683
+ };
6684
+
6685
+ const loadSourceActions = async (editorUid, state) => {
6686
+ // const editor = GetEditor.getEditor(editorUid)
6687
+ // TODO request source actions information from extensions
6688
+ const sourceActions = await getEditorSourceActions();
6689
+ // TODO avoid side effect
6690
+ return {
6691
+ ...state,
6692
+ sourceActions,
6693
+ x: 200,
6694
+ y: -200,
6695
+ width: 250,
6696
+ height: 150,
6697
+ maxHeight: 150,
6698
+ focusedIndex: 0
6699
+ };
6700
+ };
6701
+
6702
+ const create$1 = () => {
6703
+ const completionUid = create$6();
6704
+ const widget = {
6705
+ id: SourceAction,
6706
+ oldState: {
6707
+ uid: completionUid,
6708
+ x: 0,
6709
+ y: 0,
6710
+ width: 0,
6711
+ height: 0,
6712
+ focusedIndex: 0,
6713
+ sourceActions: [],
6714
+ maxHeight: 0
6715
+ },
6716
+ newState: {
6717
+ uid: completionUid,
6718
+ x: 0,
6719
+ y: 0,
6720
+ width: 0,
6721
+ height: 0,
6722
+ focusedIndex: 0,
6723
+ sourceActions: [],
6724
+ maxHeight: 0
6725
+ }
6726
+ };
6727
+ return widget;
6728
+ };
6729
+
6730
+ const showSourceActions = async editor => {
6731
+ const uid = editor.uid;
6732
+ const newStateGenerator = state => {
6733
+ return loadSourceActions(uid, state);
6734
+ };
6735
+ return addWidgetToEditor(SourceAction, SourceActions, editor, create$1, newStateGenerator);
6736
+ };
6737
+
6663
6738
  const compareString = (a, b) => {
6664
6739
  return a.localeCompare(b);
6665
6740
  };
@@ -7510,7 +7585,7 @@ const focusPrevious = editor => {
7510
7585
  };
7511
7586
 
7512
7587
  const create = () => {
7513
- const completionUid = create$5();
7588
+ const completionUid = create$6();
7514
7589
  const completionWidget = {
7515
7590
  id: CompletionDetail$1,
7516
7591
  oldState: {
@@ -7906,10 +7981,10 @@ const getEnabled = () => {
7906
7981
  };
7907
7982
 
7908
7983
  const intialize = async (syntaxHighlightingEnabled, syncIncremental) => {
7909
- await listen$6();
7984
+ await listen$5();
7910
7985
  if (syntaxHighlightingEnabled) {
7911
7986
  setEnabled$1(true);
7912
- await listen$5();
7987
+ await listen$6();
7913
7988
  }
7914
7989
  if (syncIncremental) {
7915
7990
  setEnabled(true);
@@ -8197,10 +8272,10 @@ const getTokensViewport2 = (editor, startLineIndex, endLineIndex, syncIncrementa
8197
8272
  languageId,
8198
8273
  invalidStartIndex
8199
8274
  };
8200
- return invoke('GetTokensViewport.getTokensViewport', slimEditor, startLineIndex, endLineIndex, hasLinesToSend, id, linesToSend);
8275
+ return invoke$1('GetTokensViewport.getTokensViewport', slimEditor, startLineIndex, endLineIndex, hasLinesToSend, id, linesToSend);
8201
8276
  }
8202
8277
  // TODO only send needed lines of text
8203
- return invoke('GetTokensViewport.getTokensViewport', editor, startLineIndex, endLineIndex, true, editor.id, editor.lines);
8278
+ return invoke$1('GetTokensViewport.getTokensViewport', editor, startLineIndex, endLineIndex, true, editor.id, editor.lines);
8204
8279
  }
8205
8280
  return getTokensViewport(editor, startLineIndex, endLineIndex);
8206
8281
  };
@@ -8393,7 +8468,7 @@ const getLineInfosViewport = (editor, tokens, embeddedResults, minLineY, maxLine
8393
8468
  decorations,
8394
8469
  languageId
8395
8470
  } = editor;
8396
- const tokenMap = get$3(languageId);
8471
+ const tokenMap = get$2(languageId);
8397
8472
  let offset = minLineOffset;
8398
8473
  const tabSize = 2;
8399
8474
  for (let i = minLineY; i < maxLineY; i++) {
@@ -8550,7 +8625,7 @@ const getIncrementalEdits = async (oldState, newState) => {
8550
8625
  const lines = newState.lines;
8551
8626
  const oldLine = oldState.lines[rowIndex];
8552
8627
  const newLine = lines[rowIndex];
8553
- const incrementalEdits = await invoke('TokenizeIncremental.tokenizeIncremental', newState.uid, newState.languageId, oldLine, newLine, rowIndex, newState.minLineY);
8628
+ const incrementalEdits = await invoke$1('TokenizeIncremental.tokenizeIncremental', newState.uid, newState.languageId, oldLine, newLine, rowIndex, newState.minLineY);
8554
8629
  if (incrementalEdits && incrementalEdits.length === 1) {
8555
8630
  return incrementalEdits;
8556
8631
  }
@@ -8985,7 +9060,8 @@ const commandMap = {
8985
9060
  'Editor.setSelections': setSelections,
8986
9061
  'Editor.showHover': showHover,
8987
9062
  'Editor.showHover2': showHover2,
8988
- 'Editor.showSourceActions': showSourceActions,
9063
+ 'Editor.showSourceActions': showSourceActions$1,
9064
+ 'Editor.showSourceActions2': showSourceActions,
8989
9065
  'Editor.sortLinesAscending': sortLinesAscending,
8990
9066
  'Editor.tabCompletion': tabCompletion,
8991
9067
  'Editor.toggleBlockComment': toggleBlockComment,
@@ -10452,6 +10528,10 @@ const EditorFindWidget = {
10452
10528
  render: render$1
10453
10529
  };
10454
10530
 
10531
+ const SourceActionWidget = {
10532
+ __proto__: null
10533
+ };
10534
+
10455
10535
  const render = widget => {
10456
10536
  const commands = renderHover(widget.oldState, widget.newState);
10457
10537
  const wrappedCommands = [];
@@ -10483,6 +10563,7 @@ const registerWidgets = () => {
10483
10563
  set(CompletionDetail$1, EditorCompletionDetailWidget);
10484
10564
  set(Find, EditorFindWidget);
10485
10565
  set(Hover, EditorHoverWidget);
10566
+ set(SourceAction, SourceActionWidget);
10486
10567
  };
10487
10568
 
10488
10569
  const main = async () => {