@theia/core 1.71.0-next.3 → 1.71.0-next.32

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 (104) hide show
  1. package/README.md +13 -13
  2. package/i18n/nls.cs.json +4 -4
  3. package/i18n/nls.de.json +4 -4
  4. package/i18n/nls.es.json +4 -4
  5. package/i18n/nls.fr.json +4 -4
  6. package/i18n/nls.hu.json +4 -4
  7. package/i18n/nls.it.json +4 -4
  8. package/i18n/nls.ja.json +4 -4
  9. package/i18n/nls.ko.json +4 -4
  10. package/i18n/nls.pl.json +4 -4
  11. package/i18n/nls.pt-br.json +4 -4
  12. package/i18n/nls.ru.json +4 -4
  13. package/i18n/nls.tr.json +4 -4
  14. package/i18n/nls.zh-cn.json +4 -4
  15. package/i18n/nls.zh-tw.json +4 -4
  16. package/lib/browser/catalog.json +87 -5
  17. package/lib/browser/components/card.d.ts.map +1 -1
  18. package/lib/browser/components/card.js +11 -3
  19. package/lib/browser/components/card.js.map +1 -1
  20. package/lib/browser/keyboard/index.d.ts +1 -0
  21. package/lib/browser/keyboard/index.d.ts.map +1 -1
  22. package/lib/browser/keyboard/index.js +1 -0
  23. package/lib/browser/keyboard/index.js.map +1 -1
  24. package/lib/browser/keyboard/keyboard-utils.d.ts +17 -0
  25. package/lib/browser/keyboard/keyboard-utils.d.ts.map +1 -0
  26. package/lib/browser/keyboard/keyboard-utils.js +40 -0
  27. package/lib/browser/keyboard/keyboard-utils.js.map +1 -0
  28. package/lib/browser/messaging/messaging-frontend-module.d.ts.map +1 -1
  29. package/lib/browser/messaging/messaging-frontend-module.js +3 -0
  30. package/lib/browser/messaging/messaging-frontend-module.js.map +1 -1
  31. package/lib/browser/messaging/ws-connection-source.d.ts +2 -1
  32. package/lib/browser/messaging/ws-connection-source.d.ts.map +1 -1
  33. package/lib/browser/messaging/ws-connection-source.js +4 -1
  34. package/lib/browser/messaging/ws-connection-source.js.map +1 -1
  35. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +1 -0
  36. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -1
  37. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +10 -1
  38. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
  39. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts +2 -0
  40. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts.map +1 -1
  41. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js +11 -2
  42. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js.map +1 -1
  43. package/lib/common/message-rpc/channel.d.ts.map +1 -1
  44. package/lib/common/message-rpc/channel.js +8 -2
  45. package/lib/common/message-rpc/channel.js.map +1 -1
  46. package/lib/common/messaging/index.d.ts +1 -0
  47. package/lib/common/messaging/index.d.ts.map +1 -1
  48. package/lib/common/messaging/index.js +1 -0
  49. package/lib/common/messaging/index.js.map +1 -1
  50. package/lib/common/messaging/socket-write-buffer.d.ts +4 -3
  51. package/lib/common/messaging/socket-write-buffer.d.ts.map +1 -1
  52. package/lib/common/messaging/socket-write-buffer.js +14 -4
  53. package/lib/common/messaging/socket-write-buffer.js.map +1 -1
  54. package/lib/common/resource.d.ts +2 -0
  55. package/lib/common/resource.d.ts.map +1 -1
  56. package/lib/common/resource.js +7 -3
  57. package/lib/common/resource.js.map +1 -1
  58. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  59. package/lib/electron-browser/menu/electron-main-menu-factory.js +5 -1
  60. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  61. package/lib/electron-browser/messaging/electron-messaging-frontend-module.d.ts.map +1 -1
  62. package/lib/electron-browser/messaging/electron-messaging-frontend-module.js +3 -0
  63. package/lib/electron-browser/messaging/electron-messaging-frontend-module.js.map +1 -1
  64. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  65. package/lib/electron-main/electron-api-main.js +4 -2
  66. package/lib/electron-main/electron-api-main.js.map +1 -1
  67. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  68. package/lib/electron-main/theia-electron-window.js +3 -0
  69. package/lib/electron-main/theia-electron-window.js.map +1 -1
  70. package/lib/node/messaging/index.d.ts +1 -0
  71. package/lib/node/messaging/index.d.ts.map +1 -1
  72. package/lib/node/messaging/index.js +1 -0
  73. package/lib/node/messaging/index.js.map +1 -1
  74. package/lib/node/messaging/messaging-backend-module.d.ts.map +1 -1
  75. package/lib/node/messaging/messaging-backend-module.js +4 -0
  76. package/lib/node/messaging/messaging-backend-module.js.map +1 -1
  77. package/lib/node/messaging/websocket-frontend-connection-service.d.ts +8 -5
  78. package/lib/node/messaging/websocket-frontend-connection-service.d.ts.map +1 -1
  79. package/lib/node/messaging/websocket-frontend-connection-service.js +17 -5
  80. package/lib/node/messaging/websocket-frontend-connection-service.js.map +1 -1
  81. package/lib/node/process-utils.d.ts.map +1 -1
  82. package/lib/node/process-utils.js +9 -1
  83. package/lib/node/process-utils.js.map +1 -1
  84. package/package.json +32 -32
  85. package/src/browser/components/card.tsx +13 -2
  86. package/src/browser/keyboard/index.ts +1 -0
  87. package/src/browser/keyboard/keyboard-utils.ts +37 -0
  88. package/src/browser/messaging/messaging-frontend-module.ts +3 -0
  89. package/src/browser/messaging/ws-connection-source.ts +2 -1
  90. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +14 -1
  91. package/src/browser/shell/tab-bar-toolbar/tab-toolbar-item.tsx +13 -2
  92. package/src/browser/style/card.css +4 -2
  93. package/src/common/message-rpc/channel.ts +2 -0
  94. package/src/common/messaging/index.ts +1 -0
  95. package/src/common/messaging/socket-write-buffer.ts +10 -4
  96. package/src/common/resource.ts +8 -2
  97. package/src/electron-browser/menu/electron-main-menu-factory.ts +5 -1
  98. package/src/electron-browser/messaging/electron-messaging-frontend-module.ts +3 -0
  99. package/src/electron-main/electron-api-main.ts +4 -2
  100. package/src/electron-main/theia-electron-window.ts +3 -0
  101. package/src/node/messaging/index.ts +1 -0
  102. package/src/node/messaging/messaging-backend-module.ts +5 -1
  103. package/src/node/messaging/websocket-frontend-connection-service.ts +15 -7
  104. package/src/node/process-utils.ts +9 -1
@@ -17,3 +17,4 @@
17
17
  export * from './handler';
18
18
  export * from './proxy-factory';
19
19
  export * from './connection-error-handler';
20
+ export * from './socket-write-buffer';
@@ -14,13 +14,19 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
+ import { injectable } from 'inversify';
17
18
  import { WebSocket } from './web-socket-channel';
18
19
 
20
+ @injectable()
19
21
  export class SocketWriteBuffer {
20
- private static DISCONNECTED_BUFFER_SIZE = 100 * 1024;
22
+ private static readonly DEFAULT_DISCONNECTED_BUFFER_SIZE = 100 * 1024;
21
23
 
22
- private disconnectedBuffer: Uint8Array | undefined;
23
- private bufferWritePosition = 0;
24
+ protected disconnectedBuffer: Uint8Array | undefined;
25
+ protected bufferWritePosition = 0;
26
+
27
+ protected get maxBufferSize(): number {
28
+ return SocketWriteBuffer.DEFAULT_DISCONNECTED_BUFFER_SIZE;
29
+ }
24
30
 
25
31
  buffer(data: Uint8Array): void {
26
32
  this.ensureWriteBuffer(data.byteLength);
@@ -30,7 +36,7 @@ export class SocketWriteBuffer {
30
36
 
31
37
  protected ensureWriteBuffer(byteLength: number): void {
32
38
  if (!this.disconnectedBuffer) {
33
- this.disconnectedBuffer = new Uint8Array(SocketWriteBuffer.DISCONNECTED_BUFFER_SIZE);
39
+ this.disconnectedBuffer = new Uint8Array(this.maxBufferSize);
34
40
  this.bufferWritePosition = 0;
35
41
  }
36
42
 
@@ -311,13 +311,19 @@ export class InMemoryResources implements ResourceResolver {
311
311
  }
312
312
 
313
313
  export const MEMORY_TEXT = 'mem-txt';
314
+ export const MEMORY_TEXT_READONLY = 'mem-txt-readonly';
314
315
 
315
316
  /**
316
317
  * Resource implementation for 'mem-txt' URI scheme where content is saved in URI query.
317
318
  */
318
319
  export class InMemoryTextResource implements Resource {
320
+
319
321
  constructor(readonly uri: URI) { }
320
322
 
323
+ get readOnly(): boolean {
324
+ return this.uri.scheme === MEMORY_TEXT_READONLY;
325
+ }
326
+
321
327
  async readContents(options?: { encoding?: string | undefined; } | undefined): Promise<string> {
322
328
  return this.uri.query;
323
329
  }
@@ -330,8 +336,8 @@ export class InMemoryTextResource implements Resource {
330
336
  @injectable()
331
337
  export class InMemoryTextResourceResolver implements ResourceResolver {
332
338
  resolve(uri: URI): MaybePromise<Resource> {
333
- if (uri.scheme !== MEMORY_TEXT) {
334
- throw new Error(`Expected a URI with ${MEMORY_TEXT} scheme. Was: ${uri}.`);
339
+ if (uri.scheme !== MEMORY_TEXT && uri.scheme !== MEMORY_TEXT_READONLY) {
340
+ throw new Error(`Expected a URI with ${MEMORY_TEXT} or ${MEMORY_TEXT_READONLY} scheme. Was: ${uri}.`);
335
341
  }
336
342
  return new InMemoryTextResource(uri);
337
343
  }
@@ -233,7 +233,11 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
233
233
  }
234
234
  };
235
235
 
236
- const role = this.roleFor(menu.id);
236
+ // Only assign Electron roles when no custom args are present.
237
+ // Custom args indicate that command handlers have context-dependent
238
+ // behavior (e.g. chat view copying the whole message when there is
239
+ // no DOM selection) that would be bypassed by the native role.
240
+ const role = args.length === 0 ? this.roleFor(menu.id) : undefined;
237
241
  if (role) {
238
242
  menuItem.role = role;
239
243
  delete menuItem.execute;
@@ -26,11 +26,14 @@ import { LocalConnectionProvider, RemoteConnectionProvider, ServiceConnectionPro
26
26
  import { WebSocketConnectionProvider } from '../../browser/messaging/ws-connection-provider';
27
27
  import { ConnectionCloseService, connectionCloseServicePath } from '../../common/messaging/connection-management';
28
28
  import { WebSocketConnectionSource } from '../../browser/messaging/ws-connection-source';
29
+ import { SocketWriteBuffer } from '../../common/messaging/socket-write-buffer';
29
30
 
30
31
  const backendServiceProvider = Symbol('backendServiceProvider2');
31
32
  const localServiceProvider = Symbol('localServiceProvider');
32
33
 
33
34
  export const messagingFrontendModule = new ContainerModule(bind => {
35
+ // Transient: each connection source gets its own private buffer instance.
36
+ bind(SocketWriteBuffer).toSelf();
34
37
  bind(ConnectionCloseService).toDynamicValue(ctx => WebSocketConnectionProvider.createProxy(ctx.container, connectionCloseServicePath)).inSingletonScope();
35
38
  bind(ElectronWebSocketConnectionSource).toSelf().inSingletonScope();
36
39
  bind(WebSocketConnectionSource).toService(ElectronWebSocketConnectionSource);
@@ -136,6 +136,8 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
136
136
  }
137
137
  popup.popup({
138
138
  window: electronWindow,
139
+ x,
140
+ y,
139
141
  callback: () => {
140
142
  this.openPopups.delete(menuId);
141
143
  event.sender.send(CHANNEL_ON_CLOSE_POPUP, menuId);
@@ -343,13 +345,13 @@ export namespace TheiaRendererAPI {
343
345
  const disposables = new DisposableCollection();
344
346
 
345
347
  return new Promise<boolean>(resolve => {
346
- wc.send(CHANNEL_REQUEST_CLOSE, stopReason, confirmChannel, cancelChannel);
347
348
  createDisposableListener(ipcMain, confirmChannel, e => {
348
349
  resolve(true);
349
350
  }, disposables);
350
351
  createDisposableListener(ipcMain, cancelChannel, e => {
351
352
  resolve(false);
352
353
  }, disposables);
354
+ wc.send(CHANNEL_REQUEST_CLOSE, stopReason, confirmChannel, cancelChannel);
353
355
  }).finally(() => disposables.dispose());
354
356
  }
355
357
 
@@ -360,13 +362,13 @@ export namespace TheiaRendererAPI {
360
362
  const disposables = new DisposableCollection();
361
363
 
362
364
  return new Promise<boolean>(resolve => {
363
- mainWindow.send(CHANNEL_REQUEST_SECONDARY_CLOSE, secondaryWindow.mainFrame.name, confirmChannel, cancelChannel);
364
365
  createDisposableListener(ipcMain, confirmChannel, e => {
365
366
  resolve(true);
366
367
  }, disposables);
367
368
  createDisposableListener(ipcMain, cancelChannel, e => {
368
369
  resolve(false);
369
370
  }, disposables);
371
+ mainWindow.send(CHANNEL_REQUEST_SECONDARY_CLOSE, secondaryWindow.mainFrame.name, confirmChannel, cancelChannel);
370
372
  }).finally(() => disposables.dispose());
371
373
  }
372
374
 
@@ -140,6 +140,9 @@ export class TheiaElectronWindow {
140
140
 
141
141
  protected async doCloseWindow(): Promise<void> {
142
142
  this.closeIsConfirmed = true;
143
+ // Hide the window immediately so the user perceives an instant close.
144
+ // This is done after veto checks have passed to ensure save dialogs remain visible.
145
+ this._window.hide();
143
146
  await TheiaRendererAPI.sendAboutToClose(this._window.webContents);
144
147
  this._window.close();
145
148
  }
@@ -17,3 +17,4 @@
17
17
  export * from './messaging-service';
18
18
  export * from './ipc-connection-provider';
19
19
  export * from './ipc-channel';
20
+ export * from './websocket-frontend-connection-service';
@@ -24,8 +24,9 @@ import { MessagingListener, MessagingListenerContribution } from './messaging-li
24
24
  import { FrontendConnectionService } from './frontend-connection-service';
25
25
  import { BackendApplicationContribution } from '../backend-application';
26
26
  import { connectionCloseServicePath } from '../../common/messaging/connection-management';
27
- import { WebsocketFrontendConnectionService } from './websocket-frontend-connection-service';
27
+ import { ReconnectableSocketChannel, WebsocketFrontendConnectionService } from './websocket-frontend-connection-service';
28
28
  import { WebsocketEndpoint } from './websocket-endpoint';
29
+ import { SocketWriteBuffer } from '../../common/messaging/socket-write-buffer';
29
30
 
30
31
  export const messagingBackendModule = new ContainerModule(bind => {
31
32
  bindRootContributionProvider(bind, ConnectionContainerModule);
@@ -36,6 +37,9 @@ export const messagingBackendModule = new ContainerModule(bind => {
36
37
  bind(MessagingContainer).toDynamicValue(({ container }) => container).inSingletonScope();
37
38
  bind(WebsocketEndpoint).toSelf().inSingletonScope();
38
39
  bind(BackendApplicationContribution).toService(WebsocketEndpoint);
40
+ // Transient: each connection gets its own private buffer and channel instances.
41
+ bind(SocketWriteBuffer).toSelf();
42
+ bind(ReconnectableSocketChannel).toSelf();
39
43
  bind(WebsocketFrontendConnectionService).toSelf().inSingletonScope();
40
44
  bind(FrontendConnectionService).toService(WebsocketFrontendConnectionService);
41
45
  bind(MessagingListener).toSelf().inSingletonScope();
@@ -15,9 +15,9 @@
15
15
 
16
16
  import { Channel, WriteBuffer } from '../../common/message-rpc';
17
17
  import { MessagingService } from './messaging-service';
18
- import { inject, injectable } from 'inversify';
18
+ import { inject, injectable, interfaces } from 'inversify';
19
19
  import { Socket } from 'socket.io';
20
- import { ConnectionHandlers } from './default-messaging-service';
20
+ import { ConnectionHandlers, MessagingContainer } from './default-messaging-service';
21
21
  import { SocketWriteBuffer } from '../../common/messaging/socket-write-buffer';
22
22
  import { FrontendConnectionService } from './frontend-connection-service';
23
23
  import { AbstractChannel } from '../../common/message-rpc/channel';
@@ -33,6 +33,9 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
33
33
  @inject(WebsocketEndpoint)
34
34
  protected readonly websocketServer: WebsocketEndpoint;
35
35
 
36
+ @inject(MessagingContainer)
37
+ protected readonly container: interfaces.Container;
38
+
36
39
  protected readonly wsHandlers = new ConnectionHandlers();
37
40
  protected readonly connectionsByFrontend = new Map<string, ReconnectableSocketChannel>();
38
41
  protected readonly closeTimeouts = new Map<string, NodeJS.Timeout>();
@@ -94,7 +97,7 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
94
97
 
95
98
  protected createConnection(socket: Socket, frontEndId: string): ReconnectableSocketChannel {
96
99
  console.info(`creating connection for ${frontEndId}`);
97
- const channel = new ReconnectableSocketChannel();
100
+ const channel = this.container.get(ReconnectableSocketChannel);
98
101
  channel.connect(socket);
99
102
 
100
103
  this.connectionsByFrontend.set(frontEndId, channel);
@@ -136,12 +139,17 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
136
139
  }
137
140
  }
138
141
 
139
- class ReconnectableSocketChannel extends AbstractChannel {
140
- private socket: Socket | undefined;
141
- private socketBuffer = new SocketWriteBuffer();
142
- private disposables = new DisposableCollection();
142
+ @injectable()
143
+ export class ReconnectableSocketChannel extends AbstractChannel {
144
+ protected socket: Socket | undefined;
145
+
146
+ @inject(SocketWriteBuffer)
147
+ protected socketBuffer: SocketWriteBuffer;
148
+
149
+ protected disposables = new DisposableCollection();
143
150
 
144
151
  connect(socket: Socket): void {
152
+ this.disposables.dispose();
145
153
  this.disposables = new DisposableCollection();
146
154
  this.socket = socket;
147
155
  const errorHandler = (err: Error) => {
@@ -32,7 +32,15 @@ export class ProcessUtils {
32
32
  }
33
33
 
34
34
  protected winTerminateProcessTree(ppid: number): void {
35
- this.spawnSync('taskkill.exe', ['/f', '/t', '/pid', ppid.toString(10)]);
35
+ const result = cp.spawnSync('taskkill.exe', ['/f', '/t', '/pid', ppid.toString(10)], { encoding: 'utf8' });
36
+ if (result.error) {
37
+ throw result.error;
38
+ }
39
+ // taskkill may exit with a non-zero code when some child processes have already exited.
40
+ // This is expected during shutdown — log but don't throw.
41
+ if (result.status !== 0) {
42
+ console.warn(`taskkill.exe exited with ${result.status} for PID ${ppid}. Output:\n${JSON.stringify(result.output)}`);
43
+ }
36
44
  }
37
45
 
38
46
  protected unixTerminateProcessTree(ppid: number): void {