@lvce-editor/extension-search-view 7.8.0 → 7.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);
@@ -586,7 +592,10 @@ const constructError = (message, type, name) => {
586
592
  if (ErrorConstructor === Error) {
587
593
  const error = new Error(message);
588
594
  if (name && name !== 'VError') {
589
- error.name = name;
595
+ Object.defineProperty(error, 'name', {
596
+ configurable: true,
597
+ value: name
598
+ });
590
599
  }
591
600
  return error;
592
601
  }
@@ -603,8 +612,10 @@ const getCurrentStack = () => {
603
612
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
604
613
  return currentStack;
605
614
  };
606
- const getNewLineIndex = (string, startIndex = undefined) => {
607
- return string.indexOf(NewLine, startIndex);
615
+ const getNewLineIndex = (string, startIndex) => {
616
+ {
617
+ return string.indexOf(NewLine);
618
+ }
608
619
  };
609
620
  const getParentStack = error => {
610
621
  let parentStack = error.stack || error.data || error.message || '';
@@ -615,55 +626,91 @@ const getParentStack = error => {
615
626
  };
616
627
  const MethodNotFound = -32601;
617
628
  const Custom = -32001;
629
+ const setStack = (error, stack) => {
630
+ const descriptor = Object.getOwnPropertyDescriptor(error, 'stack');
631
+ if (descriptor) {
632
+ if (!descriptor.configurable && !descriptor.writable) {
633
+ return;
634
+ }
635
+ if (!descriptor.configurable && descriptor.writable) {
636
+ error.stack = stack;
637
+ return;
638
+ }
639
+ }
640
+ Object.defineProperty(error, 'stack', {
641
+ configurable: true,
642
+ value: stack,
643
+ writable: true
644
+ });
645
+ };
646
+ const restoreExistingError = (error, currentStack) => {
647
+ if (typeof error.stack === 'string') {
648
+ setStack(error, `${error.stack}${NewLine}${currentStack}`);
649
+ }
650
+ return error;
651
+ };
652
+ const restoreMethodNotFoundError = (error, currentStack) => {
653
+ const restoredError = new JsonRpcError(error.message);
654
+ const parentStack = getParentStack(error);
655
+ setStack(restoredError, `${parentStack}${NewLine}${currentStack}`);
656
+ return restoredError;
657
+ };
658
+ const restoreStackFromData = (restoredError, error, currentStack) => {
659
+ if (error.data.stack && error.data.type && error.message) {
660
+ setStack(restoredError, `${error.data.type}: ${error.message}${NewLine}${error.data.stack}${NewLine}${currentStack}`);
661
+ return;
662
+ }
663
+ if (error.data.stack) {
664
+ setStack(restoredError, error.data.stack);
665
+ }
666
+ };
667
+ const applyDataProperties = (restoredError, error) => {
668
+ restoreStackFromData(restoredError, error, getCurrentStack());
669
+ if (error.data.codeFrame) {
670
+ // @ts-ignore
671
+ restoredError.codeFrame = error.data.codeFrame;
672
+ }
673
+ if (error.data.code) {
674
+ // @ts-ignore
675
+ restoredError.code = error.data.code;
676
+ }
677
+ if (error.data.type) {
678
+ // @ts-ignore
679
+ restoredError.name = error.data.type;
680
+ }
681
+ };
682
+ const applyDirectProperties = (restoredError, error) => {
683
+ if (error.stack) {
684
+ const lowerStack = restoredError.stack || '';
685
+ const indexNewLine = getNewLineIndex(lowerStack);
686
+ const parentStack = getParentStack(error);
687
+ // @ts-ignore
688
+ setStack(restoredError, `${parentStack}${lowerStack.slice(indexNewLine)}`);
689
+ }
690
+ if (error.codeFrame) {
691
+ // @ts-ignore
692
+ restoredError.codeFrame = error.codeFrame;
693
+ }
694
+ };
695
+ const restoreMessageError = (error, _currentStack) => {
696
+ const restoredError = constructError(error.message, error.type, error.name);
697
+ if (error.data) {
698
+ applyDataProperties(restoredError, error);
699
+ } else {
700
+ applyDirectProperties(restoredError, error);
701
+ }
702
+ return restoredError;
703
+ };
618
704
  const restoreJsonRpcError = error => {
619
705
  const currentStack = getCurrentStack();
620
706
  if (error && error instanceof Error) {
621
- if (typeof error.stack === 'string') {
622
- error.stack = error.stack + NewLine + currentStack;
623
- }
624
- return error;
707
+ return restoreExistingError(error, currentStack);
625
708
  }
626
709
  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;
710
+ return restoreMethodNotFoundError(error, currentStack);
631
711
  }
632
712
  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;
713
+ return restoreMessageError(error);
667
714
  }
668
715
  if (typeof error === 'string') {
669
716
  return new Error(`JsonRpc Error: ${error}`);
@@ -747,7 +794,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
747
794
  const errorProperty = getErrorProperty(error, prettyError);
748
795
  return create$1$1(id, errorProperty);
749
796
  };
750
- const create$9 = (message, result) => {
797
+ const create$a = (message, result) => {
751
798
  return {
752
799
  id: message.id,
753
800
  jsonrpc: Two$1,
@@ -756,7 +803,7 @@ const create$9 = (message, result) => {
756
803
  };
757
804
  const getSuccessResponse = (message, result) => {
758
805
  const resultProperty = result ?? null;
759
- return create$9(message, resultProperty);
806
+ return create$a(message, resultProperty);
760
807
  };
761
808
  const getErrorResponseSimple = (id, error) => {
762
809
  return {
@@ -850,7 +897,7 @@ const handleJsonRpcMessage = async (...args) => {
850
897
 
851
898
  const Two = '2.0';
852
899
 
853
- const create$8 = (method, params) => {
900
+ const create$9 = (method, params) => {
854
901
  return {
855
902
  jsonrpc: Two,
856
903
  method,
@@ -858,7 +905,7 @@ const create$8 = (method, params) => {
858
905
  };
859
906
  };
860
907
 
861
- const create$7 = (id, method, params) => {
908
+ const create$8 = (id, method, params) => {
862
909
  const message = {
863
910
  id,
864
911
  jsonrpc: Two,
@@ -869,12 +916,12 @@ const create$7 = (id, method, params) => {
869
916
  };
870
917
 
871
918
  let id$1 = 0;
872
- const create$6 = () => {
919
+ const create$7 = () => {
873
920
  return ++id$1;
874
921
  };
875
922
 
876
923
  const registerPromise = map => {
877
- const id = create$6();
924
+ const id = create$7();
878
925
  const {
879
926
  promise,
880
927
  resolve
@@ -891,7 +938,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
891
938
  id,
892
939
  promise
893
940
  } = registerPromise(callbacks);
894
- const message = create$7(id, method, params);
941
+ const message = create$8(id, method, params);
895
942
  if (useSendAndTransfer && ipc.sendAndTransfer) {
896
943
  ipc.sendAndTransfer(message);
897
944
  } else {
@@ -927,7 +974,7 @@ const createRpc = ipc => {
927
974
  * @deprecated
928
975
  */
929
976
  send(method, ...params) {
930
- const message = create$8(method, params);
977
+ const message = create$9(method, params);
931
978
  ipc.send(message);
932
979
  }
933
980
  };
@@ -967,7 +1014,7 @@ const listen$1 = async (module, options) => {
967
1014
  return ipc;
968
1015
  };
969
1016
 
970
- const create$5 = async ({
1017
+ const create$6 = async ({
971
1018
  commandMap,
972
1019
  isMessagePortOpen = true,
973
1020
  messagePort
@@ -985,7 +1032,7 @@ const create$5 = async ({
985
1032
  return rpc;
986
1033
  };
987
1034
 
988
- const create$4 = async ({
1035
+ const create$5 = async ({
989
1036
  commandMap,
990
1037
  isMessagePortOpen,
991
1038
  send
@@ -995,14 +1042,14 @@ const create$4 = async ({
995
1042
  port2
996
1043
  } = new MessageChannel();
997
1044
  await send(port1);
998
- return create$5({
1045
+ return create$6({
999
1046
  commandMap,
1000
1047
  isMessagePortOpen,
1001
1048
  messagePort: port2
1002
1049
  });
1003
1050
  };
1004
1051
 
1005
- const create$3 = async ({
1052
+ const create$4 = async ({
1006
1053
  commandMap
1007
1054
  }) => {
1008
1055
  // TODO create a commandMap per rpc instance
@@ -1045,7 +1092,7 @@ const remove = id => {
1045
1092
  };
1046
1093
 
1047
1094
  /* eslint-disable @typescript-eslint/explicit-function-return-type */
1048
- const create$2 = rpcId => {
1095
+ const create$3 = rpcId => {
1049
1096
  return {
1050
1097
  async dispose() {
1051
1098
  const rpc = get$1(rpcId);
@@ -1083,14 +1130,175 @@ const create$2 = rpcId => {
1083
1130
 
1084
1131
  const None$3 = 'none';
1085
1132
 
1133
+ const Audio = 0;
1086
1134
  const Button$2 = 1;
1135
+ const Col = 2;
1136
+ const ColGroup = 3;
1087
1137
  const Div = 4;
1138
+ const H1 = 5;
1088
1139
  const Input$1 = 6;
1140
+ const Kbd = 7;
1089
1141
  const Span = 8;
1142
+ const Table = 9;
1143
+ const TBody = 10;
1144
+ const Td = 11;
1090
1145
  const Text = 12;
1146
+ const Th = 13;
1147
+ const THead = 14;
1148
+ const Tr = 15;
1149
+ const I = 16;
1091
1150
  const Img = 17;
1151
+ const Root = 0;
1152
+ const Ins = 20;
1153
+ const Del = 21;
1154
+ const H2 = 22;
1155
+ const H3 = 23;
1156
+ const H4 = 24;
1157
+ const H5 = 25;
1158
+ const H6 = 26;
1159
+ const Article = 27;
1160
+ const Aside = 28;
1161
+ const Footer = 29;
1162
+ const Header = 30;
1163
+ const Nav = 40;
1164
+ const Section = 41;
1165
+ const Search = 42;
1166
+ const Dd = 43;
1167
+ const Dl = 44;
1168
+ const Figcaption = 45;
1169
+ const Figure = 46;
1170
+ const Hr = 47;
1171
+ const Li = 48;
1172
+ const Ol = 49;
1173
+ const P = 50;
1174
+ const Pre = 51;
1175
+ const A = 53;
1176
+ const Abbr = 54;
1177
+ const Br = 55;
1178
+ const Cite = 56;
1179
+ const Data = 57;
1180
+ const Time = 58;
1181
+ const Tfoot = 59;
1182
+ const Ul = 60;
1183
+ const Video = 61;
1184
+ const TextArea = 62;
1185
+ const Select = 63;
1186
+ const Option$1 = 64;
1187
+ const Code = 65;
1188
+ const Label = 66;
1189
+ const Dt = 67;
1190
+ const Iframe = 68;
1191
+ const Main = 69;
1192
+ const Strong = 70;
1193
+ const Em = 71;
1194
+ const Style = 72;
1195
+ const Html = 73;
1196
+ const Head = 74;
1197
+ const Title = 75;
1198
+ const Meta = 76;
1199
+ const Canvas = 77;
1200
+ const Form = 78;
1201
+ const BlockQuote = 79;
1202
+ const Quote = 80;
1203
+ const Circle = 81;
1204
+ const Defs = 82;
1205
+ const Ellipse = 83;
1206
+ const G = 84;
1207
+ const Line = 85;
1208
+ const Path = 86;
1209
+ const Polygon = 87;
1210
+ const Polyline = 88;
1211
+ const Rect = 89;
1212
+ const Svg = 90;
1213
+ const Use = 91;
1092
1214
  const Reference = 100;
1093
1215
 
1216
+ const VirtualDomElements = {
1217
+ __proto__: null,
1218
+ A,
1219
+ Abbr,
1220
+ Article,
1221
+ Aside,
1222
+ Audio,
1223
+ BlockQuote,
1224
+ Br,
1225
+ Button: Button$2,
1226
+ Canvas,
1227
+ Circle,
1228
+ Cite,
1229
+ Code,
1230
+ Col,
1231
+ ColGroup,
1232
+ Data,
1233
+ Dd,
1234
+ Defs,
1235
+ Del,
1236
+ Div,
1237
+ Dl,
1238
+ Dt,
1239
+ Ellipse,
1240
+ Em,
1241
+ Figcaption,
1242
+ Figure,
1243
+ Footer,
1244
+ Form,
1245
+ G,
1246
+ H1,
1247
+ H2,
1248
+ H3,
1249
+ H4,
1250
+ H5,
1251
+ H6,
1252
+ Head,
1253
+ Header,
1254
+ Hr,
1255
+ Html,
1256
+ I,
1257
+ Iframe,
1258
+ Img,
1259
+ Input: Input$1,
1260
+ Ins,
1261
+ Kbd,
1262
+ Label,
1263
+ Li,
1264
+ Line,
1265
+ Main,
1266
+ Meta,
1267
+ Nav,
1268
+ Ol,
1269
+ Option: Option$1,
1270
+ P,
1271
+ Path,
1272
+ Polygon,
1273
+ Polyline,
1274
+ Pre,
1275
+ Quote,
1276
+ Rect,
1277
+ Reference,
1278
+ Root,
1279
+ Search,
1280
+ Section,
1281
+ Select,
1282
+ Span,
1283
+ Strong,
1284
+ Style,
1285
+ Svg,
1286
+ TBody,
1287
+ THead,
1288
+ Table,
1289
+ Td,
1290
+ Text,
1291
+ TextArea,
1292
+ Tfoot,
1293
+ Th,
1294
+ Time,
1295
+ Title,
1296
+ Tr,
1297
+ Ul,
1298
+ Use,
1299
+ Video
1300
+ };
1301
+
1094
1302
  const Button$1 = 'event.button';
1095
1303
  const ClientX = 'event.clientX';
1096
1304
  const ClientY = 'event.clientY';
@@ -1119,7 +1327,7 @@ const SetPatches = 'Viewlet.setPatches';
1119
1327
  const {
1120
1328
  invoke: invoke$2,
1121
1329
  set: set$4
1122
- } = create$2(ExtensionHostWorker);
1330
+ } = create$3(ExtensionHostWorker);
1123
1331
 
1124
1332
  const ExtensionHost = {
1125
1333
  __proto__: null,
@@ -1129,13 +1337,13 @@ const ExtensionHost = {
1129
1337
 
1130
1338
  const {
1131
1339
  set: set$3
1132
- } = create$2(ExtensionManagementWorker);
1340
+ } = create$3(ExtensionManagementWorker);
1133
1341
 
1134
1342
  const {
1135
1343
  invoke: invoke$1,
1136
1344
  invokeAndTransfer,
1137
1345
  set: set$2
1138
- } = create$2(RendererWorker);
1346
+ } = create$3(RendererWorker);
1139
1347
  const showContextMenu2 = async (uid, menuId, x, y, args) => {
1140
1348
  number(uid);
1141
1349
  number(menuId);
@@ -1167,6 +1375,9 @@ const sendMessagePortToExtensionManagementWorker = async (port, rpcId) => {
1167
1375
  const openUri$1 = async (uri, focus, options) => {
1168
1376
  await invoke$1('Main.openUri', uri, focus, options);
1169
1377
  };
1378
+ const showErrorDialog = async errorInfo => {
1379
+ await invoke$1('ErrorHandling.showErrorDialog', errorInfo);
1380
+ };
1170
1381
  const uninstallExtension = async id => {
1171
1382
  return invoke$1('ExtensionManagement.uninstall', id);
1172
1383
  };
@@ -1178,11 +1389,68 @@ const toCommandId = key => {
1178
1389
  const dotIndex = key.indexOf('.');
1179
1390
  return key.slice(dotIndex + 1);
1180
1391
  };
1181
- const create$1 = () => {
1392
+ const create$2 = () => {
1393
+ const commandQueues = new Map();
1394
+ const generations = Object.create(null);
1182
1395
  const states = Object.create(null);
1183
1396
  const commandMapRef = {};
1397
+ const getGeneration = uid => generations[uid] || 0;
1398
+ const isCurrentGeneration = (uid, generation) => {
1399
+ return states[uid] !== undefined && getGeneration(uid) === generation;
1400
+ };
1401
+ const updateState = (uid, generation, fallbackState, updater) => {
1402
+ if (!isCurrentGeneration(uid, generation)) {
1403
+ return Promise.resolve(fallbackState);
1404
+ }
1405
+ const current = states[uid];
1406
+ const updatedState = updater(current.newState);
1407
+ if (updatedState !== current.newState) {
1408
+ states[uid] = {
1409
+ newState: updatedState,
1410
+ oldState: current.oldState,
1411
+ scheduledState: updatedState
1412
+ };
1413
+ }
1414
+ return Promise.resolve(updatedState);
1415
+ };
1416
+ const createAsyncCommandContext = (uid, generation) => {
1417
+ let latestState = states[uid].newState;
1418
+ return {
1419
+ getState: () => {
1420
+ if (isCurrentGeneration(uid, generation)) {
1421
+ latestState = states[uid].newState;
1422
+ }
1423
+ return latestState;
1424
+ },
1425
+ updateState: async updater => {
1426
+ latestState = await updateState(uid, generation, latestState, updater);
1427
+ return latestState;
1428
+ }
1429
+ };
1430
+ };
1431
+ const enqueueCommand = async (uid, command) => {
1432
+ const previous = commandQueues.get(uid) || Promise.resolve();
1433
+ const run = async () => {
1434
+ try {
1435
+ await previous;
1436
+ } catch {
1437
+ // The previous caller receives its error; later commands must still run.
1438
+ }
1439
+ await command();
1440
+ };
1441
+ const current = run();
1442
+ commandQueues.set(uid, current);
1443
+ try {
1444
+ await current;
1445
+ } finally {
1446
+ if (commandQueues.get(uid) === current) {
1447
+ commandQueues.delete(uid);
1448
+ }
1449
+ }
1450
+ };
1184
1451
  return {
1185
1452
  clear() {
1453
+ commandQueues.clear();
1186
1454
  for (const key of Object.keys(states)) {
1187
1455
  delete states[key];
1188
1456
  }
@@ -1202,6 +1470,7 @@ const create$1 = () => {
1202
1470
  return diffResult;
1203
1471
  },
1204
1472
  dispose(uid) {
1473
+ commandQueues.delete(uid);
1205
1474
  delete states[uid];
1206
1475
  },
1207
1476
  get(uid) {
@@ -1219,14 +1488,27 @@ const create$1 = () => {
1219
1488
  Object.assign(commandMapRef, commandMap);
1220
1489
  },
1221
1490
  set(uid, oldState, newState, scheduledState) {
1491
+ const current = states[uid];
1492
+ if (!current || oldState === newState && newState !== current.newState) {
1493
+ generations[uid] = getGeneration(uid) + 1;
1494
+ }
1222
1495
  states[uid] = {
1223
1496
  newState,
1224
1497
  oldState,
1225
1498
  scheduledState: scheduledState ?? newState
1226
1499
  };
1227
1500
  },
1501
+ wrapAsyncCommand(fn) {
1502
+ const wrapped = async (uid, ...args) => {
1503
+ const generation = getGeneration(uid);
1504
+ const context = createAsyncCommandContext(uid, generation);
1505
+ await fn(context, ...args);
1506
+ };
1507
+ return wrapped;
1508
+ },
1228
1509
  wrapCommand(fn) {
1229
1510
  const wrapped = async (uid, ...args) => {
1511
+ const generation = getGeneration(uid);
1230
1512
  const {
1231
1513
  newState,
1232
1514
  oldState
@@ -1235,6 +1517,9 @@ const create$1 = () => {
1235
1517
  if (oldState === newerState || newState === newerState) {
1236
1518
  return;
1237
1519
  }
1520
+ if (!isCurrentGeneration(uid, generation)) {
1521
+ return;
1522
+ }
1238
1523
  const latestOld = states[uid];
1239
1524
  const latestNew = {
1240
1525
  ...latestOld.newState,
@@ -1259,6 +1544,7 @@ const create$1 = () => {
1259
1544
  },
1260
1545
  wrapLoadContent(fn) {
1261
1546
  const wrapped = async (uid, ...args) => {
1547
+ const generation = getGeneration(uid);
1262
1548
  const {
1263
1549
  newState,
1264
1550
  oldState
@@ -1273,6 +1559,11 @@ const create$1 = () => {
1273
1559
  error
1274
1560
  };
1275
1561
  }
1562
+ if (!isCurrentGeneration(uid, generation)) {
1563
+ return {
1564
+ error
1565
+ };
1566
+ }
1276
1567
  const latestOld = states[uid];
1277
1568
  const latestNew = {
1278
1569
  ...latestOld.newState,
@@ -1288,6 +1579,51 @@ const create$1 = () => {
1288
1579
  };
1289
1580
  };
1290
1581
  return wrapped;
1582
+ },
1583
+ wrapSerialAsyncCommand(fn) {
1584
+ const wrapped = async (uid, ...args) => {
1585
+ await enqueueCommand(uid, async () => {
1586
+ if (!states[uid]) {
1587
+ return;
1588
+ }
1589
+ const generation = getGeneration(uid);
1590
+ const context = createAsyncCommandContext(uid, generation);
1591
+ await fn(context, ...args);
1592
+ });
1593
+ };
1594
+ return wrapped;
1595
+ },
1596
+ wrapSerialCommand(fn) {
1597
+ const wrapped = async (uid, ...args) => {
1598
+ await enqueueCommand(uid, async () => {
1599
+ if (!states[uid]) {
1600
+ return;
1601
+ }
1602
+ const generation = getGeneration(uid);
1603
+ const {
1604
+ newState,
1605
+ oldState
1606
+ } = states[uid];
1607
+ const newerState = await fn(newState, ...args);
1608
+ if (oldState === newerState || newState === newerState) {
1609
+ return;
1610
+ }
1611
+ if (!isCurrentGeneration(uid, generation)) {
1612
+ return;
1613
+ }
1614
+ const latestOld = states[uid];
1615
+ const latestNew = {
1616
+ ...latestOld.newState,
1617
+ ...newerState
1618
+ };
1619
+ states[uid] = {
1620
+ newState: latestNew,
1621
+ oldState: latestOld.oldState,
1622
+ scheduledState: latestNew
1623
+ };
1624
+ });
1625
+ };
1626
+ return wrapped;
1291
1627
  }
1292
1628
  };
1293
1629
  };
@@ -1327,16 +1663,56 @@ const handleError = async (error, notify = true, prefix = '') => {
1327
1663
  console.error(error);
1328
1664
  };
1329
1665
 
1666
+ const loadStates = new Map();
1667
+ const tokenGenerator = {
1668
+ value: 0
1669
+ };
1670
+ const cancel = uid => {
1671
+ const loadState = loadStates.get(uid);
1672
+ if (!loadState) {
1673
+ return;
1674
+ }
1675
+ loadStates.delete(uid);
1676
+ loadState.resolve();
1677
+ };
1678
+ const create$1 = uid => {
1679
+ cancel(uid);
1680
+ const {
1681
+ promise,
1682
+ resolve
1683
+ } = Promise.withResolvers();
1684
+ const token = ++tokenGenerator.value;
1685
+ loadStates.set(uid, {
1686
+ promise,
1687
+ resolve,
1688
+ token
1689
+ });
1690
+ };
1691
+ const finish = (uid, token) => {
1692
+ const loadState = loadStates.get(uid);
1693
+ if (!loadState || loadState.token !== token) {
1694
+ return;
1695
+ }
1696
+ loadStates.delete(uid);
1697
+ loadState.resolve();
1698
+ };
1699
+ const getToken = uid => {
1700
+ return loadStates.get(uid)?.token;
1701
+ };
1702
+ const wait = uid => {
1703
+ return loadStates.get(uid)?.promise || Promise.resolve();
1704
+ };
1705
+
1330
1706
  const emptyObject = {};
1331
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1332
1707
  const i18nString = (key, placeholders = emptyObject) => {
1333
1708
  if (placeholders === emptyObject) {
1334
1709
  return key;
1335
1710
  }
1336
- const replacer = (match, rest) => {
1337
- return placeholders[rest];
1338
- };
1339
- return key.replaceAll(RE_PLACEHOLDER, replacer);
1711
+ let result = key;
1712
+ for (const [placeholder, replacement] of Object.entries(placeholders)) {
1713
+ result = result.split(`{${placeholder}}`).join(String(replacement));
1714
+ }
1715
+ return result;
1340
1716
  };
1341
1717
 
1342
1718
  const NoExtensionsFound = 'No extensions found.';
@@ -1362,11 +1738,13 @@ const CopyExtensionId = 'Copy Extension Id';
1362
1738
  const Name = 'Name';
1363
1739
  const Id$1 = 'Id';
1364
1740
  const Description = 'Description';
1741
+ const Downloads = 'Downloads';
1365
1742
  const Version = 'Version';
1366
1743
  const Publisher = 'Publisher';
1744
+ const Rating = 'Rating';
1367
1745
  const MarketplaceLink = 'Marketplace Link';
1368
1746
  const Category$1 = 'Category';
1369
- const Disabled$2 = 'Disabled';
1747
+ const Disabled$3 = 'Disabled';
1370
1748
  const Featured$1 = 'Featured';
1371
1749
  const McpServers$1 = 'MCP Servers';
1372
1750
  const MostPopular$1 = 'Most Popular';
@@ -1394,9 +1772,15 @@ const version = () => {
1394
1772
  const description = () => {
1395
1773
  return i18nString(Description);
1396
1774
  };
1775
+ const downloads = () => {
1776
+ return i18nString(Downloads);
1777
+ };
1397
1778
  const publisher = () => {
1398
1779
  return i18nString(Publisher);
1399
1780
  };
1781
+ const rating = () => {
1782
+ return i18nString(Rating);
1783
+ };
1400
1784
  const marketplaceLink = () => {
1401
1785
  return i18nString(MarketplaceLink);
1402
1786
  };
@@ -1461,7 +1845,7 @@ const category = () => {
1461
1845
  return i18nString(Category$1);
1462
1846
  };
1463
1847
  const disabled = () => {
1464
- return i18nString(Disabled$2);
1848
+ return i18nString(Disabled$3);
1465
1849
  };
1466
1850
  const featured = () => {
1467
1851
  return i18nString(Featured$1);
@@ -1585,7 +1969,7 @@ const getScrollBarY$1 = (delta, finalDelta, size, scrollBarSize) => {
1585
1969
 
1586
1970
  const Installed = '@installed';
1587
1971
  const Enabled$1 = '@enabled';
1588
- const Disabled$1 = '@disabled';
1972
+ const Disabled$2 = '@disabled';
1589
1973
  const Builtin = '@builtin';
1590
1974
  const Sort = '@sort';
1591
1975
  const Id = '@id';
@@ -1593,13 +1977,13 @@ const Category = '@category';
1593
1977
  const Outdated = '@outdated';
1594
1978
  const Featured = '@featured';
1595
1979
  const McpServers = '@mcpservers';
1596
- const MostPopular = '@mostpopular';
1980
+ const MostPopular = '@most-popular';
1597
1981
  const RecentlyPublished = '@recentlypublished';
1598
1982
  const Recommended = '@recommended';
1599
1983
  const WorkspaceUnsupported = '@workspaceunsupported';
1600
1984
  const Deprecated = '@deprecated';
1601
1985
 
1602
- const RE_PARAM = /@\w+(?::\w+)?/g;
1986
+ const RE_PARAM = /@[\w-]+(?::\w+)?/g;
1603
1987
  const deserializeCategory = value => {
1604
1988
  if (value.startsWith(':"') && value.endsWith('"')) {
1605
1989
  return value.slice(2, -1);
@@ -1631,7 +2015,7 @@ const parseValue = value => {
1631
2015
  if (match.startsWith(Enabled$1)) {
1632
2016
  enabled = true;
1633
2017
  }
1634
- if (match.startsWith(Disabled$1)) {
2018
+ if (match.startsWith(Disabled$2)) {
1635
2019
  disabled = true;
1636
2020
  }
1637
2021
  if (match.startsWith(Builtin)) {
@@ -1755,6 +2139,103 @@ const searchExtensions = async (extensions, value, platform, assetDir) => {
1755
2139
  }
1756
2140
  };
1757
2141
 
2142
+ const requestVersions = new Map();
2143
+ const requestVersionGenerator = {
2144
+ value: 0
2145
+ };
2146
+ const getSearchResult = async state => {
2147
+ const {
2148
+ allExtensions,
2149
+ headerHeight,
2150
+ height,
2151
+ itemHeight,
2152
+ minimumSliderSize,
2153
+ searchValue
2154
+ } = state;
2155
+ const value = searchValue.trim();
2156
+ const inputActions = getInputActions(value.length > 0);
2157
+ const items = await searchExtensions(allExtensions, value);
2158
+ if (items.length === 0) {
2159
+ return {
2160
+ deltaY: 0,
2161
+ finalDeltaY: 0,
2162
+ focus: Input,
2163
+ inputActions,
2164
+ items,
2165
+ maxLineY: 0,
2166
+ message: noExtensionsFound(),
2167
+ minLineY: 0,
2168
+ placeholder: searchExtensionsInMarketPlace(),
2169
+ scrollBarHeight: 0
2170
+ };
2171
+ }
2172
+ const total = items.length;
2173
+ const listHeight = getListHeight(total, itemHeight, height - headerHeight);
2174
+ const scrollBarHeight = getScrollBarSize(listHeight, total * itemHeight, minimumSliderSize);
2175
+ const maxLineY = Math.min(getNumberOfVisibleItems$1(listHeight, itemHeight), total);
2176
+ const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
2177
+ const scrollBarY = getScrollBarY$1(0, finalDeltaY, listHeight, scrollBarHeight);
2178
+ return {
2179
+ deltaY: 0,
2180
+ finalDeltaY,
2181
+ focus: state.focus,
2182
+ inputActions,
2183
+ items,
2184
+ maxLineY,
2185
+ message: '',
2186
+ minLineY: 0,
2187
+ placeholder: searchExtensionsInMarketPlace(),
2188
+ scrollBarHeight,
2189
+ scrollBarY
2190
+ };
2191
+ };
2192
+ const handleChangeWithContext = async (context, update, waitForExtensions = true) => {
2193
+ const {
2194
+ uid
2195
+ } = context.getState();
2196
+ if (waitForExtensions) {
2197
+ await wait(uid);
2198
+ }
2199
+ const requestVersion = ++requestVersionGenerator.value;
2200
+ requestVersions.set(uid, requestVersion);
2201
+ const requestState = {
2202
+ ...context.getState(),
2203
+ ...update,
2204
+ initial: false
2205
+ };
2206
+ try {
2207
+ const result = await getSearchResult(requestState);
2208
+ await context.updateState(state => {
2209
+ if (requestVersions.get(state.uid) !== requestVersion) {
2210
+ return state;
2211
+ }
2212
+ return {
2213
+ ...state,
2214
+ ...update,
2215
+ initial: false,
2216
+ ...result
2217
+ };
2218
+ });
2219
+ } catch (error) {
2220
+ await handleError(error);
2221
+ await context.updateState(state => {
2222
+ if (requestVersions.get(state.uid) !== requestVersion) {
2223
+ return state;
2224
+ }
2225
+ return {
2226
+ ...state,
2227
+ ...update,
2228
+ initial: false,
2229
+ message: error instanceof Error ? error.message : String(error)
2230
+ };
2231
+ });
2232
+ } finally {
2233
+ if (requestVersions.get(uid) === requestVersion) {
2234
+ requestVersions.delete(uid);
2235
+ }
2236
+ }
2237
+ };
2238
+
1758
2239
  // TODO debounce
1759
2240
  const handleChange = async (state, update) => {
1760
2241
  const fullNewState = {
@@ -1762,71 +2243,11 @@ const handleChange = async (state, update) => {
1762
2243
  ...update
1763
2244
  };
1764
2245
  try {
1765
- const {
1766
- inputSource,
1767
- searchValue
1768
- } = fullNewState;
1769
- const value = searchValue.trim();
1770
- const hasValue = value.length > 0;
1771
- const inputActions = getInputActions(hasValue);
1772
- const {
1773
- allExtensions,
1774
- assetDir,
1775
- headerHeight,
1776
- height,
1777
- itemHeight,
1778
- minimumSliderSize,
1779
- platform
1780
- } = state;
1781
- // TODO cancel ongoing requests
1782
- // TODO handle errors
1783
- const items = await searchExtensions(allExtensions, value, platform, assetDir);
1784
- if (items.length === 0) {
1785
- return {
1786
- ...fullNewState,
1787
- allExtensions,
1788
- deltaY: 0,
1789
- finalDeltaY: 0,
1790
- focus: Input,
1791
- inputActions,
1792
- inputSource,
1793
- items,
1794
- maxLineY: 0,
1795
- message: noExtensionsFound(),
1796
- minLineY: 0,
1797
- placeholder: searchExtensionsInMarketPlace(),
1798
- scrollBarHeight: 0,
1799
- searchValue
1800
- };
1801
- }
1802
- const total = items.length;
1803
- const availableHeight = height - headerHeight;
1804
- const listHeight = getListHeight(total, itemHeight, availableHeight);
1805
- const contentHeight = total * itemHeight;
1806
- const scrollBarHeight = getScrollBarSize(listHeight, contentHeight, minimumSliderSize);
1807
- const numberOfVisible = getNumberOfVisibleItems$1(listHeight, itemHeight);
1808
- const maxLineY = Math.min(numberOfVisible, total);
1809
- const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
1810
- const scrollBarY = getScrollBarY$1(0, finalDeltaY, listHeight, scrollBarHeight);
2246
+ const result = await getSearchResult(fullNewState);
1811
2247
  return {
1812
2248
  ...fullNewState,
1813
- allExtensions,
1814
- deltaY: 0,
1815
- finalDeltaY,
1816
- inputActions,
1817
- inputSource,
1818
- items,
1819
- maxLineY,
1820
- message: '',
1821
- minLineY: 0,
1822
- placeholder: searchExtensionsInMarketPlace(),
1823
- scrollBarHeight,
1824
- scrollBarY,
1825
- searchValue
2249
+ ...result
1826
2250
  };
1827
-
1828
- // TODO handle out of order responses (a bit complicated)
1829
- // for now just assume everything comes back in order
1830
2251
  } catch (error) {
1831
2252
  // TODO send error to error worker
1832
2253
  await handleError(error);
@@ -1840,6 +2261,32 @@ const handleChange = async (state, update) => {
1840
2261
  const User = 1;
1841
2262
  const Script = 2;
1842
2263
 
2264
+ const getCompletionText = (searchValue, completion, rangeEnd) => {
2265
+ const hasTrailingWhitespace = /\s/.test(searchValue[rangeEnd] || '');
2266
+ return completion.endsWith(':') || hasTrailingWhitespace ? completion : `${completion} `;
2267
+ };
2268
+ const acceptCompletionWithContext = async (context, label) => {
2269
+ const state = context.getState();
2270
+ const completion = label || state.completionItems[state.completionFocusedIndex]?.label;
2271
+ if (!completion) {
2272
+ return;
2273
+ }
2274
+ const range = getCompletionRange(state.searchValue, state.cursorOffset);
2275
+ if (!range) {
2276
+ return;
2277
+ }
2278
+ const completionText = getCompletionText(state.searchValue, completion, range.end);
2279
+ const searchValue = `${state.searchValue.slice(0, range.start)}${completionText}${state.searchValue.slice(range.end)}`;
2280
+ await handleChangeWithContext(context, {
2281
+ completionFocusedIndex: 0,
2282
+ completionItems: [],
2283
+ cursorOffset: range.start + completionText.length,
2284
+ focus: Input,
2285
+ inputSource: Script,
2286
+ searchValue,
2287
+ suggestOpen: false
2288
+ });
2289
+ };
1843
2290
  const acceptCompletion = async (state, label) => {
1844
2291
  const completion = label || state.completionItems[state.completionFocusedIndex]?.label;
1845
2292
  if (!completion) {
@@ -1849,11 +2296,12 @@ const acceptCompletion = async (state, label) => {
1849
2296
  if (!range) {
1850
2297
  return state;
1851
2298
  }
1852
- const searchValue = `${state.searchValue.slice(0, range.start)}${completion}${state.searchValue.slice(range.end)}`;
2299
+ const completionText = getCompletionText(state.searchValue, completion, range.end);
2300
+ const searchValue = `${state.searchValue.slice(0, range.start)}${completionText}${state.searchValue.slice(range.end)}`;
1853
2301
  return handleChange(state, {
1854
2302
  completionFocusedIndex: 0,
1855
2303
  completionItems: [],
1856
- cursorOffset: range.start + completion.length,
2304
+ cursorOffset: range.start + completionText.length,
1857
2305
  focus: Input,
1858
2306
  inputSource: Script,
1859
2307
  searchValue,
@@ -1861,9 +2309,8 @@ const acceptCompletion = async (state, label) => {
1861
2309
  });
1862
2310
  };
1863
2311
 
1864
- const clearSearchResults = state => {
1865
- return handleChange(state, {
1866
- ...state,
2312
+ const clearSearchResultsWithContext = async context => {
2313
+ await handleChangeWithContext(context, {
1867
2314
  completionFocusedIndex: 0,
1868
2315
  completionItems: [],
1869
2316
  cursorOffset: 0,
@@ -1965,9 +2412,10 @@ const {
1965
2412
  getCommandIds,
1966
2413
  registerCommands,
1967
2414
  set: set$1,
2415
+ wrapAsyncCommand,
1968
2416
  wrapCommand,
1969
2417
  wrapGetter
1970
- } = create$1();
2418
+ } = create$2();
1971
2419
 
1972
2420
  const create = (id, uri, x, y, width, height, platform, assetDir, parentUid) => {
1973
2421
  const state = {
@@ -2009,6 +2457,7 @@ const create = (id, uri, x, y, width, height, platform, assetDir, parentUid) =>
2009
2457
  x,
2010
2458
  y
2011
2459
  };
2460
+ create$1(id);
2012
2461
  set$1(id, state, state);
2013
2462
  };
2014
2463
 
@@ -2064,6 +2513,7 @@ const disableWorkspace = async (state, _id) => {
2064
2513
  };
2065
2514
 
2066
2515
  const dispose = uid => {
2516
+ cancel(uid);
2067
2517
  dispose$1(uid);
2068
2518
  };
2069
2519
 
@@ -2077,6 +2527,82 @@ const enableWorkspace = async (state, _id) => {
2077
2527
  return state;
2078
2528
  };
2079
2529
 
2530
+ const CategorySuggestions = ['@category:"ai"', '@category:"azure"', '@category:"chat"', '@category:"data science"', '@category:"debuggers"', '@category:"education"', '@category:"extension packs"', '@category:"formatters"', '@category:"keymaps"', '@category:"language packs"', '@category:"linters"', '@category:"machine learning"', '@category:"notebooks"', '@category:"other"', '@category:"programming languages"', '@category:"scm providers"', '@category:"snippets"', '@category:"testing"', '@category:"themes"', '@category:"visualization"'];
2531
+
2532
+ const getFuzzyHighlights = (label, query) => {
2533
+ const lowerLabel = label.toLowerCase();
2534
+ const lowerQuery = query.toLowerCase();
2535
+ const matchedIndexes = [];
2536
+ let labelIndex = 0;
2537
+ for (const character of lowerQuery) {
2538
+ labelIndex = lowerLabel.indexOf(character, labelIndex);
2539
+ if (labelIndex === -1) {
2540
+ return undefined;
2541
+ }
2542
+ matchedIndexes.push(labelIndex);
2543
+ labelIndex++;
2544
+ }
2545
+ const highlights = [];
2546
+ for (const index of matchedIndexes) {
2547
+ const lastEnd = highlights.at(-1);
2548
+ if (lastEnd === index) {
2549
+ highlights[highlights.length - 1] = index + 1;
2550
+ } else {
2551
+ highlights.push(index, index + 1);
2552
+ }
2553
+ }
2554
+ return highlights;
2555
+ };
2556
+
2557
+ const Suggestions = ['@builtin', '@category:', '@disabled', '@enabled', '@featured', '@id:', '@installed', '@mcpservers', '@most-popular', '@outdated', '@recentlypublished', '@recommended', '@sort:installs', '@workspaceunsupported'];
2558
+
2559
+ const getCompletionItems = (value, cursorOffset) => {
2560
+ const range = getCompletionRange(value, cursorOffset);
2561
+ if (!range) {
2562
+ return [];
2563
+ }
2564
+ const suggestions = range.query.toLowerCase().startsWith('@category:') ? CategorySuggestions : Suggestions;
2565
+ const items = [];
2566
+ for (const label of suggestions) {
2567
+ const highlights = getFuzzyHighlights(label, range.query);
2568
+ if (highlights) {
2569
+ items.push({
2570
+ highlights,
2571
+ label
2572
+ });
2573
+ }
2574
+ }
2575
+ return items;
2576
+ };
2577
+
2578
+ const handleInputWithContext = async (context, value, inputSource = User, cursorOffset = value.length) => {
2579
+ const completionItems = getCompletionItems(value, cursorOffset);
2580
+ await handleChangeWithContext(context, {
2581
+ completionFocusedIndex: 0,
2582
+ completionItems,
2583
+ cursorOffset,
2584
+ focus: Input,
2585
+ inputSource,
2586
+ searchValue: value,
2587
+ suggestOpen: inputSource === User && completionItems.length > 0
2588
+ });
2589
+ };
2590
+
2591
+ const addFilter = (searchValue, filter) => {
2592
+ const values = searchValue.trim().split(/\s+/);
2593
+ if (values.includes(filter)) {
2594
+ return searchValue;
2595
+ }
2596
+ return `${searchValue.trim()} ${filter}`.trim();
2597
+ };
2598
+ const filterByMostPopularWithContext = async context => {
2599
+ const {
2600
+ searchValue
2601
+ } = context.getState();
2602
+ const value = addFilter(searchValue, MostPopular);
2603
+ await handleInputWithContext(context, value, Script);
2604
+ };
2605
+
2080
2606
  // TODO optimize this function to return the minimum number
2081
2607
  // of visible items needed, e.g. when not scrolled 5 items with
2082
2608
  // 20px fill 100px but when scrolled 6 items are needed
@@ -2091,31 +2617,31 @@ const getScrollBarY = getScrollBarOffset;
2091
2617
  const focusIndexScrollDown = (state, index, listHeight, itemHeight, itemsLength) => {
2092
2618
  const {
2093
2619
  finalDeltaY,
2094
- height,
2095
2620
  headerHeight,
2621
+ height,
2096
2622
  scrollBarHeight
2097
2623
  } = state;
2098
- const newMaxLineY = Math.min(index + 1, itemsLength);
2099
2624
  const fittingItems = getNumberOfVisibleItems(listHeight, itemHeight);
2100
- const newMinLineY = Math.max(newMaxLineY - fittingItems, 0);
2101
- const newDeltaY = itemsLength < fittingItems ? 0 : newMinLineY * itemHeight - listHeight % itemHeight + itemHeight;
2625
+ const newDeltaY = Math.min(Math.max((index + 1) * itemHeight - listHeight, 0), finalDeltaY);
2626
+ const newMinLineY = Math.floor(newDeltaY / itemHeight);
2627
+ const newMaxLineY = Math.min(newMinLineY + fittingItems, itemsLength);
2102
2628
  const scrollBarY = getScrollBarY(newDeltaY, finalDeltaY, height - headerHeight, scrollBarHeight);
2103
2629
  return {
2104
2630
  ...state,
2631
+ deltaY: newDeltaY,
2632
+ focused: true,
2105
2633
  focusedIndex: index,
2106
2634
  listFocusedIndex: index,
2107
- minLineY: newMinLineY,
2108
2635
  maxLineY: newMaxLineY,
2109
- focused: true,
2110
- deltaY: newDeltaY,
2636
+ minLineY: newMinLineY,
2111
2637
  scrollBarY
2112
2638
  };
2113
2639
  };
2114
2640
  const focusIndexScrollUp = (state, index, listHeight, itemHeight, itemsLength) => {
2115
2641
  const {
2116
2642
  finalDeltaY,
2117
- height,
2118
2643
  headerHeight,
2644
+ height,
2119
2645
  scrollBarHeight
2120
2646
  } = state;
2121
2647
  const newMinLineY = index;
@@ -2125,23 +2651,23 @@ const focusIndexScrollUp = (state, index, listHeight, itemHeight, itemsLength) =
2125
2651
  const scrollBarY = getScrollBarY(newDeltaY, finalDeltaY, height - headerHeight, scrollBarHeight);
2126
2652
  return {
2127
2653
  ...state,
2654
+ deltaY: newDeltaY,
2655
+ focused: true,
2128
2656
  focusedIndex: index,
2129
2657
  listFocusedIndex: index,
2130
- minLineY: newMinLineY,
2131
2658
  maxLineY: newMaxLineY,
2132
- focused: true,
2133
- deltaY: newDeltaY,
2659
+ minLineY: newMinLineY,
2134
2660
  scrollBarY
2135
2661
  };
2136
2662
  };
2137
2663
  const focusIndex = (state, index) => {
2138
2664
  const {
2139
- itemHeight,
2140
- minLineY,
2141
- maxLineY,
2142
2665
  headerHeight,
2143
2666
  height,
2144
- items
2667
+ itemHeight,
2668
+ items,
2669
+ maxLineY,
2670
+ minLineY
2145
2671
  } = state;
2146
2672
  const itemsLength = items.length;
2147
2673
  if (itemsLength === 0) {
@@ -2151,9 +2677,9 @@ const focusIndex = (state, index) => {
2151
2677
  if (index === -1) {
2152
2678
  return {
2153
2679
  ...state,
2680
+ focused: true,
2154
2681
  focusedIndex: -1,
2155
- listFocusedIndex: -1,
2156
- focused: true
2682
+ listFocusedIndex: -1
2157
2683
  };
2158
2684
  }
2159
2685
  const listHeight = height - headerHeight;
@@ -2165,9 +2691,9 @@ const focusIndex = (state, index) => {
2165
2691
  }
2166
2692
  return {
2167
2693
  ...state,
2694
+ focused: true,
2168
2695
  focusedIndex: index,
2169
- listFocusedIndex: index,
2170
- focused: true
2696
+ listFocusedIndex: index
2171
2697
  };
2172
2698
  };
2173
2699
  const first = () => {
@@ -2180,7 +2706,7 @@ const next = (items, index) => {
2180
2706
  return (index + 1) % items.length;
2181
2707
  };
2182
2708
  const previous = (items, index) => {
2183
- return index === 0 ? items.length - 1 : index - 1;
2709
+ return (index === 0 ? items.length : index) - 1;
2184
2710
  };
2185
2711
  const focusFirst = state => {
2186
2712
  const firstIndex = first();
@@ -2237,8 +2763,8 @@ const focusPrevious = state => {
2237
2763
  const focusPreviousPage = state => {
2238
2764
  const {
2239
2765
  focusedIndex,
2240
- minLineY,
2241
- maxLineY
2766
+ maxLineY,
2767
+ minLineY
2242
2768
  } = state;
2243
2769
  if (focusedIndex === 0 || focusedIndex === -1) {
2244
2770
  return state;
@@ -2294,7 +2820,7 @@ const getKeyBindings = () => {
2294
2820
  key: DownArrow,
2295
2821
  when: FocusExtensionsInput
2296
2822
  }, {
2297
- command: 'Extensions.toggleSuggest',
2823
+ command: 'Extensions.openSuggest',
2298
2824
  key: CtrlCmd | Space,
2299
2825
  when: FocusExtensionsInput
2300
2826
  }, {
@@ -2340,19 +2866,45 @@ const getKeyBindings = () => {
2340
2866
  }];
2341
2867
  };
2342
2868
 
2869
+ const Disabled$1 = 'disabled';
2870
+ const Enabled = 'enabled';
2871
+ const Installing = 'installing';
2872
+ const NotInstalled = 'not-installed';
2873
+ const Uninstalling = 'uninstalling';
2874
+ const statuses = [Disabled$1, Enabled, Installing, NotInstalled, Uninstalling];
2875
+ const isExtensionStatus = status => {
2876
+ return statuses.includes(status);
2877
+ };
2878
+
2343
2879
  const Separator = 1;
2344
2880
  const None$1 = 0;
2345
2881
  const SubMenu = 4;
2882
+ const Disabled = 5;
2346
2883
 
2347
- const getMenuEntriesList = () => {
2884
+ const nonEnableableStatuses = [Installing, NotInstalled, Uninstalling];
2885
+ const getEnablementFlags = (disabled, status) => {
2886
+ if (status && nonEnableableStatuses.includes(status)) {
2887
+ return {
2888
+ disable: Disabled,
2889
+ enable: Disabled
2890
+ };
2891
+ }
2892
+ const isDisabled = status === Disabled$1 || status === undefined && disabled;
2893
+ return {
2894
+ disable: isDisabled ? Disabled : None$1,
2895
+ enable: isDisabled ? None$1 : Disabled
2896
+ };
2897
+ };
2898
+ const getMenuEntriesList = (builtin, disabled = false, status) => {
2899
+ const enablementFlags = getEnablementFlags(disabled, status);
2348
2900
  return [{
2349
2901
  command: 'SearchExtensions.enable',
2350
- flags: None$1,
2902
+ flags: enablementFlags.enable,
2351
2903
  id: 'enable',
2352
2904
  label: enable$2()
2353
2905
  }, {
2354
2906
  command: 'SearchExtensions.enableWorkspace',
2355
- flags: None$1,
2907
+ flags: enablementFlags.enable,
2356
2908
  id: 'enableWorkspace',
2357
2909
  label: enableWorkspace$1()
2358
2910
  }, {
@@ -2362,12 +2914,12 @@ const getMenuEntriesList = () => {
2362
2914
  label: ''
2363
2915
  }, {
2364
2916
  command: 'SearchExtensions.disable',
2365
- flags: None$1,
2917
+ flags: enablementFlags.disable,
2366
2918
  id: 'disable',
2367
2919
  label: disable$2()
2368
2920
  }, {
2369
2921
  command: 'SearchExtensions.disableWorkspace',
2370
- flags: None$1,
2922
+ flags: enablementFlags.disable,
2371
2923
  id: 'disableWorkspace',
2372
2924
  label: disableWorkspace$1()
2373
2925
  }, {
@@ -2377,7 +2929,7 @@ const getMenuEntriesList = () => {
2377
2929
  label: ''
2378
2930
  }, {
2379
2931
  command: 'SearchExtensions.installAnotherVersion',
2380
- flags: None$1,
2932
+ flags: builtin ? Disabled : None$1,
2381
2933
  id: 'installAnotherVersion',
2382
2934
  label: installAnotherVersion$1()
2383
2935
  }, {
@@ -2405,7 +2957,7 @@ const getMenuEntriesFilter = () => {
2405
2957
  id: 'filterByMcpServers',
2406
2958
  label: mcpServers()
2407
2959
  }, {
2408
- command: 'SearchExtensions.filterByMostPopular',
2960
+ command: 'Extensions.filterByMostPopular',
2409
2961
  flags: None$1,
2410
2962
  id: 'filterByMostPopular',
2411
2963
  label: mostPopular()
@@ -2480,7 +3032,7 @@ const getMenuEntries2 = (state, props) => {
2480
3032
  case ExtensionSearchFilter:
2481
3033
  return getMenuEntriesFilter();
2482
3034
  default:
2483
- return getMenuEntriesList();
3035
+ return getMenuEntriesList(props.builtin, props.disabled, props.status);
2484
3036
  }
2485
3037
  };
2486
3038
 
@@ -2504,6 +3056,13 @@ const openUri = async uri => {
2504
3056
  return openUri$1(uri);
2505
3057
  };
2506
3058
 
3059
+ const selectIndex = (state, index) => {
3060
+ return {
3061
+ ...state,
3062
+ focusedIndex: index
3063
+ };
3064
+ };
3065
+
2507
3066
  const handleClick = async (state, index) => {
2508
3067
  const {
2509
3068
  items,
@@ -2520,7 +3079,7 @@ const handleClick = async (state, index) => {
2520
3079
  const extension = items[actualIndex];
2521
3080
  const uri = getExtensionDetailUri(extension.id);
2522
3081
  await openUri(uri);
2523
- const partialNewState = focusIndex(state, actualIndex);
3082
+ const partialNewState = selectIndex(state, actualIndex);
2524
3083
  const newState = {
2525
3084
  ...partialNewState,
2526
3085
  focus: List$2
@@ -2540,6 +3099,8 @@ const text = data => {
2540
3099
  };
2541
3100
  };
2542
3101
 
3102
+ new Set(Object.values(VirtualDomElements));
3103
+
2543
3104
  const SetText = 1;
2544
3105
  const Replace = 2;
2545
3106
  const SetAttribute = 3;
@@ -2777,17 +3338,14 @@ const diffTrees = (oldTree, newTree, patches, path) => {
2777
3338
  };
2778
3339
 
2779
3340
  const removeTrailingNavigationPatches = patches => {
2780
- // Find the last non-navigation patch
2781
- let lastNonNavigationIndex = -1;
2782
- for (let i = patches.length - 1; i >= 0; i--) {
2783
- const patch = patches[i];
3341
+ while (patches.length > 0) {
3342
+ const patch = patches.at(-1);
2784
3343
  if (patch.type !== NavigateChild && patch.type !== NavigateParent && patch.type !== NavigateSibling) {
2785
- lastNonNavigationIndex = i;
2786
3344
  break;
2787
3345
  }
3346
+ patches.pop();
2788
3347
  }
2789
- // Return patches up to and including the last non-navigation patch
2790
- return lastNonNavigationIndex === -1 ? [] : patches.slice(0, lastNonNavigationIndex + 1);
3348
+ return patches;
2791
3349
  };
2792
3350
 
2793
3351
  const diffTree = (oldNodes, newNodes) => {
@@ -2819,6 +3377,9 @@ const handleClickAt = async (state, button, eventX, eventY, name = '') => {
2819
3377
  if (name.startsWith('@')) {
2820
3378
  return handleCompletionPointerDown(state, name);
2821
3379
  }
3380
+ if (name) {
3381
+ return state;
3382
+ }
2822
3383
  if (button !== LeftClick) {
2823
3384
  return state;
2824
3385
  }
@@ -2884,21 +3445,14 @@ const handleContextMenu = async (state, button, eventX, eventY) => {
2884
3445
  return state;
2885
3446
  }
2886
3447
  await show2(uid, ManageExtension, eventX, eventY, {
2887
- menuId: ManageExtension
3448
+ builtin: items[index]?.builtin === true,
3449
+ disabled: items[index]?.disabled === true,
3450
+ menuId: ManageExtension,
3451
+ status: items[index]?.status
2888
3452
  });
2889
3453
  return state;
2890
3454
  };
2891
3455
 
2892
- const Disabled = 'disabled';
2893
- const Enabled = 'enabled';
2894
- const Installing = 'installing';
2895
- const NotInstalled = 'not-installed';
2896
- const Uninstalling = 'uninstalling';
2897
- const statuses = [Disabled, Enabled, Installing, NotInstalled, Uninstalling];
2898
- const isExtensionStatus = status => {
2899
- return statuses.includes(status);
2900
- };
2901
-
2902
3456
  const updateStatus = (extension, id, status, builtin) => {
2903
3457
  if (extension.id !== id) {
2904
3458
  return extension;
@@ -2906,7 +3460,7 @@ const updateStatus = (extension, id, status, builtin) => {
2906
3460
  return {
2907
3461
  ...extension,
2908
3462
  builtin: builtin ?? extension.builtin,
2909
- disabled: status === Disabled,
3463
+ disabled: status === Disabled$1,
2910
3464
  status
2911
3465
  };
2912
3466
  };
@@ -2923,7 +3477,7 @@ const setExtensionStatus = (state, id, status, builtin) => {
2923
3477
 
2924
3478
  const handleDisable = async (state, id) => {
2925
3479
  const error = await disableExtension(id);
2926
- return error ? state : setExtensionStatus(state, id, Disabled);
3480
+ return error ? state : setExtensionStatus(state, id, Disabled$1);
2927
3481
  };
2928
3482
 
2929
3483
  const handleDisableWorkspace = (state, id) => {
@@ -2950,64 +3504,6 @@ const handleHeaderContextMenu = async state => {
2950
3504
  return state;
2951
3505
  };
2952
3506
 
2953
- const getFuzzyHighlights = (label, query) => {
2954
- const lowerLabel = label.toLowerCase();
2955
- const lowerQuery = query.toLowerCase();
2956
- const matchedIndexes = [];
2957
- let labelIndex = 0;
2958
- for (const character of lowerQuery) {
2959
- labelIndex = lowerLabel.indexOf(character, labelIndex);
2960
- if (labelIndex === -1) {
2961
- return undefined;
2962
- }
2963
- matchedIndexes.push(labelIndex);
2964
- labelIndex++;
2965
- }
2966
- const highlights = [];
2967
- for (const index of matchedIndexes) {
2968
- const lastEnd = highlights.at(-1);
2969
- if (lastEnd === index) {
2970
- highlights[highlights.length - 1] = index + 1;
2971
- } else {
2972
- highlights.push(index, index + 1);
2973
- }
2974
- }
2975
- return highlights;
2976
- };
2977
-
2978
- const Suggestions = ['@builtin', '@category:', '@disabled', '@enabled', '@featured', '@id:', '@installed', '@mcpservers', '@mostpopular', '@outdated', '@recentlypublished', '@recommended', '@sort:installs', '@workspaceunsupported'];
2979
-
2980
- const getCompletionItems = (value, cursorOffset) => {
2981
- const range = getCompletionRange(value, cursorOffset);
2982
- if (!range) {
2983
- return [];
2984
- }
2985
- const items = [];
2986
- for (const label of Suggestions) {
2987
- const highlights = getFuzzyHighlights(label, range.query);
2988
- if (highlights) {
2989
- items.push({
2990
- highlights,
2991
- label
2992
- });
2993
- }
2994
- }
2995
- return items;
2996
- };
2997
-
2998
- const handleInput = async (state, value, inputSource = User, cursorOffset = value.length) => {
2999
- const completionItems = getCompletionItems(value, cursorOffset);
3000
- return handleChange(state, {
3001
- completionFocusedIndex: 0,
3002
- completionItems,
3003
- cursorOffset,
3004
- focus: Input,
3005
- inputSource,
3006
- searchValue: value,
3007
- suggestOpen: inputSource === User && completionItems.length > 0
3008
- });
3009
- };
3010
-
3011
3507
  const handleInputFocus = state => {
3012
3508
  return {
3013
3509
  ...state,
@@ -3173,14 +3669,22 @@ const handleSettingsButtonClick = async (state, index) => {
3173
3669
  const menuY = itemY + itemHeight - 10; // Position at the bottom of the extension item
3174
3670
 
3175
3671
  await show2(uid, ManageExtension, menuX, menuY, {
3176
- menuId: ManageExtension
3672
+ builtin: items[actualIndex].builtin === true,
3673
+ disabled: items[actualIndex].disabled === true,
3674
+ menuId: ManageExtension,
3675
+ status: items[actualIndex].status
3177
3676
  });
3178
3677
  return state;
3179
3678
  };
3180
3679
 
3181
3680
  const handleUninstall = async (state, id) => {
3182
- await uninstallExtension(id);
3183
- return setExtensionStatus(state, id, NotInstalled);
3681
+ try {
3682
+ await uninstallExtension(id);
3683
+ return setExtensionStatus(state, id, NotInstalled);
3684
+ } catch (error) {
3685
+ await showErrorDialog(error);
3686
+ return state;
3687
+ }
3184
3688
  };
3185
3689
 
3186
3690
  const handleWheel = (state, deltaMode, deltaY) => {
@@ -3195,7 +3699,7 @@ const sendMessagePortToExtensionHostWorker = async port => {
3195
3699
 
3196
3700
  const createExtensionHostWorkerRpc = async () => {
3197
3701
  try {
3198
- const rpc = await create$4({
3702
+ const rpc = await create$5({
3199
3703
  commandMap: {},
3200
3704
  send: sendMessagePortToExtensionHostWorker
3201
3705
  });
@@ -3217,7 +3721,7 @@ const initializeExtensionHostWorker = async () => {
3217
3721
 
3218
3722
  const createExtensionManagementWorkerRpc = async () => {
3219
3723
  try {
3220
- const rpc = await create$4({
3724
+ const rpc = await create$5({
3221
3725
  commandMap: {},
3222
3726
  send: port => sendMessagePortToExtensionManagementWorker(port, 0)
3223
3727
  });
@@ -3330,6 +3834,28 @@ const getExtensionIcon = (extension, platform, assetDir) => {
3330
3834
  return getRemoteUrl(extension, platform, assetDir);
3331
3835
  };
3332
3836
 
3837
+ const getDownloadCountValue = extension => {
3838
+ return extension?.downloadCount ?? extension?.downloads ?? extension?.marketplace?.downloadCount ?? extension?.marketplace?.downloads ?? extension?.packageJSON?.downloadCount ?? extension?.packageJSON?.downloads;
3839
+ };
3840
+ const getDownloadCount = extension => {
3841
+ const downloadCount = getDownloadCountValue(extension);
3842
+ if (typeof downloadCount !== 'number') {
3843
+ return 'n/a';
3844
+ }
3845
+ return downloadCount.toLocaleString();
3846
+ };
3847
+
3848
+ const getRatingValue = extension => {
3849
+ return extension?.rating ?? extension?.averageRating ?? extension?.marketplace?.rating ?? extension?.marketplace?.averageRating ?? extension?.packageJSON?.rating ?? extension?.packageJSON?.averageRating;
3850
+ };
3851
+ const getRating = extension => {
3852
+ const rating = getRatingValue(extension);
3853
+ if (typeof rating !== 'number') {
3854
+ return 'n/a';
3855
+ }
3856
+ return rating.toFixed(1);
3857
+ };
3858
+
3333
3859
  const getBuiltin = extension => {
3334
3860
  return extension?.builtin === true;
3335
3861
  };
@@ -3406,10 +3932,12 @@ const normalizeExtension = (extension, platform, assetDir) => {
3406
3932
  categories: getCategories(extension),
3407
3933
  description: getDescription(extension),
3408
3934
  disabled: getDisabled(extension),
3935
+ downloadCount: getDownloadCount(extension),
3409
3936
  icon: getIcon(extension, platform, assetDir),
3410
3937
  id: getId$1(extension),
3411
3938
  name: getName(extension),
3412
3939
  publisher: getPublisher(extension),
3940
+ rating: getRating(extension),
3413
3941
  size: getSize(extension),
3414
3942
  status: getStatus(extension),
3415
3943
  updatedDate: getUpdatedDate(extension),
@@ -3443,31 +3971,48 @@ const restoreState = savedState => {
3443
3971
  };
3444
3972
  };
3445
3973
 
3446
- const loadContent = async (state, savedState) => {
3974
+ const loadContentWithContext = async (context, savedState) => {
3447
3975
  const {
3448
- assetDir,
3449
- platform,
3450
- width
3451
- } = state;
3452
- const {
3453
- deltaY,
3454
- searchValue
3455
- } = restoreState(savedState);
3456
- // TODO just get local extensions on demand (not when query string is already different)
3457
- const allExtensions = await getAllExtensions(platform);
3458
- const size = getViewletSize(width);
3459
- const normalized = normalizeExtensions(allExtensions, platform, assetDir);
3460
- const scrollSensitivity = getIsFirefox() ? 2.5 : 1;
3461
- const updatedState = await handleInput({
3462
- ...state,
3463
- allExtensions: normalized,
3464
- deltaY,
3465
- initial: false,
3466
- inputSource: Script,
3467
- scrollSensitivity,
3468
- size
3469
- }, searchValue, Script);
3470
- return updatedState;
3976
+ uid
3977
+ } = context.getState();
3978
+ const loadToken = getToken(uid);
3979
+ try {
3980
+ const initialState = context.getState();
3981
+ const {
3982
+ assetDir,
3983
+ platform,
3984
+ width
3985
+ } = initialState;
3986
+ const {
3987
+ deltaY,
3988
+ searchValue: restoredSearchValue
3989
+ } = restoreState(savedState);
3990
+ const size = getViewletSize(width);
3991
+ const scrollSensitivity = getIsFirefox() ? 2.5 : 1;
3992
+ await context.updateState(state => {
3993
+ if (!state.initial) {
3994
+ return state;
3995
+ }
3996
+ return {
3997
+ ...state,
3998
+ deltaY,
3999
+ initial: false,
4000
+ inputSource: Script,
4001
+ scrollSensitivity,
4002
+ searchValue: restoredSearchValue,
4003
+ size
4004
+ };
4005
+ });
4006
+ const allExtensions = await getAllExtensions(platform);
4007
+ const normalized = normalizeExtensions(allExtensions, platform, assetDir);
4008
+ await context.updateState(state => ({
4009
+ ...state,
4010
+ allExtensions: normalized
4011
+ }));
4012
+ await handleChangeWithContext(context, {}, false);
4013
+ } finally {
4014
+ finish(uid, loadToken);
4015
+ }
3471
4016
  };
3472
4017
 
3473
4018
  const openSuggest = state => {
@@ -3514,6 +4059,10 @@ const getCss = state => {
3514
4059
  flex-shrink: 0;
3515
4060
  }
3516
4061
 
4062
+ .ExtensionListItemDisabled:not(.ExtensionActive) {
4063
+ background: color-mix(in srgb, var(--SideBarBackground, rgb(30, 35, 36)) 95%, black);
4064
+ }
4065
+
3517
4066
  .Extensions .ListItems {
3518
4067
  display: flex;
3519
4068
  flex-direction: column;
@@ -3527,6 +4076,24 @@ const getCss = state => {
3527
4076
  z-index: 1;
3528
4077
  }
3529
4078
 
4079
+ .ExtensionListItemFooter {
4080
+ justify-content: flex-end;
4081
+ padding-right: 2px;
4082
+ }
4083
+
4084
+ .ExtensionListItemAuthorName {
4085
+ flex: 1;
4086
+ }
4087
+
4088
+ .ExtensionActions {
4089
+ display: flex;
4090
+ gap: 6px;
4091
+ }
4092
+
4093
+ .ExtensionActionButton {
4094
+ padding: 0 5px;
4095
+ }
4096
+
3530
4097
  .ExtensionSearchCompletionWidget {
3531
4098
  position: absolute;
3532
4099
  left: ${completionLeft}px;
@@ -3641,9 +4208,14 @@ const ExtensionListItemActionInstall = 'ExtensionListItemActionInstall';
3641
4208
  const ExtensionListItemAuthorName = 'ExtensionListItemAuthorName';
3642
4209
  const ExtensionListItemDescription = 'ExtensionListItemDescription';
3643
4210
  const ExtensionListItemDetail = 'ExtensionListItemDetail';
4211
+ const ExtensionListItemDisabled = 'ExtensionListItemDisabled';
4212
+ const ExtensionListItemDownloadCount = 'ExtensionListItemDownloadCount';
3644
4213
  const ExtensionListItemFooter = 'ExtensionListItemFooter';
3645
4214
  const ExtensionListItemIcon = 'ExtensionListItemIcon';
4215
+ const ExtensionListItemMetadata = 'ExtensionListItemMetadata';
3646
4216
  const ExtensionListItemName = 'ExtensionListItemName';
4217
+ const ExtensionListItemRating = 'ExtensionListItemRating';
4218
+ const ExtensionListItemStatistic = 'ExtensionListItemStatistic';
3647
4219
  const ExtensionSearchCompletionHighlight = 'ExtensionSearchCompletionHighlight';
3648
4220
  const ExtensionSearchCompletionItem = 'ExtensionSearchCompletionItem';
3649
4221
  const ExtensionSearchCompletionItemFocused = 'ExtensionSearchCompletionItemFocused';
@@ -3733,6 +4305,8 @@ const getCompletionWidgetVirtualDom = (items, focusedIndex) => {
3733
4305
  }, ...items.flatMap((item, index) => getCompletionItemVirtualDom(item, index, focusedIndex))];
3734
4306
  };
3735
4307
 
4308
+ const Focusable = 0;
4309
+
3736
4310
  const disabledClassName = mergeClassNames(SearchFieldButton, SearchFieldButtonDisabled);
3737
4311
  const getClassName$1 = enabled => {
3738
4312
  if (enabled) {
@@ -3751,7 +4325,7 @@ const getSearchFieldButtonVirtualDom = button => {
3751
4325
  childCount: 1,
3752
4326
  className: getClassName$1(enabled),
3753
4327
  onClick,
3754
- tabIndex: 0,
4328
+ tabIndex: Focusable,
3755
4329
  title,
3756
4330
  type: Button$2
3757
4331
  }, {
@@ -3761,14 +4335,15 @@ const getSearchFieldButtonVirtualDom = button => {
3761
4335
  }];
3762
4336
  };
3763
4337
 
4338
+ const searchFieldNode = {
4339
+ childCount: 2,
4340
+ className: SearchField,
4341
+ role: None,
4342
+ type: Div
4343
+ };
3764
4344
  const getSearchFieldVirtualDom = (name, placeholder, onInput, insideButtons, outsideButtons, onFocus = '', onBlur = '', inputProperties = {}) => {
3765
4345
  // TODO avoid mutation
3766
- const dom = [{
3767
- childCount: 2,
3768
- className: SearchField,
3769
- role: None,
3770
- type: Div
3771
- }, {
4346
+ const dom = [searchFieldNode, {
3772
4347
  autocapitalize: 'off',
3773
4348
  autocomplete: 'off',
3774
4349
  autocorrect: 'off',
@@ -3870,7 +4445,7 @@ const getExtensionActions = (builtin, disabled, status) => {
3870
4445
  if (status === Uninstalling) {
3871
4446
  return builtin ? [] : [uninstalling];
3872
4447
  }
3873
- const enableOrDisable = status === Disabled || status === undefined && disabled ? enable : disable;
4448
+ const enableOrDisable = status === Disabled$1 || status === undefined && disabled ? enable : disable;
3874
4449
  return builtin ? [enableOrDisable] : [enableOrDisable, uninstall];
3875
4450
  };
3876
4451
 
@@ -3894,6 +4469,25 @@ const getExtensionActionsVirtualDom = (id, builtin, disabled, status) => {
3894
4469
  }, ...actions.flatMap(action => getActionVirtualDom$1(action, id))];
3895
4470
  };
3896
4471
 
4472
+ const extensionListItemMetadataNode = {
4473
+ childCount: 2,
4474
+ className: ExtensionListItemMetadata,
4475
+ type: Div
4476
+ };
4477
+ const getStatisticVirtualDom = (label, value, className) => {
4478
+ const accessibleLabel = `${label}: ${value}`;
4479
+ return [{
4480
+ ariaLabel: accessibleLabel,
4481
+ childCount: 1,
4482
+ className: mergeClassNames(ExtensionListItemStatistic, className),
4483
+ title: accessibleLabel,
4484
+ type: Span
4485
+ }, text(value)];
4486
+ };
4487
+ const getExtensionStatisticsVirtualDom = (downloadCount, rating$1) => {
4488
+ return [extensionListItemMetadataNode, ...getStatisticVirtualDom(downloads(), downloadCount, ExtensionListItemDownloadCount), ...getStatisticVirtualDom(rating(), rating$1, ExtensionListItemRating)];
4489
+ };
4490
+
3897
4491
  const listItemDetail = {
3898
4492
  childCount: 3,
3899
4493
  className: ExtensionListItemDetail,
@@ -3910,7 +4504,7 @@ const listItemDescription = {
3910
4504
  type: Div
3911
4505
  };
3912
4506
  const listItemFooter = {
3913
- childCount: 2,
4507
+ childCount: 3,
3914
4508
  className: ExtensionListItemFooter,
3915
4509
  type: Div
3916
4510
  };
@@ -3919,11 +4513,8 @@ const listItemAuthorName = {
3919
4513
  className: ExtensionListItemAuthorName,
3920
4514
  type: Div
3921
4515
  };
3922
- const getClassName = focused => {
3923
- if (focused) {
3924
- return mergeClassNames(ExtensionListItem, ExtensionActive);
3925
- }
3926
- return ExtensionListItem;
4516
+ const getClassName = (focused, disabled) => {
4517
+ return mergeClassNames(ExtensionListItem, focused ? ExtensionActive : '', disabled ? ExtensionListItemDisabled : '');
3927
4518
  };
3928
4519
  const getId = focused => {
3929
4520
  if (focused) {
@@ -3936,12 +4527,14 @@ const getExtensionListItemVirtualDom = extension => {
3936
4527
  builtin = false,
3937
4528
  description,
3938
4529
  disabled = false,
4530
+ downloadCount = 'n/a',
3939
4531
  focused,
3940
4532
  icon,
3941
4533
  id,
3942
4534
  name,
3943
4535
  posInSet,
3944
4536
  publisher,
4537
+ rating = 'n/a',
3945
4538
  setSize,
3946
4539
  status
3947
4540
  } = extension;
@@ -3951,7 +4544,7 @@ const getExtensionListItemVirtualDom = extension => {
3951
4544
  ariaRoleDescription: Extension,
3952
4545
  ariaSetSize: setSize,
3953
4546
  childCount: 2,
3954
- className: getClassName(focused),
4547
+ className: getClassName(focused, disabled),
3955
4548
  id: getId(focused),
3956
4549
  role: ListItem,
3957
4550
  type: Div
@@ -3961,7 +4554,7 @@ const getExtensionListItemVirtualDom = extension => {
3961
4554
  role: None,
3962
4555
  src: icon,
3963
4556
  type: Img
3964
- }, listItemDetail, listItemName, text(name), listItemDescription, text(description), listItemFooter, listItemAuthorName, text(publisher), ...actionsDom];
4557
+ }, listItemDetail, listItemName, text(name), listItemDescription, text(description), listItemFooter, listItemAuthorName, text(publisher), ...getExtensionStatisticsVirtualDom(downloadCount, rating), ...actionsDom];
3965
4558
  return dom;
3966
4559
  };
3967
4560
 
@@ -3981,7 +4574,7 @@ const getExtensionsListVirtualDom = (visibleExtensions, focusOutline) => {
3981
4574
  onTouchStart: HandleTouchStart,
3982
4575
  onWheel: HandleWheel,
3983
4576
  role: List$1,
3984
- tabIndex: 0,
4577
+ tabIndex: Focusable,
3985
4578
  type: Div
3986
4579
  }, ...visibleExtensions.flatMap(getExtensionListItemVirtualDom)];
3987
4580
  return dom;
@@ -3993,14 +4586,20 @@ const getExtensionsVirtualDom = (visibleExtensions, focusOutline) => {
3993
4586
  return dom;
3994
4587
  };
3995
4588
 
4589
+ const noExtensionsFoundNode = {
4590
+ childCount: 1,
4591
+ className: NoExtensionsFoundMessage,
4592
+ type: Div
4593
+ };
3996
4594
  const getNoExtensionsFoundVirtualDom = message => {
3997
- return [{
3998
- childCount: 1,
3999
- className: NoExtensionsFoundMessage,
4000
- type: Div
4001
- }, text(message)];
4595
+ return [noExtensionsFoundNode, text(message)];
4002
4596
  };
4003
4597
 
4598
+ const scrollBarThumbNode = {
4599
+ childCount: 0,
4600
+ className: ScrollBarThumb,
4601
+ type: Div
4602
+ };
4004
4603
  const getScrollBarVirtualDom = (scrollBarHeight, scrollBarTop) => {
4005
4604
  const shouldShowScrollbar = scrollBarHeight > 0;
4006
4605
  if (!shouldShowScrollbar) {
@@ -4012,11 +4611,7 @@ const getScrollBarVirtualDom = (scrollBarHeight, scrollBarTop) => {
4012
4611
  onPointerDown: HandleScrollBarPointerDown,
4013
4612
  // TODO support pointercapture event
4014
4613
  type: Div
4015
- }, {
4016
- childCount: 0,
4017
- className: ScrollBarThumb,
4018
- type: Div
4019
- }];
4614
+ }, scrollBarThumbNode];
4020
4615
  };
4021
4616
 
4022
4617
  const getVisibleItem = (item, setSize, itemHeight, minLineY, relative, i, focusedIndex) => {
@@ -4025,16 +4620,19 @@ const getVisibleItem = (item, setSize, itemHeight, minLineY, relative, i, focuse
4025
4620
  builtin,
4026
4621
  description,
4027
4622
  disabled,
4623
+ downloadCount,
4028
4624
  icon,
4029
4625
  id,
4030
4626
  name,
4031
4627
  publisher,
4628
+ rating,
4032
4629
  status
4033
4630
  } = item;
4034
4631
  return {
4035
4632
  builtin,
4036
4633
  description,
4037
4634
  disabled,
4635
+ downloadCount,
4038
4636
  focused: i === focusedIndex,
4039
4637
  icon,
4040
4638
  id,
@@ -4042,6 +4640,7 @@ const getVisibleItem = (item, setSize, itemHeight, minLineY, relative, i, focuse
4042
4640
  name,
4043
4641
  posInSet: i + 1,
4044
4642
  publisher,
4643
+ rating,
4045
4644
  setSize,
4046
4645
  status,
4047
4646
  top: (i - minLineY) * itemHeight - relative
@@ -4082,6 +4681,7 @@ const getExtensionsViewVirtualDom = state => {
4082
4681
  const {
4083
4682
  completionFocusedIndex,
4084
4683
  completionItems,
4684
+ focus,
4085
4685
  focusedIndex,
4086
4686
  inputActions,
4087
4687
  message,
@@ -4090,7 +4690,7 @@ const getExtensionsViewVirtualDom = state => {
4090
4690
  scrollBarY,
4091
4691
  suggestOpen
4092
4692
  } = state;
4093
- const focusOutline = focusedIndex === -1 && state.focus === List$2;
4693
+ const focusOutline = focusedIndex === -1 && focus === List$2;
4094
4694
  return [{
4095
4695
  ariaBusy: false,
4096
4696
  ariaLive: 'polite',
@@ -4145,10 +4745,7 @@ const renderScrollBar = newState => {
4145
4745
  const roundedScrollBarY = Math.round(scrollBarY);
4146
4746
  const heightString = px(scrollBarHeight);
4147
4747
  const translateString = position(0, roundedScrollBarY);
4148
- let className = ScrollBarThumb;
4149
- if (newState.scrollBarActive) {
4150
- className += ' ' + ScrollBarThumbActive;
4151
- }
4748
+ const className = mergeClassNames(ScrollBarThumb, newState.scrollBarActive ? ScrollBarThumbActive : '');
4152
4749
  return [/* method */SetScrollBar, translateString, heightString, className];
4153
4750
  };
4154
4751
 
@@ -4167,7 +4764,7 @@ const titleFilters = [{
4167
4764
  value: Enabled$1
4168
4765
  }, {
4169
4766
  label: disabled,
4170
- value: Disabled$1
4767
+ value: Disabled$2
4171
4768
  }, {
4172
4769
  label: builtIn,
4173
4770
  value: Builtin
@@ -4439,13 +5036,6 @@ const scrollDown = state => {
4439
5036
  return setDeltaY(state, newDeltaY);
4440
5037
  };
4441
5038
 
4442
- const selectIndex = (state, index) => {
4443
- return {
4444
- ...state,
4445
- focusedIndex: index
4446
- };
4447
- };
4448
-
4449
5039
  const selectNextCompletion = state => {
4450
5040
  if (!state.suggestOpen || state.completionItems.length === 0) {
4451
5041
  return state;
@@ -4473,8 +5063,8 @@ const toggleSuggest = state => {
4473
5063
  const commandMap = {
4474
5064
  'Extensions.copyExtensionId': wrapCommand(copyExtensionId),
4475
5065
  'Extensions.copyExtensionInfo': wrapCommand(copyExtensionInfo),
4476
- 'SearchExtensions.acceptCompletion': wrapCommand(acceptCompletion),
4477
- 'SearchExtensions.clearSearchResults': wrapCommand(clearSearchResults),
5066
+ 'SearchExtensions.acceptCompletion': wrapAsyncCommand(acceptCompletionWithContext),
5067
+ 'SearchExtensions.clearSearchResults': wrapAsyncCommand(clearSearchResultsWithContext),
4478
5068
  'SearchExtensions.closeSuggest': wrapCommand(closeSuggest),
4479
5069
  'SearchExtensions.copyExtensionId': wrapCommand(copyExtensionId),
4480
5070
  'SearchExtensions.copyExtensionInfo': wrapCommand(copyExtensionInfo),
@@ -4485,6 +5075,7 @@ const commandMap = {
4485
5075
  'SearchExtensions.dispose': dispose,
4486
5076
  'SearchExtensions.enable': wrapCommand(enable$1),
4487
5077
  'SearchExtensions.enableWorkspace': wrapCommand(enableWorkspace),
5078
+ 'SearchExtensions.filterByMostPopular': wrapAsyncCommand(filterByMostPopularWithContext),
4488
5079
  'SearchExtensions.focusFirst': wrapCommand(focusFirst),
4489
5080
  'SearchExtensions.focusIndex': wrapCommand(focusIndex),
4490
5081
  'SearchExtensions.focusLast': wrapCommand(focusLast),
@@ -4512,7 +5103,7 @@ const commandMap = {
4512
5103
  'SearchExtensions.handleEnableWorkspace': wrapCommand(handleEnableWorkspace),
4513
5104
  'SearchExtensions.handleFocus': wrapCommand(handleFocus),
4514
5105
  'SearchExtensions.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
4515
- 'SearchExtensions.handleInput': wrapCommand(handleInput),
5106
+ 'SearchExtensions.handleInput': wrapAsyncCommand(handleInputWithContext),
4516
5107
  'SearchExtensions.handleInputFocus': wrapCommand(handleInputFocus),
4517
5108
  'SearchExtensions.handleInstall': wrapCommand(handleInstall),
4518
5109
  'SearchExtensions.handleScrollBarCaptureLost': wrapCommand(handleScrollBarCaptureLost),
@@ -4524,7 +5115,7 @@ const commandMap = {
4524
5115
  'SearchExtensions.handleWheel': wrapCommand(handleWheel),
4525
5116
  'SearchExtensions.initialize': initialize,
4526
5117
  'SearchExtensions.installAnotherVersion': wrapCommand(installAnotherVersion),
4527
- 'SearchExtensions.loadContent': wrapCommand(loadContent),
5118
+ 'SearchExtensions.loadContent': wrapAsyncCommand(loadContentWithContext),
4528
5119
  'SearchExtensions.openSuggest': wrapCommand(openSuggest),
4529
5120
  'SearchExtensions.render3': render3,
4530
5121
  'SearchExtensions.renderActions': renderActions,
@@ -4545,7 +5136,7 @@ const commandMap = {
4545
5136
 
4546
5137
  const listen = async () => {
4547
5138
  registerCommands(commandMap);
4548
- const rpc = await create$3({
5139
+ const rpc = await create$4({
4549
5140
  commandMap: commandMap
4550
5141
  });
4551
5142
  set$2(rpc);