@lvce-editor/extension-search-view 7.7.0 → 7.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -145,7 +145,6 @@ const walkValue = (value, transferrables, isTransferrable) => {
145
145
  for (const property of Object.values(value)) {
146
146
  walkValue(property, transferrables, isTransferrable);
147
147
  }
148
- return;
149
148
  }
150
149
  };
151
150
  const getTransferrables = value => {
@@ -299,7 +298,14 @@ class IpcError extends VError {
299
298
  const cause = new Error(message);
300
299
  // @ts-ignore
301
300
  cause.code = code;
302
- cause.stack = stack;
301
+ if (stack) {
302
+ Object.defineProperty(cause, 'stack', {
303
+ configurable: true,
304
+ enumerable: false,
305
+ value: stack,
306
+ writable: true
307
+ });
308
+ }
303
309
  super(cause, betterMessage);
304
310
  } else {
305
311
  super(betterMessage);
@@ -603,8 +609,10 @@ const getCurrentStack = () => {
603
609
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
604
610
  return currentStack;
605
611
  };
606
- const getNewLineIndex = (string, startIndex = undefined) => {
607
- return string.indexOf(NewLine, startIndex);
612
+ const getNewLineIndex = (string, startIndex) => {
613
+ {
614
+ return string.indexOf(NewLine);
615
+ }
608
616
  };
609
617
  const getParentStack = error => {
610
618
  let parentStack = error.stack || error.data || error.message || '';
@@ -615,55 +623,77 @@ const getParentStack = error => {
615
623
  };
616
624
  const MethodNotFound = -32601;
617
625
  const Custom = -32001;
626
+ const restoreExistingError = (error, currentStack) => {
627
+ if (typeof error.stack === 'string') {
628
+ error.stack = error.stack + NewLine + currentStack;
629
+ }
630
+ return error;
631
+ };
632
+ const restoreMethodNotFoundError = (error, currentStack) => {
633
+ const restoredError = new JsonRpcError(error.message);
634
+ const parentStack = getParentStack(error);
635
+ restoredError.stack = parentStack + NewLine + currentStack;
636
+ return restoredError;
637
+ };
638
+ const restoreStackFromData = (restoredError, error, currentStack) => {
639
+ if (error.data.stack && error.data.type && error.message) {
640
+ restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
641
+ return;
642
+ }
643
+ if (error.data.stack) {
644
+ restoredError.stack = error.data.stack;
645
+ }
646
+ };
647
+ const applyDataProperties = (restoredError, error) => {
648
+ if (!error.data) {
649
+ return;
650
+ }
651
+ restoreStackFromData(restoredError, error, getCurrentStack());
652
+ if (error.data.codeFrame) {
653
+ // @ts-ignore
654
+ restoredError.codeFrame = error.data.codeFrame;
655
+ }
656
+ if (error.data.code) {
657
+ // @ts-ignore
658
+ restoredError.code = error.data.code;
659
+ }
660
+ if (error.data.type) {
661
+ // @ts-ignore
662
+ restoredError.name = error.data.type;
663
+ }
664
+ };
665
+ const applyDirectProperties = (restoredError, error) => {
666
+ if (error.stack) {
667
+ const lowerStack = restoredError.stack || '';
668
+ const indexNewLine = getNewLineIndex(lowerStack);
669
+ const parentStack = getParentStack(error);
670
+ // @ts-ignore
671
+ restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
672
+ }
673
+ if (error.codeFrame) {
674
+ // @ts-ignore
675
+ restoredError.codeFrame = error.codeFrame;
676
+ }
677
+ };
678
+ const restoreMessageError = (error, _currentStack) => {
679
+ const restoredError = constructError(error.message, error.type, error.name);
680
+ if (error.data) {
681
+ applyDataProperties(restoredError, error);
682
+ } else {
683
+ applyDirectProperties(restoredError, error);
684
+ }
685
+ return restoredError;
686
+ };
618
687
  const restoreJsonRpcError = error => {
619
688
  const currentStack = getCurrentStack();
620
689
  if (error && error instanceof Error) {
621
- if (typeof error.stack === 'string') {
622
- error.stack = error.stack + NewLine + currentStack;
623
- }
624
- return error;
690
+ return restoreExistingError(error, currentStack);
625
691
  }
626
692
  if (error && error.code && error.code === MethodNotFound) {
627
- const restoredError = new JsonRpcError(error.message);
628
- const parentStack = getParentStack(error);
629
- restoredError.stack = parentStack + NewLine + currentStack;
630
- return restoredError;
693
+ return restoreMethodNotFoundError(error, currentStack);
631
694
  }
632
695
  if (error && error.message) {
633
- const restoredError = constructError(error.message, error.type, error.name);
634
- if (error.data) {
635
- if (error.data.stack && error.data.type && error.message) {
636
- restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
637
- } else if (error.data.stack) {
638
- restoredError.stack = error.data.stack;
639
- }
640
- if (error.data.codeFrame) {
641
- // @ts-ignore
642
- restoredError.codeFrame = error.data.codeFrame;
643
- }
644
- if (error.data.code) {
645
- // @ts-ignore
646
- restoredError.code = error.data.code;
647
- }
648
- if (error.data.type) {
649
- // @ts-ignore
650
- restoredError.name = error.data.type;
651
- }
652
- } else {
653
- if (error.stack) {
654
- const lowerStack = restoredError.stack || '';
655
- // @ts-ignore
656
- const indexNewLine = getNewLineIndex(lowerStack);
657
- const parentStack = getParentStack(error);
658
- // @ts-ignore
659
- restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
660
- }
661
- if (error.codeFrame) {
662
- // @ts-ignore
663
- restoredError.codeFrame = error.codeFrame;
664
- }
665
- }
666
- return restoredError;
696
+ return restoreMessageError(error);
667
697
  }
668
698
  if (typeof error === 'string') {
669
699
  return new Error(`JsonRpc Error: ${error}`);
@@ -747,7 +777,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
747
777
  const errorProperty = getErrorProperty(error, prettyError);
748
778
  return create$1$1(id, errorProperty);
749
779
  };
750
- const create$9 = (message, result) => {
780
+ const create$a = (message, result) => {
751
781
  return {
752
782
  id: message.id,
753
783
  jsonrpc: Two$1,
@@ -756,7 +786,7 @@ const create$9 = (message, result) => {
756
786
  };
757
787
  const getSuccessResponse = (message, result) => {
758
788
  const resultProperty = result ?? null;
759
- return create$9(message, resultProperty);
789
+ return create$a(message, resultProperty);
760
790
  };
761
791
  const getErrorResponseSimple = (id, error) => {
762
792
  return {
@@ -850,7 +880,7 @@ const handleJsonRpcMessage = async (...args) => {
850
880
 
851
881
  const Two = '2.0';
852
882
 
853
- const create$8 = (method, params) => {
883
+ const create$9 = (method, params) => {
854
884
  return {
855
885
  jsonrpc: Two,
856
886
  method,
@@ -858,7 +888,7 @@ const create$8 = (method, params) => {
858
888
  };
859
889
  };
860
890
 
861
- const create$7 = (id, method, params) => {
891
+ const create$8 = (id, method, params) => {
862
892
  const message = {
863
893
  id,
864
894
  jsonrpc: Two,
@@ -869,12 +899,12 @@ const create$7 = (id, method, params) => {
869
899
  };
870
900
 
871
901
  let id$1 = 0;
872
- const create$6 = () => {
902
+ const create$7 = () => {
873
903
  return ++id$1;
874
904
  };
875
905
 
876
906
  const registerPromise = map => {
877
- const id = create$6();
907
+ const id = create$7();
878
908
  const {
879
909
  promise,
880
910
  resolve
@@ -891,7 +921,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
891
921
  id,
892
922
  promise
893
923
  } = registerPromise(callbacks);
894
- const message = create$7(id, method, params);
924
+ const message = create$8(id, method, params);
895
925
  if (useSendAndTransfer && ipc.sendAndTransfer) {
896
926
  ipc.sendAndTransfer(message);
897
927
  } else {
@@ -927,7 +957,7 @@ const createRpc = ipc => {
927
957
  * @deprecated
928
958
  */
929
959
  send(method, ...params) {
930
- const message = create$8(method, params);
960
+ const message = create$9(method, params);
931
961
  ipc.send(message);
932
962
  }
933
963
  };
@@ -967,7 +997,7 @@ const listen$1 = async (module, options) => {
967
997
  return ipc;
968
998
  };
969
999
 
970
- const create$5 = async ({
1000
+ const create$6 = async ({
971
1001
  commandMap,
972
1002
  isMessagePortOpen = true,
973
1003
  messagePort
@@ -985,7 +1015,7 @@ const create$5 = async ({
985
1015
  return rpc;
986
1016
  };
987
1017
 
988
- const create$4 = async ({
1018
+ const create$5 = async ({
989
1019
  commandMap,
990
1020
  isMessagePortOpen,
991
1021
  send
@@ -995,14 +1025,14 @@ const create$4 = async ({
995
1025
  port2
996
1026
  } = new MessageChannel();
997
1027
  await send(port1);
998
- return create$5({
1028
+ return create$6({
999
1029
  commandMap,
1000
1030
  isMessagePortOpen,
1001
1031
  messagePort: port2
1002
1032
  });
1003
1033
  };
1004
1034
 
1005
- const create$3 = async ({
1035
+ const create$4 = async ({
1006
1036
  commandMap
1007
1037
  }) => {
1008
1038
  // TODO create a commandMap per rpc instance
@@ -1045,7 +1075,7 @@ const remove = id => {
1045
1075
  };
1046
1076
 
1047
1077
  /* eslint-disable @typescript-eslint/explicit-function-return-type */
1048
- const create$2 = rpcId => {
1078
+ const create$3 = rpcId => {
1049
1079
  return {
1050
1080
  async dispose() {
1051
1081
  const rpc = get$1(rpcId);
@@ -1083,18 +1113,182 @@ const create$2 = rpcId => {
1083
1113
 
1084
1114
  const None$3 = 'none';
1085
1115
 
1116
+ const Audio = 0;
1086
1117
  const Button$2 = 1;
1118
+ const Col = 2;
1119
+ const ColGroup = 3;
1087
1120
  const Div = 4;
1121
+ const H1 = 5;
1088
1122
  const Input$1 = 6;
1123
+ const Kbd = 7;
1124
+ const Span = 8;
1125
+ const Table = 9;
1126
+ const TBody = 10;
1127
+ const Td = 11;
1089
1128
  const Text = 12;
1129
+ const Th = 13;
1130
+ const THead = 14;
1131
+ const Tr = 15;
1132
+ const I = 16;
1090
1133
  const Img = 17;
1134
+ const Root = 0;
1135
+ const Ins = 20;
1136
+ const Del = 21;
1137
+ const H2 = 22;
1138
+ const H3 = 23;
1139
+ const H4 = 24;
1140
+ const H5 = 25;
1141
+ const H6 = 26;
1142
+ const Article = 27;
1143
+ const Aside = 28;
1144
+ const Footer = 29;
1145
+ const Header = 30;
1146
+ const Nav = 40;
1147
+ const Section = 41;
1148
+ const Search = 42;
1149
+ const Dd = 43;
1150
+ const Dl = 44;
1151
+ const Figcaption = 45;
1152
+ const Figure = 46;
1153
+ const Hr = 47;
1154
+ const Li = 48;
1155
+ const Ol = 49;
1156
+ const P = 50;
1157
+ const Pre = 51;
1158
+ const A = 53;
1159
+ const Abbr = 54;
1160
+ const Br = 55;
1161
+ const Cite = 56;
1162
+ const Data = 57;
1163
+ const Time = 58;
1164
+ const Tfoot = 59;
1165
+ const Ul = 60;
1166
+ const Video = 61;
1167
+ const TextArea = 62;
1168
+ const Select = 63;
1169
+ const Option$1 = 64;
1170
+ const Code = 65;
1171
+ const Label = 66;
1172
+ const Dt = 67;
1173
+ const Iframe = 68;
1174
+ const Main = 69;
1175
+ const Strong = 70;
1176
+ const Em = 71;
1177
+ const Style = 72;
1178
+ const Html = 73;
1179
+ const Head = 74;
1180
+ const Title = 75;
1181
+ const Meta = 76;
1182
+ const Canvas = 77;
1183
+ const Form = 78;
1184
+ const BlockQuote = 79;
1185
+ const Quote = 80;
1186
+ const Circle = 81;
1187
+ const Defs = 82;
1188
+ const Ellipse = 83;
1189
+ const G = 84;
1190
+ const Line = 85;
1191
+ const Path = 86;
1192
+ const Polygon = 87;
1193
+ const Polyline = 88;
1194
+ const Rect = 89;
1195
+ const Svg = 90;
1196
+ const Use = 91;
1091
1197
  const Reference = 100;
1092
1198
 
1199
+ const VirtualDomElements = {
1200
+ __proto__: null,
1201
+ A,
1202
+ Abbr,
1203
+ Article,
1204
+ Aside,
1205
+ Audio,
1206
+ BlockQuote,
1207
+ Br,
1208
+ Button: Button$2,
1209
+ Canvas,
1210
+ Circle,
1211
+ Cite,
1212
+ Code,
1213
+ Col,
1214
+ ColGroup,
1215
+ Data,
1216
+ Dd,
1217
+ Defs,
1218
+ Del,
1219
+ Div,
1220
+ Dl,
1221
+ Dt,
1222
+ Ellipse,
1223
+ Em,
1224
+ Figcaption,
1225
+ Figure,
1226
+ Footer,
1227
+ Form,
1228
+ G,
1229
+ H1,
1230
+ H2,
1231
+ H3,
1232
+ H4,
1233
+ H5,
1234
+ H6,
1235
+ Head,
1236
+ Header,
1237
+ Hr,
1238
+ Html,
1239
+ I,
1240
+ Iframe,
1241
+ Img,
1242
+ Input: Input$1,
1243
+ Ins,
1244
+ Kbd,
1245
+ Label,
1246
+ Li,
1247
+ Line,
1248
+ Main,
1249
+ Meta,
1250
+ Nav,
1251
+ Ol,
1252
+ Option: Option$1,
1253
+ P,
1254
+ Path,
1255
+ Polygon,
1256
+ Polyline,
1257
+ Pre,
1258
+ Quote,
1259
+ Rect,
1260
+ Reference,
1261
+ Root,
1262
+ Search,
1263
+ Section,
1264
+ Select,
1265
+ Span,
1266
+ Strong,
1267
+ Style,
1268
+ Svg,
1269
+ TBody,
1270
+ THead,
1271
+ Table,
1272
+ Td,
1273
+ Text,
1274
+ TextArea,
1275
+ Tfoot,
1276
+ Th,
1277
+ Time,
1278
+ Title,
1279
+ Tr,
1280
+ Ul,
1281
+ Use,
1282
+ Video
1283
+ };
1284
+
1093
1285
  const Button$1 = 'event.button';
1094
1286
  const ClientX = 'event.clientX';
1095
1287
  const ClientY = 'event.clientY';
1096
1288
  const DeltaMode = 'event.deltaMode';
1097
1289
  const DeltaY = 'event.deltaY';
1290
+ const TargetName = 'event.target.name';
1291
+ const TargetSelectionStart = 'event.target.selectionStart';
1098
1292
  const TargetValue = 'event.target.value';
1099
1293
 
1100
1294
  const Script$1 = 2;
@@ -1116,7 +1310,7 @@ const SetPatches = 'Viewlet.setPatches';
1116
1310
  const {
1117
1311
  invoke: invoke$2,
1118
1312
  set: set$4
1119
- } = create$2(ExtensionHostWorker);
1313
+ } = create$3(ExtensionHostWorker);
1120
1314
 
1121
1315
  const ExtensionHost = {
1122
1316
  __proto__: null,
@@ -1126,13 +1320,13 @@ const ExtensionHost = {
1126
1320
 
1127
1321
  const {
1128
1322
  set: set$3
1129
- } = create$2(ExtensionManagementWorker);
1323
+ } = create$3(ExtensionManagementWorker);
1130
1324
 
1131
1325
  const {
1132
1326
  invoke: invoke$1,
1133
1327
  invokeAndTransfer,
1134
1328
  set: set$2
1135
- } = create$2(RendererWorker);
1329
+ } = create$3(RendererWorker);
1136
1330
  const showContextMenu2 = async (uid, menuId, x, y, args) => {
1137
1331
  number(uid);
1138
1332
  number(menuId);
@@ -1140,6 +1334,12 @@ const showContextMenu2 = async (uid, menuId, x, y, args) => {
1140
1334
  number(y);
1141
1335
  await invoke$1('ContextMenu.show2', uid, menuId, x, y, args);
1142
1336
  };
1337
+ const disableExtension = async id => {
1338
+ return invoke$1('ExtensionManagement.disable', id);
1339
+ };
1340
+ const enableExtension = async id => {
1341
+ return invoke$1('ExtensionManagement.enable', id);
1342
+ };
1143
1343
  const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1144
1344
  const command = 'HandleMessagePort.handleMessagePort2';
1145
1345
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
@@ -1158,16 +1358,82 @@ const sendMessagePortToExtensionManagementWorker = async (port, rpcId) => {
1158
1358
  const openUri$1 = async (uri, focus, options) => {
1159
1359
  await invoke$1('Main.openUri', uri, focus, options);
1160
1360
  };
1361
+ const showErrorDialog = async errorInfo => {
1362
+ await invoke$1('ErrorHandling.showErrorDialog', errorInfo);
1363
+ };
1364
+ const uninstallExtension = async id => {
1365
+ return invoke$1('ExtensionManagement.uninstall', id);
1366
+ };
1367
+ const installExtension = async id => {
1368
+ return invoke$1('ExtensionManagement.install', id);
1369
+ };
1161
1370
 
1162
1371
  const toCommandId = key => {
1163
1372
  const dotIndex = key.indexOf('.');
1164
1373
  return key.slice(dotIndex + 1);
1165
1374
  };
1166
- const create$1 = () => {
1375
+ const create$2 = () => {
1376
+ const commandQueues = new Map();
1377
+ const generations = Object.create(null);
1167
1378
  const states = Object.create(null);
1168
1379
  const commandMapRef = {};
1380
+ const getGeneration = uid => generations[uid] || 0;
1381
+ const isCurrentGeneration = (uid, generation) => {
1382
+ return states[uid] !== undefined && getGeneration(uid) === generation;
1383
+ };
1384
+ const updateState = (uid, generation, fallbackState, updater) => {
1385
+ if (!isCurrentGeneration(uid, generation)) {
1386
+ return Promise.resolve(fallbackState);
1387
+ }
1388
+ const current = states[uid];
1389
+ const updatedState = updater(current.newState);
1390
+ if (updatedState !== current.newState) {
1391
+ states[uid] = {
1392
+ newState: updatedState,
1393
+ oldState: current.oldState,
1394
+ scheduledState: updatedState
1395
+ };
1396
+ }
1397
+ return Promise.resolve(updatedState);
1398
+ };
1399
+ const createAsyncCommandContext = (uid, generation) => {
1400
+ let latestState = states[uid].newState;
1401
+ return {
1402
+ getState: () => {
1403
+ if (isCurrentGeneration(uid, generation)) {
1404
+ latestState = states[uid].newState;
1405
+ }
1406
+ return latestState;
1407
+ },
1408
+ updateState: async updater => {
1409
+ latestState = await updateState(uid, generation, latestState, updater);
1410
+ return latestState;
1411
+ }
1412
+ };
1413
+ };
1414
+ const enqueueCommand = async (uid, command) => {
1415
+ const previous = commandQueues.get(uid) || Promise.resolve();
1416
+ const run = async () => {
1417
+ try {
1418
+ await previous;
1419
+ } catch {
1420
+ // The previous caller receives its error; later commands must still run.
1421
+ }
1422
+ await command();
1423
+ };
1424
+ const current = run();
1425
+ commandQueues.set(uid, current);
1426
+ try {
1427
+ await current;
1428
+ } finally {
1429
+ if (commandQueues.get(uid) === current) {
1430
+ commandQueues.delete(uid);
1431
+ }
1432
+ }
1433
+ };
1169
1434
  return {
1170
1435
  clear() {
1436
+ commandQueues.clear();
1171
1437
  for (const key of Object.keys(states)) {
1172
1438
  delete states[key];
1173
1439
  }
@@ -1187,6 +1453,7 @@ const create$1 = () => {
1187
1453
  return diffResult;
1188
1454
  },
1189
1455
  dispose(uid) {
1456
+ commandQueues.delete(uid);
1190
1457
  delete states[uid];
1191
1458
  },
1192
1459
  get(uid) {
@@ -1204,14 +1471,27 @@ const create$1 = () => {
1204
1471
  Object.assign(commandMapRef, commandMap);
1205
1472
  },
1206
1473
  set(uid, oldState, newState, scheduledState) {
1474
+ const current = states[uid];
1475
+ if (!current || oldState === newState && newState !== current.newState) {
1476
+ generations[uid] = getGeneration(uid) + 1;
1477
+ }
1207
1478
  states[uid] = {
1208
1479
  newState,
1209
1480
  oldState,
1210
1481
  scheduledState: scheduledState ?? newState
1211
1482
  };
1212
1483
  },
1484
+ wrapAsyncCommand(fn) {
1485
+ const wrapped = async (uid, ...args) => {
1486
+ const generation = getGeneration(uid);
1487
+ const context = createAsyncCommandContext(uid, generation);
1488
+ await fn(context, ...args);
1489
+ };
1490
+ return wrapped;
1491
+ },
1213
1492
  wrapCommand(fn) {
1214
1493
  const wrapped = async (uid, ...args) => {
1494
+ const generation = getGeneration(uid);
1215
1495
  const {
1216
1496
  newState,
1217
1497
  oldState
@@ -1220,6 +1500,9 @@ const create$1 = () => {
1220
1500
  if (oldState === newerState || newState === newerState) {
1221
1501
  return;
1222
1502
  }
1503
+ if (!isCurrentGeneration(uid, generation)) {
1504
+ return;
1505
+ }
1223
1506
  const latestOld = states[uid];
1224
1507
  const latestNew = {
1225
1508
  ...latestOld.newState,
@@ -1244,6 +1527,7 @@ const create$1 = () => {
1244
1527
  },
1245
1528
  wrapLoadContent(fn) {
1246
1529
  const wrapped = async (uid, ...args) => {
1530
+ const generation = getGeneration(uid);
1247
1531
  const {
1248
1532
  newState,
1249
1533
  oldState
@@ -1258,6 +1542,11 @@ const create$1 = () => {
1258
1542
  error
1259
1543
  };
1260
1544
  }
1545
+ if (!isCurrentGeneration(uid, generation)) {
1546
+ return {
1547
+ error
1548
+ };
1549
+ }
1261
1550
  const latestOld = states[uid];
1262
1551
  const latestNew = {
1263
1552
  ...latestOld.newState,
@@ -1273,6 +1562,51 @@ const create$1 = () => {
1273
1562
  };
1274
1563
  };
1275
1564
  return wrapped;
1565
+ },
1566
+ wrapSerialAsyncCommand(fn) {
1567
+ const wrapped = async (uid, ...args) => {
1568
+ await enqueueCommand(uid, async () => {
1569
+ if (!states[uid]) {
1570
+ return;
1571
+ }
1572
+ const generation = getGeneration(uid);
1573
+ const context = createAsyncCommandContext(uid, generation);
1574
+ await fn(context, ...args);
1575
+ });
1576
+ };
1577
+ return wrapped;
1578
+ },
1579
+ wrapSerialCommand(fn) {
1580
+ const wrapped = async (uid, ...args) => {
1581
+ await enqueueCommand(uid, async () => {
1582
+ if (!states[uid]) {
1583
+ return;
1584
+ }
1585
+ const generation = getGeneration(uid);
1586
+ const {
1587
+ newState,
1588
+ oldState
1589
+ } = states[uid];
1590
+ const newerState = await fn(newState, ...args);
1591
+ if (oldState === newerState || newState === newerState) {
1592
+ return;
1593
+ }
1594
+ if (!isCurrentGeneration(uid, generation)) {
1595
+ return;
1596
+ }
1597
+ const latestOld = states[uid];
1598
+ const latestNew = {
1599
+ ...latestOld.newState,
1600
+ ...newerState
1601
+ };
1602
+ states[uid] = {
1603
+ newState: latestNew,
1604
+ oldState: latestOld.oldState,
1605
+ scheduledState: latestNew
1606
+ };
1607
+ });
1608
+ };
1609
+ return wrapped;
1276
1610
  }
1277
1611
  };
1278
1612
  };
@@ -1284,21 +1618,84 @@ const None$2 = 0;
1284
1618
  const Input = 1;
1285
1619
  const List$2 = 2;
1286
1620
 
1621
+ const isWhiteSpace = character => {
1622
+ return /\s/.test(character);
1623
+ };
1624
+ const getCompletionRange = (value, cursorOffset) => {
1625
+ const offset = Math.min(Math.max(cursorOffset, 0), value.length);
1626
+ let start = offset;
1627
+ while (start > 0 && !isWhiteSpace(value[start - 1])) {
1628
+ start--;
1629
+ }
1630
+ if (value[start] !== '@') {
1631
+ return undefined;
1632
+ }
1633
+ let end = offset;
1634
+ while (end < value.length && !isWhiteSpace(value[end])) {
1635
+ end++;
1636
+ }
1637
+ return {
1638
+ end,
1639
+ query: value.slice(start, offset),
1640
+ start
1641
+ };
1642
+ };
1643
+
1287
1644
  const handleError = async (error, notify = true, prefix = '') => {
1288
1645
  // @ts-ignore
1289
1646
  console.error(error);
1290
1647
  };
1291
1648
 
1649
+ const loadStates = new Map();
1650
+ const tokenGenerator = {
1651
+ value: 0
1652
+ };
1653
+ const cancel = uid => {
1654
+ const loadState = loadStates.get(uid);
1655
+ if (!loadState) {
1656
+ return;
1657
+ }
1658
+ loadStates.delete(uid);
1659
+ loadState.resolve();
1660
+ };
1661
+ const create$1 = uid => {
1662
+ cancel(uid);
1663
+ const {
1664
+ promise,
1665
+ resolve
1666
+ } = Promise.withResolvers();
1667
+ const token = ++tokenGenerator.value;
1668
+ loadStates.set(uid, {
1669
+ promise,
1670
+ resolve,
1671
+ token
1672
+ });
1673
+ };
1674
+ const finish = (uid, token) => {
1675
+ const loadState = loadStates.get(uid);
1676
+ if (!loadState || loadState.token !== token) {
1677
+ return;
1678
+ }
1679
+ loadStates.delete(uid);
1680
+ loadState.resolve();
1681
+ };
1682
+ const getToken = uid => {
1683
+ return loadStates.get(uid)?.token;
1684
+ };
1685
+ const wait = uid => {
1686
+ return loadStates.get(uid)?.promise || Promise.resolve();
1687
+ };
1688
+
1292
1689
  const emptyObject = {};
1293
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1294
1690
  const i18nString = (key, placeholders = emptyObject) => {
1295
1691
  if (placeholders === emptyObject) {
1296
1692
  return key;
1297
1693
  }
1298
- const replacer = (match, rest) => {
1299
- return placeholders[rest];
1300
- };
1301
- return key.replaceAll(RE_PLACEHOLDER, replacer);
1694
+ let result = key;
1695
+ for (const [placeholder, replacement] of Object.entries(placeholders)) {
1696
+ result = result.split(`{${placeholder}}`).join(String(replacement));
1697
+ }
1698
+ return result;
1302
1699
  };
1303
1700
 
1304
1701
  const NoExtensionsFound = 'No extensions found.';
@@ -1309,30 +1706,38 @@ const Enable = 'Enable';
1309
1706
  const Disable = 'Disable';
1310
1707
  const EnableWorkspace = 'Enable Workspace';
1311
1708
  const DisableWorkspace = 'Disable Workspace';
1709
+ const Uninstall = 'Uninstall';
1710
+ const Install = 'Install';
1711
+ const Installing$1 = 'Installing';
1712
+ const Uninstalling$1 = 'Uninstalling';
1312
1713
  const InstallAnotherVersion = 'Install Another Version';
1313
1714
  const SearchExtensionsInMarketplace = 'Search Extensions in Marketplace';
1314
1715
  const ViewsAndMoreActions = 'Views and more Actions...';
1315
1716
  const Extensions$2 = 'Extensions';
1316
1717
  const Installed$1 = 'Installed';
1718
+ const Marketplace = 'Marketplace';
1317
1719
  const Copy = 'Copy';
1318
1720
  const CopyExtensionId = 'Copy Extension Id';
1319
1721
  const Name = 'Name';
1320
1722
  const Id$1 = 'Id';
1321
1723
  const Description = 'Description';
1724
+ const Downloads = 'Downloads';
1322
1725
  const Version = 'Version';
1323
1726
  const Publisher = 'Publisher';
1727
+ const Rating = 'Rating';
1324
1728
  const MarketplaceLink = 'Marketplace Link';
1325
1729
  const Category$1 = 'Category';
1326
- const Disabled$1 = 'Disabled';
1327
- const Featured = 'Featured';
1328
- const McpServers = 'MCP Servers';
1329
- const MostPopular = 'Most Popular';
1330
- const RecentlyPublished = 'Recently Published';
1331
- const Recommended = 'Recommended';
1730
+ const Disabled$3 = 'Disabled';
1731
+ const Featured$1 = 'Featured';
1732
+ const McpServers$1 = 'MCP Servers';
1733
+ const MostPopular$1 = 'Most Popular';
1734
+ const RecentlyPublished$1 = 'Recently Published';
1735
+ const Recommended$1 = 'Recommended';
1332
1736
  const Updates = 'Updates';
1333
1737
  const BuiltIn = 'Built-in';
1334
- const Enabled$1 = 'Enabled';
1335
- const WorkspaceUnsupported = 'Workspace Unsupported';
1738
+ const Enabled$2 = 'Enabled';
1739
+ const WorkspaceUnsupported$1 = 'Workspace Unsupported';
1740
+ const Deprecated$1 = 'Deprecated';
1336
1741
  const SortBy = 'Sort By';
1337
1742
 
1338
1743
  const noExtensionsFound = () => {
@@ -1350,9 +1755,15 @@ const version = () => {
1350
1755
  const description = () => {
1351
1756
  return i18nString(Description);
1352
1757
  };
1758
+ const downloads = () => {
1759
+ return i18nString(Downloads);
1760
+ };
1353
1761
  const publisher = () => {
1354
1762
  return i18nString(Publisher);
1355
1763
  };
1764
+ const rating = () => {
1765
+ return i18nString(Rating);
1766
+ };
1356
1767
  const marketplaceLink = () => {
1357
1768
  return i18nString(MarketplaceLink);
1358
1769
  };
@@ -1368,10 +1779,10 @@ const extensions = () => {
1368
1779
  const clearExtensionSearchResults = () => {
1369
1780
  return i18nString(ClearExtensionSearchResults);
1370
1781
  };
1371
- const enable$1 = () => {
1782
+ const enable$2 = () => {
1372
1783
  return i18nString(Enable);
1373
1784
  };
1374
- const disable$1 = () => {
1785
+ const disable$2 = () => {
1375
1786
  return i18nString(Disable);
1376
1787
  };
1377
1788
  const enableWorkspace$1 = () => {
@@ -1380,6 +1791,18 @@ const enableWorkspace$1 = () => {
1380
1791
  const disableWorkspace$1 = () => {
1381
1792
  return i18nString(DisableWorkspace);
1382
1793
  };
1794
+ const uninstall$1 = () => {
1795
+ return i18nString(Uninstall);
1796
+ };
1797
+ const install$1 = () => {
1798
+ return i18nString(Install);
1799
+ };
1800
+ const installing$1 = () => {
1801
+ return i18nString(Installing$1);
1802
+ };
1803
+ const uninstalling$1 = () => {
1804
+ return i18nString(Uninstalling$1);
1805
+ };
1383
1806
  const installAnotherVersion$1 = () => {
1384
1807
  return i18nString(InstallAnotherVersion);
1385
1808
  };
@@ -1398,26 +1821,29 @@ const viewsAndMoreActions = () => {
1398
1821
  const installed = () => {
1399
1822
  return i18nString(Installed$1);
1400
1823
  };
1824
+ const marketplace = () => {
1825
+ return i18nString(Marketplace);
1826
+ };
1401
1827
  const category = () => {
1402
1828
  return i18nString(Category$1);
1403
1829
  };
1404
1830
  const disabled = () => {
1405
- return i18nString(Disabled$1);
1831
+ return i18nString(Disabled$3);
1406
1832
  };
1407
1833
  const featured = () => {
1408
- return i18nString(Featured);
1834
+ return i18nString(Featured$1);
1409
1835
  };
1410
1836
  const mcpServers = () => {
1411
- return i18nString(McpServers);
1837
+ return i18nString(McpServers$1);
1412
1838
  };
1413
1839
  const mostPopular = () => {
1414
- return i18nString(MostPopular);
1840
+ return i18nString(MostPopular$1);
1415
1841
  };
1416
1842
  const recentlyPublished = () => {
1417
- return i18nString(RecentlyPublished);
1843
+ return i18nString(RecentlyPublished$1);
1418
1844
  };
1419
1845
  const recommended = () => {
1420
- return i18nString(Recommended);
1846
+ return i18nString(Recommended$1);
1421
1847
  };
1422
1848
  const updates = () => {
1423
1849
  return i18nString(Updates);
@@ -1426,10 +1852,13 @@ const builtIn = () => {
1426
1852
  return i18nString(BuiltIn);
1427
1853
  };
1428
1854
  const enabled = () => {
1429
- return i18nString(Enabled$1);
1855
+ return i18nString(Enabled$2);
1430
1856
  };
1431
1857
  const workspaceUnsupported = () => {
1432
- return i18nString(WorkspaceUnsupported);
1858
+ return i18nString(WorkspaceUnsupported$1);
1859
+ };
1860
+ const deprecated = () => {
1861
+ return i18nString(Deprecated$1);
1433
1862
  };
1434
1863
  const sortBy = () => {
1435
1864
  return i18nString(SortBy);
@@ -1458,6 +1887,12 @@ const HandleTouchStart = 14;
1458
1887
  const HandleWheel = 15;
1459
1888
  const HandleHeaderContextMenu = 16;
1460
1889
  const HandleBlur = 17;
1890
+ const HandleInstall = 19;
1891
+ const HandleUninstall = 20;
1892
+ const HandleEnable = 21;
1893
+ const HandleDisable = 22;
1894
+ const HandleInputFocus = 23;
1895
+ const HandleInputBlur = 24;
1461
1896
 
1462
1897
  const ClearAll = 'ClearAll';
1463
1898
  const Filter = 'Filter';
@@ -1516,15 +1951,22 @@ const getScrollBarY$1 = (delta, finalDelta, size, scrollBarSize) => {
1516
1951
  };
1517
1952
 
1518
1953
  const Installed = '@installed';
1519
- const Enabled = '@enabled';
1520
- const Disabled = '@disabled';
1954
+ const Enabled$1 = '@enabled';
1955
+ const Disabled$2 = '@disabled';
1521
1956
  const Builtin = '@builtin';
1522
1957
  const Sort = '@sort';
1523
1958
  const Id = '@id';
1524
1959
  const Category = '@category';
1525
1960
  const Outdated = '@outdated';
1526
-
1527
- const RE_PARAM = /@\w+(?::\w+)?/g;
1961
+ const Featured = '@featured';
1962
+ const McpServers = '@mcpservers';
1963
+ const MostPopular = '@most-popular';
1964
+ const RecentlyPublished = '@recentlypublished';
1965
+ const Recommended = '@recommended';
1966
+ const WorkspaceUnsupported = '@workspaceunsupported';
1967
+ const Deprecated = '@deprecated';
1968
+
1969
+ const RE_PARAM = /@[\w-]+(?::\w+)?/g;
1528
1970
  const deserializeCategory = value => {
1529
1971
  if (value.startsWith(':"') && value.endsWith('"')) {
1530
1972
  return value.slice(2, -1);
@@ -1553,10 +1995,10 @@ const parseValue = value => {
1553
1995
  if (match.startsWith(Installed)) {
1554
1996
  installed = true;
1555
1997
  }
1556
- if (match.startsWith(Enabled)) {
1998
+ if (match.startsWith(Enabled$1)) {
1557
1999
  enabled = true;
1558
2000
  }
1559
- if (match.startsWith(Disabled)) {
2001
+ if (match.startsWith(Disabled$2)) {
1560
2002
  disabled = true;
1561
2003
  }
1562
2004
  if (match.startsWith(Builtin)) {
@@ -1680,6 +2122,103 @@ const searchExtensions = async (extensions, value, platform, assetDir) => {
1680
2122
  }
1681
2123
  };
1682
2124
 
2125
+ const requestVersions = new Map();
2126
+ const requestVersionGenerator = {
2127
+ value: 0
2128
+ };
2129
+ const getSearchResult = async state => {
2130
+ const {
2131
+ allExtensions,
2132
+ headerHeight,
2133
+ height,
2134
+ itemHeight,
2135
+ minimumSliderSize,
2136
+ searchValue
2137
+ } = state;
2138
+ const value = searchValue.trim();
2139
+ const inputActions = getInputActions(value.length > 0);
2140
+ const items = await searchExtensions(allExtensions, value);
2141
+ if (items.length === 0) {
2142
+ return {
2143
+ deltaY: 0,
2144
+ finalDeltaY: 0,
2145
+ focus: Input,
2146
+ inputActions,
2147
+ items,
2148
+ maxLineY: 0,
2149
+ message: noExtensionsFound(),
2150
+ minLineY: 0,
2151
+ placeholder: searchExtensionsInMarketPlace(),
2152
+ scrollBarHeight: 0
2153
+ };
2154
+ }
2155
+ const total = items.length;
2156
+ const listHeight = getListHeight(total, itemHeight, height - headerHeight);
2157
+ const scrollBarHeight = getScrollBarSize(listHeight, total * itemHeight, minimumSliderSize);
2158
+ const maxLineY = Math.min(getNumberOfVisibleItems$1(listHeight, itemHeight), total);
2159
+ const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
2160
+ const scrollBarY = getScrollBarY$1(0, finalDeltaY, listHeight, scrollBarHeight);
2161
+ return {
2162
+ deltaY: 0,
2163
+ finalDeltaY,
2164
+ focus: state.focus,
2165
+ inputActions,
2166
+ items,
2167
+ maxLineY,
2168
+ message: '',
2169
+ minLineY: 0,
2170
+ placeholder: searchExtensionsInMarketPlace(),
2171
+ scrollBarHeight,
2172
+ scrollBarY
2173
+ };
2174
+ };
2175
+ const handleChangeWithContext = async (context, update, waitForExtensions = true) => {
2176
+ const {
2177
+ uid
2178
+ } = context.getState();
2179
+ if (waitForExtensions) {
2180
+ await wait(uid);
2181
+ }
2182
+ const requestVersion = ++requestVersionGenerator.value;
2183
+ requestVersions.set(uid, requestVersion);
2184
+ const requestState = {
2185
+ ...context.getState(),
2186
+ ...update,
2187
+ initial: false
2188
+ };
2189
+ try {
2190
+ const result = await getSearchResult(requestState);
2191
+ await context.updateState(state => {
2192
+ if (requestVersions.get(state.uid) !== requestVersion) {
2193
+ return state;
2194
+ }
2195
+ return {
2196
+ ...state,
2197
+ ...update,
2198
+ initial: false,
2199
+ ...result
2200
+ };
2201
+ });
2202
+ } catch (error) {
2203
+ await handleError(error);
2204
+ await context.updateState(state => {
2205
+ if (requestVersions.get(state.uid) !== requestVersion) {
2206
+ return state;
2207
+ }
2208
+ return {
2209
+ ...state,
2210
+ ...update,
2211
+ initial: false,
2212
+ message: error instanceof Error ? error.message : String(error)
2213
+ };
2214
+ });
2215
+ } finally {
2216
+ if (requestVersions.get(uid) === requestVersion) {
2217
+ requestVersions.delete(uid);
2218
+ }
2219
+ }
2220
+ };
2221
+
1683
2222
  // TODO debounce
1684
2223
  const handleChange = async (state, update) => {
1685
2224
  const fullNewState = {
@@ -1687,70 +2226,11 @@ const handleChange = async (state, update) => {
1687
2226
  ...update
1688
2227
  };
1689
2228
  try {
1690
- const value = fullNewState.searchValue.trim();
1691
- const {
1692
- inputSource
1693
- } = fullNewState;
1694
- const hasValue = value.length > 0;
1695
- const inputActions = getInputActions(hasValue);
1696
- const {
1697
- allExtensions,
1698
- assetDir,
1699
- headerHeight,
1700
- height,
1701
- itemHeight,
1702
- minimumSliderSize,
1703
- platform
1704
- } = state;
1705
- // TODO cancel ongoing requests
1706
- // TODO handle errors
1707
- const items = await searchExtensions(allExtensions, value, platform, assetDir);
1708
- if (items.length === 0) {
1709
- return {
1710
- ...state,
1711
- allExtensions,
1712
- deltaY: 0,
1713
- finalDeltaY: 0,
1714
- focus: Input,
1715
- inputActions,
1716
- inputSource,
1717
- items,
1718
- maxLineY: 0,
1719
- message: noExtensionsFound(),
1720
- minLineY: 0,
1721
- placeholder: searchExtensionsInMarketPlace(),
1722
- scrollBarHeight: 0,
1723
- searchValue: value
1724
- };
1725
- }
1726
- const total = items.length;
1727
- const availableHeight = height - headerHeight;
1728
- const listHeight = getListHeight(total, itemHeight, availableHeight);
1729
- const contentHeight = total * itemHeight;
1730
- const scrollBarHeight = getScrollBarSize(listHeight, contentHeight, minimumSliderSize);
1731
- const numberOfVisible = getNumberOfVisibleItems$1(listHeight, itemHeight);
1732
- const maxLineY = Math.min(numberOfVisible, total);
1733
- const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
1734
- const scrollBarY = getScrollBarY$1(0, finalDeltaY, listHeight, scrollBarHeight);
2229
+ const result = await getSearchResult(fullNewState);
1735
2230
  return {
1736
- ...state,
1737
- allExtensions,
1738
- deltaY: 0,
1739
- finalDeltaY,
1740
- inputActions,
1741
- inputSource,
1742
- items,
1743
- maxLineY,
1744
- message: '',
1745
- minLineY: 0,
1746
- placeholder: searchExtensionsInMarketPlace(),
1747
- scrollBarHeight,
1748
- scrollBarY,
1749
- searchValue: value
2231
+ ...fullNewState,
2232
+ ...result
1750
2233
  };
1751
-
1752
- // TODO handle out of order responses (a bit complicated)
1753
- // for now just assume everything comes back in order
1754
2234
  } catch (error) {
1755
2235
  // TODO send error to error worker
1756
2236
  await handleError(error);
@@ -1761,17 +2241,71 @@ const handleChange = async (state, update) => {
1761
2241
  }
1762
2242
  };
1763
2243
 
1764
- const clearSearchResults = state => {
2244
+ const User = 1;
2245
+ const Script = 2;
2246
+
2247
+ const acceptCompletionWithContext = async (context, label) => {
2248
+ const state = context.getState();
2249
+ const completion = label || state.completionItems[state.completionFocusedIndex]?.label;
2250
+ if (!completion) {
2251
+ return;
2252
+ }
2253
+ const range = getCompletionRange(state.searchValue, state.cursorOffset);
2254
+ if (!range) {
2255
+ return;
2256
+ }
2257
+ const searchValue = `${state.searchValue.slice(0, range.start)}${completion}${state.searchValue.slice(range.end)}`;
2258
+ await handleChangeWithContext(context, {
2259
+ completionFocusedIndex: 0,
2260
+ completionItems: [],
2261
+ cursorOffset: range.start + completion.length,
2262
+ focus: Input,
2263
+ inputSource: Script,
2264
+ searchValue,
2265
+ suggestOpen: false
2266
+ });
2267
+ };
2268
+ const acceptCompletion = async (state, label) => {
2269
+ const completion = label || state.completionItems[state.completionFocusedIndex]?.label;
2270
+ if (!completion) {
2271
+ return state;
2272
+ }
2273
+ const range = getCompletionRange(state.searchValue, state.cursorOffset);
2274
+ if (!range) {
2275
+ return state;
2276
+ }
2277
+ const searchValue = `${state.searchValue.slice(0, range.start)}${completion}${state.searchValue.slice(range.end)}`;
1765
2278
  return handleChange(state, {
1766
- ...state,
2279
+ completionFocusedIndex: 0,
2280
+ completionItems: [],
2281
+ cursorOffset: range.start + completion.length,
2282
+ focus: Input,
2283
+ inputSource: Script,
2284
+ searchValue,
2285
+ suggestOpen: false
2286
+ });
2287
+ };
2288
+
2289
+ const clearSearchResultsWithContext = async context => {
2290
+ await handleChangeWithContext(context, {
2291
+ completionFocusedIndex: 0,
2292
+ completionItems: [],
2293
+ cursorOffset: 0,
1767
2294
  focus: Input,
1768
2295
  inputSource: Script$1,
1769
- searchValue: ''
2296
+ searchValue: '',
2297
+ suggestOpen: false
1770
2298
  });
1771
2299
  };
1772
2300
 
1773
2301
  const closeSuggest = state => {
1774
- return state;
2302
+ if (!state.suggestOpen) {
2303
+ return state;
2304
+ }
2305
+ return {
2306
+ ...state,
2307
+ suggestOpen: false
2308
+ };
1775
2309
  };
1776
2310
 
1777
2311
  const getFocusedItem = state => {
@@ -1855,14 +2389,18 @@ const {
1855
2389
  getCommandIds,
1856
2390
  registerCommands,
1857
2391
  set: set$1,
2392
+ wrapAsyncCommand,
1858
2393
  wrapCommand,
1859
2394
  wrapGetter
1860
- } = create$1();
2395
+ } = create$2();
1861
2396
 
1862
- const create = (id, uri, x, y, width, height, platform, assetDir) => {
2397
+ const create = (id, uri, x, y, width, height, platform, assetDir, parentUid) => {
1863
2398
  const state = {
1864
2399
  allExtensions: [],
1865
2400
  assetDir,
2401
+ completionFocusedIndex: 0,
2402
+ completionItems: [],
2403
+ cursorOffset: 0,
1866
2404
  deltaY: 0,
1867
2405
  finalDeltaY: 0,
1868
2406
  focus: 0,
@@ -1881,11 +2419,13 @@ const create = (id, uri, x, y, width, height, platform, assetDir) => {
1881
2419
  minimumSliderSize: 0,
1882
2420
  minLineY: 0,
1883
2421
  negativeMargin: 0,
2422
+ parentUid,
1884
2423
  placeholder: '',
1885
2424
  platform,
1886
2425
  scrollBarActive: false,
1887
2426
  scrollBarHeight: 0,
1888
2427
  scrollBarY: 0,
2428
+ scrollSensitivity: 1,
1889
2429
  searchValue: '',
1890
2430
  size: 0,
1891
2431
  suggestOpen: false,
@@ -1894,29 +2434,31 @@ const create = (id, uri, x, y, width, height, platform, assetDir) => {
1894
2434
  x,
1895
2435
  y
1896
2436
  };
2437
+ create$1(id);
1897
2438
  set$1(id, state, state);
1898
2439
  };
1899
2440
 
1900
- const isEqual$3 = (oldState, newState) => {
1901
- return oldState.scrollBarHeight === newState.scrollBarHeight && oldState.scrollBarY === newState.scrollBarY && oldState.initial === newState.initial && oldState.deltaY === newState.deltaY;
2441
+ const isEqual$4 = (oldState, newState) => {
2442
+ return oldState.cursorOffset === newState.cursorOffset && oldState.scrollBarHeight === newState.scrollBarHeight && oldState.scrollBarY === newState.scrollBarY && oldState.initial === newState.initial && oldState.deltaY === newState.deltaY && oldState.width === newState.width;
1902
2443
  };
1903
2444
 
1904
- const isEqual$2 = (oldState, newState) => {
2445
+ const isEqual$3 = (oldState, newState) => {
1905
2446
  if (!newState.focus) {
1906
2447
  return true;
1907
2448
  }
1908
2449
  return oldState.focus === newState.focus && oldState.inputSource === newState.inputSource;
1909
2450
  };
1910
2451
 
1911
- const isEqual$1 = (oldState, newState) => {
1912
- return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex && oldState.message === newState.message && oldState.focus === newState.focus && oldState.inputActions === newState.inputActions && oldState.placeholder === newState.placeholder;
2452
+ const isEqual$2 = (oldState, newState) => {
2453
+ return oldState.completionFocusedIndex === newState.completionFocusedIndex && oldState.completionItems === newState.completionItems && oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex && oldState.message === newState.message && oldState.focus === newState.focus && oldState.inputActions === newState.inputActions && oldState.placeholder === newState.placeholder && oldState.suggestOpen === newState.suggestOpen;
1913
2454
  };
1914
2455
 
1915
- const User = 1;
1916
- const Script = 2;
2456
+ const isEqual$1 = (oldState, newState) => {
2457
+ return newState.inputSource === User || oldState.searchValue === newState.searchValue;
2458
+ };
1917
2459
 
1918
2460
  const isEqual = (oldState, newState) => {
1919
- return newState.inputSource === User || oldState.searchValue === newState.searchValue;
2461
+ return newState.parentUid === undefined || oldState.searchValue === newState.searchValue;
1920
2462
  };
1921
2463
 
1922
2464
  const RenderHeader = 1;
@@ -1928,15 +2470,16 @@ const RenderSearchValue = 7;
1928
2470
  const RenderFocusContext = 8;
1929
2471
  const RenderIncremental = 9;
1930
2472
  const RenderCss = 10;
2473
+ const RenderTitle = 11;
1931
2474
 
1932
- const modules = [isEqual$1, isEqual$2, isEqual, isEqual$2, isEqual$3];
1933
- const numbers = [RenderIncremental, RenderFocus, RenderSearchValue, RenderFocusContext, RenderCss];
2475
+ const modules = [isEqual$2, isEqual$3, isEqual$1, isEqual$3, isEqual$4, isEqual];
2476
+ const numbers = [RenderIncremental, RenderFocus, RenderSearchValue, RenderFocusContext, RenderCss, RenderTitle];
1934
2477
 
1935
2478
  const diff2 = uid => {
1936
2479
  return diff(uid, modules, numbers);
1937
2480
  };
1938
2481
 
1939
- const disable = async (state, _id) => {
2482
+ const disable$1 = async (state, _id) => {
1940
2483
  await confirm('not implemented');
1941
2484
  return state;
1942
2485
  };
@@ -1947,10 +2490,11 @@ const disableWorkspace = async (state, _id) => {
1947
2490
  };
1948
2491
 
1949
2492
  const dispose = uid => {
2493
+ cancel(uid);
1950
2494
  dispose$1(uid);
1951
2495
  };
1952
2496
 
1953
- const enable = async (state, _id) => {
2497
+ const enable$1 = async (state, _id) => {
1954
2498
  await confirm('not implemented');
1955
2499
  return state;
1956
2500
  };
@@ -1960,45 +2504,118 @@ const enableWorkspace = async (state, _id) => {
1960
2504
  return state;
1961
2505
  };
1962
2506
 
1963
- // TODO optimize this function to return the minimum number
1964
- // of visible items needed, e.g. when not scrolled 5 items with
1965
- // 20px fill 100px but when scrolled 6 items are needed
1966
- const getNumberOfVisibleItems = (listHeight, itemHeight) => {
1967
- return Math.ceil(listHeight / itemHeight) + 1;
2507
+ const getFuzzyHighlights = (label, query) => {
2508
+ const lowerLabel = label.toLowerCase();
2509
+ const lowerQuery = query.toLowerCase();
2510
+ const matchedIndexes = [];
2511
+ let labelIndex = 0;
2512
+ for (const character of lowerQuery) {
2513
+ labelIndex = lowerLabel.indexOf(character, labelIndex);
2514
+ if (labelIndex === -1) {
2515
+ return undefined;
2516
+ }
2517
+ matchedIndexes.push(labelIndex);
2518
+ labelIndex++;
2519
+ }
2520
+ const highlights = [];
2521
+ for (const index of matchedIndexes) {
2522
+ const lastEnd = highlights.at(-1);
2523
+ if (lastEnd === index) {
2524
+ highlights[highlights.length - 1] = index + 1;
2525
+ } else {
2526
+ highlights.push(index, index + 1);
2527
+ }
2528
+ }
2529
+ return highlights;
1968
2530
  };
1969
- const getScrollBarOffset = (delta, finalDelta, size, scrollBarSize) => {
1970
- const scrollBarOffset = delta / finalDelta * (size - scrollBarSize);
1971
- return scrollBarOffset;
2531
+
2532
+ const Suggestions = ['@builtin', '@category:', '@disabled', '@enabled', '@featured', '@id:', '@installed', '@mcpservers', '@most-popular', '@outdated', '@recentlypublished', '@recommended', '@sort:installs', '@workspaceunsupported'];
2533
+
2534
+ const getCompletionItems = (value, cursorOffset) => {
2535
+ const range = getCompletionRange(value, cursorOffset);
2536
+ if (!range) {
2537
+ return [];
2538
+ }
2539
+ const items = [];
2540
+ for (const label of Suggestions) {
2541
+ const highlights = getFuzzyHighlights(label, range.query);
2542
+ if (highlights) {
2543
+ items.push({
2544
+ highlights,
2545
+ label
2546
+ });
2547
+ }
2548
+ }
2549
+ return items;
1972
2550
  };
1973
- const getScrollBarY = getScrollBarOffset;
1974
- const focusIndexScrollDown = (state, index, listHeight, itemHeight, itemsLength) => {
1975
- const {
1976
- finalDeltaY,
1977
- height,
2551
+
2552
+ const handleInputWithContext = async (context, value, inputSource = User, cursorOffset = value.length) => {
2553
+ const completionItems = getCompletionItems(value, cursorOffset);
2554
+ await handleChangeWithContext(context, {
2555
+ completionFocusedIndex: 0,
2556
+ completionItems,
2557
+ cursorOffset,
2558
+ focus: Input,
2559
+ inputSource,
2560
+ searchValue: value,
2561
+ suggestOpen: inputSource === User && completionItems.length > 0
2562
+ });
2563
+ };
2564
+
2565
+ const addFilter = (searchValue, filter) => {
2566
+ const values = searchValue.trim().split(/\s+/);
2567
+ if (values.includes(filter)) {
2568
+ return searchValue;
2569
+ }
2570
+ return `${searchValue.trim()} ${filter}`.trim();
2571
+ };
2572
+ const filterByMostPopularWithContext = async context => {
2573
+ const {
2574
+ searchValue
2575
+ } = context.getState();
2576
+ const value = addFilter(searchValue, MostPopular);
2577
+ await handleInputWithContext(context, value, Script);
2578
+ };
2579
+
2580
+ // TODO optimize this function to return the minimum number
2581
+ // of visible items needed, e.g. when not scrolled 5 items with
2582
+ // 20px fill 100px but when scrolled 6 items are needed
2583
+ const getNumberOfVisibleItems = (listHeight, itemHeight) => {
2584
+ return Math.ceil(listHeight / itemHeight) + 1;
2585
+ };
2586
+ const getScrollBarOffset = (delta, finalDelta, size, scrollBarSize) => {
2587
+ const scrollBarOffset = delta / finalDelta * (size - scrollBarSize);
2588
+ return scrollBarOffset;
2589
+ };
2590
+ const getScrollBarY = getScrollBarOffset;
2591
+ const focusIndexScrollDown = (state, index, listHeight, itemHeight, itemsLength) => {
2592
+ const {
2593
+ finalDeltaY,
1978
2594
  headerHeight,
2595
+ height,
1979
2596
  scrollBarHeight
1980
2597
  } = state;
1981
- const newMaxLineY = Math.min(index + 1, itemsLength);
1982
2598
  const fittingItems = getNumberOfVisibleItems(listHeight, itemHeight);
1983
- const newMinLineY = Math.max(newMaxLineY - fittingItems, 0);
1984
- const newDeltaY = itemsLength < fittingItems ? 0 : newMinLineY * itemHeight - listHeight % itemHeight + itemHeight;
2599
+ const newDeltaY = Math.min(Math.max((index + 1) * itemHeight - listHeight, 0), finalDeltaY);
2600
+ const newMinLineY = Math.floor(newDeltaY / itemHeight);
2601
+ const newMaxLineY = Math.min(newMinLineY + fittingItems, itemsLength);
1985
2602
  const scrollBarY = getScrollBarY(newDeltaY, finalDeltaY, height - headerHeight, scrollBarHeight);
1986
2603
  return {
1987
2604
  ...state,
2605
+ deltaY: newDeltaY,
2606
+ focused: true,
1988
2607
  focusedIndex: index,
1989
2608
  listFocusedIndex: index,
1990
- minLineY: newMinLineY,
1991
2609
  maxLineY: newMaxLineY,
1992
- focused: true,
1993
- deltaY: newDeltaY,
2610
+ minLineY: newMinLineY,
1994
2611
  scrollBarY
1995
2612
  };
1996
2613
  };
1997
2614
  const focusIndexScrollUp = (state, index, listHeight, itemHeight, itemsLength) => {
1998
2615
  const {
1999
2616
  finalDeltaY,
2000
- height,
2001
2617
  headerHeight,
2618
+ height,
2002
2619
  scrollBarHeight
2003
2620
  } = state;
2004
2621
  const newMinLineY = index;
@@ -2008,23 +2625,23 @@ const focusIndexScrollUp = (state, index, listHeight, itemHeight, itemsLength) =
2008
2625
  const scrollBarY = getScrollBarY(newDeltaY, finalDeltaY, height - headerHeight, scrollBarHeight);
2009
2626
  return {
2010
2627
  ...state,
2628
+ deltaY: newDeltaY,
2629
+ focused: true,
2011
2630
  focusedIndex: index,
2012
2631
  listFocusedIndex: index,
2013
- minLineY: newMinLineY,
2014
2632
  maxLineY: newMaxLineY,
2015
- focused: true,
2016
- deltaY: newDeltaY,
2633
+ minLineY: newMinLineY,
2017
2634
  scrollBarY
2018
2635
  };
2019
2636
  };
2020
2637
  const focusIndex = (state, index) => {
2021
2638
  const {
2022
- itemHeight,
2023
- minLineY,
2024
- maxLineY,
2025
2639
  headerHeight,
2026
2640
  height,
2027
- items
2641
+ itemHeight,
2642
+ items,
2643
+ maxLineY,
2644
+ minLineY
2028
2645
  } = state;
2029
2646
  const itemsLength = items.length;
2030
2647
  if (itemsLength === 0) {
@@ -2034,9 +2651,9 @@ const focusIndex = (state, index) => {
2034
2651
  if (index === -1) {
2035
2652
  return {
2036
2653
  ...state,
2654
+ focused: true,
2037
2655
  focusedIndex: -1,
2038
- listFocusedIndex: -1,
2039
- focused: true
2656
+ listFocusedIndex: -1
2040
2657
  };
2041
2658
  }
2042
2659
  const listHeight = height - headerHeight;
@@ -2048,9 +2665,9 @@ const focusIndex = (state, index) => {
2048
2665
  }
2049
2666
  return {
2050
2667
  ...state,
2668
+ focused: true,
2051
2669
  focusedIndex: index,
2052
- listFocusedIndex: index,
2053
- focused: true
2670
+ listFocusedIndex: index
2054
2671
  };
2055
2672
  };
2056
2673
  const first = () => {
@@ -2063,7 +2680,7 @@ const next = (items, index) => {
2063
2680
  return (index + 1) % items.length;
2064
2681
  };
2065
2682
  const previous = (items, index) => {
2066
- return index === 0 ? items.length - 1 : index - 1;
2683
+ return (index === 0 ? items.length : index) - 1;
2067
2684
  };
2068
2685
  const focusFirst = state => {
2069
2686
  const firstIndex = first();
@@ -2120,8 +2737,8 @@ const focusPrevious = state => {
2120
2737
  const focusPreviousPage = state => {
2121
2738
  const {
2122
2739
  focusedIndex,
2123
- minLineY,
2124
- maxLineY
2740
+ maxLineY,
2741
+ minLineY
2125
2742
  } = state;
2126
2743
  if (focusedIndex === 0 || focusedIndex === -1) {
2127
2744
  return state;
@@ -2145,6 +2762,7 @@ const getActions = () => {
2145
2762
  };
2146
2763
 
2147
2764
  const Enter = 3;
2765
+ const Escape = 8;
2148
2766
  const Space = 9;
2149
2767
  const PageUp = 10;
2150
2768
  const PageDown = 11;
@@ -2160,6 +2778,26 @@ const FocusExtensionsInput = 7000;
2160
2778
 
2161
2779
  const getKeyBindings = () => {
2162
2780
  return [{
2781
+ command: 'Extensions.closeSuggest',
2782
+ key: Escape,
2783
+ when: FocusExtensionsInput
2784
+ }, {
2785
+ command: 'Extensions.acceptCompletion',
2786
+ key: Enter,
2787
+ when: FocusExtensionsInput
2788
+ }, {
2789
+ command: 'Extensions.selectPreviousCompletion',
2790
+ key: UpArrow,
2791
+ when: FocusExtensionsInput
2792
+ }, {
2793
+ command: 'Extensions.selectNextCompletion',
2794
+ key: DownArrow,
2795
+ when: FocusExtensionsInput
2796
+ }, {
2797
+ command: 'Extensions.openSuggest',
2798
+ key: CtrlCmd | Space,
2799
+ when: FocusExtensionsInput
2800
+ }, {
2163
2801
  command: 'Extensions.focusFirst',
2164
2802
  key: Home,
2165
2803
  when: FocusExtensions
@@ -2202,19 +2840,45 @@ const getKeyBindings = () => {
2202
2840
  }];
2203
2841
  };
2204
2842
 
2843
+ const Disabled$1 = 'disabled';
2844
+ const Enabled = 'enabled';
2845
+ const Installing = 'installing';
2846
+ const NotInstalled = 'not-installed';
2847
+ const Uninstalling = 'uninstalling';
2848
+ const statuses = [Disabled$1, Enabled, Installing, NotInstalled, Uninstalling];
2849
+ const isExtensionStatus = status => {
2850
+ return statuses.includes(status);
2851
+ };
2852
+
2205
2853
  const Separator = 1;
2206
2854
  const None$1 = 0;
2207
2855
  const SubMenu = 4;
2856
+ const Disabled = 5;
2208
2857
 
2209
- const getMenuEntriesList = () => {
2858
+ const nonEnableableStatuses = [Installing, NotInstalled, Uninstalling];
2859
+ const getEnablementFlags = (disabled, status) => {
2860
+ if (status && nonEnableableStatuses.includes(status)) {
2861
+ return {
2862
+ disable: Disabled,
2863
+ enable: Disabled
2864
+ };
2865
+ }
2866
+ const isDisabled = status === Disabled$1 || status === undefined && disabled;
2867
+ return {
2868
+ disable: isDisabled ? Disabled : None$1,
2869
+ enable: isDisabled ? None$1 : Disabled
2870
+ };
2871
+ };
2872
+ const getMenuEntriesList = (builtin, disabled = false, status) => {
2873
+ const enablementFlags = getEnablementFlags(disabled, status);
2210
2874
  return [{
2211
2875
  command: 'SearchExtensions.enable',
2212
- flags: None$1,
2876
+ flags: enablementFlags.enable,
2213
2877
  id: 'enable',
2214
- label: enable$1()
2878
+ label: enable$2()
2215
2879
  }, {
2216
2880
  command: 'SearchExtensions.enableWorkspace',
2217
- flags: None$1,
2881
+ flags: enablementFlags.enable,
2218
2882
  id: 'enableWorkspace',
2219
2883
  label: enableWorkspace$1()
2220
2884
  }, {
@@ -2224,12 +2888,12 @@ const getMenuEntriesList = () => {
2224
2888
  label: ''
2225
2889
  }, {
2226
2890
  command: 'SearchExtensions.disable',
2227
- flags: None$1,
2891
+ flags: enablementFlags.disable,
2228
2892
  id: 'disable',
2229
- label: disable$1()
2893
+ label: disable$2()
2230
2894
  }, {
2231
2895
  command: 'SearchExtensions.disableWorkspace',
2232
- flags: None$1,
2896
+ flags: enablementFlags.disable,
2233
2897
  id: 'disableWorkspace',
2234
2898
  label: disableWorkspace$1()
2235
2899
  }, {
@@ -2239,7 +2903,7 @@ const getMenuEntriesList = () => {
2239
2903
  label: ''
2240
2904
  }, {
2241
2905
  command: 'SearchExtensions.installAnotherVersion',
2242
- flags: None$1,
2906
+ flags: builtin ? Disabled : None$1,
2243
2907
  id: 'installAnotherVersion',
2244
2908
  label: installAnotherVersion$1()
2245
2909
  }, {
@@ -2267,7 +2931,7 @@ const getMenuEntriesFilter = () => {
2267
2931
  id: 'filterByMcpServers',
2268
2932
  label: mcpServers()
2269
2933
  }, {
2270
- command: 'SearchExtensions.filterByMostPopular',
2934
+ command: 'Extensions.filterByMostPopular',
2271
2935
  flags: None$1,
2272
2936
  id: 'filterByMostPopular',
2273
2937
  label: mostPopular()
@@ -2342,7 +3006,7 @@ const getMenuEntries2 = (state, props) => {
2342
3006
  case ExtensionSearchFilter:
2343
3007
  return getMenuEntriesFilter();
2344
3008
  default:
2345
- return getMenuEntriesList();
3009
+ return getMenuEntriesList(props.builtin, props.disabled, props.status);
2346
3010
  }
2347
3011
  };
2348
3012
 
@@ -2353,7 +3017,8 @@ const getMenuIds = () => {
2353
3017
  const handleBlur = state => {
2354
3018
  return {
2355
3019
  ...state,
2356
- focus: None$2
3020
+ focus: None$2,
3021
+ suggestOpen: false
2357
3022
  };
2358
3023
  };
2359
3024
 
@@ -2365,6 +3030,13 @@ const openUri = async uri => {
2365
3030
  return openUri$1(uri);
2366
3031
  };
2367
3032
 
3033
+ const selectIndex = (state, index) => {
3034
+ return {
3035
+ ...state,
3036
+ focusedIndex: index
3037
+ };
3038
+ };
3039
+
2368
3040
  const handleClick = async (state, index) => {
2369
3041
  const {
2370
3042
  items,
@@ -2381,7 +3053,7 @@ const handleClick = async (state, index) => {
2381
3053
  const extension = items[actualIndex];
2382
3054
  const uri = getExtensionDetailUri(extension.id);
2383
3055
  await openUri(uri);
2384
- const partialNewState = focusIndex(state, actualIndex);
3056
+ const partialNewState = selectIndex(state, actualIndex);
2385
3057
  const newState = {
2386
3058
  ...partialNewState,
2387
3059
  focus: List$2
@@ -2401,6 +3073,8 @@ const text = data => {
2401
3073
  };
2402
3074
  };
2403
3075
 
3076
+ new Set(Object.values(VirtualDomElements));
3077
+
2404
3078
  const SetText = 1;
2405
3079
  const Replace = 2;
2406
3080
  const SetAttribute = 3;
@@ -2669,7 +3343,20 @@ const getListIndex = (eventX, eventY, x, y, deltaY, itemHeight, headerHeight) =>
2669
3343
  return index;
2670
3344
  };
2671
3345
 
2672
- const handleClickAt = async (state, button, eventX, eventY) => {
3346
+ const handleCompletionPointerDown = (state, label) => {
3347
+ if (state.completionItems.every(item => item.label !== label)) {
3348
+ return Promise.resolve(state);
3349
+ }
3350
+ return acceptCompletion(state, label);
3351
+ };
3352
+
3353
+ const handleClickAt = async (state, button, eventX, eventY, name = '') => {
3354
+ if (name.startsWith('@')) {
3355
+ return handleCompletionPointerDown(state, name);
3356
+ }
3357
+ if (name) {
3358
+ return state;
3359
+ }
2673
3360
  if (button !== LeftClick) {
2674
3361
  return state;
2675
3362
  }
@@ -2735,22 +3422,48 @@ const handleContextMenu = async (state, button, eventX, eventY) => {
2735
3422
  return state;
2736
3423
  }
2737
3424
  await show2(uid, ManageExtension, eventX, eventY, {
2738
- menuId: ManageExtension
3425
+ builtin: items[index]?.builtin === true,
3426
+ disabled: items[index]?.disabled === true,
3427
+ menuId: ManageExtension,
3428
+ status: items[index]?.status
2739
3429
  });
2740
3430
  return state;
2741
3431
  };
2742
3432
 
2743
- const handleDisable = (state, id) => {
2744
- return state;
2745
- // TODO
3433
+ const updateStatus = (extension, id, status, builtin) => {
3434
+ if (extension.id !== id) {
3435
+ return extension;
3436
+ }
3437
+ return {
3438
+ ...extension,
3439
+ builtin: builtin ?? extension.builtin,
3440
+ disabled: status === Disabled$1,
3441
+ status
3442
+ };
3443
+ };
3444
+ const setExtensionStatus = (state, id, status, builtin) => {
3445
+ if (!isExtensionStatus(status)) {
3446
+ throw new TypeError(`Invalid extension status: ${status}`);
3447
+ }
3448
+ return {
3449
+ ...state,
3450
+ allExtensions: state.allExtensions.map(extension => updateStatus(extension, id, status, builtin)),
3451
+ items: state.items.map(extension => updateStatus(extension, id, status, builtin))
3452
+ };
3453
+ };
3454
+
3455
+ const handleDisable = async (state, id) => {
3456
+ const error = await disableExtension(id);
3457
+ return error ? state : setExtensionStatus(state, id, Disabled$1);
2746
3458
  };
2747
3459
 
2748
3460
  const handleDisableWorkspace = (state, id) => {
2749
3461
  return state;
2750
3462
  };
2751
3463
 
2752
- const handleEnable = (state, id) => {
2753
- return state;
3464
+ const handleEnable = async (state, id) => {
3465
+ const error = await enableExtension(id);
3466
+ return error ? state : setExtensionStatus(state, id, Enabled);
2754
3467
  };
2755
3468
 
2756
3469
  const handleEnableWorkspace = (state, id) => {
@@ -2768,17 +3481,16 @@ const handleHeaderContextMenu = async state => {
2768
3481
  return state;
2769
3482
  };
2770
3483
 
2771
- const handleInput = async (state, value, inputSource = User) => {
2772
- return handleChange(state, {
2773
- inputSource,
2774
- searchValue: value
2775
- });
3484
+ const handleInputFocus = state => {
3485
+ return {
3486
+ ...state,
3487
+ focus: Input
3488
+ };
2776
3489
  };
2777
3490
 
2778
- // TODO show error / warning when installment fails / times out
2779
3491
  const handleInstall = async (state, id) => {
2780
- return state;
2781
- // TODO
3492
+ await installExtension(id);
3493
+ return setExtensionStatus(state, id, Enabled);
2782
3494
  };
2783
3495
 
2784
3496
  const handleScrollBarCaptureLost = state => {
@@ -2934,20 +3646,28 @@ const handleSettingsButtonClick = async (state, index) => {
2934
3646
  const menuY = itemY + itemHeight - 10; // Position at the bottom of the extension item
2935
3647
 
2936
3648
  await show2(uid, ManageExtension, menuX, menuY, {
2937
- menuId: ManageExtension
3649
+ builtin: items[actualIndex].builtin === true,
3650
+ disabled: items[actualIndex].disabled === true,
3651
+ menuId: ManageExtension,
3652
+ status: items[actualIndex].status
2938
3653
  });
2939
3654
  return state;
2940
3655
  };
2941
3656
 
2942
- // TODO show error / warning when installment fails / times out
2943
3657
  const handleUninstall = async (state, id) => {
2944
- return state;
3658
+ try {
3659
+ await uninstallExtension(id);
3660
+ return setExtensionStatus(state, id, NotInstalled);
3661
+ } catch (error) {
3662
+ await showErrorDialog(error);
3663
+ return state;
3664
+ }
2945
3665
  };
2946
3666
 
2947
3667
  const handleWheel = (state, deltaMode, deltaY) => {
2948
3668
  number(deltaMode);
2949
3669
  number(deltaY);
2950
- return setDeltaY(state, state.deltaY + deltaY);
3670
+ return setDeltaY(state, state.deltaY + deltaY * state.scrollSensitivity);
2951
3671
  };
2952
3672
 
2953
3673
  const sendMessagePortToExtensionHostWorker = async port => {
@@ -2956,7 +3676,7 @@ const sendMessagePortToExtensionHostWorker = async port => {
2956
3676
 
2957
3677
  const createExtensionHostWorkerRpc = async () => {
2958
3678
  try {
2959
- const rpc = await create$4({
3679
+ const rpc = await create$5({
2960
3680
  commandMap: {},
2961
3681
  send: sendMessagePortToExtensionHostWorker
2962
3682
  });
@@ -2978,7 +3698,7 @@ const initializeExtensionHostWorker = async () => {
2978
3698
 
2979
3699
  const createExtensionManagementWorkerRpc = async () => {
2980
3700
  try {
2981
- const rpc = await create$4({
3701
+ const rpc = await create$5({
2982
3702
  commandMap: {},
2983
3703
  send: port => sendMessagePortToExtensionManagementWorker(port, 0)
2984
3704
  });
@@ -3041,6 +3761,11 @@ const getViewletSize = width => {
3041
3761
  return Large;
3042
3762
  };
3043
3763
 
3764
+ const getIsFirefox = () => {
3765
+ const globalWithNavigator = globalThis;
3766
+ return globalWithNavigator.navigator?.userAgent.toLowerCase().includes('firefox') ?? false;
3767
+ };
3768
+
3044
3769
  const getRemoteUrl = (extension, platform, assetDir) => {
3045
3770
  if (platform === Remote || platform === Electron) {
3046
3771
  if (extension.builtin) {
@@ -3086,6 +3811,37 @@ const getExtensionIcon = (extension, platform, assetDir) => {
3086
3811
  return getRemoteUrl(extension, platform, assetDir);
3087
3812
  };
3088
3813
 
3814
+ const getDownloadCountValue = extension => {
3815
+ return extension?.downloadCount ?? extension?.downloads ?? extension?.marketplace?.downloadCount ?? extension?.marketplace?.downloads ?? extension?.packageJSON?.downloadCount ?? extension?.packageJSON?.downloads;
3816
+ };
3817
+ const getDownloadCount = extension => {
3818
+ const downloadCount = getDownloadCountValue(extension);
3819
+ if (typeof downloadCount !== 'number') {
3820
+ return 'n/a';
3821
+ }
3822
+ return downloadCount.toLocaleString();
3823
+ };
3824
+
3825
+ const getRatingValue = extension => {
3826
+ return extension?.rating ?? extension?.averageRating ?? extension?.marketplace?.rating ?? extension?.marketplace?.averageRating ?? extension?.packageJSON?.rating ?? extension?.packageJSON?.averageRating;
3827
+ };
3828
+ const getRating = extension => {
3829
+ const rating = getRatingValue(extension);
3830
+ if (typeof rating !== 'number') {
3831
+ return 'n/a';
3832
+ }
3833
+ return rating.toFixed(1);
3834
+ };
3835
+
3836
+ const getBuiltin = extension => {
3837
+ return extension?.builtin === true;
3838
+ };
3839
+ const getDisabled = extension => {
3840
+ return extension?.disabled === true;
3841
+ };
3842
+ const getStatus = extension => {
3843
+ return typeof extension?.status === 'string' ? extension.status : undefined;
3844
+ };
3089
3845
  const getIcon = (extension, platform, assetDir) => {
3090
3846
  return getExtensionIcon(extension, platform, assetDir);
3091
3847
  };
@@ -3149,13 +3905,18 @@ const getPublisher = extension => {
3149
3905
 
3150
3906
  const normalizeExtension = (extension, platform, assetDir) => {
3151
3907
  return {
3908
+ builtin: getBuiltin(extension),
3152
3909
  categories: getCategories(extension),
3153
3910
  description: getDescription(extension),
3911
+ disabled: getDisabled(extension),
3912
+ downloadCount: getDownloadCount(extension),
3154
3913
  icon: getIcon(extension, platform, assetDir),
3155
3914
  id: getId$1(extension),
3156
3915
  name: getName(extension),
3157
3916
  publisher: getPublisher(extension),
3917
+ rating: getRating(extension),
3158
3918
  size: getSize(extension),
3919
+ status: getStatus(extension),
3159
3920
  updatedDate: getUpdatedDate(extension),
3160
3921
  uri: ''
3161
3922
  };
@@ -3187,44 +3948,78 @@ const restoreState = savedState => {
3187
3948
  };
3188
3949
  };
3189
3950
 
3190
- const loadContent = async (state, savedState) => {
3191
- const {
3192
- assetDir,
3193
- platform,
3194
- width
3195
- } = state;
3951
+ const loadContentWithContext = async (context, savedState) => {
3196
3952
  const {
3197
- deltaY,
3198
- searchValue
3199
- } = restoreState(savedState);
3200
- // TODO just get local extensions on demand (not when query string is already different)
3201
- const allExtensions = await getAllExtensions(platform);
3202
- const size = getViewletSize(width);
3203
- const normalized = normalizeExtensions(allExtensions, platform, assetDir);
3204
- const updatedState = await handleInput({
3205
- ...state,
3206
- allExtensions: normalized,
3207
- deltaY,
3208
- initial: false,
3209
- inputSource: Script,
3210
- size
3211
- }, searchValue, Script);
3212
- return updatedState;
3953
+ uid
3954
+ } = context.getState();
3955
+ const loadToken = getToken(uid);
3956
+ try {
3957
+ const initialState = context.getState();
3958
+ const {
3959
+ assetDir,
3960
+ platform,
3961
+ width
3962
+ } = initialState;
3963
+ const {
3964
+ deltaY,
3965
+ searchValue: restoredSearchValue
3966
+ } = restoreState(savedState);
3967
+ const size = getViewletSize(width);
3968
+ const scrollSensitivity = getIsFirefox() ? 2.5 : 1;
3969
+ await context.updateState(state => {
3970
+ if (!state.initial) {
3971
+ return state;
3972
+ }
3973
+ return {
3974
+ ...state,
3975
+ deltaY,
3976
+ initial: false,
3977
+ inputSource: Script,
3978
+ scrollSensitivity,
3979
+ searchValue: restoredSearchValue,
3980
+ size
3981
+ };
3982
+ });
3983
+ const allExtensions = await getAllExtensions(platform);
3984
+ const normalized = normalizeExtensions(allExtensions, platform, assetDir);
3985
+ await context.updateState(state => ({
3986
+ ...state,
3987
+ allExtensions: normalized
3988
+ }));
3989
+ await handleChangeWithContext(context, {}, false);
3990
+ } finally {
3991
+ finish(uid, loadToken);
3992
+ }
3213
3993
  };
3214
3994
 
3215
3995
  const openSuggest = state => {
3216
- return state;
3996
+ const completionItems = getCompletionItems(state.searchValue, state.cursorOffset);
3997
+ if (completionItems.length === 0) {
3998
+ return state;
3999
+ }
4000
+ return {
4001
+ ...state,
4002
+ completionFocusedIndex: 0,
4003
+ completionItems,
4004
+ suggestOpen: true
4005
+ };
3217
4006
  };
3218
4007
 
3219
4008
  const getCss = state => {
3220
4009
  const {
4010
+ cursorOffset,
3221
4011
  deltaY,
4012
+ headerHeight,
3222
4013
  itemHeight,
3223
4014
  scrollBarHeight,
3224
- scrollBarY
4015
+ scrollBarY,
4016
+ width
3225
4017
  } = state;
3226
4018
  const relative = -(deltaY % itemHeight);
3227
4019
  const roundedScrollBarY = Math.round(scrollBarY);
4020
+ const maximumCompletionLeft = Math.max(8, width - 168);
4021
+ const completionLeft = Math.min(Math.round(8 + cursorOffset * 7.5), maximumCompletionLeft);
4022
+ const completionTop = Math.max(0, headerHeight - 10);
3228
4023
  return `.Extensions .ScrollBarThumb {
3229
4024
  height: ${scrollBarHeight}px;
3230
4025
  translate: 0 ${roundedScrollBarY}px;
@@ -3247,6 +4042,79 @@ const getCss = state => {
3247
4042
  gap: 0;
3248
4043
  overflow-y: hidden;
3249
4044
  }
4045
+
4046
+ .ExtensionHeader {
4047
+ contain: layout style;
4048
+ position: relative;
4049
+ z-index: 1;
4050
+ }
4051
+
4052
+ .ExtensionListItemFooter {
4053
+ justify-content: flex-end;
4054
+ padding-right: 2px;
4055
+ }
4056
+
4057
+ .ExtensionListItemAuthorName {
4058
+ flex: 1;
4059
+ }
4060
+
4061
+ .ExtensionActions {
4062
+ display: flex;
4063
+ gap: 6px;
4064
+ }
4065
+
4066
+ .ExtensionActionButton {
4067
+ padding: 0 5px;
4068
+ }
4069
+
4070
+ .ExtensionSearchCompletionWidget {
4071
+ position: absolute;
4072
+ left: ${completionLeft}px;
4073
+ top: ${completionTop}px;
4074
+ width: min(320px, calc(100% - ${completionLeft + 8}px));
4075
+ max-height: 240px;
4076
+ overflow-y: auto;
4077
+ z-index: 10;
4078
+ box-sizing: border-box;
4079
+ border: 1px solid var(--CompletionListBorder, #95a29d);
4080
+ background: var(--CompletionListBackground, #282e2f);
4081
+ color: var(--CompletionListForeground, white);
4082
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.36);
4083
+ font-size: 13px;
4084
+ line-height: 20px;
4085
+ user-select: none;
4086
+ }
4087
+
4088
+ .ExtensionSearchCompletionItem {
4089
+ display: block;
4090
+ width: 100%;
4091
+ min-height: 20px;
4092
+ padding: 0 6px;
4093
+ border: 0;
4094
+ background: transparent;
4095
+ color: inherit;
4096
+ font: inherit;
4097
+ line-height: inherit;
4098
+ text-align: left;
4099
+ overflow: hidden;
4100
+ text-overflow: ellipsis;
4101
+ white-space: nowrap;
4102
+ cursor: pointer;
4103
+ }
4104
+
4105
+ .ExtensionSearchCompletionItem:hover {
4106
+ background: var(--CompletionListItemHoverBackground, rgba(64, 92, 80, 0.2));
4107
+ }
4108
+
4109
+ .ExtensionSearchCompletionItemFocused {
4110
+ background: var(--CompletionListItemActiveBackground, #405c50);
4111
+ color: var(--CompletionListItemActiveForeground);
4112
+ }
4113
+
4114
+ .ExtensionSearchCompletionHighlight {
4115
+ color: var(--CompletionHighlightForeground, #e1b974);
4116
+ font-weight: 700;
4117
+ }
3250
4118
  `;
3251
4119
  };
3252
4120
 
@@ -3295,21 +4163,39 @@ const renderFocusContext = newState => {
3295
4163
  return [];
3296
4164
  };
3297
4165
 
4166
+ const ComboBox = 'combobox';
4167
+ const List$1 = 'list';
4168
+ const ListBox = 'listbox';
4169
+ const ListItem = 'listitem';
4170
+ const None = 'none';
4171
+ const Option = 'option';
4172
+ const ToolBar = 'toolbar';
4173
+
3298
4174
  const Actions = 'Actions';
3299
4175
  const ExtensionActions = 'ExtensionActions';
4176
+ const ExtensionActionButton = 'ExtensionActionButton';
3300
4177
  const ExtensionActive = 'ExtensionActive';
3301
4178
  const ExtensionHeader = 'ExtensionHeader';
3302
4179
  const ExtensionListItem = 'ExtensionListItem';
4180
+ const ExtensionListItemActionInstall = 'ExtensionListItemActionInstall';
3303
4181
  const ExtensionListItemAuthorName = 'ExtensionListItemAuthorName';
3304
4182
  const ExtensionListItemDescription = 'ExtensionListItemDescription';
3305
4183
  const ExtensionListItemDetail = 'ExtensionListItemDetail';
4184
+ const ExtensionListItemDownloadCount = 'ExtensionListItemDownloadCount';
3306
4185
  const ExtensionListItemFooter = 'ExtensionListItemFooter';
3307
4186
  const ExtensionListItemIcon = 'ExtensionListItemIcon';
4187
+ const ExtensionListItemMetadata = 'ExtensionListItemMetadata';
3308
4188
  const ExtensionListItemName = 'ExtensionListItemName';
4189
+ const ExtensionListItemRating = 'ExtensionListItemRating';
4190
+ const ExtensionListItemStatistic = 'ExtensionListItemStatistic';
4191
+ const ExtensionSearchCompletionHighlight = 'ExtensionSearchCompletionHighlight';
4192
+ const ExtensionSearchCompletionItem = 'ExtensionSearchCompletionItem';
4193
+ const ExtensionSearchCompletionItemFocused = 'ExtensionSearchCompletionItemFocused';
4194
+ const ExtensionSearchCompletionWidget = 'ExtensionSearchCompletionWidget';
3309
4195
  const Extensions = 'Extensions';
3310
4196
  const FocusOutline = 'FocusOutline';
3311
4197
  const IconButton = 'IconButton';
3312
- const List$1 = 'List';
4198
+ const List = 'List';
3313
4199
  const ListItems = 'ListItems';
3314
4200
  const MaskIcon = 'MaskIcon';
3315
4201
  const MultilineInputBox = 'MultilineInputBox';
@@ -3325,10 +4211,73 @@ const SearchFieldButtons = 'SearchFieldButtons';
3325
4211
  const SearchFieldContainer = 'SearchFieldContainer';
3326
4212
  const Viewlet = 'Viewlet';
3327
4213
 
3328
- const List = 'list';
3329
- const ListItem = 'listitem';
3330
- const None = 'none';
3331
- const ToolBar = 'toolbar';
4214
+ const getCompletionLabelVirtualDom = (label, highlights) => {
4215
+ const dom = [];
4216
+ let position = 0;
4217
+ for (let i = 0; i < highlights.length; i += 2) {
4218
+ const start = highlights[i];
4219
+ const end = highlights[i + 1];
4220
+ if (position < start) {
4221
+ dom.push(text(label.slice(position, start)));
4222
+ }
4223
+ dom.push({
4224
+ childCount: 1,
4225
+ className: ExtensionSearchCompletionHighlight,
4226
+ name: label,
4227
+ type: Span
4228
+ }, text(label.slice(start, end)));
4229
+ position = end;
4230
+ }
4231
+ if (position < label.length) {
4232
+ dom.push(text(label.slice(position)));
4233
+ }
4234
+ return dom;
4235
+ };
4236
+
4237
+ const getRootNodeCount = nodes => {
4238
+ let count = 0;
4239
+ const remainingChildCounts = [];
4240
+ for (const node of nodes) {
4241
+ while (remainingChildCounts.length > 0 && remainingChildCounts.at(-1) === 0) {
4242
+ remainingChildCounts.pop();
4243
+ }
4244
+ if (remainingChildCounts.length === 0) {
4245
+ count++;
4246
+ } else {
4247
+ const lastIndex = remainingChildCounts.length - 1;
4248
+ remainingChildCounts[lastIndex]--;
4249
+ }
4250
+ remainingChildCounts.push(node.childCount);
4251
+ }
4252
+ return count;
4253
+ };
4254
+ const getCompletionItemVirtualDom = (item, index, focusedIndex) => {
4255
+ const labelDom = getCompletionLabelVirtualDom(item.label, item.highlights);
4256
+ const focused = index === focusedIndex;
4257
+ return [{
4258
+ ariaSelected: focused,
4259
+ childCount: getRootNodeCount(labelDom),
4260
+ className: focused ? mergeClassNames(ExtensionSearchCompletionItem, ExtensionSearchCompletionItemFocused) : ExtensionSearchCompletionItem,
4261
+ id: `ExtensionSearchCompletion-${index}`,
4262
+ name: item.label,
4263
+ onPointerDown: HandlePointerDown,
4264
+ role: Option,
4265
+ type: Button$2
4266
+ }, ...labelDom];
4267
+ };
4268
+
4269
+ const getCompletionWidgetVirtualDom = (items, focusedIndex) => {
4270
+ return [{
4271
+ ariaLabel: 'Extension search completions',
4272
+ childCount: items.length,
4273
+ className: ExtensionSearchCompletionWidget,
4274
+ id: 'ExtensionSearchCompletions',
4275
+ role: ListBox,
4276
+ type: Div
4277
+ }, ...items.flatMap((item, index) => getCompletionItemVirtualDom(item, index, focusedIndex))];
4278
+ };
4279
+
4280
+ const Focusable = 0;
3332
4281
 
3333
4282
  const disabledClassName = mergeClassNames(SearchFieldButton, SearchFieldButtonDisabled);
3334
4283
  const getClassName$1 = enabled => {
@@ -3348,7 +4297,7 @@ const getSearchFieldButtonVirtualDom = button => {
3348
4297
  childCount: 1,
3349
4298
  className: getClassName$1(enabled),
3350
4299
  onClick,
3351
- tabIndex: 0,
4300
+ tabIndex: Focusable,
3352
4301
  title,
3353
4302
  type: Button$2
3354
4303
  }, {
@@ -3358,14 +4307,15 @@ const getSearchFieldButtonVirtualDom = button => {
3358
4307
  }];
3359
4308
  };
3360
4309
 
3361
- const getSearchFieldVirtualDom = (name, placeholder, onInput, insideButtons, outsideButtons, onFocus = '') => {
4310
+ const searchFieldNode = {
4311
+ childCount: 2,
4312
+ className: SearchField,
4313
+ role: None,
4314
+ type: Div
4315
+ };
4316
+ const getSearchFieldVirtualDom = (name, placeholder, onInput, insideButtons, outsideButtons, onFocus = '', onBlur = '', inputProperties = {}) => {
3362
4317
  // TODO avoid mutation
3363
- const dom = [{
3364
- childCount: 2,
3365
- className: SearchField,
3366
- role: None,
3367
- type: Div
3368
- }, {
4318
+ const dom = [searchFieldNode, {
3369
4319
  autocapitalize: 'off',
3370
4320
  autocomplete: 'off',
3371
4321
  autocorrect: 'off',
@@ -3373,11 +4323,15 @@ const getSearchFieldVirtualDom = (name, placeholder, onInput, insideButtons, out
3373
4323
  className: MultilineInputBox,
3374
4324
  inputType: 'search',
3375
4325
  name,
4326
+ ...(onBlur && {
4327
+ onBlur
4328
+ }),
3376
4329
  onFocus,
3377
4330
  onInput,
3378
4331
  placeholder,
3379
4332
  spellcheck: false,
3380
- type: Input$1
4333
+ type: Input$1,
4334
+ ...inputProperties
3381
4335
  }, {
3382
4336
  childCount: insideButtons.length,
3383
4337
  className: SearchFieldButtons,
@@ -3395,24 +4349,117 @@ const getSearchFieldVirtualDom = (name, placeholder, onInput, insideButtons, out
3395
4349
  return dom;
3396
4350
  };
3397
4351
 
3398
- const parentNode = {
3399
- childCount: 1,
3400
- className: ExtensionHeader,
3401
- onContextMenu: HandleHeaderContextMenu,
3402
- type: Div
3403
- };
3404
- const getExtensionHeaderVirtualDom = (placeholder, actions) => {
3405
- return [parentNode, ...getSearchFieldVirtualDom(Extensions$1, placeholder, HandleExtensionsInput, actions, [])];
4352
+ const getExtensionHeaderVirtualDom = (placeholder, actions, completionItems = [], completionFocusedIndex = 0, suggestOpen = false) => {
4353
+ const inputProperties = suggestOpen ? {
4354
+ ariaActivedescendant: `ExtensionSearchCompletion-${completionFocusedIndex}`,
4355
+ ariaAutoComplete: 'list',
4356
+ ariaControls: 'ExtensionSearchCompletions',
4357
+ ariaExpanded: true,
4358
+ role: ComboBox
4359
+ } : {
4360
+ ariaAutoComplete: 'list',
4361
+ ariaExpanded: false,
4362
+ role: ComboBox
4363
+ };
4364
+ return [{
4365
+ childCount: suggestOpen ? 2 : 1,
4366
+ className: ExtensionHeader,
4367
+ onContextMenu: HandleHeaderContextMenu,
4368
+ type: Div
4369
+ }, ...getSearchFieldVirtualDom(Extensions$1, placeholder, HandleExtensionsInput, actions, [], HandleInputFocus, HandleInputBlur, inputProperties), ...(suggestOpen ? getCompletionWidgetVirtualDom(completionItems, completionFocusedIndex) : [])];
3406
4370
  };
3407
4371
 
3408
4372
  const renderHeader = newState => {
3409
4373
  const actions = getInputActions(newState.searchValue.length > 0);
3410
- const dom = getExtensionHeaderVirtualDom(newState.placeholder, actions);
4374
+ const dom = getExtensionHeaderVirtualDom(newState.placeholder, actions, newState.completionItems, newState.completionFocusedIndex, newState.suggestOpen);
3411
4375
  return ['setHeaderDom', dom];
3412
4376
  };
3413
4377
 
3414
4378
  const Extension = 'Extension';
3415
4379
 
4380
+ const install = {
4381
+ disabled: false,
4382
+ label: install$1(),
4383
+ onClick: HandleInstall
4384
+ };
4385
+ const installing = {
4386
+ disabled: true,
4387
+ label: installing$1(),
4388
+ onClick: HandleInstall
4389
+ };
4390
+ const enable = {
4391
+ disabled: false,
4392
+ label: enable$2(),
4393
+ onClick: HandleEnable
4394
+ };
4395
+ const disable = {
4396
+ disabled: false,
4397
+ label: disable$2(),
4398
+ onClick: HandleDisable
4399
+ };
4400
+ const uninstall = {
4401
+ disabled: false,
4402
+ label: uninstall$1(),
4403
+ onClick: HandleUninstall
4404
+ };
4405
+ const uninstalling = {
4406
+ disabled: true,
4407
+ label: uninstalling$1(),
4408
+ onClick: HandleUninstall
4409
+ };
4410
+ const getExtensionActions = (builtin, disabled, status) => {
4411
+ if (status === NotInstalled) {
4412
+ return [install];
4413
+ }
4414
+ if (status === Installing) {
4415
+ return [installing];
4416
+ }
4417
+ if (status === Uninstalling) {
4418
+ return builtin ? [] : [uninstalling];
4419
+ }
4420
+ const enableOrDisable = status === Disabled$1 || status === undefined && disabled ? enable : disable;
4421
+ return builtin ? [enableOrDisable] : [enableOrDisable, uninstall];
4422
+ };
4423
+
4424
+ const className = mergeClassNames(ExtensionListItemActionInstall, ExtensionActionButton);
4425
+ const getActionVirtualDom$1 = (action, id) => {
4426
+ return [{
4427
+ childCount: 1,
4428
+ className,
4429
+ disabled: action.disabled,
4430
+ name: id,
4431
+ onClick: action.onClick,
4432
+ type: Button$2
4433
+ }, text(action.label)];
4434
+ };
4435
+ const getExtensionActionsVirtualDom = (id, builtin, disabled, status) => {
4436
+ const actions = getExtensionActions(builtin, disabled, status);
4437
+ return [{
4438
+ childCount: actions.length,
4439
+ className: ExtensionActions,
4440
+ type: Div
4441
+ }, ...actions.flatMap(action => getActionVirtualDom$1(action, id))];
4442
+ };
4443
+
4444
+ const extensionListItemMetadataNode = {
4445
+ childCount: 2,
4446
+ className: ExtensionListItemMetadata,
4447
+ type: Div
4448
+ };
4449
+ const getStatisticVirtualDom = (label, value, className) => {
4450
+ const accessibleLabel = `${label}: ${value}`;
4451
+ return [{
4452
+ ariaLabel: accessibleLabel,
4453
+ childCount: 1,
4454
+ className: mergeClassNames(ExtensionListItemStatistic, className),
4455
+ title: accessibleLabel,
4456
+ type: Span
4457
+ }, text(value)];
4458
+ };
4459
+ const getExtensionStatisticsVirtualDom = (downloadCount, rating$1) => {
4460
+ return [extensionListItemMetadataNode, ...getStatisticVirtualDom(downloads(), downloadCount, ExtensionListItemDownloadCount), ...getStatisticVirtualDom(rating(), rating$1, ExtensionListItemRating)];
4461
+ };
4462
+
3416
4463
  const listItemDetail = {
3417
4464
  childCount: 3,
3418
4465
  className: ExtensionListItemDetail,
@@ -3429,7 +4476,7 @@ const listItemDescription = {
3429
4476
  type: Div
3430
4477
  };
3431
4478
  const listItemFooter = {
3432
- childCount: 2,
4479
+ childCount: 3,
3433
4480
  className: ExtensionListItemFooter,
3434
4481
  type: Div
3435
4482
  };
@@ -3452,14 +4499,21 @@ const getId = focused => {
3452
4499
  };
3453
4500
  const getExtensionListItemVirtualDom = extension => {
3454
4501
  const {
4502
+ builtin = false,
3455
4503
  description,
4504
+ disabled = false,
4505
+ downloadCount = 'n/a',
3456
4506
  focused,
3457
4507
  icon,
4508
+ id,
3458
4509
  name,
3459
4510
  posInSet,
3460
4511
  publisher,
3461
- setSize
4512
+ rating = 'n/a',
4513
+ setSize,
4514
+ status
3462
4515
  } = extension;
4516
+ const actionsDom = getExtensionActionsVirtualDom(id, builtin, disabled, status);
3463
4517
  const dom = [{
3464
4518
  ariaPosInSet: posInSet,
3465
4519
  ariaRoleDescription: Extension,
@@ -3475,11 +4529,7 @@ const getExtensionListItemVirtualDom = extension => {
3475
4529
  role: None,
3476
4530
  src: icon,
3477
4531
  type: Img
3478
- }, listItemDetail, listItemName, text(name), listItemDescription, text(description), listItemFooter, listItemAuthorName, text(publisher), {
3479
- childCount: 0,
3480
- className: ExtensionActions,
3481
- type: Div
3482
- }];
4532
+ }, listItemDetail, listItemName, text(name), listItemDescription, text(description), listItemFooter, listItemAuthorName, text(publisher), ...getExtensionStatisticsVirtualDom(downloadCount, rating), ...actionsDom];
3483
4533
  return dom;
3484
4534
  };
3485
4535
 
@@ -3498,8 +4548,8 @@ const getExtensionsListVirtualDom = (visibleExtensions, focusOutline) => {
3498
4548
  onTouchMove: HandleTouchMove,
3499
4549
  onTouchStart: HandleTouchStart,
3500
4550
  onWheel: HandleWheel,
3501
- role: List,
3502
- tabIndex: 0,
4551
+ role: List$1,
4552
+ tabIndex: Focusable,
3503
4553
  type: Div
3504
4554
  }, ...visibleExtensions.flatMap(getExtensionListItemVirtualDom)];
3505
4555
  return dom;
@@ -3511,14 +4561,20 @@ const getExtensionsVirtualDom = (visibleExtensions, focusOutline) => {
3511
4561
  return dom;
3512
4562
  };
3513
4563
 
4564
+ const noExtensionsFoundNode = {
4565
+ childCount: 1,
4566
+ className: NoExtensionsFoundMessage,
4567
+ type: Div
4568
+ };
3514
4569
  const getNoExtensionsFoundVirtualDom = message => {
3515
- return [{
3516
- childCount: 1,
3517
- className: NoExtensionsFoundMessage,
3518
- type: Div
3519
- }, text(message)];
4570
+ return [noExtensionsFoundNode, text(message)];
3520
4571
  };
3521
4572
 
4573
+ const scrollBarThumbNode = {
4574
+ childCount: 0,
4575
+ className: ScrollBarThumb,
4576
+ type: Div
4577
+ };
3522
4578
  const getScrollBarVirtualDom = (scrollBarHeight, scrollBarTop) => {
3523
4579
  const shouldShowScrollbar = scrollBarHeight > 0;
3524
4580
  if (!shouldShowScrollbar) {
@@ -3530,24 +4586,28 @@ const getScrollBarVirtualDom = (scrollBarHeight, scrollBarTop) => {
3530
4586
  onPointerDown: HandleScrollBarPointerDown,
3531
4587
  // TODO support pointercapture event
3532
4588
  type: Div
3533
- }, {
3534
- childCount: 0,
3535
- className: ScrollBarThumb,
3536
- type: Div
3537
- }];
4589
+ }, scrollBarThumbNode];
3538
4590
  };
3539
4591
 
3540
4592
  const getVisibleItem = (item, setSize, itemHeight, minLineY, relative, i, focusedIndex) => {
3541
4593
  // TODO use normal parameters
3542
4594
  const {
4595
+ builtin,
3543
4596
  description,
4597
+ disabled,
4598
+ downloadCount,
3544
4599
  icon,
3545
4600
  id,
3546
4601
  name,
3547
- publisher
4602
+ publisher,
4603
+ rating,
4604
+ status
3548
4605
  } = item;
3549
4606
  return {
4607
+ builtin,
3550
4608
  description,
4609
+ disabled,
4610
+ downloadCount,
3551
4611
  focused: i === focusedIndex,
3552
4612
  icon,
3553
4613
  id,
@@ -3555,7 +4615,9 @@ const getVisibleItem = (item, setSize, itemHeight, minLineY, relative, i, focuse
3555
4615
  name,
3556
4616
  posInSet: i + 1,
3557
4617
  publisher,
4618
+ rating,
3558
4619
  setSize,
4620
+ status,
3559
4621
  top: (i - minLineY) * itemHeight - relative
3560
4622
  };
3561
4623
  };
@@ -3585,21 +4647,25 @@ const getContentVirtualDom = (visibleExtensions, message, scrollBarHeight, scrol
3585
4647
  }
3586
4648
  return [{
3587
4649
  childCount: 2,
3588
- className: mergeClassNames(Viewlet, List$1),
4650
+ className: mergeClassNames(Viewlet, List),
3589
4651
  type: Div
3590
4652
  }, ...getExtensionsVirtualDom(visibleExtensions, focusOutline), ...getScrollBarVirtualDom(scrollBarHeight)];
3591
4653
  };
3592
4654
  const getExtensionsViewVirtualDom = state => {
3593
4655
  const visibleExtensions = getVisible(state);
3594
4656
  const {
4657
+ completionFocusedIndex,
4658
+ completionItems,
4659
+ focus,
3595
4660
  focusedIndex,
3596
4661
  inputActions,
3597
4662
  message,
3598
4663
  placeholder,
3599
4664
  scrollBarHeight,
3600
- scrollBarY
4665
+ scrollBarY,
4666
+ suggestOpen
3601
4667
  } = state;
3602
- const focusOutline = focusedIndex === -1 && state.focus === List$2;
4668
+ const focusOutline = focusedIndex === -1 && focus === List$2;
3603
4669
  return [{
3604
4670
  ariaBusy: false,
3605
4671
  ariaLive: 'polite',
@@ -3607,7 +4673,7 @@ const getExtensionsViewVirtualDom = state => {
3607
4673
  className: mergeClassNames(Viewlet, Extensions),
3608
4674
  role: None$3,
3609
4675
  type: Div
3610
- }, ...getExtensionHeaderVirtualDom(placeholder, inputActions), ...getContentVirtualDom(visibleExtensions, message, scrollBarHeight, scrollBarY, focusOutline)];
4676
+ }, ...getExtensionHeaderVirtualDom(placeholder, inputActions, completionItems, completionFocusedIndex, suggestOpen), ...getContentVirtualDom(visibleExtensions, message, scrollBarHeight, scrollBarY, focusOutline)];
3611
4677
  };
3612
4678
 
3613
4679
  const renderItems2 = newState => {
@@ -3654,10 +4720,7 @@ const renderScrollBar = newState => {
3654
4720
  const roundedScrollBarY = Math.round(scrollBarY);
3655
4721
  const heightString = px(scrollBarHeight);
3656
4722
  const translateString = position(0, roundedScrollBarY);
3657
- let className = ScrollBarThumb;
3658
- if (newState.scrollBarActive) {
3659
- className += ' ' + ScrollBarThumbActive;
3660
- }
4723
+ const className = mergeClassNames(ScrollBarThumb, newState.scrollBarActive ? ScrollBarThumbActive : '');
3661
4724
  return [/* method */SetScrollBar, translateString, heightString, className];
3662
4725
  };
3663
4726
 
@@ -3665,6 +4728,66 @@ const renderSearchValue = newState => {
3665
4728
  return [/* method */'Viewlet.setValueByName', newState.uid, Extensions$1, newState.searchValue];
3666
4729
  };
3667
4730
 
4731
+ const titleFilters = [{
4732
+ label: deprecated,
4733
+ value: Deprecated
4734
+ }, {
4735
+ label: installed,
4736
+ value: Installed
4737
+ }, {
4738
+ label: enabled,
4739
+ value: Enabled$1
4740
+ }, {
4741
+ label: disabled,
4742
+ value: Disabled$2
4743
+ }, {
4744
+ label: builtIn,
4745
+ value: Builtin
4746
+ }, {
4747
+ label: updates,
4748
+ value: Outdated
4749
+ }, {
4750
+ label: featured,
4751
+ value: Featured
4752
+ }, {
4753
+ label: mcpServers,
4754
+ value: McpServers
4755
+ }, {
4756
+ label: mostPopular,
4757
+ value: MostPopular
4758
+ }, {
4759
+ label: recentlyPublished,
4760
+ value: RecentlyPublished
4761
+ }, {
4762
+ label: recommended,
4763
+ value: Recommended
4764
+ }, {
4765
+ label: workspaceUnsupported,
4766
+ value: WorkspaceUnsupported
4767
+ }];
4768
+ const getTitleSuffix = searchValue => {
4769
+ if (!searchValue.trim()) {
4770
+ return installed();
4771
+ }
4772
+ const normalizedSearchValue = searchValue.toLowerCase();
4773
+ for (const filter of titleFilters) {
4774
+ if (normalizedSearchValue.includes(filter.value)) {
4775
+ return filter.label();
4776
+ }
4777
+ }
4778
+ return marketplace();
4779
+ };
4780
+ const renderTitle = state => {
4781
+ return `${extensions()}: ${getTitleSuffix(state.searchValue)}`;
4782
+ };
4783
+
4784
+ const renderTitleCommand = newState => {
4785
+ if (newState.parentUid === undefined) {
4786
+ return [];
4787
+ }
4788
+ return ['Viewlet.send', newState.parentUid, 'setTitle', renderTitle(newState)];
4789
+ };
4790
+
3668
4791
  const getRenderer = diffType => {
3669
4792
  switch (diffType) {
3670
4793
  case RenderCss:
@@ -3685,6 +4808,8 @@ const getRenderer = diffType => {
3685
4808
  return renderScrollBar;
3686
4809
  case RenderSearchValue:
3687
4810
  return renderSearchValue;
4811
+ case RenderTitle:
4812
+ return renderTitleCommand;
3688
4813
  default:
3689
4814
  throw new Error('unknown renderer');
3690
4815
  }
@@ -3773,7 +4898,7 @@ const renderEventListeners = () => {
3773
4898
  preventDefault: true
3774
4899
  }, {
3775
4900
  name: HandlePointerDown,
3776
- params: ['handleClickAt', Button$1, ClientX, ClientY],
4901
+ params: ['handleClickAt', Button$1, ClientX, ClientY, TargetName],
3777
4902
  preventDefault: true
3778
4903
  }, {
3779
4904
  name: HandleScrollBarPointerDown,
@@ -3792,7 +4917,7 @@ const renderEventListeners = () => {
3792
4917
  passive: true
3793
4918
  }, {
3794
4919
  name: HandleExtensionsInput,
3795
- params: ['handleInput', TargetValue, User]
4920
+ params: ['handleInput', TargetValue, User, TargetSelectionStart]
3796
4921
  }, {
3797
4922
  name: HandleClearSearchResults,
3798
4923
  params: ['clearSearchResults']
@@ -3805,6 +4930,24 @@ const renderEventListeners = () => {
3805
4930
  }, {
3806
4931
  name: HandleBlur,
3807
4932
  params: ['handleBlur']
4933
+ }, {
4934
+ name: HandleInstall,
4935
+ params: ['handleInstall', TargetName]
4936
+ }, {
4937
+ name: HandleUninstall,
4938
+ params: ['handleUninstall', TargetName]
4939
+ }, {
4940
+ name: HandleEnable,
4941
+ params: ['handleEnable', TargetName]
4942
+ }, {
4943
+ name: HandleDisable,
4944
+ params: ['handleDisable', TargetName]
4945
+ }, {
4946
+ name: HandleInputFocus,
4947
+ params: ['handleInputFocus']
4948
+ }, {
4949
+ name: HandleInputBlur,
4950
+ params: ['handleBlur']
3808
4951
  }];
3809
4952
  };
3810
4953
 
@@ -3868,34 +5011,46 @@ const scrollDown = state => {
3868
5011
  return setDeltaY(state, newDeltaY);
3869
5012
  };
3870
5013
 
3871
- const selectIndex = (state, index) => {
5014
+ const selectNextCompletion = state => {
5015
+ if (!state.suggestOpen || state.completionItems.length === 0) {
5016
+ return state;
5017
+ }
3872
5018
  return {
3873
5019
  ...state,
3874
- focusedIndex: index
5020
+ completionFocusedIndex: (state.completionFocusedIndex + 1) % state.completionItems.length
3875
5021
  };
3876
5022
  };
3877
5023
 
3878
- const toggleSuggest = state => {
5024
+ const selectPreviousCompletion = state => {
5025
+ if (!state.suggestOpen || state.completionItems.length === 0) {
5026
+ return state;
5027
+ }
3879
5028
  return {
3880
5029
  ...state,
3881
- suggestOpen: !state.suggestOpen
5030
+ completionFocusedIndex: (state.completionFocusedIndex - 1 + state.completionItems.length) % state.completionItems.length
3882
5031
  };
3883
5032
  };
3884
5033
 
5034
+ const toggleSuggest = state => {
5035
+ return state.suggestOpen ? closeSuggest(state) : openSuggest(state);
5036
+ };
5037
+
3885
5038
  const commandMap = {
3886
5039
  'Extensions.copyExtensionId': wrapCommand(copyExtensionId),
3887
5040
  'Extensions.copyExtensionInfo': wrapCommand(copyExtensionInfo),
3888
- 'SearchExtensions.clearSearchResults': wrapCommand(clearSearchResults),
5041
+ 'SearchExtensions.acceptCompletion': wrapAsyncCommand(acceptCompletionWithContext),
5042
+ 'SearchExtensions.clearSearchResults': wrapAsyncCommand(clearSearchResultsWithContext),
3889
5043
  'SearchExtensions.closeSuggest': wrapCommand(closeSuggest),
3890
5044
  'SearchExtensions.copyExtensionId': wrapCommand(copyExtensionId),
3891
5045
  'SearchExtensions.copyExtensionInfo': wrapCommand(copyExtensionInfo),
3892
5046
  'SearchExtensions.create': create,
3893
5047
  'SearchExtensions.diff2': diff2,
3894
- 'SearchExtensions.disable': wrapCommand(disable),
5048
+ 'SearchExtensions.disable': wrapCommand(disable$1),
3895
5049
  'SearchExtensions.disableWorkspace': wrapCommand(disableWorkspace),
3896
5050
  'SearchExtensions.dispose': dispose,
3897
- 'SearchExtensions.enable': wrapCommand(enable),
5051
+ 'SearchExtensions.enable': wrapCommand(enable$1),
3898
5052
  'SearchExtensions.enableWorkspace': wrapCommand(enableWorkspace),
5053
+ 'SearchExtensions.filterByMostPopular': wrapAsyncCommand(filterByMostPopularWithContext),
3899
5054
  'SearchExtensions.focusFirst': wrapCommand(focusFirst),
3900
5055
  'SearchExtensions.focusIndex': wrapCommand(focusIndex),
3901
5056
  'SearchExtensions.focusLast': wrapCommand(focusLast),
@@ -3923,7 +5078,8 @@ const commandMap = {
3923
5078
  'SearchExtensions.handleEnableWorkspace': wrapCommand(handleEnableWorkspace),
3924
5079
  'SearchExtensions.handleFocus': wrapCommand(handleFocus),
3925
5080
  'SearchExtensions.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
3926
- 'SearchExtensions.handleInput': wrapCommand(handleInput),
5081
+ 'SearchExtensions.handleInput': wrapAsyncCommand(handleInputWithContext),
5082
+ 'SearchExtensions.handleInputFocus': wrapCommand(handleInputFocus),
3927
5083
  'SearchExtensions.handleInstall': wrapCommand(handleInstall),
3928
5084
  'SearchExtensions.handleScrollBarCaptureLost': wrapCommand(handleScrollBarCaptureLost),
3929
5085
  'SearchExtensions.handleScrollBarClick': wrapCommand(handleScrollBarClick),
@@ -3934,7 +5090,7 @@ const commandMap = {
3934
5090
  'SearchExtensions.handleWheel': wrapCommand(handleWheel),
3935
5091
  'SearchExtensions.initialize': initialize,
3936
5092
  'SearchExtensions.installAnotherVersion': wrapCommand(installAnotherVersion),
3937
- 'SearchExtensions.loadContent': wrapCommand(loadContent),
5093
+ 'SearchExtensions.loadContent': wrapAsyncCommand(loadContentWithContext),
3938
5094
  'SearchExtensions.openSuggest': wrapCommand(openSuggest),
3939
5095
  'SearchExtensions.render3': render3,
3940
5096
  'SearchExtensions.renderActions': renderActions,
@@ -3945,14 +5101,17 @@ const commandMap = {
3945
5101
  'SearchExtensions.scrollDown': wrapCommand(scrollDown),
3946
5102
  'SearchExtensions.searchExtensions': searchExtensions,
3947
5103
  'SearchExtensions.selectIndex': wrapCommand(selectIndex),
5104
+ 'SearchExtensions.selectNextCompletion': wrapCommand(selectNextCompletion),
5105
+ 'SearchExtensions.selectPreviousCompletion': wrapCommand(selectPreviousCompletion),
3948
5106
  'SearchExtensions.setDeltaY': wrapCommand(setDeltaY),
5107
+ 'SearchExtensions.setExtensionStatus': wrapCommand(setExtensionStatus),
3949
5108
  'SearchExtensions.terminate': terminate,
3950
5109
  'SearchExtensions.toggleSuggest': wrapCommand(toggleSuggest)
3951
5110
  };
3952
5111
 
3953
5112
  const listen = async () => {
3954
5113
  registerCommands(commandMap);
3955
- const rpc = await create$3({
5114
+ const rpc = await create$4({
3956
5115
  commandMap: commandMap
3957
5116
  });
3958
5117
  set$2(rpc);