@lvce-editor/source-control-worker 1.0.0 → 1.2.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.
@@ -54,6 +54,47 @@ class VError extends Error {
54
54
  }
55
55
  }
56
56
 
57
+ class AssertionError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'AssertionError';
61
+ }
62
+ }
63
+ const getType = value => {
64
+ switch (typeof value) {
65
+ case 'number':
66
+ return 'number';
67
+ case 'function':
68
+ return 'function';
69
+ case 'string':
70
+ return 'string';
71
+ case 'object':
72
+ if (value === null) {
73
+ return 'null';
74
+ }
75
+ if (Array.isArray(value)) {
76
+ return 'array';
77
+ }
78
+ return 'object';
79
+ case 'boolean':
80
+ return 'boolean';
81
+ default:
82
+ return 'unknown';
83
+ }
84
+ };
85
+ const number = value => {
86
+ const type = getType(value);
87
+ if (type !== 'number') {
88
+ throw new AssertionError('expected value to be of type number');
89
+ }
90
+ };
91
+ const string = value => {
92
+ const type = getType(value);
93
+ if (type !== 'string') {
94
+ throw new AssertionError('expected value to be of type string');
95
+ }
96
+ };
97
+
57
98
  const isMessagePort = value => {
58
99
  return value && value instanceof MessagePort;
59
100
  };
@@ -379,6 +420,100 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
379
420
  listen: listen$6,
380
421
  wrap: wrap$e
381
422
  };
423
+ const addListener = (emitter, type, callback) => {
424
+ if ('addEventListener' in emitter) {
425
+ emitter.addEventListener(type, callback);
426
+ } else {
427
+ emitter.on(type, callback);
428
+ }
429
+ };
430
+ const removeListener = (emitter, type, callback) => {
431
+ if ('removeEventListener' in emitter) {
432
+ emitter.removeEventListener(type, callback);
433
+ } else {
434
+ emitter.off(type, callback);
435
+ }
436
+ };
437
+ const getFirstEvent = (eventEmitter, eventMap) => {
438
+ const {
439
+ resolve,
440
+ promise
441
+ } = withResolvers();
442
+ const listenerMap = Object.create(null);
443
+ const cleanup = value => {
444
+ for (const event of Object.keys(eventMap)) {
445
+ removeListener(eventEmitter, event, listenerMap[event]);
446
+ }
447
+ resolve(value);
448
+ };
449
+ for (const [event, type] of Object.entries(eventMap)) {
450
+ const listener = event => {
451
+ cleanup({
452
+ type,
453
+ event
454
+ });
455
+ };
456
+ addListener(eventEmitter, event, listener);
457
+ listenerMap[event] = listener;
458
+ }
459
+ return promise;
460
+ };
461
+ const Message$1 = 3;
462
+ const create$5$1 = async ({
463
+ messagePort,
464
+ isMessagePortOpen
465
+ }) => {
466
+ if (!isMessagePort(messagePort)) {
467
+ throw new IpcError('port must be of type MessagePort');
468
+ }
469
+ if (isMessagePortOpen) {
470
+ return messagePort;
471
+ }
472
+ const eventPromise = getFirstEvent(messagePort, {
473
+ message: Message$1
474
+ });
475
+ messagePort.start();
476
+ const {
477
+ type,
478
+ event
479
+ } = await eventPromise;
480
+ if (type !== Message$1) {
481
+ throw new IpcError('Failed to wait for ipc message');
482
+ }
483
+ if (event.data !== readyMessage) {
484
+ throw new IpcError('unexpected first message');
485
+ }
486
+ return messagePort;
487
+ };
488
+ const signal$1 = messagePort => {
489
+ messagePort.start();
490
+ };
491
+ class IpcParentWithMessagePort extends Ipc {
492
+ getData = getData$2;
493
+ send(message) {
494
+ this._rawIpc.postMessage(message);
495
+ }
496
+ sendAndTransfer(message) {
497
+ const transfer = getTransferrables(message);
498
+ this._rawIpc.postMessage(message, transfer);
499
+ }
500
+ dispose() {
501
+ this._rawIpc.close();
502
+ }
503
+ onMessage(callback) {
504
+ this._rawIpc.addEventListener('message', callback);
505
+ }
506
+ onClose(callback) {}
507
+ }
508
+ const wrap$5 = messagePort => {
509
+ return new IpcParentWithMessagePort(messagePort);
510
+ };
511
+ const IpcParentWithMessagePort$1 = {
512
+ __proto__: null,
513
+ create: create$5$1,
514
+ signal: signal$1,
515
+ wrap: wrap$5
516
+ };
382
517
 
383
518
  const Two = '2.0';
384
519
  const create$4 = (method, params) => {
@@ -389,10 +524,10 @@ const create$4 = (method, params) => {
389
524
  };
390
525
  };
391
526
  const callbacks = Object.create(null);
392
- const set$1 = (id, fn) => {
527
+ const set$2 = (id, fn) => {
393
528
  callbacks[id] = fn;
394
529
  };
395
- const get = id => {
530
+ const get$3 = id => {
396
531
  return callbacks[id];
397
532
  };
398
533
  const remove = id => {
@@ -408,7 +543,7 @@ const registerPromise = () => {
408
543
  resolve,
409
544
  promise
410
545
  } = Promise.withResolvers();
411
- set$1(id, resolve);
546
+ set$2(id, resolve);
412
547
  return {
413
548
  id,
414
549
  promise
@@ -565,7 +700,7 @@ const warn = (...args) => {
565
700
  console.warn(...args);
566
701
  };
567
702
  const resolve = (id, response) => {
568
- const fn = get(id);
703
+ const fn = get$3(id);
569
704
  if (!fn) {
570
705
  console.log(response);
571
706
  warn(`callback ${id} may already be disposed`);
@@ -604,7 +739,7 @@ const getErrorProperty = (error, prettyError) => {
604
739
  }
605
740
  };
606
741
  };
607
- const create$1 = (message, error) => {
742
+ const create$1$1 = (message, error) => {
608
743
  return {
609
744
  jsonrpc: Two,
610
745
  id: message.id,
@@ -615,7 +750,7 @@ const getErrorResponse = (message, error, preparePrettyError, logError) => {
615
750
  const prettyError = preparePrettyError(error);
616
751
  logError(error, prettyError);
617
752
  const errorProperty = getErrorProperty(error, prettyError);
618
- return create$1(message, errorProperty);
753
+ return create$1$1(message, errorProperty);
619
754
  };
620
755
  const create$5 = (message, result) => {
621
756
  return {
@@ -719,10 +854,10 @@ const send = (transport, method, ...params) => {
719
854
  const message = create$4(method, params);
720
855
  transport.send(message);
721
856
  };
722
- const invoke = (ipc, method, ...params) => {
857
+ const invoke$2 = (ipc, method, ...params) => {
723
858
  return invokeHelper(ipc, method, params, false);
724
859
  };
725
- const invokeAndTransfer = (ipc, method, ...params) => {
860
+ const invokeAndTransfer$1 = (ipc, method, ...params) => {
726
861
  return invokeHelper(ipc, method, params, true);
727
862
  };
728
863
 
@@ -752,10 +887,10 @@ const createRpc = ipc => {
752
887
  send(ipc, method, ...params);
753
888
  },
754
889
  invoke(method, ...params) {
755
- return invoke(ipc, method, ...params);
890
+ return invoke$2(ipc, method, ...params);
756
891
  },
757
892
  invokeAndTransfer(method, ...params) {
758
- return invokeAndTransfer(ipc, method, ...params);
893
+ return invokeAndTransfer$1(ipc, method, ...params);
759
894
  },
760
895
  async dispose() {
761
896
  await ipc?.dispose();
@@ -793,7 +928,27 @@ const listen$1 = async (module, options) => {
793
928
  const ipc = module.wrap(rawIpc);
794
929
  return ipc;
795
930
  };
796
- const create = async ({
931
+ const create$8 = async ({
932
+ commandMap,
933
+ messagePort,
934
+ isMessagePortOpen
935
+ }) => {
936
+ // TODO create a commandMap per rpc instance
937
+ register(commandMap);
938
+ const rawIpc = await IpcParentWithMessagePort$1.create({
939
+ messagePort,
940
+ isMessagePortOpen
941
+ });
942
+ const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
943
+ handleIpc(ipc);
944
+ const rpc = createRpc(ipc);
945
+ return rpc;
946
+ };
947
+ const MessagePortRpcParent = {
948
+ __proto__: null,
949
+ create: create$8
950
+ };
951
+ const create$1 = async ({
797
952
  commandMap
798
953
  }) => {
799
954
  // TODO create a commandMap per rpc instance
@@ -805,23 +960,970 @@ const create = async ({
805
960
  };
806
961
  const WebWorkerRpcClient = {
807
962
  __proto__: null,
808
- create
963
+ create: create$1
809
964
  };
810
965
 
811
- const terminate = () => {
812
- globalThis.close();
966
+ const create = () => {
967
+ const states = Object.create(null);
968
+ return {
969
+ get(uid) {
970
+ return states[uid];
971
+ },
972
+ set(uid, oldState, newState) {
973
+ states[uid] = {
974
+ oldState,
975
+ newState
976
+ };
977
+ },
978
+ dispose(uid) {
979
+ delete states[uid];
980
+ },
981
+ getKeys() {
982
+ return Object.keys(states).map(key => {
983
+ return Number.parseInt(key);
984
+ });
985
+ },
986
+ clear() {
987
+ for (const key of Object.keys(states)) {
988
+ delete states[key];
989
+ }
990
+ },
991
+ wrapCommand(fn) {
992
+ const wrapped = async (uid, ...args) => {
993
+ const {
994
+ newState
995
+ } = states[uid];
996
+ const newerState = await fn(newState, ...args);
997
+ if (newState === newerState) {
998
+ return;
999
+ }
1000
+ const latest = states[uid];
1001
+ states[uid] = {
1002
+ oldState: latest.oldState,
1003
+ newState: newerState
1004
+ };
1005
+ };
1006
+ return wrapped;
1007
+ },
1008
+ diff(uid, modules, numbers) {
1009
+ const {
1010
+ oldState,
1011
+ newState
1012
+ } = states[uid];
1013
+ const diffResult = [];
1014
+ for (let i = 0; i < modules.length; i++) {
1015
+ const fn = modules[i];
1016
+ if (!fn(oldState, newState)) {
1017
+ diffResult.push(numbers[i]);
1018
+ }
1019
+ }
1020
+ return diffResult;
1021
+ }
1022
+ };
813
1023
  };
814
1024
 
815
- const commandMap = {
816
- 'SourceControl.terminate': terminate
1025
+ const {
1026
+ get: get$2,
1027
+ set: set$1,
1028
+ wrapCommand
1029
+ } = create();
1030
+
1031
+ const create2 = (id, uri, x, y, width, height, workspacePath) => {
1032
+ const state = {
1033
+ id,
1034
+ root: '',
1035
+ items: [],
1036
+ x,
1037
+ y,
1038
+ width,
1039
+ height,
1040
+ deltaY: 0,
1041
+ minLineY: 0,
1042
+ maxLineY: 0,
1043
+ fileIconCache: Object.create(null),
1044
+ icons: [],
1045
+ finalDeltaY: 0,
1046
+ handleOffset: 0,
1047
+ scrollBarActive: false,
1048
+ scrollBarHeight: 0,
1049
+ merge: [],
1050
+ index: [],
1051
+ untracked: [],
1052
+ workingTree: [],
1053
+ inputValue: '',
1054
+ displayItems: [],
1055
+ buttonIndex: -1,
1056
+ enabledProviderIds: [],
1057
+ isExpanded: true,
1058
+ buttons: [],
1059
+ providerId: '',
1060
+ splitButtonEnabled: false,
1061
+ allGroups: [],
1062
+ gitRoot: '',
1063
+ itemHeight: 20,
1064
+ minimumSliderSize: 20,
1065
+ workspacePath
1066
+ };
1067
+ set$1(id, state, state);
1068
+ };
1069
+
1070
+ const RenderItems = 4;
1071
+
1072
+ const diffType = RenderItems;
1073
+ const isEqual = (oldState, newState) => {
1074
+ return oldState.allGroups === newState.allGroups && oldState.displayItems === newState.displayItems && oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.deltaY === newState.deltaY && oldState.buttonIndex === newState.buttonIndex && oldState.buttons === newState.buttons;
1075
+ };
1076
+
1077
+ const modules = [isEqual];
1078
+ const numbers = [diffType];
1079
+
1080
+ const diff = (oldState, newState) => {
1081
+ const diffResult = [];
1082
+ for (let i = 0; i < modules.length; i++) {
1083
+ const fn = modules[i];
1084
+ if (!fn(oldState, newState)) {
1085
+ diffResult.push(numbers[i]);
1086
+ }
1087
+ }
1088
+ return diffResult;
1089
+ };
1090
+
1091
+ const diff2 = uid => {
1092
+ const {
1093
+ oldState,
1094
+ newState
1095
+ } = get$2(uid);
1096
+ const result = diff(oldState, newState);
1097
+ return result;
1098
+ };
1099
+
1100
+ const commandIds = ['acceptInput', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'focusPrevious', 'handleClick', 'handleClickAt', 'handleIconThemeChange', 'handleWheel'];
1101
+
1102
+ const getCommandIds = () => {
1103
+ return commandIds;
817
1104
  };
818
1105
 
819
1106
  const RendererWorker = 1;
1107
+ const ExtensionHostWorker = 44;
1108
+ const DebugWorker = 55;
820
1109
 
821
1110
  const rpcs = Object.create(null);
822
1111
  const set = (id, rpc) => {
823
1112
  rpcs[id] = rpc;
824
1113
  };
1114
+ const get$1 = id => {
1115
+ return rpcs[id];
1116
+ };
1117
+
1118
+ const invoke$1 = (method, ...params) => {
1119
+ const rpc = get$1(RendererWorker);
1120
+ // @ts-ignore
1121
+ return rpc.invoke(method, ...params);
1122
+ };
1123
+ const invokeAndTransfer = (method, ...params) => {
1124
+ const rpc = get$1(RendererWorker);
1125
+ // @ts-ignore
1126
+ return rpc.invokeAndTransfer(method, ...params);
1127
+ };
1128
+
1129
+ const activateByEvent = event => {
1130
+ return invoke$1('ExtensionHostManagement.activateByEvent', event);
1131
+ };
1132
+
1133
+ const invoke = async (method, ...params) => {
1134
+ const rpc = get$1(ExtensionHostWorker);
1135
+ return rpc.invoke(method, ...params);
1136
+ };
1137
+
1138
+ const executeProvider = async ({
1139
+ event,
1140
+ method,
1141
+ params
1142
+ }) => {
1143
+ await activateByEvent(event);
1144
+ const result = await invoke(method, ...params);
1145
+ return result;
1146
+ };
1147
+
1148
+ const CommandExecute = 'ExtensionHostCommand.executeCommand';
1149
+ const SourceControlGetEnabledProviderIds = 'ExtensionHostSourceControl.getEnabledProviderIds';
1150
+ const SourceControlGetGroups = 'ExtensionHostSourceControl.getGroups';
1151
+
1152
+ const executeCommand = (id, ...args) => {
1153
+ return executeProvider({
1154
+ event: `onCommand:${id}`,
1155
+ method: CommandExecute,
1156
+ params: [id, ...args]
1157
+ });
1158
+ };
1159
+
1160
+ const Directory = 3;
1161
+ const DirectoryExpanded = 4;
1162
+ const File = 7;
1163
+
1164
+ const getFileIcon = ({
1165
+ name
1166
+ }) => {
1167
+ return '';
1168
+ };
1169
+
1170
+ // TODO this should be in FileSystem module
1171
+ const pathBaseName = path => {
1172
+ return path.slice(path.lastIndexOf('/') + 1);
1173
+ };
1174
+
1175
+ const getDisplayItemsGroup = (group, isExpanded) => {
1176
+ const displayItems = [];
1177
+ const {
1178
+ id,
1179
+ label,
1180
+ items
1181
+ } = group;
1182
+ if (!items) {
1183
+ throw new Error('Source control group is missing an items property');
1184
+ }
1185
+ const length = items.length;
1186
+ const type = DirectoryExpanded ;
1187
+ const icon = 'ChevronDown' ;
1188
+ if (length > 0) {
1189
+ displayItems.push({
1190
+ file: '',
1191
+ label,
1192
+ detail: '',
1193
+ posInSet: 1,
1194
+ setSize: 1,
1195
+ icon,
1196
+ decorationIcon: '',
1197
+ decorationIconTitle: '',
1198
+ decorationStrikeThrough: false,
1199
+ type,
1200
+ badgeCount: length,
1201
+ groupId: id
1202
+ });
1203
+ }
1204
+ {
1205
+ for (let i = 0; i < length; i++) {
1206
+ const item = items[i];
1207
+ const {
1208
+ file,
1209
+ icon,
1210
+ iconTitle,
1211
+ strikeThrough
1212
+ } = item;
1213
+ const baseName = pathBaseName(file);
1214
+ const folderName = file.slice(0, -baseName.length - 1);
1215
+ displayItems.push({
1216
+ file,
1217
+ label: baseName,
1218
+ detail: folderName,
1219
+ posInSet: i + 1,
1220
+ setSize: length,
1221
+ icon: getFileIcon({
1222
+ name: file
1223
+ }),
1224
+ decorationIcon: icon,
1225
+ decorationIconTitle: iconTitle,
1226
+ decorationStrikeThrough: strikeThrough,
1227
+ type: File,
1228
+ badgeCount: 0,
1229
+ groupId: id
1230
+ });
1231
+ }
1232
+ }
1233
+ return displayItems;
1234
+ };
1235
+ const getDisplayItems = (allGroups, isExpanded) => {
1236
+ const displayItems = [];
1237
+ for (const group of allGroups) {
1238
+ const groupDisplayItems = getDisplayItemsGroup(group);
1239
+ displayItems.push(...groupDisplayItems);
1240
+ }
1241
+ return displayItems;
1242
+ };
1243
+
1244
+ const getFinalDeltaY = (height, itemHeight, itemsLength) => {
1245
+ const contentHeight = itemsLength * itemHeight;
1246
+ const finalDeltaY = Math.max(contentHeight - height, 0);
1247
+ return finalDeltaY;
1248
+ };
1249
+
1250
+ const getListHeight = (itemsLength, itemHeight, maxHeight) => {
1251
+ number(itemsLength);
1252
+ number(itemHeight);
1253
+ number(maxHeight);
1254
+ if (itemsLength === 0) {
1255
+ return itemHeight;
1256
+ }
1257
+ const totalHeight = itemsLength * itemHeight;
1258
+ return Math.min(totalHeight, maxHeight);
1259
+ };
1260
+
1261
+ // TODO optimize this function to return the minimum number
1262
+ // of visible items needed, e.g. when not scrolled 5 items with
1263
+ // 20px fill 100px but when scrolled 6 items are needed
1264
+ const getNumberOfVisibleItems = (listHeight, itemHeight) => {
1265
+ return Math.ceil(listHeight / itemHeight) + 1;
1266
+ };
1267
+
1268
+ const Disk = 'file';
1269
+
1270
+ const RE_PROTOCOL = /^([a-z-]+):\/\//;
1271
+ const getProtocol = uri => {
1272
+ if (!uri) {
1273
+ return Disk;
1274
+ }
1275
+ const protocolMatch = uri.match(RE_PROTOCOL);
1276
+ if (protocolMatch) {
1277
+ return protocolMatch[1];
1278
+ }
1279
+ return Disk;
1280
+ };
1281
+
1282
+ const get = key => {
1283
+ return false;
1284
+ };
1285
+
1286
+ const getScrollBarSize = (size, contentSize, minimumSliderSize) => {
1287
+ if (size >= contentSize) {
1288
+ return 0;
1289
+ }
1290
+ return Math.max(Math.round(size ** 2 / contentSize), minimumSliderSize);
1291
+ };
1292
+
1293
+ const getGroups$2 = (providerId, path) => {
1294
+ return executeProvider({
1295
+ event: 'none',
1296
+ method: SourceControlGetGroups,
1297
+ params: [providerId, path]
1298
+ // noProviderFoundMessage: 'No source control provider found',
1299
+ });
1300
+ };
1301
+ const getEnabledProviderIds$1 = (scheme, root) => {
1302
+ return executeProvider({
1303
+ event: `onSourceControl:${scheme}`,
1304
+ method: SourceControlGetEnabledProviderIds,
1305
+ params: [scheme, root]
1306
+ // noProviderFoundMessage: 'No source control provider found',
1307
+ });
1308
+ };
1309
+
1310
+ const getEnabledProviderIds = (scheme, root) => {
1311
+ string(scheme);
1312
+ string(root);
1313
+ return getEnabledProviderIds$1(scheme, root);
1314
+ };
1315
+ const getGroups$1 = (providerId, root) => {
1316
+ return getGroups$2(providerId, root);
1317
+ };
1318
+
1319
+ const getExtensions = async () => {
1320
+ return invoke('Extensions.getExtensions');
1321
+ };
1322
+
1323
+ const state = {
1324
+ cache: Object.create(null)
1325
+ };
1326
+ const getContextId = (groupId, type) => {
1327
+ if (type === File) {
1328
+ return `${groupId}-item`;
1329
+ }
1330
+ return groupId;
1331
+ };
1332
+ const ensureActions = async () => {
1333
+ if (Object.keys(state.cache).length > 0) {
1334
+ return;
1335
+ }
1336
+ const extensions = await getExtensions();
1337
+ for (const extension of extensions) {
1338
+ if (extension && extension['source-control-actions']) {
1339
+ for (const [key, value] of Object.entries(extension['source-control-actions'])) {
1340
+ state.cache[key] = value;
1341
+ }
1342
+ }
1343
+ }
1344
+ };
1345
+ const getSourceControlActions = async (providerId, groupId, type) => {
1346
+ string(groupId);
1347
+ await ensureActions();
1348
+ const contextId = getContextId(groupId, type);
1349
+ const value = state.cache[contextId] || [];
1350
+ return value;
1351
+ };
1352
+
1353
+ const getGroups = async enabledProviderIds => {
1354
+ const allGroups = [];
1355
+ for (const providerId of enabledProviderIds) {
1356
+ // @ts-ignore
1357
+ const groups = await getGroups$1(providerId);
1358
+ allGroups.push(...groups);
1359
+ }
1360
+ return {
1361
+ allGroups,
1362
+ gitRoot: ''
1363
+ };
1364
+ };
1365
+ const getNewButtons = async (displayItems, providerId, buttonIndex) => {
1366
+ if (buttonIndex === -1) {
1367
+ return [];
1368
+ }
1369
+ const item = displayItems[buttonIndex];
1370
+ if (!item) {
1371
+ return [];
1372
+ }
1373
+ const actions = await getSourceControlActions(providerId, item.groupId, item.type);
1374
+ return actions;
1375
+ };
1376
+ const loadContent = async state => {
1377
+ const {
1378
+ itemHeight,
1379
+ height,
1380
+ minimumSliderSize,
1381
+ workspacePath
1382
+ } = state;
1383
+ const root = workspacePath;
1384
+ const scheme = getProtocol(root);
1385
+ const enabledProviderIds = await getEnabledProviderIds(scheme, root);
1386
+ const {
1387
+ allGroups,
1388
+ gitRoot
1389
+ } = await getGroups(enabledProviderIds);
1390
+ const isExpanded = true;
1391
+ const items = getDisplayItems(allGroups);
1392
+ const buttons = await getNewButtons(items, state.providerId, state.buttonIndex);
1393
+ const splitButtonEnabled = get();
1394
+ const total = items.length;
1395
+ const contentHeight = total * itemHeight;
1396
+ const listHeight = getListHeight(total, itemHeight, height);
1397
+ const scrollBarHeight = getScrollBarSize(height, contentHeight, minimumSliderSize);
1398
+ const numberOfVisible = getNumberOfVisibleItems(listHeight, itemHeight);
1399
+ const maxLineY = Math.min(numberOfVisible, total);
1400
+ const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
1401
+ return {
1402
+ ...state,
1403
+ allGroups,
1404
+ gitRoot,
1405
+ items,
1406
+ enabledProviderIds,
1407
+ isExpanded,
1408
+ buttons,
1409
+ root,
1410
+ splitButtonEnabled,
1411
+ maxLineY,
1412
+ scrollBarHeight,
1413
+ finalDeltaY
1414
+ };
1415
+ };
1416
+
1417
+ const handleButtonClick = async (state, clickedIndex) => {
1418
+ const {
1419
+ buttonIndex,
1420
+ buttons,
1421
+ items
1422
+ } = state;
1423
+ const button = buttons[clickedIndex];
1424
+ const item = items[buttonIndex];
1425
+ if (!button) {
1426
+ return state;
1427
+ }
1428
+ await executeCommand(button.command, item.file);
1429
+ const newState = await loadContent(state);
1430
+ return newState;
1431
+ };
1432
+
1433
+ const show = async (x, y, id, ...args) => {
1434
+ return invoke$1('ContextMenu.show', x, y, id, ...args);
1435
+ };
1436
+
1437
+ const SourceControl = 22;
1438
+
1439
+ const handleContextMenu = async (state, button, x, y) => {
1440
+ await show(x, y, SourceControl);
1441
+ return state;
1442
+ };
1443
+
1444
+ const getPortTuple = () => {
1445
+ const {
1446
+ port1,
1447
+ port2
1448
+ } = new MessageChannel();
1449
+ return {
1450
+ port1,
1451
+ port2
1452
+ };
1453
+ };
1454
+
1455
+ const sendMessagePortToExtensionHostWorker = async port => {
1456
+ const command = 'HandleMessagePort.handleMessagePort';
1457
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, DebugWorker);
1458
+ };
1459
+
1460
+ const createExtensionHostRpc = async () => {
1461
+ try {
1462
+ const {
1463
+ port1,
1464
+ port2
1465
+ } = getPortTuple();
1466
+ await sendMessagePortToExtensionHostWorker(port2);
1467
+ port1.start();
1468
+ const rpc = await MessagePortRpcParent.create({
1469
+ commandMap: {},
1470
+ messagePort: port1,
1471
+ isMessagePortOpen: false
1472
+ });
1473
+ // TODO createMessageportRpcParent should call port start
1474
+ return rpc;
1475
+ } catch (error) {
1476
+ throw new VError(error, `Failed to create extension host rpc`);
1477
+ }
1478
+ };
1479
+
1480
+ const initialize = async () => {
1481
+ const extensionHostRpc = await createExtensionHostRpc();
1482
+ set(ExtensionHostWorker, extensionHostRpc);
1483
+ };
1484
+
1485
+ const HandleClick = 'handleClick';
1486
+ const HandleContextMenu = 'handleContextMenu';
1487
+ const HandleMouseOut = 'handleMouseOut';
1488
+ const HandleMouseOver = 'handleMouseOver';
1489
+ const HandleWheel = 'handleWheel';
1490
+
1491
+ const None = 'none';
1492
+ const ToolBar = 'toolbar';
1493
+ const Tree = 'tree';
1494
+ const TreeItem$1 = 'treeitem';
1495
+
1496
+ const Actions = 'Actions';
1497
+ const Chevron = 'Chevron';
1498
+ const ChevronRight = 'ChevronRight';
1499
+ const DecorationIcon = 'DecorationIcon';
1500
+ const FileIcon = 'FileIcon';
1501
+ const IconButton = 'IconButton';
1502
+ const InputBox = 'InputBox';
1503
+ const Label = 'Label';
1504
+ const LabelDetail = 'LabelDetail';
1505
+ const MaskIcon = 'MaskIcon';
1506
+ const MaskIconChevronDown = 'MaskIconChevronDown';
1507
+ const SourceControlBadge = 'SourceControlBadge';
1508
+ const SourceControlButton = 'SourceControlButton';
1509
+ const SourceControlHeader = 'SourceControlHeader';
1510
+ const SourceControlItems = 'SourceControlItems';
1511
+ const SplitButton = 'SplitButton';
1512
+ const SplitButtonContent = 'SplitButtonContent';
1513
+ const SplitButtonContentDisabled = 'SplitButtonContentDisabled';
1514
+ const SplitButtonDisabled = 'SplitButtonDisabled';
1515
+ const SplitButtonDropDown = 'SplitButtonDropDown';
1516
+ const SplitButtonDropDownDisabled = 'SplitButtonDropDownDisabled';
1517
+ const SplitButtonSeparator = 'SplitButtonSeparator';
1518
+ const StrikeThrough = 'StrikeThrough';
1519
+ const TreeItem = 'TreeItem';
1520
+
1521
+ const emptySourceControlButtons = [];
1522
+
1523
+ const Button$1 = 1;
1524
+ const Div = 4;
1525
+ const Input = 6;
1526
+ const Span = 8;
1527
+ const Img = 17;
1528
+
1529
+ const Text = 12;
1530
+ const text = data => {
1531
+ return {
1532
+ type: Text,
1533
+ text: data,
1534
+ childCount: 0
1535
+ };
1536
+ };
1537
+
1538
+ const getBadgeVirtualDom = (className, count) => {
1539
+ return [{
1540
+ type: Div,
1541
+ className: `Badge ${className}`,
1542
+ childCount: 1
1543
+ }, text(`${count}`)];
1544
+ };
1545
+
1546
+ const getFileIconVirtualDom = icon => {
1547
+ return {
1548
+ type: Img,
1549
+ className: FileIcon,
1550
+ src: icon,
1551
+ role: None,
1552
+ childCount: 0
1553
+ };
1554
+ };
1555
+
1556
+ const getIconVirtualDom = (icon, type = Div) => {
1557
+ return {
1558
+ type,
1559
+ className: `MaskIcon MaskIcon${icon}`,
1560
+ role: None,
1561
+ childCount: 0
1562
+ };
1563
+ };
1564
+
1565
+ const PaddingLeft = '1rem';
1566
+ const PaddingRight = '12px';
1567
+
1568
+ const getLabelClassName = decorationStrikeThrough => {
1569
+ let className = Label + ' Grow';
1570
+ if (decorationStrikeThrough) {
1571
+ className += ` ${StrikeThrough}`;
1572
+ }
1573
+ return className;
1574
+ };
1575
+ const addButtons = (dom, buttons) => {
1576
+ if (buttons === emptySourceControlButtons) {
1577
+ return;
1578
+ }
1579
+ dom[0].childCount += buttons.length;
1580
+ for (const button of buttons) {
1581
+ const {
1582
+ icon,
1583
+ label
1584
+ } = button;
1585
+ dom.push({
1586
+ type: Button$1,
1587
+ className: SourceControlButton,
1588
+ title: label,
1589
+ ariaLabel: label,
1590
+ childCount: 1
1591
+ }, getIconVirtualDom(icon, Span));
1592
+ }
1593
+ };
1594
+ const createItemDirectory = item => {
1595
+ const {
1596
+ posInSet,
1597
+ setSize,
1598
+ icon,
1599
+ label,
1600
+ badgeCount,
1601
+ decorationStrikeThrough,
1602
+ type,
1603
+ buttons
1604
+ } = item;
1605
+ const labelClassName = getLabelClassName(decorationStrikeThrough);
1606
+ const dom = [{
1607
+ type: Div,
1608
+ className: TreeItem,
1609
+ role: TreeItem$1,
1610
+ ariaExpanded: type === DirectoryExpanded,
1611
+ ariaPosInSet: posInSet,
1612
+ ariaSetSize: setSize,
1613
+ childCount: 3,
1614
+ paddingLeft: PaddingLeft,
1615
+ paddingRight: PaddingRight
1616
+ }, {
1617
+ type: Div,
1618
+ className: `${Chevron} MaskIcon${icon}`,
1619
+ childCount: 0
1620
+ }, {
1621
+ type: Div,
1622
+ className: labelClassName,
1623
+ childCount: 1
1624
+ }, text(label)];
1625
+ addButtons(dom, buttons);
1626
+ dom.push(...getBadgeVirtualDom(SourceControlBadge, badgeCount));
1627
+ return dom;
1628
+ };
1629
+ const createItemOther = item => {
1630
+ const {
1631
+ posInSet,
1632
+ setSize,
1633
+ icon,
1634
+ file,
1635
+ label,
1636
+ decorationIcon,
1637
+ decorationIconTitle,
1638
+ decorationStrikeThrough,
1639
+ detail,
1640
+ buttons
1641
+ } = item;
1642
+ const labelClassName = getLabelClassName(decorationStrikeThrough);
1643
+ /**
1644
+ * @type {any[]}
1645
+ */
1646
+ const dom = [];
1647
+ dom.push({
1648
+ type: Div,
1649
+ className: TreeItem,
1650
+ role: TreeItem$1,
1651
+ ariaPosInSet: posInSet,
1652
+ ariaSetSize: setSize,
1653
+ title: file,
1654
+ childCount: 3,
1655
+ paddingLeft: '1rem',
1656
+ paddingRight: '12px'
1657
+ }, ...(icon === ChevronRight ? [{
1658
+ type: Div,
1659
+ className: Chevron,
1660
+ childCount: 1
1661
+ }, getIconVirtualDom(icon)] : [getFileIconVirtualDom(icon)]));
1662
+ const labelDom = {
1663
+ type: Div,
1664
+ className: labelClassName,
1665
+ childCount: 1
1666
+ };
1667
+ dom.push(labelDom, text(label));
1668
+ if (detail) {
1669
+ labelDom.childCount++;
1670
+ dom.push({
1671
+ type: Span,
1672
+ className: LabelDetail,
1673
+ childCount: 1
1674
+ }, text(detail));
1675
+ }
1676
+ addButtons(dom, buttons);
1677
+ dom.push({
1678
+ type: Img,
1679
+ className: DecorationIcon,
1680
+ title: decorationIconTitle,
1681
+ src: decorationIcon,
1682
+ childCount: 0
1683
+ });
1684
+ return dom;
1685
+ };
1686
+ const getSourceControlItemVirtualDom = item => {
1687
+ switch (item.type) {
1688
+ case DirectoryExpanded:
1689
+ case Directory:
1690
+ return createItemDirectory(item);
1691
+ default:
1692
+ return createItemOther(item);
1693
+ }
1694
+ };
1695
+
1696
+ const getSourceControlItemsVirtualDom$1 = (hasItems, buttonText) => {
1697
+ const dom = [];
1698
+ dom.push({
1699
+ type: Div,
1700
+ className: `${SplitButton} ${hasItems ? '' : SplitButtonDisabled}`,
1701
+ childCount: 3
1702
+ }, {
1703
+ type: Div,
1704
+ className: `${SplitButtonContent} ${hasItems ? '' : SplitButtonContentDisabled}`,
1705
+ childCount: 1,
1706
+ tabIndex: 0
1707
+ }, text(buttonText), {
1708
+ type: Div,
1709
+ className: SplitButtonSeparator,
1710
+ childCount: 0
1711
+ }, {
1712
+ type: Div,
1713
+ className: `${SplitButtonDropDown} ${hasItems ? '' : SplitButtonDropDownDisabled}`,
1714
+ childCount: 1,
1715
+ tabIndex: 0
1716
+ }, {
1717
+ type: Div,
1718
+ className: `${MaskIcon} ${MaskIconChevronDown}`,
1719
+ childCount: 0
1720
+ });
1721
+ return dom;
1722
+ };
1723
+
1724
+ const emptyObject = {};
1725
+ const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1726
+ const i18nString = (key, placeholders = emptyObject) => {
1727
+ if (placeholders === emptyObject) {
1728
+ return key;
1729
+ }
1730
+ const replacer = (match, rest) => {
1731
+ return placeholders[rest];
1732
+ };
1733
+ return key.replaceAll(RE_PLACEHOLDER, replacer);
1734
+ };
1735
+
1736
+ const MessageEnterToCommitOnMaster = `Message (Enter) to commit on 'master'`;
1737
+ const SourceControlInput = 'Source Control Input';
1738
+
1739
+ const messageEnterToCommitOnMaster = () => {
1740
+ return i18nString(MessageEnterToCommitOnMaster);
1741
+ };
1742
+ const sourceControlInput = () => {
1743
+ return i18nString(SourceControlInput);
1744
+ };
1745
+
1746
+ const getSourceControlItemsVirtualDom = (items, splitButtonEnabled) => {
1747
+ const dom = [];
1748
+ dom.push({
1749
+ type: Div,
1750
+ className: SourceControlHeader,
1751
+ childCount: 1
1752
+ }, {
1753
+ type: Input,
1754
+ className: InputBox,
1755
+ spellcheck: false,
1756
+ autocapitalize: 'off',
1757
+ autocorrect: 'off',
1758
+ placeholder: messageEnterToCommitOnMaster(),
1759
+ ariaLabel: sourceControlInput(),
1760
+ childCount: 0,
1761
+ onInput: 'handleInput',
1762
+ onFocus: 'handleFocus'
1763
+ });
1764
+ if (splitButtonEnabled) {
1765
+ const hasItems = items.length > 0;
1766
+ dom.push(...getSourceControlItemsVirtualDom$1(hasItems, 'Commit'));
1767
+ }
1768
+ dom.push({
1769
+ type: Div,
1770
+ className: SourceControlItems,
1771
+ role: Tree,
1772
+ childCount: items.length
1773
+ }, ...items.flatMap(getSourceControlItemVirtualDom));
1774
+ return dom;
1775
+ };
1776
+
1777
+ const getSourceControlVirtualDom = (items, splitButtonEnabled) => {
1778
+ const dom = [{
1779
+ type: Div,
1780
+ className: 'Viewlet SourceControl',
1781
+ tabIndex: 0,
1782
+ onClick: HandleClick,
1783
+ onContextMenu: HandleContextMenu,
1784
+ onMouseOver: HandleMouseOver,
1785
+ onMouseOut: HandleMouseOut,
1786
+ onWheel: HandleWheel,
1787
+ childCount: splitButtonEnabled ? 3 : 2
1788
+ }, ...getSourceControlItemsVirtualDom(items, splitButtonEnabled)];
1789
+ return dom;
1790
+ };
1791
+
1792
+ const getVisibleSourceControlItems = (items, minLineY, maxLineY, buttons, buttonIndex) => {
1793
+ const visible = [];
1794
+ for (let i = minLineY; i < maxLineY; i++) {
1795
+ const item = items[i];
1796
+ const itemButtons = i === buttonIndex ? buttons : emptySourceControlButtons;
1797
+ visible.push({
1798
+ ...item,
1799
+ buttons: itemButtons
1800
+ });
1801
+ }
1802
+ return visible;
1803
+ };
1804
+
1805
+ const renderItems = (oldState, newState) => {
1806
+ const visible = getVisibleSourceControlItems(newState.items, newState.minLineY, newState.maxLineY, newState.buttons, newState.buttonIndex);
1807
+ const dom = getSourceControlVirtualDom(visible, newState.splitButtonEnabled);
1808
+ return ['Viewlet.setDom2', dom];
1809
+ };
1810
+
1811
+ const getRenderer = diffType => {
1812
+ switch (diffType) {
1813
+ case RenderItems:
1814
+ return renderItems;
1815
+ default:
1816
+ throw new Error('unknown renderer');
1817
+ }
1818
+ };
1819
+
1820
+ const applyRender = (oldState, newState, diffResult) => {
1821
+ const commands = [];
1822
+ for (const item of diffResult) {
1823
+ const fn = getRenderer(item);
1824
+ const result = fn(oldState, newState);
1825
+ if (result.length > 0) {
1826
+ commands.push(result);
1827
+ }
1828
+ }
1829
+ return commands;
1830
+ };
1831
+
1832
+ const render2 = (uid, diffResult) => {
1833
+ const {
1834
+ oldState,
1835
+ newState
1836
+ } = get$2(uid);
1837
+ set$1(uid, newState, newState);
1838
+ const commands = applyRender(oldState, newState, diffResult);
1839
+ return commands;
1840
+ };
1841
+
1842
+ const Button = 1;
1843
+
1844
+ const getActionButtonVirtualDom = action => {
1845
+ const {
1846
+ id,
1847
+ icon,
1848
+ command
1849
+ } = action;
1850
+ return [{
1851
+ type: Button$1,
1852
+ className: IconButton,
1853
+ title: id,
1854
+ 'data-command': command,
1855
+ childCount: 1
1856
+ }, getIconVirtualDom(icon)];
1857
+ };
1858
+
1859
+ const getActionVirtualDom = action => {
1860
+ switch (action.type) {
1861
+ case Button:
1862
+ return getActionButtonVirtualDom(action);
1863
+ default:
1864
+ return [];
1865
+ }
1866
+ };
1867
+
1868
+ const getActionsVirtualDom = actions => {
1869
+ return [{
1870
+ type: Div,
1871
+ className: Actions,
1872
+ role: ToolBar,
1873
+ childCount: actions.length
1874
+ }, ...actions.flatMap(getActionVirtualDom)];
1875
+ };
1876
+
1877
+ const renderActions = uid => {
1878
+ const actions = [];
1879
+ const dom = getActionsVirtualDom(actions);
1880
+ return dom;
1881
+ };
1882
+
1883
+ const renderEventListeners = () => {
1884
+ return [{
1885
+ name: HandleWheel,
1886
+ params: ['handleWheel', 'event.deltaMode', 'event.deltaY'],
1887
+ passive: true
1888
+ }];
1889
+ };
1890
+
1891
+ const saveState = uid => {
1892
+ number(uid);
1893
+ const value = get$2(uid);
1894
+ const {
1895
+ newState
1896
+ } = value;
1897
+ const {
1898
+ root,
1899
+ maxLineY
1900
+ } = newState;
1901
+ return {
1902
+ root,
1903
+ minLineY: 0,
1904
+ maxLineY,
1905
+ deltaY: 0
1906
+ };
1907
+ };
1908
+
1909
+ const terminate = () => {
1910
+ globalThis.close();
1911
+ };
1912
+
1913
+ const commandMap = {
1914
+ 'Initialize.initialize': initialize,
1915
+ 'SourceControl.create2': create2,
1916
+ 'SourceControl.diff2': diff2,
1917
+ 'SourceControl.getCommandIds': getCommandIds,
1918
+ 'SourceControl.handleButtonClick': wrapCommand(handleButtonClick),
1919
+ 'SourceControl.handleContextMenu': wrapCommand(handleContextMenu),
1920
+ 'SourceControl.loadContent': wrapCommand(loadContent),
1921
+ 'SourceControl.render2': render2,
1922
+ 'SourceControl.renderActions2': renderActions,
1923
+ 'SourceControl.renderEventListeners': renderEventListeners,
1924
+ 'SourceControl.saveState': saveState,
1925
+ 'SourceControl.terminate': terminate
1926
+ };
825
1927
 
826
1928
  const listen = async () => {
827
1929
  const rpc = await WebWorkerRpcClient.create({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/source-control-worker",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Source Control Worker",
5
5
  "keywords": [
6
6
  "Lvce Editor"