@lvce-editor/completion-worker 1.4.0 → 1.5.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.
@@ -82,6 +82,12 @@ const getType = value => {
82
82
  return 'unknown';
83
83
  }
84
84
  };
85
+ const object = value => {
86
+ const type = getType(value);
87
+ if (type !== 'object') {
88
+ throw new AssertionError('expected value to be of type object');
89
+ }
90
+ };
85
91
  const number = value => {
86
92
  const type = getType(value);
87
93
  if (type !== 'number') {
@@ -848,11 +854,11 @@ const commands = Object.create(null);
848
854
  const register = commandMap => {
849
855
  Object.assign(commands, commandMap);
850
856
  };
851
- const getCommand = key => {
857
+ const getCommand$1 = key => {
852
858
  return commands[key];
853
859
  };
854
860
  const execute$1 = (command, ...args) => {
855
- const fn = getCommand(command);
861
+ const fn = getCommand$1(command);
856
862
  if (!fn) {
857
863
  throw new Error(`command not found ${command}`);
858
864
  }
@@ -1046,16 +1052,20 @@ const create$1 = (uid, x, y, width, height, editorUid, editorLanguageId) => {
1046
1052
  set$2(uid, state, state);
1047
1053
  };
1048
1054
 
1049
- const isEqual$3 = (oldState, newState) => {
1055
+ const isEqual$4 = (oldState, newState) => {
1050
1056
  return oldState.x === newState.x && oldState.y === newState.y && oldState.width === newState.width && oldState.height === newState.height;
1051
1057
  };
1052
1058
 
1059
+ const isEqual$3 = (oldState, newState) => {
1060
+ return oldState.version === newState.version;
1061
+ };
1062
+
1053
1063
  const isEqual$2 = (oldState, newState) => {
1054
1064
  return oldState.version === newState.version;
1055
1065
  };
1056
1066
 
1057
1067
  const isEqual$1 = (oldState, newState) => {
1058
- return oldState.items === newState.items;
1068
+ return oldState.items === newState.items && oldState.focusedIndex === newState.focusedIndex;
1059
1069
  };
1060
1070
 
1061
1071
  const isEqual = (oldState, newState) => {
@@ -1067,9 +1077,10 @@ const RenderBounds = 8;
1067
1077
  const RenderEventListeners = 11;
1068
1078
  const RenderUid = 12;
1069
1079
  const RenderContent = 13;
1080
+ const RenderFocusContext = 14;
1070
1081
 
1071
- const modules = [isEqual$2, isEqual$1, isEqual$3, isEqual];
1072
- const numbers = [RenderEventListeners, RenderItems, RenderBounds, RenderUid];
1082
+ const modules = [isEqual$3, isEqual$1, isEqual$4, isEqual, isEqual$2];
1083
+ const numbers = [RenderEventListeners, RenderItems, RenderBounds, RenderUid, RenderFocusContext];
1073
1084
 
1074
1085
  const diff = (oldState, newState) => {
1075
1086
  const diffResult = [];
@@ -1091,12 +1102,246 @@ const diff2 = uid => {
1091
1102
  return diffResult;
1092
1103
  };
1093
1104
 
1105
+ const focusIndex = (state, index) => {
1106
+ const newState = {
1107
+ ...state,
1108
+ focusedIndex: index,
1109
+ focused: true
1110
+ };
1111
+ return newState;
1112
+ };
1113
+
1114
+ const focusFirst = state => {
1115
+ const firstIndex = 0;
1116
+ return focusIndex(state, firstIndex);
1117
+ };
1118
+
1119
+ const focusNext = state => {
1120
+ const {
1121
+ focusedIndex
1122
+ } = state;
1123
+ const nextIndex = focusedIndex + 1;
1124
+ return focusIndex(state, nextIndex);
1125
+ };
1126
+
1127
+ const focusPrevious = state => {
1128
+ const previousIndex = state.focusedIndex - 1;
1129
+ return focusIndex(state, previousIndex);
1130
+ };
1131
+
1132
+ const openDetails = async state => {
1133
+ // TODO ask editor worker to add completion details widget
1134
+ return state;
1135
+ };
1136
+
1137
+ const OnCompletion = 'onCompletion';
1138
+
1139
+ const CompletionExecute = 'ExtensionHostCompletion.execute';
1140
+
1141
+ const rpcs = Object.create(null);
1142
+ const set$a = (id, rpc) => {
1143
+ rpcs[id] = rpc;
1144
+ };
1145
+ const get = id => {
1146
+ return rpcs[id];
1147
+ };
1148
+
1149
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
1150
+
1151
+ const create = rpcId => {
1152
+ return {
1153
+ // @ts-ignore
1154
+ invoke(method, ...params) {
1155
+ const rpc = get(rpcId);
1156
+ // @ts-ignore
1157
+ return rpc.invoke(method, ...params);
1158
+ },
1159
+ // @ts-ignore
1160
+ invokeAndTransfer(method, ...params) {
1161
+ const rpc = get(rpcId);
1162
+ // @ts-ignore
1163
+ return rpc.invokeAndTransfer(method, ...params);
1164
+ },
1165
+ set(rpc) {
1166
+ set$a(rpcId, rpc);
1167
+ }
1168
+ };
1169
+ };
1170
+ const EditorWorker$1 = 99;
1171
+ const ExtensionHostWorker = 44;
1172
+ const {
1173
+ invoke: invoke$9,
1174
+ invokeAndTransfer: invokeAndTransfer$9,
1175
+ set: set$9
1176
+ } = create(EditorWorker$1);
1177
+ const EditorWorker = {
1178
+ __proto__: null,
1179
+ invoke: invoke$9,
1180
+ invokeAndTransfer: invokeAndTransfer$9,
1181
+ set: set$9
1182
+ };
1183
+ const {
1184
+ invoke: invoke$7,
1185
+ set: set$7
1186
+ } = create(ExtensionHostWorker);
1187
+ const ExtensionHost = {
1188
+ __proto__: null,
1189
+ invoke: invoke$7,
1190
+ set: set$7
1191
+ };
1192
+
1193
+ const {
1194
+ invoke: invoke$1,
1195
+ set: set$1,
1196
+ invokeAndTransfer
1197
+ } = EditorWorker;
1198
+
1199
+ // TODO add tests for this
1200
+ const activateByEvent = async event => {
1201
+ // @ts-ignore
1202
+ await invoke$1('ActivateByEvent.activateByEvent', event);
1203
+ };
1204
+
1205
+ const {
1206
+ invoke,
1207
+ set
1208
+ } = ExtensionHost;
1209
+
1210
+ const execute = async ({
1211
+ editorLanguageId,
1212
+ editorUid,
1213
+ args,
1214
+ event,
1215
+ method,
1216
+ noProviderFoundMessage,
1217
+ noProviderFoundResult = undefined
1218
+ }) => {
1219
+ const fullEvent = `${event}:${editorLanguageId}`;
1220
+ await activateByEvent(fullEvent);
1221
+ const result = await invoke(method, editorUid, ...args);
1222
+ return result;
1223
+ };
1224
+
1225
+ const executeCompletionProvider = async (editorUid, editorLanguageId, offset) => {
1226
+ return execute({
1227
+ editorUid,
1228
+ editorLanguageId,
1229
+ event: OnCompletion,
1230
+ method: CompletionExecute,
1231
+ args: [offset],
1232
+ noProviderFoundMessage: 'no completion provider found',
1233
+ noProviderFoundResult: []});
1234
+ };
1235
+
1236
+ const getOffsetAtCursor = editorUid => {
1237
+ // TODO ask editor worker
1238
+ return 0;
1239
+ };
1240
+
1241
+ // TODO possible to do this with events/state machine instead of promises -> enables canceling operations / concurrent calls
1242
+ const getCompletions = async (editorUid, editorLanguageId) => {
1243
+ const offset = getOffsetAtCursor();
1244
+ const completions = await executeCompletionProvider(editorUid, editorLanguageId, offset);
1245
+ return completions;
1246
+ };
1247
+
1248
+ const select = async (state, completionItem) => {
1249
+ // TODO ask editor worker to apply changes and close completion widget
1250
+ // const changes = await getEdits(state, completionItem)
1251
+ // TODO ask editor worker to remove widget
1252
+ // const index = state.widgets
1253
+ // .indexOf
1254
+ // // ViewletModuleId.EditorCompletion
1255
+ // ()
1256
+ // if (index !== -1) {
1257
+ // state.widgets.splice(index, 1)
1258
+ // state.completionState = EditorCompletionState.None
1259
+ // state.completionUid = 0
1260
+ // }
1261
+ // // TODO dispose completion widget
1262
+ // // TODO apply edit in editor worker instead of asking renderer worker
1263
+ // // await RendererWorker.invoke('Viewlet.dispose', state.uid)
1264
+ // const { widgets } = state
1265
+ // const newWidgets = RemoveEditorWidget.removeEditorWidget(widgets, WidgetId.Completion)
1266
+ // const intermediateEditor = await EditorCommandApplyEdit.applyEdit(state, changes)
1267
+ return {
1268
+ ...state
1269
+ };
1270
+ };
1271
+ const selectIndex = async (state, index) => {
1272
+ const {
1273
+ items
1274
+ } = state;
1275
+ if (index === -1) {
1276
+ return state;
1277
+ }
1278
+ if (index > items.length) {
1279
+ throw new Error('index too large');
1280
+ }
1281
+ return select(state);
1282
+ };
1283
+
1284
+ const selectCurrent = state => {
1285
+ const {
1286
+ focusedIndex
1287
+ } = state;
1288
+ return selectIndex(state, focusedIndex);
1289
+ };
1290
+
1094
1291
  const commandIds = ['handleSliderPointerDown', 'handleSliderPointerMove', 'initialize'];
1095
1292
 
1096
1293
  const getCommandIds = () => {
1097
1294
  return commandIds;
1098
1295
  };
1099
1296
 
1297
+ const Enter = 3;
1298
+ const Space$1 = 9;
1299
+ const End = 255;
1300
+ const Home = 12;
1301
+ const UpArrow = 14;
1302
+ const DownArrow = 16;
1303
+
1304
+ const CtrlCmd = 1 << 11 >>> 0;
1305
+
1306
+ const FocusEditorCompletions = 9;
1307
+ const FocusEditorRename = 11;
1308
+
1309
+ const Completion = 3;
1310
+
1311
+ const getCommand = shortId => {
1312
+ return {
1313
+ command: 'Editor.executeWidgetCommand',
1314
+ args: ['Completions', `Completions.${shortId}`, 0, Completion]
1315
+ };
1316
+ };
1317
+ const getKeyBindings = () => {
1318
+ return [{
1319
+ key: DownArrow,
1320
+ ...getCommand('focusNext'),
1321
+ when: FocusEditorCompletions
1322
+ }, {
1323
+ key: UpArrow,
1324
+ ...getCommand('focusPrevious'),
1325
+ when: FocusEditorCompletions
1326
+ }, {
1327
+ key: Enter,
1328
+ ...getCommand('selectCurrent'),
1329
+ when: FocusEditorCompletions
1330
+ }, {
1331
+ key: End,
1332
+ ...getCommand('focusLast'),
1333
+ when: FocusEditorCompletions
1334
+ }, {
1335
+ key: Home,
1336
+ ...getCommand('focusFirst'),
1337
+ when: FocusEditorCompletions
1338
+ }, {
1339
+ key: CtrlCmd | Space$1,
1340
+ ...getCommand('toggleDetails'),
1341
+ when: FocusEditorCompletions
1342
+ }];
1343
+ };
1344
+
1100
1345
  const Diagonal = 1;
1101
1346
  const Left = 2;
1102
1347
 
@@ -1304,63 +1549,40 @@ const getListHeight = (itemsLength, itemHeight, maxHeight) => {
1304
1549
  return Math.min(totalHeight, maxHeight);
1305
1550
  };
1306
1551
 
1307
- const rpcs = Object.create(null);
1308
- const set$a = (id, rpc) => {
1309
- rpcs[id] = rpc;
1310
- };
1311
- const get = id => {
1312
- return rpcs[id];
1552
+ const getWordAtOffset = async editorUid => {
1553
+ return invoke$1('Editor.getWordAtOffset2', editorUid);
1313
1554
  };
1314
1555
 
1315
- /* eslint-disable @typescript-eslint/explicit-function-return-type */
1316
-
1317
- const create = rpcId => {
1556
+ const handleEditorDeleteLeft = async state => {
1557
+ const {
1558
+ unfilteredItems,
1559
+ itemHeight,
1560
+ maxHeight,
1561
+ editorUid
1562
+ } = state;
1563
+ const x = 0; // TODO
1564
+ // @ts-ignore
1565
+ const y = 0; // TODP
1566
+ const wordAtOffset = await getWordAtOffset(editorUid);
1567
+ if (!wordAtOffset) {
1568
+ return {
1569
+ ...state,
1570
+ disposed: true
1571
+ };
1572
+ }
1573
+ const items = filterCompletionItems(unfilteredItems, wordAtOffset);
1574
+ const newMaxLineY = Math.min(items.length, 8);
1575
+ const height = getListHeight(items.length, itemHeight, maxHeight);
1318
1576
  return {
1319
- // @ts-ignore
1320
- invoke(method, ...params) {
1321
- const rpc = get(rpcId);
1322
- // @ts-ignore
1323
- return rpc.invoke(method, ...params);
1324
- },
1325
- // @ts-ignore
1326
- invokeAndTransfer(method, ...params) {
1327
- const rpc = get(rpcId);
1328
- // @ts-ignore
1329
- return rpc.invokeAndTransfer(method, ...params);
1330
- },
1331
- set(rpc) {
1332
- set$a(rpcId, rpc);
1333
- }
1577
+ ...state,
1578
+ items,
1579
+ x,
1580
+ y,
1581
+ maxLineY: newMaxLineY,
1582
+ leadingWord: wordAtOffset,
1583
+ height
1334
1584
  };
1335
1585
  };
1336
- const EditorWorker$1 = 99;
1337
- const ExtensionHostWorker = 44;
1338
- const {
1339
- invoke: invoke$9,
1340
- invokeAndTransfer: invokeAndTransfer$9,
1341
- set: set$9
1342
- } = create(EditorWorker$1);
1343
- const EditorWorker = {
1344
- __proto__: null,
1345
- invoke: invoke$9,
1346
- invokeAndTransfer: invokeAndTransfer$9,
1347
- set: set$9
1348
- };
1349
- const {
1350
- invoke: invoke$7,
1351
- set: set$7
1352
- } = create(ExtensionHostWorker);
1353
- const ExtensionHost = {
1354
- __proto__: null,
1355
- invoke: invoke$7,
1356
- set: set$7
1357
- };
1358
-
1359
- const {
1360
- invoke: invoke$1,
1361
- set: set$1,
1362
- invokeAndTransfer
1363
- } = EditorWorker;
1364
1586
 
1365
1587
  const getPositionAtCursor = async parentUid => {
1366
1588
  const position = await invoke$1('Editor.getPositionAtCursor', parentUid);
@@ -1368,7 +1590,6 @@ const getPositionAtCursor = async parentUid => {
1368
1590
  };
1369
1591
 
1370
1592
  const getWordBefore = async (editorUid, rowIndex, columnIndex) => {
1371
- // @ts-ignore
1372
1593
  return invoke$1('Editor.getWordBefore2', editorUid, rowIndex, columnIndex);
1373
1594
  };
1374
1595
 
@@ -1404,6 +1625,52 @@ const handleEditorType = async state => {
1404
1625
  };
1405
1626
  };
1406
1627
 
1628
+ const clamp = (num, min, max) => {
1629
+ number(num);
1630
+ number(min);
1631
+ number(max);
1632
+ return Math.min(Math.max(num, min), max);
1633
+ };
1634
+
1635
+ // TODO optimize this function to return the minimum number
1636
+ // of visible items needed, e.g. when not scrolled 5 items with
1637
+ // 20px fill 100px but when scrolled 6 items are needed
1638
+ const getNumberOfVisibleItems = (listHeight, itemHeight) => {
1639
+ return Math.ceil(listHeight / itemHeight) + 1;
1640
+ };
1641
+
1642
+ const setDeltaY = (state, value) => {
1643
+ object(state);
1644
+ number(value);
1645
+ const {
1646
+ itemHeight,
1647
+ finalDeltaY,
1648
+ deltaY,
1649
+ height,
1650
+ headerHeight
1651
+ } = state;
1652
+ const listHeight = height - headerHeight;
1653
+ const newDeltaY = clamp(value, 0, finalDeltaY);
1654
+ if (deltaY === newDeltaY) {
1655
+ return state;
1656
+ }
1657
+ // TODO when it only moves by one px, extensions don't need to be rerendered, only negative margin
1658
+ const minLineY = Math.floor(newDeltaY / itemHeight);
1659
+ const maxLineY = minLineY + getNumberOfVisibleItems(listHeight, itemHeight);
1660
+ return {
1661
+ ...state,
1662
+ deltaY: newDeltaY,
1663
+ minLineY,
1664
+ maxLineY
1665
+ };
1666
+ };
1667
+
1668
+ const handleWheel = (state, deltaMode, deltaY) => {
1669
+ number(deltaMode);
1670
+ number(deltaY);
1671
+ return setDeltaY(state, state.deltaY + deltaY);
1672
+ };
1673
+
1407
1674
  const getPortTuple = () => {
1408
1675
  const {
1409
1676
  port1,
@@ -1441,74 +1708,17 @@ const createExtensionHostRpc = async () => {
1441
1708
  }
1442
1709
  };
1443
1710
 
1444
- const {
1445
- invoke,
1446
- set
1447
- } = ExtensionHost;
1448
-
1449
1711
  const initialize = async () => {
1450
1712
  const rpc = await createExtensionHostRpc();
1451
1713
  set(rpc);
1452
1714
  };
1453
1715
 
1454
- const OnCompletion = 'onCompletion';
1455
-
1456
- const CompletionExecute = 'ExtensionHostCompletion.execute';
1457
-
1458
- // TODO add tests for this
1459
- const activateByEvent = async event => {
1460
- // @ts-ignore
1461
- await invoke$1('ActivateByEvent.activateByEvent', event);
1462
- };
1463
-
1464
- const execute = async ({
1465
- editorLanguageId,
1466
- editorUid,
1467
- args,
1468
- event,
1469
- method,
1470
- noProviderFoundMessage,
1471
- noProviderFoundResult = undefined
1472
- }) => {
1473
- const fullEvent = `${event}:${editorLanguageId}`;
1474
- await activateByEvent(fullEvent);
1475
- const result = await invoke(method, editorUid, ...args);
1476
- return result;
1477
- };
1478
-
1479
- const executeCompletionProvider = async (editorUid, editorLanguageId, offset) => {
1480
- return execute({
1481
- editorUid,
1482
- editorLanguageId,
1483
- event: OnCompletion,
1484
- method: CompletionExecute,
1485
- args: [offset],
1486
- noProviderFoundMessage: 'no completion provider found',
1487
- noProviderFoundResult: []});
1488
- };
1489
-
1490
- const getOffsetAtCursor = editorUid => {
1491
- // TODO ask editor worker
1492
- return 0;
1493
- };
1494
-
1495
- // TODO possible to do this with events/state machine instead of promises -> enables canceling operations / concurrent calls
1496
- const getCompletions = async (editorUid, editorLanguageId) => {
1497
- const offset = getOffsetAtCursor();
1498
- const completions = await executeCompletionProvider(editorUid, editorLanguageId, offset);
1499
- return completions;
1500
- };
1501
-
1502
1716
  const getFinalDeltaY = (height, itemHeight, itemsLength) => {
1503
1717
  const contentHeight = itemsLength * itemHeight;
1504
1718
  const finalDeltaY = Math.max(contentHeight - height, 0);
1505
1719
  return finalDeltaY;
1506
1720
  };
1507
1721
 
1508
- const getWordAtOffset = async editorUid => {
1509
- return invoke$1('Editor.getWordAtOffset2', editorUid);
1510
- };
1511
-
1512
1722
  const loadContent = async state => {
1513
1723
  const {
1514
1724
  itemHeight,
@@ -1545,7 +1755,8 @@ const loadContent = async state => {
1545
1755
  // @ts-ignore
1546
1756
  rowIndex,
1547
1757
  columnIndex,
1548
- width: 200
1758
+ width: 200,
1759
+ version: 1
1549
1760
  };
1550
1761
  };
1551
1762
 
@@ -1585,6 +1796,10 @@ const renderEventListeners = state => {
1585
1796
  return [SetEventListeners, uid, eventListeners];
1586
1797
  };
1587
1798
 
1799
+ const renderFocusContext = (oldState, newState) => {
1800
+ return [/* method */'Viewlet.setFocusContext', FocusEditorRename];
1801
+ };
1802
+
1588
1803
  const ColoredMaskIcon = 'ColoredMaskIcon';
1589
1804
  const EditorCompletion = 'EditorCompletion';
1590
1805
  const EditorCompletionItem = 'EditorCompletionItem';
@@ -1870,6 +2085,8 @@ const getRenderer = diffType => {
1870
2085
  return renderUid;
1871
2086
  case RenderItems:
1872
2087
  return renderItems;
2088
+ case RenderFocusContext:
2089
+ return renderFocusContext;
1873
2090
  default:
1874
2091
  throw new Error('unknown renderer');
1875
2092
  }
@@ -1901,12 +2118,22 @@ const terminate = () => {
1901
2118
  const commandMap = {
1902
2119
  'Completions.create': create$1,
1903
2120
  'Completions.diff2': diff2,
2121
+ 'Completions.focusFirst': wrapCommand(focusFirst),
2122
+ 'Completions.focusIndex': wrapCommand(focusIndex),
2123
+ 'Completions.focusNext': wrapCommand(focusNext),
2124
+ 'Completions.focusPrevious': wrapCommand(focusPrevious),
1904
2125
  'Completions.getCommandIds': getCommandIds,
2126
+ 'Completions.getKeyBindings': getKeyBindings,
2127
+ 'Completions.handleEditorDeleteLeft': wrapCommand(handleEditorDeleteLeft),
2128
+ 'Completions.handleEditorType': handleEditorType,
2129
+ 'Completions.handleWheel': wrapCommand(handleWheel),
2130
+ 'Completions.initialize': initialize,
1905
2131
  'Completions.loadContent': wrapCommand(loadContent),
1906
2132
  'Completions.render2': render2,
2133
+ 'Completions.selectCurrent': wrapCommand(selectCurrent),
2134
+ 'Completions.selectIndex': wrapCommand(selectIndex),
1907
2135
  'Completions.terminate': terminate,
1908
- 'Completions.initialize': initialize,
1909
- 'Completions.handleEditorType': handleEditorType
2136
+ 'Completions.openDetails': wrapCommand(openDetails)
1910
2137
  };
1911
2138
 
1912
2139
  const listen = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/completion-worker",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Web Worker for the find widget in Lvce Editor",
5
5
  "repository": {
6
6
  "type": "git",