@theia/core 1.51.0 → 1.53.0-next.4

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 (91) hide show
  1. package/README.md +11 -7
  2. package/i18n/nls.cs.json +4 -0
  3. package/i18n/nls.de.json +4 -0
  4. package/i18n/nls.es.json +4 -0
  5. package/i18n/nls.fr.json +4 -0
  6. package/i18n/nls.hu.json +4 -0
  7. package/i18n/nls.it.json +4 -0
  8. package/i18n/nls.ja.json +4 -0
  9. package/i18n/nls.json +4 -0
  10. package/i18n/nls.pl.json +4 -0
  11. package/i18n/nls.pt-br.json +4 -0
  12. package/i18n/nls.pt-pt.json +4 -0
  13. package/i18n/nls.ru.json +4 -0
  14. package/i18n/nls.zh-cn.json +4 -0
  15. package/lib/browser/browser.d.ts +2 -0
  16. package/lib/browser/browser.d.ts.map +1 -1
  17. package/lib/browser/browser.js +6 -1
  18. package/lib/browser/browser.js.map +1 -1
  19. package/lib/browser/common-frontend-contribution.d.ts +4 -0
  20. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  21. package/lib/browser/common-frontend-contribution.js +98 -3
  22. package/lib/browser/common-frontend-contribution.js.map +1 -1
  23. package/lib/browser/frontend-application-module.d.ts.map +1 -1
  24. package/lib/browser/frontend-application-module.js +5 -0
  25. package/lib/browser/frontend-application-module.js.map +1 -1
  26. package/lib/browser/index.d.ts +1 -0
  27. package/lib/browser/index.d.ts.map +1 -1
  28. package/lib/browser/index.js +1 -0
  29. package/lib/browser/index.js.map +1 -1
  30. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  31. package/lib/browser/shell/application-shell.js +5 -1
  32. package/lib/browser/shell/application-shell.js.map +1 -1
  33. package/lib/browser/shell/split-panels.d.ts +1 -1
  34. package/lib/browser/shell/split-panels.d.ts.map +1 -1
  35. package/lib/browser/shell/split-panels.js +4 -3
  36. package/lib/browser/shell/split-panels.js.map +1 -1
  37. package/lib/browser/shell/tab-bars.js +1 -1
  38. package/lib/browser/shell/tab-bars.js.map +1 -1
  39. package/lib/browser/undo-redo-handler.d.ts +22 -0
  40. package/lib/browser/undo-redo-handler.d.ts.map +1 -0
  41. package/lib/browser/undo-redo-handler.js +83 -0
  42. package/lib/browser/undo-redo-handler.js.map +1 -0
  43. package/lib/browser/widget-manager.d.ts +2 -1
  44. package/lib/browser/widget-manager.d.ts.map +1 -1
  45. package/lib/browser/widget-manager.js +16 -9
  46. package/lib/browser/widget-manager.js.map +1 -1
  47. package/lib/browser/widget-open-handler.js +1 -1
  48. package/lib/browser/widget-open-handler.js.map +1 -1
  49. package/lib/common/preferences/preference-schema.d.ts +5 -0
  50. package/lib/common/preferences/preference-schema.d.ts.map +1 -1
  51. package/lib/common/preferences/preference-schema.js.map +1 -1
  52. package/lib/common/quick-pick-service.d.ts +0 -9
  53. package/lib/common/quick-pick-service.d.ts.map +1 -1
  54. package/lib/common/quick-pick-service.js.map +1 -1
  55. package/lib/electron-browser/preload.js +1 -1
  56. package/lib/electron-browser/preload.js.map +1 -1
  57. package/lib/electron-browser/window/electron-window-service.js +1 -1
  58. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  59. package/lib/electron-common/electron-api.d.ts +1 -1
  60. package/lib/electron-common/electron-api.d.ts.map +1 -1
  61. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  62. package/lib/electron-main/electron-main-application.js +4 -0
  63. package/lib/electron-main/electron-main-application.js.map +1 -1
  64. package/lib/electron-main/theia-electron-window.d.ts +1 -1
  65. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  66. package/lib/electron-main/theia-electron-window.js +8 -3
  67. package/lib/electron-main/theia-electron-window.js.map +1 -1
  68. package/lib/node/messaging/websocket-frontend-connection-service.d.ts +1 -0
  69. package/lib/node/messaging/websocket-frontend-connection-service.d.ts.map +1 -1
  70. package/lib/node/messaging/websocket-frontend-connection-service.js +8 -1
  71. package/lib/node/messaging/websocket-frontend-connection-service.js.map +1 -1
  72. package/package.json +7 -7
  73. package/src/browser/browser.ts +10 -1
  74. package/src/browser/common-frontend-contribution.ts +112 -3
  75. package/src/browser/frontend-application-module.ts +6 -0
  76. package/src/browser/index.ts +1 -0
  77. package/src/browser/shell/application-shell.ts +5 -1
  78. package/src/browser/shell/split-panels.ts +4 -3
  79. package/src/browser/shell/tab-bars.ts +1 -1
  80. package/src/browser/style/tabs.css +11 -0
  81. package/src/browser/undo-redo-handler.ts +85 -0
  82. package/src/browser/widget-manager.ts +19 -11
  83. package/src/browser/widget-open-handler.ts +3 -3
  84. package/src/common/preferences/preference-schema.ts +5 -0
  85. package/src/common/quick-pick-service.ts +0 -3
  86. package/src/electron-browser/preload.ts +1 -1
  87. package/src/electron-browser/window/electron-window-service.ts +1 -1
  88. package/src/electron-common/electron-api.ts +1 -1
  89. package/src/electron-main/electron-main-application.ts +8 -2
  90. package/src/electron-main/theia-electron-window.ts +7 -3
  91. package/src/node/messaging/websocket-frontend-connection-service.ts +11 -1
@@ -0,0 +1,85 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 TypeFox 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, named, postConstruct } from 'inversify';
18
+ import { ContributionProvider } from '../common';
19
+
20
+ export const UndoRedoHandler = Symbol('UndoRedoHandler');
21
+
22
+ export interface UndoRedoHandler<T> {
23
+ priority: number;
24
+ select(): T | undefined;
25
+ undo(item: T): void;
26
+ redo(item: T): void;
27
+ }
28
+
29
+ @injectable()
30
+ export class UndoRedoHandlerService {
31
+
32
+ @inject(ContributionProvider) @named(UndoRedoHandler)
33
+ protected readonly provider: ContributionProvider<UndoRedoHandler<unknown>>;
34
+
35
+ protected handlers: UndoRedoHandler<unknown>[];
36
+
37
+ @postConstruct()
38
+ protected init(): void {
39
+ this.handlers = this.provider.getContributions().sort((a, b) => b.priority - a.priority);
40
+ }
41
+
42
+ undo(): void {
43
+ for (const handler of this.handlers) {
44
+ const selection = handler.select();
45
+ if (selection) {
46
+ handler.undo(selection);
47
+ return;
48
+ }
49
+ }
50
+ }
51
+
52
+ redo(): void {
53
+ for (const handler of this.handlers) {
54
+ const selection = handler.select();
55
+ if (selection) {
56
+ handler.redo(selection);
57
+ return;
58
+ }
59
+ }
60
+ }
61
+
62
+ }
63
+
64
+ @injectable()
65
+ export class DomInputUndoRedoHandler implements UndoRedoHandler<Element> {
66
+
67
+ priority = 1000;
68
+
69
+ select(): Element | undefined {
70
+ const element = document.activeElement;
71
+ if (element && ['input', 'textarea'].includes(element.tagName.toLowerCase())) {
72
+ return element;
73
+ }
74
+ return undefined;
75
+ }
76
+
77
+ undo(item: Element): void {
78
+ document.execCommand('undo');
79
+ }
80
+
81
+ redo(item: Element): void {
82
+ document.execCommand('redo');
83
+ }
84
+
85
+ }
@@ -114,7 +114,7 @@ export class WidgetManager {
114
114
 
115
115
  protected _cachedFactories: Map<string, WidgetFactory>;
116
116
  protected readonly widgets = new Map<string, Widget>();
117
- protected readonly pendingWidgetPromises = new Map<string, MaybePromise<Widget>>();
117
+ protected readonly pendingWidgetPromises = new Map<string, Promise<Widget>>();
118
118
 
119
119
  @inject(ContributionProvider) @named(WidgetFactory)
120
120
  protected readonly factoryProvider: ContributionProvider<WidgetFactory>;
@@ -207,9 +207,9 @@ export class WidgetManager {
207
207
  return widget as T;
208
208
  }
209
209
  }
210
- for (const [key, widget] of this.pendingWidgetPromises.entries()) {
210
+ for (const [key, widgetPromise] of this.pendingWidgetPromises.entries()) {
211
211
  if (this.testPredicate(key, factoryId, predicate)) {
212
- return widget as T;
212
+ return widgetPromise as Promise<T>;
213
213
  }
214
214
  }
215
215
  }
@@ -244,18 +244,26 @@ export class WidgetManager {
244
244
  if (!factory) {
245
245
  throw Error("No widget factory '" + factoryId + "' has been registered.");
246
246
  }
247
- try {
248
- const widgetPromise = factory.createWidget(options);
249
- this.pendingWidgetPromises.set(key, widgetPromise);
250
- const widget = await widgetPromise;
251
- await WaitUntilEvent.fire(this.onWillCreateWidgetEmitter, { factoryId, widget });
247
+ const widgetPromise = this.doCreateWidget<T>(factory, options).then(widget => {
252
248
  this.widgets.set(key, widget);
253
249
  widget.disposed.connect(() => this.widgets.delete(key));
254
250
  this.onDidCreateWidgetEmitter.fire({ factoryId, widget });
255
- return widget as T;
256
- } finally {
257
- this.pendingWidgetPromises.delete(key);
251
+ return widget;
252
+ }).finally(() => this.pendingWidgetPromises.delete(key));
253
+ this.pendingWidgetPromises.set(key, widgetPromise);
254
+ return widgetPromise;
255
+ }
256
+
257
+ protected async doCreateWidget<T extends Widget>(factory: WidgetFactory, options?: any): Promise<T> {
258
+ const widget = await factory.createWidget(options);
259
+ // Note: the widget creation process also includes the 'onWillCreateWidget' part, which can potentially fail
260
+ try {
261
+ await WaitUntilEvent.fire(this.onWillCreateWidgetEmitter, { factoryId: factory.id, widget });
262
+ } catch (e) {
263
+ widget.dispose();
264
+ throw e;
258
265
  }
266
+ return widget as T;
259
267
  }
260
268
 
261
269
  /**
@@ -96,7 +96,7 @@ export abstract class WidgetOpenHandler<W extends BaseWidget> implements OpenHan
96
96
  ...options
97
97
  };
98
98
  if (!widget.isAttached) {
99
- this.shell.addWidget(widget, op.widgetOptions || { area: 'main' });
99
+ await this.shell.addWidget(widget, op.widgetOptions || { area: 'main' });
100
100
  }
101
101
  if (op.mode === 'activate') {
102
102
  await this.shell.activateWidget(widget.id);
@@ -143,12 +143,12 @@ export abstract class WidgetOpenHandler<W extends BaseWidget> implements OpenHan
143
143
 
144
144
  protected getWidget(uri: URI, options?: WidgetOpenerOptions): Promise<W | undefined> {
145
145
  const widgetOptions = this.createWidgetOptions(uri, options);
146
- return this.widgetManager.getWidget<W>(this.id, widgetOptions);
146
+ return this.widgetManager.getWidget(this.id, widgetOptions);
147
147
  }
148
148
 
149
149
  protected getOrCreateWidget(uri: URI, options?: WidgetOpenerOptions): Promise<W> {
150
150
  const widgetOptions = this.createWidgetOptions(uri, options);
151
- return this.widgetManager.getOrCreateWidget<W>(this.id, widgetOptions);
151
+ return this.widgetManager.getOrCreateWidget(this.id, widgetOptions);
152
152
  }
153
153
 
154
154
  protected abstract createWidgetOptions(uri: URI, options?: WidgetOpenerOptions): Object;
@@ -25,6 +25,11 @@ export interface PreferenceSchema {
25
25
  [name: string]: any,
26
26
  scope?: 'application' | 'window' | 'resource' | PreferenceScope,
27
27
  overridable?: boolean;
28
+ /**
29
+ * The title of the preference schema.
30
+ * It is used in the preference UI to associate a localized group of preferences.
31
+ */
32
+ title?: string;
28
33
  properties: PreferenceSchemaProperties
29
34
  }
30
35
  export namespace PreferenceSchema {
@@ -18,7 +18,6 @@ import * as fuzzy from 'fuzzy';
18
18
  import { Event } from './event';
19
19
  import { KeySequence } from './keys';
20
20
  import { CancellationToken } from './cancellation';
21
- import { URI as Uri } from 'vscode-uri';
22
21
 
23
22
  export const quickPickServicePath = '/services/quickPick';
24
23
  export const QuickPickService = Symbol('QuickPickService');
@@ -53,7 +52,6 @@ export interface QuickPickItem {
53
52
  description?: string;
54
53
  detail?: string;
55
54
  keySequence?: KeySequence;
56
- iconPath?: { light?: Uri; dark: Uri };
57
55
  iconClasses?: string[];
58
56
  alwaysShow?: boolean;
59
57
  highlights?: QuickPickItemHighlights;
@@ -94,7 +92,6 @@ export interface QuickPickValue<V> extends QuickPickItem {
94
92
  }
95
93
 
96
94
  export interface QuickInputButton {
97
- iconPath?: { light?: Uri; dark: Uri };
98
95
  iconClass?: string;
99
96
  tooltip?: string;
100
97
  /**
@@ -199,7 +199,7 @@ const api: TheiaCoreAPI = {
199
199
  ipcRenderer.send(CHANNEL_TOGGLE_FULL_SCREEN);
200
200
  },
201
201
 
202
- requestReload: () => ipcRenderer.send(CHANNEL_REQUEST_RELOAD),
202
+ requestReload: (newUrl?: string) => ipcRenderer.send(CHANNEL_REQUEST_RELOAD, newUrl),
203
203
  restart: () => ipcRenderer.send(CHANNEL_RESTART),
204
204
 
205
205
  applicationStateChanged: state => {
@@ -100,7 +100,7 @@ export class ElectronWindowService extends DefaultWindowService {
100
100
  if (params.hash) {
101
101
  newLocation.hash = '#' + params.hash;
102
102
  }
103
- location.assign(newLocation);
103
+ window.electronTheiaCore.requestReload(newLocation.toString());
104
104
  } else {
105
105
  window.electronTheiaCore.requestReload();
106
106
  }
@@ -84,7 +84,7 @@ export interface TheiaCoreAPI {
84
84
  isFullScreen(): boolean; // TODO: this should really be async, since it blocks the renderer process
85
85
  toggleFullScreen(): void;
86
86
 
87
- requestReload(): void;
87
+ requestReload(newUrl?: string): void;
88
88
  restart(): void;
89
89
 
90
90
  applicationStateChanged(state: FrontendApplicationState): void;
@@ -15,8 +15,10 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { inject, injectable, named } from 'inversify';
18
- import { screen, app, BrowserWindow, WebContents, Event as ElectronEvent, BrowserWindowConstructorOptions, nativeImage,
19
- nativeTheme, shell, dialog } from '../../electron-shared/electron';
18
+ import {
19
+ screen, app, BrowserWindow, WebContents, Event as ElectronEvent, BrowserWindowConstructorOptions, nativeImage,
20
+ nativeTheme, shell, dialog
21
+ } from '../../electron-shared/electron';
20
22
  import * as path from 'path';
21
23
  import { Argv } from 'yargs';
22
24
  import { AddressInfo } from 'net';
@@ -350,6 +352,9 @@ export class ElectronMainApplication {
350
352
  alwaysOnTop: true,
351
353
  show: false,
352
354
  transparent: true,
355
+ webPreferences: {
356
+ backgroundThrottling: false
357
+ }
353
358
  });
354
359
 
355
360
  if (this.isShowWindowEarly()) {
@@ -458,6 +463,7 @@ export class ElectronMainApplication {
458
463
  // Setting the following option to `true` causes some features to break, somehow.
459
464
  // Issue: https://github.com/eclipse-theia/theia/issues/8577
460
465
  nodeIntegrationInWorker: false,
466
+ backgroundThrottling: false,
461
467
  preload: path.resolve(this.globals.THEIA_APP_PROJECT_PATH, 'lib', 'frontend', 'preload.js').toString()
462
468
  },
463
469
  ...this.config.electron?.windowOptions || {},
@@ -147,10 +147,14 @@ export class TheiaElectronWindow {
147
147
  return this.handleStopRequest(() => this.doCloseWindow(), reason);
148
148
  }
149
149
 
150
- protected reload(): void {
150
+ protected reload(newUrl?: string): void {
151
151
  this.handleStopRequest(async () => {
152
152
  this.applicationState = 'init';
153
- this._window.reload();
153
+ if (newUrl) {
154
+ this._window.loadURL(newUrl);
155
+ } else {
156
+ this._window.reload();
157
+ }
154
158
  }, StopReason.Reload);
155
159
  }
156
160
 
@@ -195,7 +199,7 @@ export class TheiaElectronWindow {
195
199
  }
196
200
 
197
201
  protected attachReloadListener(): void {
198
- this.toDispose.push(TheiaRendererAPI.onRequestReload(this.window.webContents, () => this.reload()));
202
+ this.toDispose.push(TheiaRendererAPI.onRequestReload(this.window.webContents, (newUrl?: string) => this.reload(newUrl)));
199
203
  }
200
204
 
201
205
  dispose(): void {
@@ -105,7 +105,8 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
105
105
  socket.on('disconnect', evt => {
106
106
  console.info('socked closed');
107
107
  channel.disconnect();
108
- const timeout = BackendApplicationConfigProvider.get().frontendConnectionTimeout;
108
+
109
+ const timeout = this.frontendConnectionTimeout();
109
110
  const isMarkedForClose = this.channelsMarkedForClose.delete(frontEndId);
110
111
  if (timeout === 0 || isMarkedForClose) {
111
112
  this.closeConnection(frontEndId, evt);
@@ -124,6 +125,15 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
124
125
  markForClose(channelId: string): void {
125
126
  this.channelsMarkedForClose.add(channelId);
126
127
  }
128
+
129
+ private frontendConnectionTimeout(): number {
130
+ const envValue = Number(process.env['FRONTEND_CONNECTION_TIMEOUT']);
131
+ if (!isNaN(envValue)) {
132
+ return envValue;
133
+ }
134
+
135
+ return BackendApplicationConfigProvider.get().frontendConnectionTimeout;
136
+ }
127
137
  }
128
138
 
129
139
  class ReconnectableSocketChannel extends AbstractChannel {