From 1f32a87864f01a00cebe4f4caa503d7b0e8ae0da Mon Sep 17 00:00:00 2001 From: Remi Schnekenburger Date: Tue, 21 Nov 2023 09:15:23 +0100 Subject: [PATCH] [vscode] Support env.onDidChangeShell event contributed on behalf of STMicroelectronics Signed-off-by: Remi Schnekenburger Address review comments - remove indirection from TerminalService - change shellPath as getter rather than property - use instanceof instead of is() --- CHANGELOG.md | 3 ++- packages/plugin-ext/src/common/plugin-api-rpc.ts | 1 + .../plugin-ext/src/main/browser/terminal-main.ts | 7 +++++++ packages/plugin-ext/src/plugin/env.ts | 8 -------- packages/plugin-ext/src/plugin/plugin-context.ts | 5 ++++- packages/plugin-ext/src/plugin/plugin-manager.ts | 2 +- packages/plugin-ext/src/plugin/terminal-ext.ts | 15 +++++++++++++++ packages/plugin/src/theia.d.ts | 10 +++++++++- .../src/browser/shell-terminal-profile.ts | 5 +++++ .../src/browser/terminal-profile-service.ts | 10 ++++++++++ 10 files changed, 54 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fafcbb56844f3..b5948347a3e7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ ## v1.44.0 - [task] prevent task widget title from being changed by task process [#13003](https://github.com/eclipse-theia/theia/pull/13003) -- [vscode] Added Notebook CodeActionKind [#13093](https://github.com/eclipse-theia/theia/pull/13093) - contributed on behalf of STMicroelectronics +- [vscode] added Notebook CodeActionKind [#13093](https://github.com/eclipse-theia/theia/pull/13093) - contributed on behalf of STMicroelectronics +- [vscode] added support to env.ondidChangeShell event [#13097](https://github.com/eclipse-theia/theia/pull/13097) - contributed on behalf of STMicroelectronics ## v1.43.0 - 10/26/2023 diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index c0ce507624058..03031c4ca30a1 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -296,6 +296,7 @@ export interface TerminalServiceExt { $provideTerminalLinks(line: string, terminalId: string, token: theia.CancellationToken): Promise; $handleTerminalLink(link: ProvidedTerminalLink): Promise; getEnvironmentVariableCollection(extensionIdentifier: string): theia.GlobalEnvironmentVariableCollection; + $setShell(shell: string): void; } export interface OutputChannelRegistryExt { createOutputChannel(name: string, pluginInfo: PluginInfo): theia.OutputChannel, diff --git a/packages/plugin-ext/src/main/browser/terminal-main.ts b/packages/plugin-ext/src/main/browser/terminal-main.ts index d894afd779f03..fe1876c7bf8b4 100644 --- a/packages/plugin-ext/src/main/browser/terminal-main.ts +++ b/packages/plugin-ext/src/main/browser/terminal-main.ts @@ -18,6 +18,7 @@ import { interfaces } from '@theia/core/shared/inversify'; import { ApplicationShell, WidgetOpenerOptions } from '@theia/core/lib/browser'; import { TerminalEditorLocationOptions, TerminalOptions } from '@theia/plugin'; import { TerminalLocation, TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget'; +import { TerminalProfileService } from '@theia/terminal/lib/browser/terminal-profile-service'; import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service'; import { TerminalServiceMain, TerminalServiceExt, MAIN_RPC_CONTEXT } from '../../common/plugin-api-rpc'; import { RPCProtocol } from '../../common/rpc-protocol'; @@ -36,6 +37,7 @@ import { HostedPluginSupport } from '../../hosted/browser/hosted-plugin'; export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLinkProvider, Disposable { private readonly terminals: TerminalService; + private readonly terminalProfileService: TerminalProfileService; private readonly pluginTerminalRegistry: PluginTerminalRegistry; private readonly hostedPluginSupport: HostedPluginSupport; private readonly shell: ApplicationShell; @@ -47,6 +49,7 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin constructor(rpc: RPCProtocol, container: interfaces.Container) { this.terminals = container.get(TerminalService); + this.terminalProfileService = container.get(TerminalProfileService); this.pluginTerminalRegistry = container.get(PluginTerminalRegistry); this.hostedPluginSupport = container.get(HostedPluginSupport); this.shell = container.get(ApplicationShell); @@ -64,6 +67,10 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin this.pluginTerminalRegistry.startCallback = id => this.startProfile(id); container.bind(TerminalLinkProvider).toDynamicValue(() => this); + + this.toDispose.push(this.terminalProfileService.onDidChangeDefaultShell(shell => { + this.extProxy.$setShell(shell); + })); } async startProfile(id: string): Promise { diff --git a/packages/plugin-ext/src/plugin/env.ts b/packages/plugin-ext/src/plugin/env.ts index 80547683d52fa..8fe8494a49c47 100644 --- a/packages/plugin-ext/src/plugin/env.ts +++ b/packages/plugin-ext/src/plugin/env.ts @@ -25,7 +25,6 @@ export abstract class EnvExtImpl { private queryParameters: QueryParameters; private lang: string; private applicationName: string; - private defaultShell: string; private ui: theia.UIKind; private envMachineId: string; private envSessionId: string; @@ -68,10 +67,6 @@ export abstract class EnvExtImpl { this.lang = lang; } - setShell(shell: string): void { - this.defaultShell = shell; - } - setUIKind(uiKind: theia.UIKind): void { this.ui = uiKind; } @@ -112,9 +107,6 @@ export abstract class EnvExtImpl { get uriScheme(): string { return 'theia'; } - get shell(): string { - return this.defaultShell; - } get uiKind(): theia.UIKind { return this.ui; } diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts index f972127dbec48..448183017274d 100644 --- a/packages/plugin-ext/src/plugin/plugin-context.ts +++ b/packages/plugin-ext/src/plugin/plugin-context.ts @@ -796,7 +796,10 @@ export function createAPIFactory( get machineId(): string { return envExt.machineId; }, get sessionId(): string { return envExt.sessionId; }, get uriScheme(): string { return envExt.uriScheme; }, - get shell(): string { return envExt.shell; }, + get shell(): string { return terminalExt.defaultShell; }, + get onDidChangeShell(): theia.Event { + return terminalExt.onDidChangeShell; + }, get uiKind(): theia.UIKind { return envExt.uiKind; }, clipboard, getEnvVariable(envVarName: string): PromiseLike { diff --git a/packages/plugin-ext/src/plugin/plugin-manager.ts b/packages/plugin-ext/src/plugin/plugin-manager.ts index 3d3c5296bdc7a..e3a95e87970de 100644 --- a/packages/plugin-ext/src/plugin/plugin-manager.ts +++ b/packages/plugin-ext/src/plugin/plugin-manager.ts @@ -206,7 +206,7 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager { this.envExt.setQueryParameters(params.env.queryParams); this.envExt.setLanguage(params.env.language); - this.envExt.setShell(params.env.shell); + this.terminalService.$setShell(params.env.shell); this.envExt.setUIKind(params.env.uiKind); this.envExt.setApplicationName(params.env.appName); this.envExt.setAppHost(params.env.appHost); diff --git a/packages/plugin-ext/src/plugin/terminal-ext.ts b/packages/plugin-ext/src/plugin/terminal-ext.ts index c48e618a0e651..7c158fd36a8cb 100644 --- a/packages/plugin-ext/src/plugin/terminal-ext.ts +++ b/packages/plugin-ext/src/plugin/terminal-ext.ts @@ -71,6 +71,10 @@ export class TerminalServiceExtImpl implements TerminalServiceExt { protected environmentVariableCollections: MultiKeyMap = new MultiKeyMap(2); + private shell: string; + private readonly onDidChangeShellEmitter = new Emitter(); + readonly onDidChangeShell: theia.Event = this.onDidChangeShellEmitter.event; + constructor(rpc: RPCProtocol) { this.proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.TERMINAL_MAIN); } @@ -79,6 +83,17 @@ export class TerminalServiceExtImpl implements TerminalServiceExt { return [...this._terminals.values()]; } + get defaultShell(): string { + return this.shell || ''; + } + + async $setShell(shell: string): Promise { + if (this.shell !== shell) { + this.shell = shell; + this.onDidChangeShellEmitter.fire(shell); + } + } + createTerminal( nameOrOptions: TerminalOptions | PseudoTerminalOptions | ExtensionTerminalOptions | (string | undefined), shellPath?: string, shellArgs?: string[] | string diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index cd00002eb4ae4..5ed50fdd221f7 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -7720,6 +7720,12 @@ export module '@theia/plugin' { */ export const isTelemetryEnabled: boolean; + /** + * An {@link Event} which fires when the default shell changes. This fires with the new + * shell path. + */ + export const onDidChangeShell: Event; + /** * An {@link Event} which fires when the user enabled or disables telemetry. * `true` if the user has enabled telemetry or `false` if the user has disabled telemetry. @@ -7747,7 +7753,9 @@ export module '@theia/plugin' { export const remoteName: string | undefined; /** - * The detected default shell for the extension host. + * The detected default shell for the extension host, this is overridden by the + * `terminal.integrated.defaultProfile` setting for the extension host's platform. Note that in + * environments that do not support a shell the value is the empty string. */ export const shell: string; diff --git a/packages/terminal/src/browser/shell-terminal-profile.ts b/packages/terminal/src/browser/shell-terminal-profile.ts index aaefd630bd67d..8d320320b72d6 100644 --- a/packages/terminal/src/browser/shell-terminal-profile.ts +++ b/packages/terminal/src/browser/shell-terminal-profile.ts @@ -20,6 +20,11 @@ import { TerminalWidget, TerminalWidgetOptions } from './base/terminal-widget'; import { TerminalProfile } from './terminal-profile-service'; export class ShellTerminalProfile implements TerminalProfile { + + get shellPath(): string | undefined { + return this.options.shellPath; + } + constructor(protected readonly terminalService: TerminalService, protected readonly options: TerminalWidgetOptions) { } async start(): Promise { diff --git a/packages/terminal/src/browser/terminal-profile-service.ts b/packages/terminal/src/browser/terminal-profile-service.ts index 5d8094ce24021..2a3f9b4570835 100644 --- a/packages/terminal/src/browser/terminal-profile-service.ts +++ b/packages/terminal/src/browser/terminal-profile-service.ts @@ -17,6 +17,7 @@ import { Emitter, Event } from '@theia/core'; import { injectable } from '@theia/core/shared/inversify'; import { TerminalWidget } from './base/terminal-widget'; +import { ShellTerminalProfile } from './shell-terminal-profile'; export const TerminalProfileService = Symbol('TerminalProfileService'); export const ContributedTerminalProfileStore = Symbol('ContributedTerminalProfileStore'); @@ -36,6 +37,7 @@ export interface TerminalProfileService { getProfile(id: string): TerminalProfile | undefined readonly all: [string, TerminalProfile][]; setDefaultProfile(id: string): void; + readonly onDidChangeDefaultShell: Event; readonly defaultProfile: TerminalProfile | undefined; } @@ -87,9 +89,11 @@ export class DefaultTerminalProfileService implements TerminalProfileService { protected readonly onAddedEmitter: Emitter = new Emitter(); protected readonly onRemovedEmitter: Emitter = new Emitter(); + protected readonly onDidChangeDefaultShellEmitter: Emitter = new Emitter(); onAdded: Event = this.onAddedEmitter.event; onRemoved: Event = this.onRemovedEmitter.event; + onDidChangeDefaultShell: Event = this.onDidChangeDefaultShellEmitter.event; constructor(...stores: TerminalProfileStore[]) { this.stores = stores; @@ -144,6 +148,12 @@ export class DefaultTerminalProfileService implements TerminalProfileService { throw new Error(`Cannot set default to unknown profile '${id}' `); } this.defaultProfileIndex = this.order.indexOf(id); + + if (profile instanceof ShellTerminalProfile && profile.shellPath) { + this.onDidChangeDefaultShellEmitter.fire(profile.shellPath); + } else { + this.onDidChangeDefaultShellEmitter.fire(''); + } } getProfile(id: string): TerminalProfile | undefined {