@lvce-editor/title-bar-worker 4.24.0 → 4.25.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.
@@ -54,6 +54,61 @@ class VError extends Error {
54
54
  }
55
55
  }
56
56
 
57
+ class AssertionError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'AssertionError';
61
+ }
62
+ }
63
+ const Object$1 = 1;
64
+ const Number$1 = 2;
65
+ const Array$1 = 3;
66
+ const String$1 = 4;
67
+ const Boolean$1 = 5;
68
+ const Function = 6;
69
+ const Null = 7;
70
+ const Unknown$1 = 8;
71
+ const getType = value => {
72
+ switch (typeof value) {
73
+ case 'number':
74
+ return Number$1;
75
+ case 'function':
76
+ return Function;
77
+ case 'string':
78
+ return String$1;
79
+ case 'object':
80
+ if (value === null) {
81
+ return Null;
82
+ }
83
+ if (Array.isArray(value)) {
84
+ return Array$1;
85
+ }
86
+ return Object$1;
87
+ case 'boolean':
88
+ return Boolean$1;
89
+ default:
90
+ return Unknown$1;
91
+ }
92
+ };
93
+ const object = value => {
94
+ const type = getType(value);
95
+ if (type !== Object$1) {
96
+ throw new AssertionError('expected value to be of type object');
97
+ }
98
+ };
99
+ const number = value => {
100
+ const type = getType(value);
101
+ if (type !== Number$1) {
102
+ throw new AssertionError('expected value to be of type number');
103
+ }
104
+ };
105
+ const array = value => {
106
+ const type = getType(value);
107
+ if (type !== Array$1) {
108
+ throw new AssertionError('expected value to be of type array');
109
+ }
110
+ };
111
+
57
112
  const isMessagePort = value => {
58
113
  return value && value instanceof MessagePort;
59
114
  };
@@ -602,6 +657,9 @@ const restoreExistingError = (error, currentStack) => {
602
657
  };
603
658
  const restoreMethodNotFoundError = (error, currentStack) => {
604
659
  const restoredError = new JsonRpcError(error.message);
660
+ Object.assign(restoredError, {
661
+ code: error.code
662
+ });
605
663
  const parentStack = getParentStack(error);
606
664
  setStack(restoredError, `${parentStack}${NewLine}${currentStack}`);
607
665
  return restoredError;
@@ -621,9 +679,13 @@ const applyDataProperties = (restoredError, error) => {
621
679
  // @ts-ignore
622
680
  restoredError.codeFrame = error.data.codeFrame;
623
681
  }
624
- if (error.data.code) {
682
+ if (typeof error.data.code === 'string' || typeof error.data.code === 'number') {
625
683
  // @ts-ignore
626
- restoredError.code = error.data.code;
684
+ Object.defineProperty(restoredError, 'code', {
685
+ configurable: true,
686
+ value: error.data.code,
687
+ writable: true
688
+ });
627
689
  }
628
690
  if (error.data.type) {
629
691
  // @ts-ignore
@@ -644,7 +706,14 @@ const applyDirectProperties = (restoredError, error) => {
644
706
  }
645
707
  };
646
708
  const restoreMessageError = (error, _currentStack) => {
647
- const restoredError = constructError(error.message, error.type, error.name);
709
+ const restoredError = constructError(error.message, error.type || error.data?.type, error.name);
710
+ if (typeof error.code === 'string' || typeof error.code === 'number') {
711
+ Object.defineProperty(restoredError, 'code', {
712
+ configurable: true,
713
+ value: error.code,
714
+ writable: true
715
+ });
716
+ }
648
717
  if (error.data) {
649
718
  applyDataProperties(restoredError, error);
650
719
  } else {
@@ -723,9 +792,9 @@ const getErrorProperty = (error, prettyError) => {
723
792
  return {
724
793
  code: Custom,
725
794
  data: {
726
- code: prettyError.code,
795
+ code: prettyError.code ?? error?.code,
727
796
  codeFrame: prettyError.codeFrame,
728
- name: prettyError.name,
797
+ name: prettyError.name ?? error?.name,
729
798
  stack: getStack(prettyError),
730
799
  type: getErrorType(prettyError)
731
800
  },
@@ -745,7 +814,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
745
814
  const errorProperty = getErrorProperty(error, prettyError);
746
815
  return create$1$1(id, errorProperty);
747
816
  };
748
- const create$9 = (message, result) => {
817
+ const create$a = (message, result) => {
749
818
  return {
750
819
  id: message.id,
751
820
  jsonrpc: Two$1,
@@ -754,13 +823,18 @@ const create$9 = (message, result) => {
754
823
  };
755
824
  const getSuccessResponse = (message, result) => {
756
825
  const resultProperty = result ?? null;
757
- return create$9(message, resultProperty);
826
+ return create$a(message, resultProperty);
758
827
  };
759
828
  const getErrorResponseSimple = (id, error) => {
760
829
  return {
761
830
  error: {
762
831
  code: Custom,
763
- data: error,
832
+ data: error instanceof Error ? {
833
+ ...error,
834
+ code: 'code' in error ? error.code : undefined,
835
+ stack: error.stack,
836
+ type: error.name
837
+ } : error,
764
838
  // @ts-ignore
765
839
  message: error.message
766
840
  },
@@ -848,7 +922,7 @@ const handleJsonRpcMessage = async (...args) => {
848
922
 
849
923
  const Two = '2.0';
850
924
 
851
- const create$8 = (method, params) => {
925
+ const create$9 = (method, params) => {
852
926
  return {
853
927
  jsonrpc: Two,
854
928
  method,
@@ -856,7 +930,7 @@ const create$8 = (method, params) => {
856
930
  };
857
931
  };
858
932
 
859
- const create$7 = (id, method, params) => {
933
+ const create$8 = (id, method, params) => {
860
934
  const message = {
861
935
  id,
862
936
  jsonrpc: Two,
@@ -867,12 +941,12 @@ const create$7 = (id, method, params) => {
867
941
  };
868
942
 
869
943
  let id = 0;
870
- const create$6 = () => {
944
+ const create$7 = () => {
871
945
  return ++id;
872
946
  };
873
947
 
874
948
  const registerPromise = map => {
875
- const id = create$6();
949
+ const id = create$7();
876
950
  const {
877
951
  promise,
878
952
  resolve
@@ -889,7 +963,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
889
963
  id,
890
964
  promise
891
965
  } = registerPromise(callbacks);
892
- const message = create$7(id, method, params);
966
+ const message = create$8(id, method, params);
893
967
  if (useSendAndTransfer && ipc.sendAndTransfer) {
894
968
  ipc.sendAndTransfer(message);
895
969
  } else {
@@ -925,7 +999,7 @@ const createRpc = ipc => {
925
999
  * @deprecated
926
1000
  */
927
1001
  send(method, ...params) {
928
- const message = create$8(method, params);
1002
+ const message = create$9(method, params);
929
1003
  ipc.send(message);
930
1004
  }
931
1005
  };
@@ -965,7 +1039,7 @@ const listen$1 = async (module, options) => {
965
1039
  return ipc;
966
1040
  };
967
1041
 
968
- const create$5 = async ({
1042
+ const create$6 = async ({
969
1043
  commandMap,
970
1044
  isMessagePortOpen = true,
971
1045
  messagePort
@@ -983,7 +1057,7 @@ const create$5 = async ({
983
1057
  return rpc;
984
1058
  };
985
1059
 
986
- const create$4 = async ({
1060
+ const create$5 = async ({
987
1061
  commandMap,
988
1062
  isMessagePortOpen,
989
1063
  send
@@ -993,13 +1067,55 @@ const create$4 = async ({
993
1067
  port2
994
1068
  } = new MessageChannel();
995
1069
  await send(port1);
996
- return create$5({
1070
+ return create$6({
997
1071
  commandMap,
998
1072
  isMessagePortOpen,
999
1073
  messagePort: port2
1000
1074
  });
1001
1075
  };
1002
1076
 
1077
+ const createSharedLazyRpc = factory => {
1078
+ let rpcPromise;
1079
+ const getOrCreate = () => {
1080
+ if (!rpcPromise) {
1081
+ rpcPromise = factory();
1082
+ }
1083
+ return rpcPromise;
1084
+ };
1085
+ return {
1086
+ async dispose() {
1087
+ const rpc = await getOrCreate();
1088
+ await rpc.dispose();
1089
+ },
1090
+ async invoke(method, ...params) {
1091
+ const rpc = await getOrCreate();
1092
+ return rpc.invoke(method, ...params);
1093
+ },
1094
+ async invokeAndTransfer(method, ...params) {
1095
+ const rpc = await getOrCreate();
1096
+ return rpc.invokeAndTransfer(method, ...params);
1097
+ },
1098
+ async send(method, ...params) {
1099
+ const rpc = await getOrCreate();
1100
+ rpc.send(method, ...params);
1101
+ }
1102
+ };
1103
+ };
1104
+
1105
+ const create$4 = async ({
1106
+ commandMap,
1107
+ isMessagePortOpen,
1108
+ send
1109
+ }) => {
1110
+ return createSharedLazyRpc(() => {
1111
+ return create$5({
1112
+ commandMap,
1113
+ isMessagePortOpen,
1114
+ send
1115
+ });
1116
+ });
1117
+ };
1118
+
1003
1119
  const create$3 = async ({
1004
1120
  commandMap
1005
1121
  }) => {
@@ -1032,7 +1148,7 @@ const createMockRpc = ({
1032
1148
  };
1033
1149
 
1034
1150
  const rpcs = Object.create(null);
1035
- const set$4 = (id, rpc) => {
1151
+ const set$5 = (id, rpc) => {
1036
1152
  rpcs[id] = rpc;
1037
1153
  };
1038
1154
  const get$1 = id => {
@@ -1065,7 +1181,7 @@ const create$2 = rpcId => {
1065
1181
  const mockRpc = createMockRpc({
1066
1182
  commandMap
1067
1183
  });
1068
- set$4(rpcId, mockRpc);
1184
+ set$5(rpcId, mockRpc);
1069
1185
  // @ts-ignore
1070
1186
  mockRpc[Symbol.dispose] = () => {
1071
1187
  remove(rpcId);
@@ -1074,7 +1190,7 @@ const create$2 = rpcId => {
1074
1190
  return mockRpc;
1075
1191
  },
1076
1192
  set(rpc) {
1077
- set$4(rpcId, rpc);
1193
+ set$5(rpcId, rpc);
1078
1194
  }
1079
1195
  };
1080
1196
  };
@@ -1328,7 +1444,7 @@ const Backslash$2 = 91;
1328
1444
  const Star$1 = 131;
1329
1445
  const Plus$1 = 132;
1330
1446
 
1331
- const Unknown$1 = 'Unknown';
1447
+ const Unknown = 'Unknown';
1332
1448
  const Backspace = 'Backspace';
1333
1449
  const Tab = 'Tab';
1334
1450
  const Enter = 'Enter';
@@ -1461,7 +1577,7 @@ const keyCodeStringMap = {
1461
1577
  [UpArrow$1]: UpArrow
1462
1578
  };
1463
1579
  const getKeyCodeString = keyCode => {
1464
- return keyCodeStringMap[keyCode] || Unknown$1;
1580
+ return keyCodeStringMap[keyCode] || Unknown;
1465
1581
  };
1466
1582
 
1467
1583
  const CtrlCmd = 1 << 11 >>> 0;
@@ -1495,6 +1611,7 @@ const parseKey = rawKey => {
1495
1611
 
1496
1612
  const Electron$1 = 2;
1497
1613
 
1614
+ const MainProcess = -5;
1498
1615
  const RendererProcess = 1670;
1499
1616
  const RendererWorker = 1;
1500
1617
 
@@ -1504,66 +1621,16 @@ const SetFocusContext = 'Viewlet.setFocusContext';
1504
1621
 
1505
1622
  const FocusTitleBarMenuBar = 26;
1506
1623
 
1624
+ const {
1625
+ invoke: invoke$3,
1626
+ set: set$4
1627
+ } = create$2(MainProcess);
1628
+
1507
1629
  const {
1508
1630
  invoke: invoke$2,
1509
1631
  set: set$3
1510
1632
  } = create$2(RendererProcess);
1511
1633
 
1512
- class AssertionError extends Error {
1513
- constructor(message) {
1514
- super(message);
1515
- this.name = 'AssertionError';
1516
- }
1517
- }
1518
- const Object$1 = 1;
1519
- const Number$1 = 2;
1520
- const Array$1 = 3;
1521
- const String$1 = 4;
1522
- const Boolean$1 = 5;
1523
- const Function = 6;
1524
- const Null = 7;
1525
- const Unknown = 8;
1526
- const getType = value => {
1527
- switch (typeof value) {
1528
- case 'number':
1529
- return Number$1;
1530
- case 'function':
1531
- return Function;
1532
- case 'string':
1533
- return String$1;
1534
- case 'object':
1535
- if (value === null) {
1536
- return Null;
1537
- }
1538
- if (Array.isArray(value)) {
1539
- return Array$1;
1540
- }
1541
- return Object$1;
1542
- case 'boolean':
1543
- return Boolean$1;
1544
- default:
1545
- return Unknown;
1546
- }
1547
- };
1548
- const object = value => {
1549
- const type = getType(value);
1550
- if (type !== Object$1) {
1551
- throw new AssertionError('expected value to be of type object');
1552
- }
1553
- };
1554
- const number = value => {
1555
- const type = getType(value);
1556
- if (type !== Number$1) {
1557
- throw new AssertionError('expected value to be of type number');
1558
- }
1559
- };
1560
- const array = value => {
1561
- const type = getType(value);
1562
- if (type !== Array$1) {
1563
- throw new AssertionError('expected value to be of type array');
1564
- }
1565
- };
1566
-
1567
1634
  const {
1568
1635
  invoke: invoke$1,
1569
1636
  invokeAndTransfer,
@@ -1580,9 +1647,6 @@ const sendMessagePortToTextMeasurementWorker = async port => {
1580
1647
  const command = 'TextMeasurement.handleMessagePort';
1581
1648
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToTextMeasurementWorker', port, command, 0);
1582
1649
  };
1583
- const getWindowId$1 = async () => {
1584
- return invoke$1('GetWindowId.getWindowId');
1585
- };
1586
1650
  const minimizeWindow = async () => {
1587
1651
  return invoke$1('ElectronWindow.minimize');
1588
1652
  };
@@ -2116,8 +2180,9 @@ const {
2116
2180
  getCommandIds,
2117
2181
  registerCommands,
2118
2182
  set: set$1,
2119
- wrapCommand,
2120
- wrapGetter
2183
+ wrapCommand: wrapNotification,
2184
+ wrapGetter,
2185
+ wrapSerialCommand: wrapCommand
2121
2186
  } = create$1();
2122
2187
 
2123
2188
  const create3 = (id, uri, x, y, width, height, platform, controlsOverlayEnabled, titleBarStyleCustom, assetDir) => {
@@ -2606,7 +2671,7 @@ const getMenuEntries$b = async (platform, autoSave$1, hasActiveTextEditor = fals
2606
2671
  const saveFlags = getSaveFlags(hasActiveTextEditor);
2607
2672
  const entries = [{
2608
2673
  command: 'Main.newFile',
2609
- flags: None,
2674
+ flags: RestoreEditorFocus,
2610
2675
  id: 'newFile',
2611
2676
  label: newFile()
2612
2677
  }, {
@@ -3203,11 +3268,18 @@ const getEntryMap = async (state, menuIds, platform) => {
3203
3268
  return map;
3204
3269
  };
3205
3270
 
3206
- // TODO cache window id
3207
-
3208
- const getWindowId = async () => {
3209
- const windowId = await getWindowId$1();
3210
- return windowId;
3271
+ const send = async port => {
3272
+ await invokeAndTransfer('SendMessagePortToMainProcess.sendMessagePortToMainProcess', port, 'HandleElectronMessagePort.handleElectronMessagePort', 0);
3273
+ };
3274
+ const initializeMainProcess = async () => {
3275
+ if (get$1(MainProcess)) {
3276
+ return;
3277
+ }
3278
+ const rpc = await create$4({
3279
+ commandMap: {},
3280
+ send
3281
+ });
3282
+ set$4(rpc);
3211
3283
  };
3212
3284
 
3213
3285
  // based on https://www.electronjs.org/docs/latest/api/menu-item#new-menuitemoptions
@@ -3349,8 +3421,8 @@ const toElectronMenu = (map, rootId) => {
3349
3421
  };
3350
3422
 
3351
3423
  const setItems = async items => {
3352
- const windowId = await getWindowId();
3353
- return invoke$1('WebView.compatSharedProcessInvoke', 'ElectronApplicationMenu.setItems', windowId, items);
3424
+ await initializeMainProcess();
3425
+ return invoke$3('ElectronApplicationMenu.setItems', items);
3354
3426
  };
3355
3427
  const hydrate = async state => {
3356
3428
  const {
@@ -3753,164 +3825,47 @@ const handleClick$1 = async (state, buttonName) => {
3753
3825
  return state;
3754
3826
  };
3755
3827
 
3756
- const commandCenterItems = [{
3757
- command: 'QuickPick.showFile',
3758
- label: 'Go to File'
3759
- }, {
3760
- command: 'QuickPick.showCommands',
3761
- label: 'Show and Run Commands'
3762
- }, {
3763
- args: ['Search'],
3764
- command: 'Layout.openSideBarViewlet',
3765
- label: 'Search for Text'
3766
- }, {
3767
- args: ['symbol'],
3768
- command: 'QuickPick.show',
3769
- label: 'Go to Symbol in Editor'
3770
- }, {
3771
- args: ['Run And Debug'],
3772
- command: 'Layout.openSideBarViewlet',
3773
- label: 'Start Debugging'
3774
- }, {
3775
- command: 'QuickPick.showCommands',
3776
- label: 'Run Task'
3777
- }, {
3778
- command: 'QuickPick.showEverything',
3779
- label: 'More'
3780
- }];
3781
- const handleCommandCenterClick = async state => {
3782
- await invoke$1('QuickPick.show', 'custom', commandCenterItems, undefined, {
3783
- executeItemCommand: true,
3784
- mode: 'quickPick',
3785
- placeholder: 'Search files by name (append : to go to line or @ to go to symbol)',
3786
- waitUntil: 'visible'
3787
- });
3788
- return state;
3789
- };
3790
-
3791
- const handleCommandCenterKeyDown = async (state, key) => {
3792
- if (key !== 'Enter' && key !== ' ' && key !== 'Space') {
3793
- return state;
3794
- }
3795
- return handleCommandCenterClick(state);
3796
- };
3797
-
3798
- const show2 = async (uid, menuId, x, y, args) => {
3799
- await showContextMenu2(uid, menuId, x, y, args);
3800
- };
3801
-
3802
- const handleContextMenu = async (state, button, eventX, eventY) => {
3828
+ const getNavigableTitleBarEntries = state => {
3803
3829
  const {
3804
- uid
3830
+ focusedIndex,
3831
+ isMenuOpen,
3832
+ titleBarEntries,
3833
+ width
3805
3834
  } = state;
3806
- await show2(uid, MenuIdTitleBarContextMenu, eventX, eventY, {
3807
- menuId: MenuIdTitleBarContextMenu
3808
- });
3809
- return state;
3835
+ return getVisibleTitleBarEntries(titleBarEntries, width, focusedIndex, isMenuOpen);
3810
3836
  };
3811
3837
 
3812
- const handleElectronMenuClick = async (state, label) => {
3838
+ const LeftClick = 0;
3839
+
3840
+ const closeMenu = (state, keepFocus) => {
3813
3841
  const {
3814
- commandMap
3842
+ focused,
3843
+ focusedIndex,
3844
+ isMenuOpen,
3845
+ menus
3815
3846
  } = state;
3816
- const commandPair = commandMap[label];
3817
- if (!commandPair) {
3818
- throw new Error(`no command found for ${label}`);
3847
+ // TODO send to renderer process
3848
+ // 1. close menu
3849
+ // 2. focus top level entry
3850
+ const newFocused = keepFocus ? focused : false;
3851
+ const newFocusedIndex = keepFocus ? focusedIndex : -1;
3852
+ if (!isMenuOpen && menus.length === 0 && focused === newFocused && focusedIndex === newFocusedIndex) {
3853
+ return state;
3819
3854
  }
3820
- const {
3821
- args = [],
3822
- command
3823
- } = commandPair;
3824
- await invoke$1(command, ...args);
3825
- return state;
3855
+ return {
3856
+ ...state,
3857
+ focused: newFocused,
3858
+ focusedIndex: newFocusedIndex,
3859
+ isMenuOpen: false,
3860
+ menus: []
3861
+ };
3826
3862
  };
3827
3863
 
3828
- const state = {
3829
- connected: false
3830
- };
3831
- const isConnected = () => {
3832
- const {
3833
- connected
3834
- } = state;
3835
- return connected;
3836
- };
3837
- const invoke = (method, ...params) => {
3838
- return invoke$2(method, ...params);
3839
- };
3840
- const set = rpc => {
3841
- set$3(rpc);
3842
- state.connected = true;
3843
- };
3844
-
3845
- const commandQueues = new Map();
3846
- const handleMessagePort = async (port, viewletCommandMap, setAsRendererProcess = true) => {
3847
- const executeViewletCommand = async (uid, command, ...args) => {
3848
- const fn = viewletCommandMap[`TitleBar.${command}`];
3849
- if (typeof fn !== 'function') {
3850
- throw new TypeError(`Viewlet command not found: ${command}`);
3851
- }
3852
- const previous = commandQueues.get(uid);
3853
- const {
3854
- promise: next,
3855
- resolve
3856
- } = Promise.withResolvers();
3857
- commandQueues.set(uid, next);
3858
- if (previous) {
3859
- await previous;
3860
- }
3861
- try {
3862
- await fn(uid, ...args);
3863
- await invoke$1('Viewlet.requestRender', uid);
3864
- } finally {
3865
- resolve();
3866
- if (commandQueues.get(uid) === next) {
3867
- commandQueues.delete(uid);
3868
- }
3869
- }
3870
- };
3871
- const rpc = await create$5({
3872
- commandMap: {
3873
- 'Viewlet.executeViewletCommand': executeViewletCommand
3874
- },
3875
- messagePort: port
3876
- });
3877
- if (setAsRendererProcess) {
3878
- set(rpc);
3879
- }
3880
- };
3881
-
3882
- const getMenuOffset = (x, clientX, iconWidth) => {
3883
- return clientX - x - iconWidth;
3884
- };
3885
-
3886
- const getNavigableTitleBarEntries = state => {
3887
- const {
3888
- focusedIndex,
3889
- isMenuOpen,
3890
- titleBarEntries,
3891
- width
3892
- } = state;
3893
- return getVisibleTitleBarEntries(titleBarEntries, width, focusedIndex, isMenuOpen);
3894
- };
3895
-
3896
- const getTitleBarIndexFromPosition = (titleBarEntries, x, y) => {
3897
- let currentX = 0;
3898
- for (let i = 0; i < titleBarEntries.length; i++) {
3899
- const entry = titleBarEntries[i];
3900
- const entryWidth = entry.width;
3901
- if (x >= currentX && x < currentX + entryWidth) {
3902
- return i;
3903
- }
3904
- currentX += entryWidth;
3905
- }
3906
- return -1;
3907
- };
3908
-
3909
- const toCommandInfo = entry => {
3910
- return {
3911
- args: entry.args,
3912
- command: entry.command
3913
- };
3864
+ const toCommandInfo = entry => {
3865
+ return {
3866
+ args: entry.args,
3867
+ command: entry.command
3868
+ };
3914
3869
  };
3915
3870
  const addMenuEntryKeyBindings = async entries => {
3916
3871
  try {
@@ -4093,6 +4048,180 @@ const openMenuAtIndex = async (state, index, shouldBeFocused) => {
4093
4048
  };
4094
4049
  };
4095
4050
 
4051
+ const toggleIndex = async (state, index) => {
4052
+ const {
4053
+ focusedIndex,
4054
+ isMenuOpen
4055
+ } = state;
4056
+ if (isMenuOpen && focusedIndex === index) {
4057
+ return closeMenu(state, /* keepFocus */true);
4058
+ }
4059
+ return openMenuAtIndex(state, index, /* focus */false);
4060
+ };
4061
+
4062
+ const handleClick = async (state, button, index) => {
4063
+ if (button !== LeftClick) {
4064
+ return state;
4065
+ }
4066
+ if (index === -1) {
4067
+ return state;
4068
+ }
4069
+ const newState = await toggleIndex(state, index);
4070
+ return {
4071
+ ...newState,
4072
+ focused: true
4073
+ };
4074
+ };
4075
+
4076
+ const handleClickByName = async (state, button, name) => {
4077
+ const entries = getNavigableTitleBarEntries(state);
4078
+ const index = entries.findIndex(entry => entry.label === name);
4079
+ return handleClick(state, button, index);
4080
+ };
4081
+
4082
+ const commandCenterItems = [{
4083
+ command: 'QuickPick.showFile',
4084
+ label: 'Go to File'
4085
+ }, {
4086
+ command: 'QuickPick.showCommands',
4087
+ label: 'Show and Run Commands'
4088
+ }, {
4089
+ args: ['Search'],
4090
+ command: 'Layout.openSideBarViewlet',
4091
+ label: 'Search for Text'
4092
+ }, {
4093
+ args: ['symbol'],
4094
+ command: 'QuickPick.show',
4095
+ label: 'Go to Symbol in Editor'
4096
+ }, {
4097
+ args: ['Run And Debug'],
4098
+ command: 'Layout.openSideBarViewlet',
4099
+ label: 'Start Debugging'
4100
+ }, {
4101
+ command: 'QuickPick.showCommands',
4102
+ label: 'Run Task'
4103
+ }, {
4104
+ command: 'QuickPick.showEverything',
4105
+ label: 'More'
4106
+ }];
4107
+ const handleCommandCenterClick = async state => {
4108
+ await invoke$1('QuickPick.show', 'custom', commandCenterItems, undefined, {
4109
+ executeItemCommand: true,
4110
+ mode: 'quickPick',
4111
+ placeholder: 'Search files by name (append : to go to line or @ to go to symbol)',
4112
+ waitUntil: 'visible'
4113
+ });
4114
+ return state;
4115
+ };
4116
+
4117
+ const handleCommandCenterKeyDown = async (state, key) => {
4118
+ if (key !== 'Enter' && key !== ' ' && key !== 'Space') {
4119
+ return state;
4120
+ }
4121
+ return handleCommandCenterClick(state);
4122
+ };
4123
+
4124
+ const show2 = async (uid, menuId, x, y, args) => {
4125
+ await showContextMenu2(uid, menuId, x, y, args);
4126
+ };
4127
+
4128
+ const handleContextMenu = async (state, button, eventX, eventY) => {
4129
+ const {
4130
+ uid
4131
+ } = state;
4132
+ await show2(uid, MenuIdTitleBarContextMenu, eventX, eventY, {
4133
+ menuId: MenuIdTitleBarContextMenu
4134
+ });
4135
+ return state;
4136
+ };
4137
+
4138
+ const handleElectronMenuClick = async (state, label) => {
4139
+ const {
4140
+ commandMap
4141
+ } = state;
4142
+ const commandPair = commandMap[label];
4143
+ if (!commandPair) {
4144
+ throw new Error(`no command found for ${label}`);
4145
+ }
4146
+ const {
4147
+ args = [],
4148
+ command
4149
+ } = commandPair;
4150
+ await invoke$1(command, ...args);
4151
+ return state;
4152
+ };
4153
+
4154
+ const state = {
4155
+ connected: false
4156
+ };
4157
+ const isConnected = () => {
4158
+ const {
4159
+ connected
4160
+ } = state;
4161
+ return connected;
4162
+ };
4163
+ const invoke = (method, ...params) => {
4164
+ return invoke$2(method, ...params);
4165
+ };
4166
+ const set = rpc => {
4167
+ set$3(rpc);
4168
+ state.connected = true;
4169
+ };
4170
+
4171
+ const commandQueues = new Map();
4172
+ const handleMessagePort = async (port, viewletCommandMap, setAsRendererProcess = true) => {
4173
+ const executeViewletCommand = async (uid, command, ...args) => {
4174
+ const fn = viewletCommandMap[`TitleBar.${command}`];
4175
+ if (typeof fn !== 'function') {
4176
+ throw new TypeError(`Viewlet command not found: ${command}`);
4177
+ }
4178
+ const previous = commandQueues.get(uid);
4179
+ const {
4180
+ promise: next,
4181
+ resolve
4182
+ } = Promise.withResolvers();
4183
+ commandQueues.set(uid, next);
4184
+ if (previous) {
4185
+ await previous;
4186
+ }
4187
+ try {
4188
+ await fn(uid, ...args);
4189
+ await invoke$1('Viewlet.requestRender', uid);
4190
+ } finally {
4191
+ resolve();
4192
+ if (commandQueues.get(uid) === next) {
4193
+ commandQueues.delete(uid);
4194
+ }
4195
+ }
4196
+ };
4197
+ const rpc = await create$6({
4198
+ commandMap: {
4199
+ 'Viewlet.executeViewletCommand': executeViewletCommand
4200
+ },
4201
+ messagePort: port
4202
+ });
4203
+ if (setAsRendererProcess) {
4204
+ set(rpc);
4205
+ }
4206
+ };
4207
+
4208
+ const getMenuOffset = (x, clientX, iconWidth) => {
4209
+ return clientX - x - iconWidth;
4210
+ };
4211
+
4212
+ const getTitleBarIndexFromPosition = (titleBarEntries, x, y) => {
4213
+ let currentX = 0;
4214
+ for (let i = 0; i < titleBarEntries.length; i++) {
4215
+ const entry = titleBarEntries[i];
4216
+ const entryWidth = entry.width;
4217
+ if (x >= currentX && x < currentX + entryWidth) {
4218
+ return i;
4219
+ }
4220
+ currentX += entryWidth;
4221
+ }
4222
+ return -1;
4223
+ };
4224
+
4096
4225
  const focusIndex = async (state, index) => {
4097
4226
  object(state);
4098
4227
  number(index);
@@ -4242,7 +4371,7 @@ const getTitle = (workspaceUri, titleTemplate, appName) => {
4242
4371
  };
4243
4372
 
4244
4373
  const launchTextMeasurementWorker = async () => {
4245
- const rpc = await create$4({
4374
+ const rpc = await create$5({
4246
4375
  commandMap: {},
4247
4376
  async send(port) {
4248
4377
  await sendMessagePortToTextMeasurementWorker(port);
@@ -4286,7 +4415,9 @@ const handleWorkspaceChange = async (state, uri) => {
4286
4415
  labelFontSize,
4287
4416
  labelFontWeight,
4288
4417
  labelLetterSpacing,
4289
- titleTemplate
4418
+ titleTemplate,
4419
+ titleWidth: oldTitleWidth,
4420
+ width
4290
4421
  } = state;
4291
4422
  const title = getTitle(uri, titleTemplate, appName);
4292
4423
  const titleWidth = await measureTitleWidth(title, labelFontWeight, labelFontSize, labelFontFamily, labelLetterSpacing);
@@ -4294,6 +4425,8 @@ const handleWorkspaceChange = async (state, uri) => {
4294
4425
  ...state,
4295
4426
  title,
4296
4427
  titleWidth,
4428
+ // The title is centered, so half its width change becomes available to the menu.
4429
+ width: width + (oldTitleWidth - titleWidth) / 2,
4297
4430
  workspaceUri: uri
4298
4431
  };
4299
4432
  };
@@ -4410,7 +4543,7 @@ const renderFocusedIndex = (oldState, newState) => {
4410
4543
  if (newState.focusedIndex === -1) {
4411
4544
  return [];
4412
4545
  }
4413
- return [FocusSelector, newState.uid, '.ViewletTitleBarMenuBar'];
4546
+ return [FocusSelector, newState.uid, '.TitleBarMenuBar'];
4414
4547
  };
4415
4548
 
4416
4549
  const getKeyBindingString = (key, altKey, ctrlKey, shiftKey, metaKey) => {
@@ -4716,13 +4849,18 @@ const renderDirect = async (uid, commands) => {
4716
4849
  return [...rendererWorkerCommands, ['Viewlet.commitPending', uid, transactionId]];
4717
4850
  };
4718
4851
  const render3 = async (uid, diffResult) => {
4852
+ // State may change between the renderer worker's diff and render RPCs.
4853
+ const pendingDiffs = new Set([...diffResult, ...diff3(uid)]);
4719
4854
  const {
4720
4855
  newState,
4721
4856
  oldState
4722
4857
  } = get(uid);
4723
4858
  set$1(uid, newState, newState);
4724
4859
  const commands = [];
4725
- for (const item of diffResult) {
4860
+ for (const item of numbers) {
4861
+ if (!pendingDiffs.has(item)) {
4862
+ continue;
4863
+ }
4726
4864
  const fn = getRenderer3(item);
4727
4865
  const result = fn(oldState, newState);
4728
4866
  if (result.length > 0) {
@@ -4770,7 +4908,7 @@ const renderEventListeners = () => {
4770
4908
  params: ['handleMenuMouseOver', ClientX, ClientY]
4771
4909
  }, {
4772
4910
  name: HandleClick,
4773
- params: ['handleClickAt', Button, ClientX, ClientY]
4911
+ params: ['handleClickByName', Button, TargetName]
4774
4912
  }, {
4775
4913
  name: HandlePointerOut,
4776
4914
  params: ['handlePointerOut', ClientX, ClientY]
@@ -4842,6 +4980,8 @@ const setTitleTemplate = async (state, titleTemplate) => {
4842
4980
  labelFontSize,
4843
4981
  labelFontWeight,
4844
4982
  labelLetterSpacing,
4983
+ titleWidth: oldTitleWidth,
4984
+ width,
4845
4985
  workspaceUri
4846
4986
  } = state;
4847
4987
  const title = getTitle(workspaceUri, titleTemplate, appName);
@@ -4850,7 +4990,9 @@ const setTitleTemplate = async (state, titleTemplate) => {
4850
4990
  ...state,
4851
4991
  title,
4852
4992
  titleTemplate,
4853
- titleWidth
4993
+ titleWidth,
4994
+ // The title is centered, so half its width change becomes available to the menu.
4995
+ width: width + (oldTitleWidth - titleWidth) / 2
4854
4996
  };
4855
4997
  };
4856
4998
 
@@ -4911,30 +5053,6 @@ const create = (id, uri, x, y, width, height) => {
4911
5053
  return state;
4912
5054
  };
4913
5055
 
4914
- const closeMenu = (state, keepFocus) => {
4915
- const {
4916
- focused,
4917
- focusedIndex,
4918
- isMenuOpen,
4919
- menus
4920
- } = state;
4921
- // TODO send to renderer process
4922
- // 1. close menu
4923
- // 2. focus top level entry
4924
- const newFocused = keepFocus ? focused : false;
4925
- const newFocusedIndex = keepFocus ? focusedIndex : -1;
4926
- if (!isMenuOpen && menus.length === 0 && focused === newFocused && focusedIndex === newFocusedIndex) {
4927
- return state;
4928
- }
4929
- return {
4930
- ...state,
4931
- focused: newFocused,
4932
- focusedIndex: newFocusedIndex,
4933
- isMenuOpen: false,
4934
- menus: []
4935
- };
4936
- };
4937
-
4938
5056
  const first = () => {
4939
5057
  return 0;
4940
5058
  };
@@ -4981,33 +5099,6 @@ const focusPrevious = state => {
4981
5099
  return focusIndex(state, indexToFocus);
4982
5100
  };
4983
5101
 
4984
- const LeftClick = 0;
4985
-
4986
- const toggleIndex = async (state, index) => {
4987
- const {
4988
- focusedIndex,
4989
- isMenuOpen
4990
- } = state;
4991
- if (isMenuOpen && focusedIndex === index) {
4992
- return closeMenu(state, /* keepFocus */true);
4993
- }
4994
- return openMenuAtIndex(state, index, /* focus */false);
4995
- };
4996
-
4997
- const handleClick = async (state, button, index) => {
4998
- if (button !== LeftClick) {
4999
- return state;
5000
- }
5001
- if (index === -1) {
5002
- return state;
5003
- }
5004
- const newState = await toggleIndex(state, index);
5005
- return {
5006
- ...newState,
5007
- focused: true
5008
- };
5009
- };
5010
-
5011
5102
  const handleClickAt = async (state, button, eventX, eventY) => {
5012
5103
  const {
5013
5104
  iconWidth,
@@ -5556,6 +5647,7 @@ const commandMap = {
5556
5647
  'TitleBar.handleButtonsClick': handleClick$1,
5557
5648
  'TitleBar.handleClick': wrapCommand(handleClick),
5558
5649
  'TitleBar.handleClickAt': wrapCommand(handleClickAt),
5650
+ 'TitleBar.handleClickByName': wrapCommand(handleClickByName),
5559
5651
  'TitleBar.handleClickClose': wrapCommand(handleClickClose),
5560
5652
  'TitleBar.handleClickMinimize': wrapCommand(handleClickMinimize),
5561
5653
  'TitleBar.handleClickToggleMaximize': wrapCommand(handleClickToggleMaximize),
@@ -5582,7 +5674,8 @@ const commandMap = {
5582
5674
  'TitleBar.handlePointerOut': wrapCommand(handlePointerOut),
5583
5675
  'TitleBar.handlePointerOver': wrapCommand(handlePointerOver),
5584
5676
  'TitleBar.handleTitleBarContextMenu': wrapCommand(handleTitleBarContextMenu),
5585
- 'TitleBar.handleWorkspaceChange': wrapCommand(handleWorkspaceChange),
5677
+ // Workspace actions await this callback while holding the ordinary command queue.
5678
+ 'TitleBar.handleWorkspaceChange': wrapNotification(handleWorkspaceChange),
5586
5679
  'TitleBar.hideCommandCenter': wrapCommand(hideCommandCenter),
5587
5680
  'TitleBar.hideMenuBar': wrapCommand(hideMenuBar),
5588
5681
  'TitleBar.hydrateElectronApplicationMenu': wrapCommand(hydrate),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/title-bar-worker",
3
- "version": "4.24.0",
3
+ "version": "4.25.1",
4
4
  "description": "Title Bar Worker",
5
5
  "repository": {
6
6
  "type": "git",