@theia/core 1.37.0-next.8 → 1.37.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.
Files changed (175) hide show
  1. package/README.md +7 -9
  2. package/i18n/nls.cs.json +6 -1
  3. package/i18n/nls.de.json +6 -1
  4. package/i18n/nls.es.json +6 -1
  5. package/i18n/nls.fr.json +6 -1
  6. package/i18n/nls.hu.json +6 -1
  7. package/i18n/nls.it.json +6 -1
  8. package/i18n/nls.ja.json +6 -1
  9. package/i18n/nls.json +6 -1
  10. package/i18n/nls.pl.json +6 -1
  11. package/i18n/nls.pt-br.json +6 -1
  12. package/i18n/nls.pt-pt.json +6 -1
  13. package/i18n/nls.ru.json +6 -1
  14. package/i18n/nls.zh-cn.json +6 -1
  15. package/lib/browser/core-preferences.d.ts +4 -0
  16. package/lib/browser/core-preferences.d.ts.map +1 -1
  17. package/lib/browser/core-preferences.js +22 -0
  18. package/lib/browser/core-preferences.js.map +1 -1
  19. package/lib/browser/hover-service.d.ts +5 -0
  20. package/lib/browser/hover-service.d.ts.map +1 -1
  21. package/lib/browser/hover-service.js +7 -1
  22. package/lib/browser/hover-service.js.map +1 -1
  23. package/lib/browser/icon-theme-service.js +1 -1
  24. package/lib/browser/icon-theme-service.js.map +1 -1
  25. package/lib/browser/shell/application-shell.d.ts +2 -1
  26. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  27. package/lib/browser/shell/application-shell.js +30 -3
  28. package/lib/browser/shell/application-shell.js.map +1 -1
  29. package/lib/browser/shell/tab-bars.d.ts +21 -5
  30. package/lib/browser/shell/tab-bars.d.ts.map +1 -1
  31. package/lib/browser/shell/tab-bars.js +94 -17
  32. package/lib/browser/shell/tab-bars.js.map +1 -1
  33. package/lib/browser/test/jsdom.js +1 -1
  34. package/lib/browser/test/jsdom.js.map +1 -1
  35. package/lib/browser/tree/tree-iterator.js +4 -4
  36. package/lib/browser/tree/tree-iterator.js.map +1 -1
  37. package/lib/browser/tree/tree-selection-state.spec.js +26 -2
  38. package/lib/browser/tree/tree-selection-state.spec.js.map +1 -1
  39. package/lib/common/i18n/localization.d.ts +1 -0
  40. package/lib/common/i18n/localization.d.ts.map +1 -1
  41. package/lib/common/i18n/localization.js +2 -16
  42. package/lib/common/i18n/localization.js.map +1 -1
  43. package/lib/common/nls.d.ts +1 -0
  44. package/lib/common/nls.d.ts.map +1 -1
  45. package/lib/common/nls.js +2 -1
  46. package/lib/common/nls.js.map +1 -1
  47. package/lib/common/quick-pick-service.d.ts +2 -1
  48. package/lib/common/quick-pick-service.d.ts.map +1 -1
  49. package/lib/common/quick-pick-service.js.map +1 -1
  50. package/lib/electron-browser/electron-clipboard-service.d.ts.map +1 -1
  51. package/lib/electron-browser/electron-clipboard-service.js +2 -3
  52. package/lib/electron-browser/electron-clipboard-service.js.map +1 -1
  53. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.d.ts.map +1 -1
  54. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.js +1 -2
  55. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.js.map +1 -1
  56. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts +2 -3
  57. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts.map +1 -1
  58. package/lib/electron-browser/menu/electron-context-menu-renderer.js +10 -18
  59. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  60. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +10 -8
  61. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  62. package/lib/electron-browser/menu/electron-main-menu-factory.js +33 -32
  63. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  64. package/lib/electron-browser/menu/electron-menu-contribution.d.ts +6 -6
  65. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  66. package/lib/electron-browser/menu/electron-menu-contribution.js +39 -54
  67. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  68. package/lib/electron-browser/messaging/electron-ipc-connection-provider.d.ts.map +1 -1
  69. package/lib/electron-browser/messaging/electron-ipc-connection-provider.js +2 -6
  70. package/lib/electron-browser/messaging/electron-ipc-connection-provider.js.map +1 -1
  71. package/lib/electron-browser/preload.d.ts +2 -0
  72. package/lib/electron-browser/preload.d.ts.map +1 -0
  73. package/lib/electron-browser/preload.js +183 -0
  74. package/lib/electron-browser/preload.js.map +1 -0
  75. package/lib/electron-browser/token/electron-token-frontend-module.d.ts.map +1 -1
  76. package/lib/electron-browser/token/electron-token-frontend-module.js +1 -2
  77. package/lib/electron-browser/token/electron-token-frontend-module.js.map +1 -1
  78. package/lib/electron-browser/window/electron-frontend-application-state.d.ts.map +1 -1
  79. package/lib/electron-browser/window/electron-frontend-application-state.js +1 -3
  80. package/lib/electron-browser/window/electron-frontend-application-state.js.map +1 -1
  81. package/lib/electron-browser/window/electron-secondary-window-service.d.ts +1 -3
  82. package/lib/electron-browser/window/electron-secondary-window-service.d.ts.map +1 -1
  83. package/lib/electron-browser/window/electron-secondary-window-service.js +6 -34
  84. package/lib/electron-browser/window/electron-secondary-window-service.js.map +1 -1
  85. package/lib/electron-browser/window/electron-window-service.d.ts +1 -8
  86. package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
  87. package/lib/electron-browser/window/electron-window-service.js +8 -25
  88. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  89. package/lib/electron-common/electron-api.d.ts +94 -0
  90. package/lib/electron-common/electron-api.d.ts.map +1 -0
  91. package/lib/electron-common/electron-api.js +53 -0
  92. package/lib/electron-common/electron-api.js.map +1 -0
  93. package/lib/electron-common/messaging/electron-connection-handler.d.ts +0 -7
  94. package/lib/electron-common/messaging/electron-connection-handler.d.ts.map +1 -1
  95. package/lib/electron-common/messaging/electron-connection-handler.js +1 -5
  96. package/lib/electron-common/messaging/electron-connection-handler.js.map +1 -1
  97. package/lib/electron-main/electron-api-main.d.ts +21 -0
  98. package/lib/electron-main/electron-api-main.d.ts.map +1 -0
  99. package/lib/electron-main/electron-api-main.js +261 -0
  100. package/lib/electron-main/electron-api-main.js.map +1 -0
  101. package/lib/electron-main/electron-main-application-module.d.ts.map +1 -1
  102. package/lib/electron-main/electron-main-application-module.js +3 -3
  103. package/lib/electron-main/electron-main-application-module.js.map +1 -1
  104. package/lib/electron-main/electron-main-application.d.ts +8 -2
  105. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  106. package/lib/electron-main/electron-main-application.js +32 -29
  107. package/lib/electron-main/electron-main-application.js.map +1 -1
  108. package/lib/electron-main/electron-security-token-service.d.ts.map +1 -1
  109. package/lib/electron-main/electron-security-token-service.js +2 -1
  110. package/lib/electron-main/electron-security-token-service.js.map +1 -1
  111. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +4 -5
  112. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts.map +1 -1
  113. package/lib/electron-main/messaging/electron-messaging-contribution.js +4 -7
  114. package/lib/electron-main/messaging/electron-messaging-contribution.js.map +1 -1
  115. package/lib/electron-main/theia-electron-window.d.ts +2 -4
  116. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  117. package/lib/electron-main/theia-electron-window.js +11 -34
  118. package/lib/electron-main/theia-electron-window.js.map +1 -1
  119. package/lib/node/i18n/localization-backend-contribution.d.ts.map +1 -1
  120. package/lib/node/i18n/localization-backend-contribution.js +2 -1
  121. package/lib/node/i18n/localization-backend-contribution.js.map +1 -1
  122. package/lib/node/i18n/localization-provider.d.ts.map +1 -1
  123. package/lib/node/i18n/localization-provider.js +2 -1
  124. package/lib/node/i18n/localization-provider.js.map +1 -1
  125. package/package.json +9 -6
  126. package/src/browser/core-preferences.ts +26 -0
  127. package/src/browser/hover-service.ts +12 -1
  128. package/src/browser/icon-theme-service.ts +1 -1
  129. package/src/browser/shell/application-shell.ts +29 -1
  130. package/src/browser/shell/tab-bars.ts +111 -17
  131. package/src/browser/style/hover-service.css +4 -0
  132. package/src/browser/style/tabs.css +25 -0
  133. package/src/browser/style/tree.css +1 -0
  134. package/src/browser/test/jsdom.ts +1 -1
  135. package/src/browser/tree/tree-iterator.ts +4 -4
  136. package/src/browser/tree/tree-selection-state.spec.ts +29 -2
  137. package/src/common/i18n/localization.ts +6 -16
  138. package/src/common/nls.ts +3 -1
  139. package/src/common/quick-pick-service.ts +2 -1
  140. package/src/electron-browser/electron-clipboard-service.ts +2 -3
  141. package/src/electron-browser/keyboard/electron-keyboard-layout-change-notifier.ts +1 -2
  142. package/src/electron-browser/menu/electron-context-menu-renderer.ts +10 -17
  143. package/src/electron-browser/menu/electron-main-menu-factory.ts +51 -44
  144. package/src/electron-browser/menu/electron-menu-contribution.ts +46 -57
  145. package/src/electron-browser/messaging/electron-ipc-connection-provider.ts +4 -9
  146. package/src/electron-browser/preload.ts +208 -0
  147. package/src/electron-browser/token/electron-token-frontend-module.ts +1 -2
  148. package/src/electron-browser/window/electron-frontend-application-state.ts +1 -3
  149. package/src/electron-browser/window/electron-secondary-window-service.ts +7 -31
  150. package/src/electron-browser/window/electron-window-service.ts +8 -25
  151. package/src/electron-common/electron-api.ts +134 -0
  152. package/src/electron-common/messaging/electron-connection-handler.ts +0 -9
  153. package/src/electron-main/electron-api-main.ts +291 -0
  154. package/src/electron-main/electron-main-application-module.ts +3 -4
  155. package/src/electron-main/electron-main-application.ts +33 -37
  156. package/src/electron-main/electron-security-token-service.ts +2 -1
  157. package/src/electron-main/messaging/electron-messaging-contribution.ts +8 -10
  158. package/src/electron-main/theia-electron-window.ts +8 -33
  159. package/src/node/i18n/localization-backend-contribution.ts +2 -1
  160. package/src/node/i18n/localization-provider.ts +2 -1
  161. package/LICENSE +0 -642
  162. package/electron-shared/@electron/remote/index.d.ts +0 -1
  163. package/electron-shared/@electron/remote/index.js +0 -1
  164. package/electron-shared/@electron/remote/main/index.d.ts +0 -1
  165. package/electron-shared/@electron/remote/main/index.js +0 -1
  166. package/lib/electron-common/messaging/electron-messages.d.ts +0 -25
  167. package/lib/electron-common/messaging/electron-messages.d.ts.map +0 -1
  168. package/lib/electron-common/messaging/electron-messages.js +0 -37
  169. package/lib/electron-common/messaging/electron-messages.js.map +0 -1
  170. package/lib/electron-main/electron-native-keymap.d.ts +0 -8
  171. package/lib/electron-main/electron-native-keymap.d.ts.map +0 -1
  172. package/lib/electron-main/electron-native-keymap.js +0 -48
  173. package/lib/electron-main/electron-native-keymap.js.map +0 -1
  174. package/src/electron-common/messaging/electron-messages.ts +0 -42
  175. package/src/electron-main/electron-native-keymap.ts +0 -40
@@ -67,6 +67,10 @@ export interface SideBarRenderData extends TabBar.IRenderData<Widget> {
67
67
  paddingBottom?: number;
68
68
  }
69
69
 
70
+ export interface ScrollableRenderData extends TabBar.IRenderData<Widget> {
71
+ tabWidth?: number;
72
+ }
73
+
70
74
  /**
71
75
  * A tab bar renderer that offers a context menu. In addition, this renderer is able to
72
76
  * set an explicit position and size on the icon and label of each tab in a side bar.
@@ -157,9 +161,7 @@ export class TabBarRenderer extends TabBar.Renderer {
157
161
  ? nls.localizeByDefault('Unpin')
158
162
  : nls.localizeByDefault('Close');
159
163
 
160
- const hover = this.tabBar && this.tabBar.orientation === 'horizontal' ? {
161
- title: title.caption
162
- } : {
164
+ const hover = this.tabBar && (this.tabBar.orientation === 'horizontal' && !this.corePreferences?.['window.tabbar.enhancedPreview']) ? { title: title.caption } : {
163
165
  onmouseenter: this.handleMouseEnterEvent
164
166
  };
165
167
 
@@ -204,11 +206,12 @@ export class TabBarRenderer extends TabBar.Renderer {
204
206
  * If size information is available for the label and icon, set an explicit height on the tab.
205
207
  * The height value also considers padding, which should be derived from CSS settings.
206
208
  */
207
- override createTabStyle(data: SideBarRenderData): ElementInlineStyle {
209
+ override createTabStyle(data: SideBarRenderData & ScrollableRenderData): ElementInlineStyle {
208
210
  const zIndex = `${data.zIndex}`;
209
211
  const labelSize = data.labelSize;
210
212
  const iconSize = data.iconSize;
211
213
  let height: string | undefined;
214
+ let width: string | undefined;
212
215
  if (labelSize || iconSize) {
213
216
  const labelHeight = labelSize ? (this.tabBar && this.tabBar.orientation === 'horizontal' ? labelSize.height : labelSize.width) : 0;
214
217
  const iconHeight = iconSize ? iconSize.height : 0;
@@ -220,7 +223,12 @@ export class TabBarRenderer extends TabBar.Renderer {
220
223
  const paddingBottom = data.paddingBottom || 0;
221
224
  height = `${labelHeight + iconHeight + paddingTop + paddingBottom}px`;
222
225
  }
223
- return { zIndex, height };
226
+ if (data.tabWidth) {
227
+ width = `${data.tabWidth}px`;
228
+ } else {
229
+ width = '';
230
+ }
231
+ return { zIndex, height, width };
224
232
  }
225
233
 
226
234
  /**
@@ -474,16 +482,41 @@ export class TabBarRenderer extends TabBar.Renderer {
474
482
  return h.div({ className: baseClassName, style }, data.title.iconLabel);
475
483
  }
476
484
 
485
+ protected renderEnhancedPreview = (title: Title<Widget>) => {
486
+ const hoverBox = document.createElement('div');
487
+ hoverBox.classList.add('theia-horizontal-tabBar-hover-div');
488
+ const labelElement = document.createElement('p');
489
+ labelElement.classList.add('theia-horizontal-tabBar-hover-title');
490
+ labelElement.textContent = title.label;
491
+ hoverBox.append(labelElement);
492
+ if (title.caption) {
493
+ const captionElement = document.createElement('p');
494
+ captionElement.classList.add('theia-horizontal-tabBar-hover-caption');
495
+ captionElement.textContent = title.caption;
496
+ hoverBox.appendChild(captionElement);
497
+ }
498
+ return hoverBox;
499
+ };
500
+
477
501
  protected handleMouseEnterEvent = (event: MouseEvent) => {
478
502
  if (this.tabBar && this.hoverService && event.currentTarget instanceof HTMLElement) {
479
503
  const id = event.currentTarget.id;
480
504
  const title = this.tabBar.titles.find(t => this.createTabId(t) === id);
481
505
  if (title) {
482
- this.hoverService.requestHover({
483
- content: title.caption,
484
- target: event.currentTarget,
485
- position: 'right'
486
- });
506
+ if (this.tabBar.orientation === 'horizontal') {
507
+ this.hoverService.requestHover({
508
+ content: this.renderEnhancedPreview(title),
509
+ target: event.currentTarget,
510
+ position: 'bottom',
511
+ cssClasses: ['extended-tab-preview']
512
+ });
513
+ } else {
514
+ this.hoverService.requestHover({
515
+ content: title.caption,
516
+ target: event.currentTarget,
517
+ position: 'right'
518
+ });
519
+ }
487
520
  }
488
521
  }
489
522
  };
@@ -542,6 +575,13 @@ export class TabBarRenderer extends TabBar.Renderer {
542
575
 
543
576
  }
544
577
 
578
+ export namespace ScrollableTabBar {
579
+ export interface Options {
580
+ minimumTabSize: number;
581
+ defaultTabSize: number;
582
+ }
583
+ }
584
+
545
585
  /**
546
586
  * A specialized tab bar for the main and bottom areas.
547
587
  */
@@ -551,12 +591,26 @@ export class ScrollableTabBar extends TabBar<Widget> {
551
591
 
552
592
  private scrollBarFactory: () => PerfectScrollbar;
553
593
  private pendingReveal?: Promise<void>;
594
+ private isMouseOver = false;
595
+ protected needsRecompute = false;
596
+ protected tabSize = 0;
597
+ private _dynamicTabOptions?: ScrollableTabBar.Options;
554
598
 
555
599
  protected readonly toDispose = new DisposableCollection();
556
600
 
557
- constructor(options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options) {
601
+ constructor(options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options, dynamicTabOptions?: ScrollableTabBar.Options) {
558
602
  super(options);
559
603
  this.scrollBarFactory = () => new PerfectScrollbar(this.scrollbarHost, options);
604
+ this._dynamicTabOptions = dynamicTabOptions;
605
+ }
606
+
607
+ set dynamicTabOptions(options: ScrollableTabBar.Options | undefined) {
608
+ this._dynamicTabOptions = options;
609
+ this.updateTabs();
610
+ }
611
+
612
+ get dynamicTabOptions(): ScrollableTabBar.Options | undefined {
613
+ return this._dynamicTabOptions;
560
614
  }
561
615
 
562
616
  override dispose(): void {
@@ -571,6 +625,14 @@ export class ScrollableTabBar extends TabBar<Widget> {
571
625
  if (!this.scrollBar) {
572
626
  this.scrollBar = this.scrollBarFactory();
573
627
  }
628
+ this.node.addEventListener('mouseenter', () => { this.isMouseOver = true; });
629
+ this.node.addEventListener('mouseleave', () => {
630
+ this.isMouseOver = false;
631
+ if (this.needsRecompute) {
632
+ this.updateTabs();
633
+ }
634
+ });
635
+
574
636
  super.onAfterAttach(msg);
575
637
  }
576
638
 
@@ -583,7 +645,34 @@ export class ScrollableTabBar extends TabBar<Widget> {
583
645
  }
584
646
 
585
647
  protected override onUpdateRequest(msg: Message): void {
586
- super.onUpdateRequest(msg);
648
+ this.updateTabs();
649
+ }
650
+
651
+ protected updateTabs(): void {
652
+
653
+ const content = [];
654
+ if (this.dynamicTabOptions) {
655
+ if (this.isMouseOver) {
656
+ this.needsRecompute = true;
657
+ } else {
658
+ this.needsRecompute = false;
659
+ if (this.orientation === 'horizontal') {
660
+ this.tabSize = Math.max(Math.min(this.scrollbarHost.clientWidth / this.titles.length,
661
+ this.dynamicTabOptions.defaultTabSize), this.dynamicTabOptions.minimumTabSize);
662
+ }
663
+ }
664
+ }
665
+ for (let i = 0, n = this.titles.length; i < n; ++i) {
666
+ const title = this.titles[i];
667
+ const current = title === this.currentTitle;
668
+ const zIndex = current ? n : n - i - 1;
669
+ const renderData: ScrollableRenderData = { title: title, current: current, zIndex: zIndex };
670
+ if (this.dynamicTabOptions && this.orientation === 'horizontal') {
671
+ renderData.tabWidth = this.tabSize;
672
+ }
673
+ content[i] = this.renderer.renderTab(renderData);
674
+ }
675
+ VirtualDOM.render(content, this.contentNode);
587
676
  if (this.scrollBar) {
588
677
  this.scrollBar.update();
589
678
  }
@@ -591,6 +680,9 @@ export class ScrollableTabBar extends TabBar<Widget> {
591
680
 
592
681
  protected override onResize(msg: Widget.ResizeMessage): void {
593
682
  super.onResize(msg);
683
+ if (this.dynamicTabOptions) {
684
+ this.updateTabs();
685
+ }
594
686
  if (this.scrollBar) {
595
687
  if (this.currentIndex >= 0) {
596
688
  this.revealTab(this.currentIndex);
@@ -680,9 +772,10 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
680
772
  protected readonly tabBarToolbarRegistry: TabBarToolbarRegistry,
681
773
  protected readonly tabBarToolbarFactory: () => TabBarToolbar,
682
774
  protected readonly breadcrumbsRendererFactory: BreadcrumbsRendererFactory,
683
- protected readonly options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options,
775
+ options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options,
776
+ dynamicTabOptions?: ScrollableTabBar.Options
684
777
  ) {
685
- super(options);
778
+ super(options, dynamicTabOptions);
686
779
  this.breadcrumbsRenderer = this.breadcrumbsRendererFactory();
687
780
  this.rewireDOM();
688
781
  this.toDispose.push(this.tabBarToolbarRegistry.onDidChange(() => this.update()));
@@ -756,6 +849,7 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
756
849
  }
757
850
  const widget = this.currentTitle?.owner ?? undefined;
758
851
  this.toolbar.updateTarget(widget);
852
+ this.updateTabs();
759
853
  }
760
854
 
761
855
  override handleEvent(event: Event): void {
@@ -859,7 +953,7 @@ export class SideTabBar extends ScrollableTabBar {
859
953
 
860
954
  protected override onAfterAttach(msg: Message): void {
861
955
  super.onAfterAttach(msg);
862
- this.renderTabBar();
956
+ this.updateTabs();
863
957
  this.node.addEventListener('p-dragenter', this);
864
958
  this.node.addEventListener('p-dragover', this);
865
959
  this.node.addEventListener('p-dragleave', this);
@@ -875,7 +969,7 @@ export class SideTabBar extends ScrollableTabBar {
875
969
  }
876
970
 
877
971
  protected override onUpdateRequest(msg: Message): void {
878
- this.renderTabBar();
972
+ this.updateTabs();
879
973
  if (this.scrollBar) {
880
974
  this.scrollBar.update();
881
975
  }
@@ -885,7 +979,7 @@ export class SideTabBar extends ScrollableTabBar {
885
979
  * Render the tab bar in the _hidden content node_ (see `hiddenContentNode` for explanation),
886
980
  * then gather size information for labels and render it again in the proper content node.
887
981
  */
888
- protected renderTabBar(): void {
982
+ protected override updateTabs(): void {
889
983
  if (this.isAttached) {
890
984
  // Render into the invisible node
891
985
  this.renderTabs(this.hiddenContentNode);
@@ -93,3 +93,7 @@
93
93
  border-top: 5px solid transparent;
94
94
  border-bottom: 5px solid transparent;
95
95
  }
96
+
97
+ .theia-hover.extended-tab-preview {
98
+ border-radius: 10px;
99
+ }
@@ -410,3 +410,28 @@
410
410
  flex-flow: row nowrap;
411
411
  min-width: 100%;
412
412
  }
413
+
414
+ .p-TabBar-tab .theia-tab-icon-label {
415
+ flex: 1;
416
+ }
417
+
418
+ .p-TabBar[data-orientation='horizontal'] .p-TabBar-tab.p-mod-closable:hover .theia-tab-icon-label,
419
+ .p-TabBar[data-orientation='horizontal'] .p-TabBar-tab.p-mod-current .theia-tab-icon-label {
420
+ overflow: hidden;
421
+ }
422
+
423
+ .theia-horizontal-tabBar-hover-div {
424
+ margin: 0px 4px;
425
+ }
426
+
427
+ .theia-horizontal-tabBar-hover-title {
428
+ font-weight: bolder;
429
+ font-size: medium;
430
+ margin: 0px 0px;
431
+ }
432
+
433
+ .theia-horizontal-tabBar-hover-caption {
434
+ font-size: small;
435
+ margin: 0px 0px;
436
+ margin-top: 4px;
437
+ }
@@ -177,6 +177,7 @@
177
177
  position: absolute;
178
178
  height: var(--theia-content-line-height);
179
179
  border-right: var(--theia-border-width) solid transparent;
180
+ pointer-events: none;
180
181
  }
181
182
 
182
183
  .theia-tree-node-indent.always,
@@ -47,7 +47,7 @@ export function enableJSDOM(): () => void {
47
47
 
48
48
  const toCleanup: string[] = [];
49
49
  Object.getOwnPropertyNames((dom.window as any)).forEach(property => {
50
- if (typeof (global as any)[property] === 'undefined') {
50
+ if (!(property in global)) {
51
51
  (global as any)[property] = (dom.window as any)[property];
52
52
  toCleanup.push(property);
53
53
  }
@@ -202,12 +202,12 @@ export namespace Iterators {
202
202
  * Generator for depth first, pre-order tree traversal iteration.
203
203
  */
204
204
  export function* depthFirst<T>(root: T, children: (node: T) => T[] | undefined, include: (node: T) => boolean = () => true): IterableIterator<T> {
205
- const stack: T[] = [];
205
+ let stack: T[] = [];
206
206
  stack.push(root);
207
207
  while (stack.length > 0) {
208
208
  const top = stack.pop()!;
209
209
  yield top;
210
- stack.push(...(children(top) || []).filter(include).reverse());
210
+ stack = stack.concat((children(top) || []).filter(include).reverse());
211
211
  }
212
212
  }
213
213
 
@@ -215,12 +215,12 @@ export namespace Iterators {
215
215
  * Generator for breadth first tree traversal iteration.
216
216
  */
217
217
  export function* breadthFirst<T>(root: T, children: (node: T) => T[] | undefined, include: (node: T) => boolean = () => true): IterableIterator<T> {
218
- const queue: T[] = [];
218
+ let queue: T[] = [];
219
219
  queue.push(root);
220
220
  while (queue.length > 0) {
221
221
  const head = queue.shift()!;
222
222
  yield head;
223
- queue.push(...(children(head) || []).filter(include));
223
+ queue = queue.concat((children(head) || []).filter(include));
224
224
  }
225
225
  }
226
226
 
@@ -16,10 +16,10 @@
16
16
 
17
17
  import { expect } from 'chai';
18
18
  import { MockTreeModel } from './test/mock-tree-model';
19
- import { TreeSelectionState } from './tree-selection-state';
20
19
  import { createTreeTestContainer } from './test/tree-test-container';
21
- import { SelectableTreeNode, TreeSelection } from './tree-selection';
22
20
  import { TreeModel } from './tree-model';
21
+ import { SelectableTreeNode, TreeSelection } from './tree-selection';
22
+ import { TreeSelectionState } from './tree-selection-state';
23
23
 
24
24
  namespace TreeSelectionState {
25
25
 
@@ -34,6 +34,16 @@ namespace TreeSelectionState {
34
34
 
35
35
  }
36
36
 
37
+ const LARGE_FLAT_MOCK_ROOT = (length = 250000) => {
38
+ const children = Array.from({ length }, (_, idx) => ({ 'id': (idx + 1).toString() }));
39
+ return MockTreeModel.Node.toTreeNode({
40
+ 'id': 'ROOT',
41
+ 'children': [
42
+ ...children
43
+ ]
44
+ });
45
+ };
46
+
37
47
  describe('tree-selection-state', () => {
38
48
 
39
49
  const model = createTreeModel();
@@ -391,6 +401,23 @@ describe('tree-selection-state', () => {
391
401
  });
392
402
  });
393
403
 
404
+ it('should be able to handle range selection on large tree', () => {
405
+ model.root = LARGE_FLAT_MOCK_ROOT();
406
+ expect(model.selectedNodes).to.be.empty;
407
+
408
+ const start = 10;
409
+ const end = 20;
410
+ newState()
411
+ .nextState('toggle', start.toString(), {
412
+ focus: start.toString(),
413
+ selection: [start.toString()]
414
+ })
415
+ .nextState('range', end.toString(), {
416
+ focus: start.toString(),
417
+ selection: Array.from({ length: end - start + 1 }, (_, idx) => (start + idx).toString())
418
+ });
419
+ });
420
+
394
421
  function newState(): TreeSelectionState.Assert {
395
422
  return nextState(new TreeSelectionState(model));
396
423
  }
@@ -39,22 +39,12 @@ export type FormatType = string | number | boolean | undefined;
39
39
 
40
40
  export namespace Localization {
41
41
 
42
- export function format(message: string, args: FormatType[]): string {
43
- let result = message;
44
- if (args.length > 0) {
45
- result = message.replace(/\{(\d+)\}/g, (match, rest) => {
46
- const index = rest[0];
47
- const arg = args[index];
48
- let replacement = match;
49
- if (typeof arg === 'string') {
50
- replacement = arg;
51
- } else if (typeof arg === 'number' || typeof arg === 'boolean' || !arg) {
52
- replacement = String(arg);
53
- }
54
- return replacement;
55
- });
56
- }
57
- return result;
42
+ const formatRegexp = /{([^}]+)}/g;
43
+
44
+ export function format(message: string, args: FormatType[]): string;
45
+ export function format(message: string, args: Record<string | number, FormatType>): string;
46
+ export function format(message: string, args: Record<string | number, FormatType> | FormatType[]): string {
47
+ return message.replace(formatRegexp, (match, group) => (args[group] ?? match) as string);
58
48
  }
59
49
 
60
50
  export function localize(localization: Localization | undefined, key: string, defaultValue: string, ...args: FormatType[]): string {
package/src/common/nls.ts CHANGED
@@ -20,6 +20,8 @@ export namespace nls {
20
20
 
21
21
  export let localization: Localization | undefined;
22
22
 
23
+ export const defaultLocale = 'en';
24
+
23
25
  export const localeId = 'localeId';
24
26
 
25
27
  export const locale = typeof window === 'object' && window && window.localStorage.getItem(localeId) || undefined;
@@ -57,7 +59,7 @@ export namespace nls {
57
59
  }
58
60
 
59
61
  export function isSelectedLocale(id: string): boolean {
60
- if (locale === undefined && id === 'en') {
62
+ if (locale === undefined && id === defaultLocale) {
61
63
  return true;
62
64
  }
63
65
  return locale === id;
@@ -67,6 +67,7 @@ export interface QuickPickSeparator {
67
67
  }
68
68
 
69
69
  export type QuickPickItemOrSeparator = QuickPickItem | QuickPickSeparator;
70
+ export type QuickPickInput<T = QuickPickItem> = T | QuickPickSeparator;
70
71
 
71
72
  export namespace QuickPickItem {
72
73
  export function is(item: QuickPickSeparator | QuickPickItem): item is QuickPickItem {
@@ -278,7 +279,7 @@ export interface QuickInputService {
278
279
  open(filter: string): void;
279
280
  createInputBox(): InputBox;
280
281
  input(options?: InputOptions, token?: CancellationToken): Promise<string | undefined>;
281
- pick<T extends QuickPickItem, O extends PickOptions<T>>(picks: Promise<T[]> | T[], options?: O, token?: CancellationToken):
282
+ pick<T extends QuickPickItem, O extends PickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: O, token?: CancellationToken):
282
283
  Promise<(O extends { canPickMany: true } ? T[] : T) | undefined>;
283
284
  showQuickPick<T extends QuickPickItem>(items: Array<T | QuickPickSeparator>, options?: QuickPickOptions<T>): Promise<T | undefined>;
284
285
  hide(): void;
@@ -15,7 +15,6 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  // eslint-disable-next-line import/no-extraneous-dependencies
18
- import { clipboard } from 'electron';
19
18
  import { injectable } from 'inversify';
20
19
  import { ClipboardService } from '../browser/clipboard-service';
21
20
 
@@ -23,11 +22,11 @@ import { ClipboardService } from '../browser/clipboard-service';
23
22
  export class ElectronClipboardService implements ClipboardService {
24
23
 
25
24
  readText(): string {
26
- return clipboard.readText();
25
+ return window.electronTheiaCore.readClipboard();
27
26
  }
28
27
 
29
28
  writeText(value: string): void {
30
- clipboard.writeText(value);
29
+ window.electronTheiaCore.writeClipboard(value);
31
30
  }
32
31
 
33
32
  }
@@ -14,7 +14,6 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { ipcRenderer } from '@theia/electron/shared/electron';
18
17
  import { postConstruct, injectable } from 'inversify';
19
18
  import { KeyboardLayoutChangeNotifier, NativeKeyboardLayout } from '../../common/keyboard/keyboard-layout-provider';
20
19
  import { Emitter, Event } from '../../common/event';
@@ -34,7 +33,7 @@ export class ElectronKeyboardLayoutChangeNotifier implements KeyboardLayoutChang
34
33
 
35
34
  @postConstruct()
36
35
  protected initialize(): void {
37
- ipcRenderer.on('keyboardLayoutChanged', (event: Electron.IpcRendererEvent, newLayout: NativeKeyboardLayout) => this.nativeLayoutChanged.fire(newLayout));
36
+ window.electronTheiaCore.onKeyboardLayoutChanged((newLayout: NativeKeyboardLayout) => this.nativeLayoutChanged.fire(newLayout));
38
37
  }
39
38
 
40
39
  }
@@ -16,7 +16,6 @@
16
16
 
17
17
  /* eslint-disable @typescript-eslint/no-explicit-any */
18
18
 
19
- import * as electron from '../../../electron-shared/electron';
20
19
  import { inject, injectable, postConstruct } from 'inversify';
21
20
  import {
22
21
  ContextMenuRenderer, RenderContextMenuOptions, ContextMenuAccess, FrontendApplicationContribution, CommonCommands, coordinateFromAnchor, PreferenceService
@@ -25,12 +24,11 @@ import { ElectronMainMenuFactory } from './electron-main-menu-factory';
25
24
  import { ContextMenuContext } from '../../browser/menu/context-menu-context';
26
25
  import { MenuPath, MenuContribution, MenuModelRegistry } from '../../common';
27
26
  import { BrowserContextMenuRenderer } from '../../browser/menu/browser-context-menu-renderer';
28
- import { RequestTitleBarStyle, TitleBarStyleAtStartup } from '../../electron-common/messaging/electron-messages';
29
27
 
30
28
  export class ElectronContextMenuAccess extends ContextMenuAccess {
31
- constructor(readonly menu: electron.Menu) {
29
+ constructor(readonly menuHandle: Promise<number>) {
32
30
  super({
33
- dispose: () => menu.closePopup()
31
+ dispose: () => menuHandle.then(handle => window.electronTheiaCore.closePopup(handle))
34
32
  });
35
33
  }
36
34
  }
@@ -93,10 +91,7 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {
93
91
 
94
92
  @postConstruct()
95
93
  protected async init(): Promise<void> {
96
- electron.ipcRenderer.on(TitleBarStyleAtStartup, (_event, style: string) => {
97
- this.useNativeStyle = style === 'native';
98
- });
99
- electron.ipcRenderer.send(RequestTitleBarStyle);
94
+ this.useNativeStyle = await window.electronTheiaCore.getTitleBarStyleAtStartup() === 'native';
100
95
  }
101
96
 
102
97
  protected override doRender(options: RenderContextMenuOptions): ContextMenuAccess {
@@ -104,17 +99,15 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {
104
99
  const { menuPath, anchor, args, onHide, context, contextKeyService } = options;
105
100
  const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context, contextKeyService);
106
101
  const { x, y } = coordinateFromAnchor(anchor);
107
- const zoom = electron.webFrame.getZoomFactor();
108
- // TODO: Remove the offset once Electron fixes https://github.com/electron/electron/issues/31641
109
- const offset = process.platform === 'win32' ? 0 : 2;
110
- // x and y values must be Ints or else there is a conversion error
111
- menu.popup({ x: Math.round(x * zoom) + offset, y: Math.round(y * zoom) + offset });
102
+
103
+ const menuHandle = window.electronTheiaCore.popup(menu, x, y, () => {
104
+ if (onHide) {
105
+ onHide();
106
+ }
107
+ });
112
108
  // native context menu stops the event loop, so there is no keyboard events
113
109
  this.context.resetAltPressed();
114
- if (onHide) {
115
- menu.once('menu-will-close', () => onHide());
116
- }
117
- return new ElectronContextMenuAccess(menu);
110
+ return new ElectronContextMenuAccess(menuHandle);
118
111
  } else {
119
112
  return super.doRender(options);
120
113
  }