@lvce-editor/completion-worker 1.5.0 → 1.6.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.
@@ -94,6 +94,12 @@ const number = value => {
94
94
  throw new AssertionError('expected value to be of type number');
95
95
  }
96
96
  };
97
+ const string = value => {
98
+ const type = getType(value);
99
+ if (type !== 'string') {
100
+ throw new AssertionError('expected value to be of type string');
101
+ }
102
+ };
97
103
 
98
104
  const isMessagePort = value => {
99
105
  return value && value instanceof MessagePort;
@@ -1134,10 +1140,6 @@ const openDetails = async state => {
1134
1140
  return state;
1135
1141
  };
1136
1142
 
1137
- const OnCompletion = 'onCompletion';
1138
-
1139
- const CompletionExecute = 'ExtensionHostCompletion.execute';
1140
-
1141
1143
  const rpcs = Object.create(null);
1142
1144
  const set$a = (id, rpc) => {
1143
1145
  rpcs[id] = rpc;
@@ -1196,6 +1198,11 @@ const {
1196
1198
  invokeAndTransfer
1197
1199
  } = EditorWorker;
1198
1200
 
1201
+ const OnCompletion = 'onCompletion';
1202
+
1203
+ const CompletionExecute = 'ExtensionHostCompletion.execute';
1204
+ const CompletionResolveExecute = 'ExtensionHostCompletion.executeResolve';
1205
+
1199
1206
  // TODO add tests for this
1200
1207
  const activateByEvent = async event => {
1201
1208
  // @ts-ignore
@@ -1232,6 +1239,14 @@ const executeCompletionProvider = async (editorUid, editorLanguageId, offset) =>
1232
1239
  noProviderFoundMessage: 'no completion provider found',
1233
1240
  noProviderFoundResult: []});
1234
1241
  };
1242
+ const executeResolveCompletionItem = async (editor, offset, name, completionItem) => {
1243
+ return execute({
1244
+ event: OnCompletion,
1245
+ method: CompletionResolveExecute,
1246
+ args: [offset, name, completionItem],
1247
+ noProviderFoundMessage: 'no completion provider found',
1248
+ noProviderFoundResult: []});
1249
+ };
1235
1250
 
1236
1251
  const getOffsetAtCursor = editorUid => {
1237
1252
  // TODO ask editor worker
@@ -1245,29 +1260,99 @@ const getCompletions = async (editorUid, editorLanguageId) => {
1245
1260
  return completions;
1246
1261
  };
1247
1262
 
1263
+ // TODO don't send unnecessary parts of completion item like matches
1264
+ const resolveCompletion = async (editorUid, name, completionItem) => {
1265
+ try {
1266
+ string(name);
1267
+ object(completionItem);
1268
+ const offset = getOffsetAtCursor(editorUid);
1269
+ // @ts-ignore
1270
+ const resolvedCompletionItem = await executeResolveCompletionItem(editor, offset, name, completionItem);
1271
+ return resolvedCompletionItem;
1272
+ } catch {
1273
+ return undefined;
1274
+ }
1275
+ };
1276
+
1277
+ const getSelectionPairs = (selections, i) => {
1278
+ const first = selections[i];
1279
+ const second = selections[i + 1];
1280
+ const third = selections[i + 2];
1281
+ const fourth = selections[i + 3];
1282
+ if (first > third || first === third && second >= fourth) {
1283
+ return [third, fourth, first, second, 1];
1284
+ }
1285
+ return [first, second, third, fourth, 0];
1286
+ };
1287
+
1288
+ const getSelectionText = (lines, range) => {
1289
+ const startRowIndex = range.start.rowIndex;
1290
+ const startColumnIndex = range.start.columnIndex;
1291
+ const endRowIndex = Math.min(range.end.rowIndex, lines.length - 1);
1292
+ const endColumnIndex = range.end.columnIndex;
1293
+ if (startRowIndex === endRowIndex) {
1294
+ return [lines[startRowIndex].slice(startColumnIndex, endColumnIndex)];
1295
+ }
1296
+ const selectedLines = [lines[startRowIndex].slice(startColumnIndex), ...lines.slice(startRowIndex + 1, endRowIndex), lines[endRowIndex].slice(0, endColumnIndex)];
1297
+ return selectedLines;
1298
+ };
1299
+
1300
+ // TODO add more exact types
1301
+ const replaceRange = (lines, ranges, replacement, origin) => {
1302
+ const changes = [];
1303
+ const rangesLength = ranges.length;
1304
+ for (let i = 0; i < rangesLength; i += 4) {
1305
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(ranges, i);
1306
+ const start = {
1307
+ rowIndex: selectionStartRow,
1308
+ columnIndex: selectionStartColumn
1309
+ };
1310
+ const end = {
1311
+ rowIndex: selectionEndRow,
1312
+ columnIndex: selectionEndColumn
1313
+ };
1314
+ const selection = {
1315
+ start,
1316
+ end
1317
+ };
1318
+ changes.push({
1319
+ start: start,
1320
+ end: end,
1321
+ inserted: replacement,
1322
+ deleted: getSelectionText(lines, selection),
1323
+ origin
1324
+ });
1325
+ }
1326
+ return changes;
1327
+ };
1328
+
1329
+ const getEdits = async (editorUid, leadingWord, completionItem) => {
1330
+ const word = completionItem.label;
1331
+ const resolvedItem = await resolveCompletion(editorUid, word, completionItem);
1332
+ const inserted = resolvedItem ? resolvedItem.snippet : word;
1333
+ const lines = await invoke$1('Editor.getLines2', editorUid);
1334
+ const selections = await invoke$1('Editor.getSelections2', editorUid);
1335
+ const [startRowIndex, startColumnIndex] = selections;
1336
+ const leadingWordLength = leadingWord.length;
1337
+ const replaceRange$1 = new Uint32Array([startRowIndex, startColumnIndex - leadingWordLength, startRowIndex, startColumnIndex]);
1338
+ const changes = replaceRange(lines, replaceRange$1, [inserted], '');
1339
+ return changes;
1340
+ };
1341
+
1248
1342
  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)
1343
+ const {
1344
+ editorUid,
1345
+ leadingWord
1346
+ } = state;
1347
+ const changes = await getEdits(editorUid, leadingWord, completionItem);
1348
+ // @ts-ignore
1349
+ await invoke$1('Editor.applyEdit2', editorUid, changes);
1350
+ // TODO remove completion widget from editor
1267
1351
  return {
1268
1352
  ...state
1269
1353
  };
1270
1354
  };
1355
+
1271
1356
  const selectIndex = async (state, index) => {
1272
1357
  const {
1273
1358
  items
@@ -1278,7 +1363,9 @@ const selectIndex = async (state, index) => {
1278
1363
  if (index > items.length) {
1279
1364
  throw new Error('index too large');
1280
1365
  }
1281
- return select(state);
1366
+ const actualIndex = index;
1367
+ const completionItem = items[actualIndex];
1368
+ return select(state, completionItem);
1282
1369
  };
1283
1370
 
1284
1371
  const selectCurrent = state => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/completion-worker",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Web Worker for the find widget in Lvce Editor",
5
5
  "repository": {
6
6
  "type": "git",