@theia/core 1.61.0-next.8 → 1.61.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.
Files changed (102) hide show
  1. package/README.md +7 -7
  2. package/i18n/nls.cs.json +34 -5
  3. package/i18n/nls.de.json +34 -5
  4. package/i18n/nls.es.json +34 -5
  5. package/i18n/nls.fr.json +34 -5
  6. package/i18n/nls.hu.json +34 -5
  7. package/i18n/nls.it.json +34 -5
  8. package/i18n/nls.ja.json +34 -5
  9. package/i18n/nls.json +35 -6
  10. package/i18n/nls.ko.json +34 -5
  11. package/i18n/nls.pl.json +34 -5
  12. package/i18n/nls.pt-br.json +34 -5
  13. package/i18n/nls.ru.json +34 -5
  14. package/i18n/nls.tr.json +34 -5
  15. package/i18n/nls.zh-cn.json +34 -5
  16. package/i18n/nls.zh-tw.json +34 -5
  17. package/lib/browser/catalog.json +322 -45
  18. package/lib/browser/dialogs.d.ts +8 -1
  19. package/lib/browser/dialogs.d.ts.map +1 -1
  20. package/lib/browser/dialogs.js +11 -4
  21. package/lib/browser/dialogs.js.map +1 -1
  22. package/lib/browser/frontend-application-module.js +1 -1
  23. package/lib/browser/frontend-application-module.js.map +1 -1
  24. package/lib/browser/preload/i18n-preload-contribution.js +1 -1
  25. package/lib/browser/preload/i18n-preload-contribution.js.map +1 -1
  26. package/lib/browser/shell/application-shell.d.ts +17 -5
  27. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  28. package/lib/browser/shell/application-shell.js +94 -40
  29. package/lib/browser/shell/application-shell.js.map +1 -1
  30. package/lib/browser/shell/index.d.ts +1 -0
  31. package/lib/browser/shell/index.d.ts.map +1 -1
  32. package/lib/browser/shell/index.js +1 -0
  33. package/lib/browser/shell/index.js.map +1 -1
  34. package/lib/browser/shell/tab-bars.d.ts.map +1 -1
  35. package/lib/browser/shell/tab-bars.js +3 -2
  36. package/lib/browser/shell/tab-bars.js.map +1 -1
  37. package/lib/browser/shell/theia-dock-panel.d.ts +4 -10
  38. package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
  39. package/lib/browser/shell/theia-dock-panel.js +7 -84
  40. package/lib/browser/shell/theia-dock-panel.js.map +1 -1
  41. package/lib/browser/shell/theia-split-panel.d.ts +6 -0
  42. package/lib/browser/shell/theia-split-panel.d.ts.map +1 -0
  43. package/lib/browser/shell/theia-split-panel.js +56 -0
  44. package/lib/browser/shell/theia-split-panel.js.map +1 -0
  45. package/lib/browser/tree/tree-widget.d.ts +1 -0
  46. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  47. package/lib/browser/tree/tree-widget.js +6 -0
  48. package/lib/browser/tree/tree-widget.js.map +1 -1
  49. package/lib/browser/view-container.d.ts.map +1 -1
  50. package/lib/browser/view-container.js +2 -1
  51. package/lib/browser/view-container.js.map +1 -1
  52. package/lib/browser/widgets/widget.d.ts.map +1 -1
  53. package/lib/browser/widgets/widget.js.map +1 -1
  54. package/lib/common/content-replacer.d.ts.map +1 -1
  55. package/lib/common/content-replacer.js +2 -1
  56. package/lib/common/content-replacer.js.map +1 -1
  57. package/lib/common/content-replacer.spec.js +2 -2
  58. package/lib/common/content-replacer.spec.js.map +1 -1
  59. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +1 -1
  60. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  61. package/lib/electron-browser/menu/electron-main-menu-factory.js +15 -13
  62. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  63. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  64. package/lib/electron-browser/menu/electron-menu-contribution.js +1 -4
  65. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  66. package/lib/electron-main/electron-main-application.d.ts +1 -1
  67. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  68. package/lib/electron-main/electron-main-application.js +7 -5
  69. package/lib/electron-main/electron-main-application.js.map +1 -1
  70. package/lib/node/backend-application-module.d.ts.map +1 -1
  71. package/lib/node/backend-application-module.js +3 -0
  72. package/lib/node/backend-application-module.js.map +1 -1
  73. package/lib/node/index.d.ts +1 -0
  74. package/lib/node/index.d.ts.map +1 -1
  75. package/lib/node/index.js +1 -0
  76. package/lib/node/index.js.map +1 -1
  77. package/lib/node/setting-service.d.ts +20 -0
  78. package/lib/node/setting-service.d.ts.map +1 -0
  79. package/lib/node/setting-service.js +80 -0
  80. package/lib/node/setting-service.js.map +1 -0
  81. package/package.json +7 -9
  82. package/src/browser/dialogs.ts +11 -4
  83. package/src/browser/frontend-application-module.ts +1 -1
  84. package/src/browser/preload/i18n-preload-contribution.ts +1 -1
  85. package/src/browser/shell/application-shell.ts +96 -34
  86. package/src/browser/shell/index.ts +1 -0
  87. package/src/browser/shell/tab-bars.ts +3 -2
  88. package/src/browser/shell/theia-dock-panel.ts +10 -91
  89. package/src/browser/shell/theia-split-panel.ts +56 -0
  90. package/src/browser/style/index.css +3 -11
  91. package/src/browser/style/sidepanel.css +2 -4
  92. package/src/browser/tree/tree-widget.tsx +7 -0
  93. package/src/browser/view-container.ts +2 -1
  94. package/src/browser/widgets/widget.ts +1 -0
  95. package/src/common/content-replacer.spec.ts +2 -2
  96. package/src/common/content-replacer.ts +2 -1
  97. package/src/electron-browser/menu/electron-main-menu-factory.ts +15 -14
  98. package/src/electron-browser/menu/electron-menu-contribution.ts +1 -4
  99. package/src/electron-main/electron-main-application.ts +8 -5
  100. package/src/node/backend-application-module.ts +4 -0
  101. package/src/node/index.ts +1 -0
  102. package/src/node/setting-service.ts +78 -0
@@ -0,0 +1,56 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 STMicroelectronics and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { SplitLayout, SplitPanel } from '@lumino/widgets';
18
+
19
+ export class TheiaSplitPanel extends SplitPanel {
20
+ constructor(options?: SplitPanel.IOptions) {
21
+ super(options);
22
+
23
+ let oldCursor: string | undefined;
24
+ let pointerId: number | undefined;
25
+
26
+ this['_evtPointerDown'] = (event: PointerEvent) => {
27
+ super['_evtPointerDown'](event);
28
+ if (this['_pressData']) { // indicating that the drag has started
29
+ this.node.setPointerCapture(event.pointerId);
30
+ pointerId = event.pointerId;
31
+ const layout = this.layout as SplitLayout;
32
+ const handle = layout.handles.find(h => h.contains(event.target as HTMLElement));
33
+ if (handle) {
34
+ const style = window.getComputedStyle(handle);
35
+ oldCursor = this.node.style.cursor;
36
+ this.node.style.cursor = style.cursor;
37
+ }
38
+ }
39
+ };
40
+ this['_releaseMouse'] = () => {
41
+ super['_releaseMouse']();
42
+ if (oldCursor !== undefined) {
43
+ this.node.style.cursor = oldCursor;
44
+ oldCursor = undefined;
45
+ }
46
+ if (pointerId) {
47
+ this.node.releasePointerCapture(pointerId);
48
+ pointerId = undefined;
49
+ }
50
+ };
51
+ }
52
+
53
+ override handleEvent(event: Event): void {
54
+ super.handleEvent(event);
55
+ }
56
+ }
@@ -90,6 +90,7 @@ body {
90
90
  color: var(--theia-foreground);
91
91
  border: 1px solid var(--theia-window-activeBorder);
92
92
  }
93
+
93
94
  body:window-inactive,
94
95
  body:-moz-window-inactive {
95
96
  border-color: var(--theia-window-inactiveBorder);
@@ -139,19 +140,10 @@ blockquote {
139
140
  }
140
141
 
141
142
  .theia-maximized {
142
- position: fixed !important;
143
143
  top: 0 !important;
144
- bottom: 0 !important;
145
144
  left: 0 !important;
146
- right: 0 !important;
147
- width: auto !important;
148
- height: auto !important;
149
- z-index: 255 !important;
150
- background: var(--theia-editor-background);
151
- }
152
-
153
- .theia-visible-menu-maximized {
154
- top: var(--theia-private-menubar-height) !important;
145
+ width: 100% !important;
146
+ height: 100% !important;
155
147
  }
156
148
 
157
149
  .theia-ApplicationShell {
@@ -188,7 +188,7 @@
188
188
  }
189
189
 
190
190
  .lm-Widget .theia-sidebar-menu-item {
191
- cursor: pointer;
191
+ cursor: pointer;
192
192
  }
193
193
 
194
194
  .lm-Widget.theia-sidebar-menu i {
@@ -334,6 +334,7 @@
334
334
  padding-left: 5px;
335
335
  align-items: center;
336
336
  background-color: var(--theia-sideBar-background);
337
+ overflow: hidden;
337
338
  }
338
339
 
339
340
  .theia-sidepanel-toolbar .theia-sidepanel-title {
@@ -366,6 +367,3 @@
366
367
  overflow: hidden;
367
368
  text-overflow: ellipsis;
368
369
  }
369
-
370
-
371
-
@@ -445,6 +445,13 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
445
445
  super.onUpdateRequest(msg);
446
446
  }
447
447
 
448
+ protected override handleVisiblityChanged(isNowVisible: boolean): void {
449
+ super.handleVisiblityChanged(isNowVisible);
450
+ if (isNowVisible) {
451
+ this.update();
452
+ }
453
+ }
454
+
448
455
  protected override onResize(msg: Widget.ResizeMessage): void {
449
456
  super.onResize(msg);
450
457
  this.update();
@@ -38,6 +38,7 @@ import { Drag } from '@lumino/dragdrop';
38
38
  import { MimeData } from '@lumino/coreutils';
39
39
  import { ElementExt } from '@lumino/domutils';
40
40
  import { TabBarDecoratorService } from './shell/tab-bar-decorator';
41
+ import { TheiaSplitPanel } from './shell/theia-split-panel';
41
42
 
42
43
  export interface ViewContainerTitleOptions {
43
44
  label: string;
@@ -152,7 +153,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
152
153
  this.addClass('theia-view-container');
153
154
  const layout = new PanelLayout();
154
155
  this.layout = layout;
155
- this.panel = new SplitPanel({
156
+ this.panel = new TheiaSplitPanel({
156
157
  layout: new ViewContainerLayout({
157
158
  renderer: SplitPanel.defaultRenderer,
158
159
  orientation: this.orientation,
@@ -295,6 +295,7 @@ export function addKeyListener<K extends keyof HTMLElementEventMap = never>(
295
295
  return (actual: KeyCode) => KeysOrKeyCodes.toKeyCodes(keysOrKeyCodes).some(k => k.equals(actual));
296
296
  }
297
297
  })();
298
+
298
299
  toDispose.push(addEventListener(element, 'keydown', e => {
299
300
  const kc = KeyCode.createKeyCode(e);
300
301
  if (keyCodePredicate(kc)) {
@@ -63,7 +63,7 @@ describe('ContentReplacer', () => {
63
63
  ];
64
64
  const result = contentReplacer.applyReplacements(originalContent, replacements);
65
65
  expect(result.updatedContent).to.equal(originalContent);
66
- expect(result.errors).to.include('Multiple occurrences found for: "Repeat"');
66
+ expect(result.errors.some(candidate => candidate.startsWith('Multiple occurrences found for: "Repeat"'))).to.be.true;
67
67
  });
68
68
 
69
69
  it('should prepend newContent when oldContent is an empty string', () => {
@@ -108,7 +108,7 @@ describe('ContentReplacer', () => {
108
108
  ];
109
109
  const result = contentReplacer.applyReplacements(originalContent, replacements);
110
110
  expect(result.updatedContent).to.equal(originalContent);
111
- expect(result.errors).to.include('Multiple occurrences found for: "Repeat"');
111
+ expect(result.errors.some(candidate => candidate.startsWith('Multiple occurrences found for: "Repeat"'))).to.be.true;
112
112
  });
113
113
 
114
114
  it('should return an error when conflicting replacements for the same oldContent are provided', () => {
@@ -60,7 +60,8 @@ export class ContentReplacer {
60
60
  if (multiple) {
61
61
  updatedContent = this.replaceContentAll(updatedContent, oldContent, newContent);
62
62
  } else {
63
- errorMessages.push(`Multiple occurrences found for: "${oldContent}"`);
63
+ errorMessages.push(`Multiple occurrences found for: "${oldContent}". Set 'multiple' to true if multiple occurrences of the oldContent are expected to be\
64
+ replaced at once.`);
64
65
  }
65
66
  } else {
66
67
  updatedContent = this.replaceContentOnce(updatedContent, oldContent, newContent);
@@ -21,7 +21,6 @@ import { isOSX, MAIN_MENU_BAR, MenuPath, MenuNode, CommandMenuNode, CompoundMenu
21
21
  import { Keybinding } from '../../common/keybinding';
22
22
  import { PreferenceService, CommonCommands } from '../../browser';
23
23
  import debounce = require('lodash.debounce');
24
- import { MAXIMIZED_CLASS } from '../../browser/shell/theia-dock-panel';
25
24
  import { BrowserMainMenuFactory } from '../../browser/menu/browser-menu-plugin';
26
25
  import { ContextMatcher } from '../../browser/context-key-service';
27
26
  import { MenuDto, MenuRole } from '../../electron-common/electron-api';
@@ -111,22 +110,24 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
111
110
  }
112
111
 
113
112
  doSetMenuBar(): void {
114
- this.menu = this.createElectronMenuBar();
115
- window.electronTheiaCore.setMenu(this.menu);
113
+ const preference = this.preferencesService.get<string>('window.menuBarVisibility') || 'classic';
114
+ const shouldShowTop = !window.electronTheiaCore.isFullScreen() || preference === 'visible';
115
+ if (shouldShowTop) {
116
+ this.menu = this.createElectronMenuBar();
117
+ window.electronTheiaCore.setMenu(this.menu);
118
+ window.electronTheiaCore.setMenuBarVisible(true);
119
+ } else {
120
+ window.electronTheiaCore.setMenuBarVisible(false);
121
+ }
116
122
  }
117
123
 
118
- createElectronMenuBar(): MenuDto[] | undefined {
119
- const preference = this.preferencesService.get<string>('window.menuBarVisibility') || 'classic';
120
- const maxWidget = document.getElementsByClassName(MAXIMIZED_CLASS);
121
- if (preference === 'visible' || (preference === 'classic' && maxWidget.length === 0)) {
122
- const menuModel = this.menuProvider.getMenu(MAIN_MENU_BAR);
123
- const menu = this.fillMenuTemplate([], menuModel, [], { honorDisabled: false, rootMenuPath: MAIN_MENU_BAR }, false);
124
- if (isOSX) {
125
- menu.unshift(this.createOSXMenu());
126
- }
127
- return menu;
124
+ createElectronMenuBar(): MenuDto[] {
125
+ const menuModel = this.menuProvider.getMenu(MAIN_MENU_BAR)!;
126
+ const menu = this.fillMenuTemplate([], menuModel, [], { honorDisabled: false, rootMenuPath: MAIN_MENU_BAR }, false);
127
+ if (isOSX) {
128
+ menu.unshift(this.createOSXMenu());
128
129
  }
129
- return undefined;
130
+ return menu;
130
131
  }
131
132
 
132
133
  createElectronContextMenu(menuPath: MenuPath, args?: any[], context?: HTMLElement, contextKeyService?: ContextMatcher, skipSingleRootNode?: boolean): MenuDto[] {
@@ -120,10 +120,7 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
120
120
  }
121
121
  };
122
122
  onStateChange = this.stateService.onStateChanged(stateServiceListener);
123
- this.shell.mainPanel.onDidToggleMaximized(() => {
124
- this.handleToggleMaximized();
125
- });
126
- this.shell.bottomPanel.onDidToggleMaximized(() => {
123
+ this.shell.onDidToggleMaximized(() => {
127
124
  this.handleToggleMaximized();
128
125
  });
129
126
  this.attachMenuBarVisibilityListener();
@@ -746,11 +746,14 @@ export class ElectronMainApplication {
746
746
  this.stopContributions();
747
747
  }
748
748
 
749
- protected async onSecondInstance(event: ElectronEvent, argv: string[], cwd: string): Promise<void> {
750
- if (argv.includes('--open-url')) {
751
- this.openUrl(argv[argv.length - 1]);
749
+ protected async onSecondInstance(event: ElectronEvent, _: string[], cwd: string, originalArgv: string[]): Promise<void> {
750
+ // the second instance passes it's original argument array as the fourth argument to this method
751
+ // The `argv` second parameter is not usable for us since it is mangled by electron before being passed here
752
+
753
+ if (originalArgv.includes('--open-url')) {
754
+ this.openUrl(originalArgv[originalArgv.length - 1]);
752
755
  } else {
753
- createYargs(this.processArgv.getProcessArgvWithoutBin(argv), process.cwd())
756
+ createYargs(this.processArgv.getProcessArgvWithoutBin(originalArgv), cwd)
754
757
  .help(false)
755
758
  .command('$0 [file]', false,
756
759
  cmd => cmd
@@ -758,7 +761,7 @@ export class ElectronMainApplication {
758
761
  async args => {
759
762
  await this.handleMainCommand({
760
763
  file: args.file,
761
- cwd: process.cwd(),
764
+ cwd: cwd,
762
765
  secondInstance: true
763
766
  });
764
767
  },
@@ -43,6 +43,7 @@ import { BackendRequestFacade } from './request/backend-request-facade';
43
43
  import { FileSystemLocking, FileSystemLockingImpl } from './filesystem-locking';
44
44
  import { BackendRemoteService } from './remote/backend-remote-service';
45
45
  import { RemoteCliContribution } from './remote/remote-cli-contribution';
46
+ import { SettingService, SettingServiceImpl } from './setting-service';
46
47
 
47
48
  decorate(injectable(), ApplicationPackage);
48
49
 
@@ -136,4 +137,7 @@ export const backendApplicationModule = new ContainerModule(bind => {
136
137
  bindBackendStopwatchServer(bind);
137
138
 
138
139
  bind(FileSystemLocking).to(FileSystemLockingImpl).inSingletonScope();
140
+
141
+ bind(SettingServiceImpl).toSelf().inSingletonScope();
142
+ bind(SettingService).toService(SettingServiceImpl);
139
143
  });
package/src/node/index.ts CHANGED
@@ -19,4 +19,5 @@ export * from './debug';
19
19
  export * from '../common/file-uri';
20
20
  export * from './messaging';
21
21
  export * from './cli';
22
+ export * from './setting-service';
22
23
  export { FileSystemLocking } from './filesystem-locking';
@@ -0,0 +1,78 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 STMicroelectronics and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { inject, injectable, postConstruct } from 'inversify';
18
+ import { EnvVariablesServer } from '../common/env-variables';
19
+ import { Deferred } from '../common/promise-util';
20
+ import { promises as fs } from 'fs';
21
+ import { URI } from '../common';
22
+
23
+ export const SettingService = Symbol('SettingService');
24
+
25
+ /**
26
+ * A service providing a simple user-level, persistent key-value store on the back end
27
+ */
28
+ export interface SettingService {
29
+ set(key: string, value: string): Promise<void>;
30
+ get(key: string): Promise<string | undefined>;
31
+ }
32
+
33
+ @injectable()
34
+ export class SettingServiceImpl implements SettingService {
35
+
36
+ @inject(EnvVariablesServer)
37
+ protected readonly envVarServer: EnvVariablesServer;
38
+
39
+ protected readonly ready = new Deferred<void>();
40
+ protected values: Record<string, string> = {};
41
+
42
+ @postConstruct()
43
+ protected init(): void {
44
+ const asyncInit = async () => {
45
+ const configDir = new URI(await this.envVarServer.getConfigDirUri());
46
+ const path: string = configDir.resolve('backend-settings.json').path.fsPath();
47
+ try {
48
+ const contents = await fs.readFile(path, {
49
+ encoding: 'utf-8'
50
+ });
51
+ this.values = JSON.parse(contents);
52
+ } catch (e) {
53
+ console.log(e);
54
+ } finally {
55
+ this.ready.resolve();
56
+ }
57
+ };
58
+ asyncInit();
59
+ }
60
+
61
+ async set(key: string, value: string): Promise<void> {
62
+ await this.ready.promise;
63
+ this.values[key] = value;
64
+ await this.writeFile();
65
+ }
66
+
67
+ async writeFile(): Promise<void> {
68
+ const configDir = new URI(await this.envVarServer.getConfigDirUri());
69
+ const path: string = configDir.resolve('backend-settings.json').path.fsPath();
70
+ const values = JSON.stringify(this.values);
71
+ await fs.writeFile(path, values);
72
+ }
73
+
74
+ async get(key: string): Promise<string | undefined> {
75
+ await this.ready.promise;
76
+ return this.values[key];
77
+ }
78
+ }