diff --git a/CHANGELOG.md b/CHANGELOG.md index 717aefbb64758..b2a2a28ab3d55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,12 @@ - [Previous Changelogs](https://github.com/eclipse-theia/theia/tree/master/doc/changelogs/) -## v1.27.0 - 6/30/2022 + +## v1.27.0 - Unreleased [Breaking Changes:](#breaking_changes_1.27.0) +- [plugin-dev] moved and renamed interface from: `@theia/debug/lib/browser/debug-contribution/DebugPluginConfiguration` to: `plugin-dev/src/common/PluginDebugConfiguration` [#11224](https://github.com/eclipse-theia/theia/pull/11224) - [core] Refactored the core messaging API. Replaced `vscode-ws-jsonrpc` with a custom RPC protocol that is better suited for handling binary data and enables message tunneling. This impacts all main concepts of the messaging API. The API no longer exposes a `Connection` object and uses a generic `Channel` implementation instead. - Replaces usage of `vscode-json-rpc`'s `Connection` with the new generic `Channel`. Affects `AbstractConnectionProvider`, `MessagingService`, `IPCConnectionProvider`, `ElectronMessagingService` diff --git a/doc/Developing.md b/doc/Developing.md index effa760e0daed..394fbaf7ca39b 100644 --- a/doc/Developing.md +++ b/doc/Developing.md @@ -515,7 +515,7 @@ etc.) by opening `packages//coverage/index.html`. - If you need to install `windows-build-tools`, see [`Installing Windows Build Tools`](#installing-windows-build-tools). - If you run into problems with installing the required build tools, the `node-gyp` documentation offers a useful [guide](https://github.com/nodejs/node-gyp#on-windows) how to install the dependencies manually. The versions required for building Theia are: - Python 3.6 or higher -- Visual Studio [build tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) 17 + - Visual Studio [build tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) 17 - If you have multiple versions of either python or Visual Studio installed or if the tool is not found, you may adjust the used version via the npm config: - `npm config set python /path/to/executable/python --global` - `npm config set msvs_version 2017 --global` diff --git a/packages/core/src/browser/style/menus.css b/packages/core/src/browser/style/menus.css index ed0a4d2e209ea..ce0c6a1665a1e 100644 --- a/packages/core/src/browser/style/menus.css +++ b/packages/core/src/browser/style/menus.css @@ -128,6 +128,7 @@ color: var(--theia-menu-selectionForeground); border: thin solid var(--theia-menu-selectionBorder); opacity: 1; + cursor: pointer; } diff --git a/packages/core/src/common/index.ts b/packages/core/src/common/index.ts index e82ecddfa1268..cedfd254d0009 100644 --- a/packages/core/src/common/index.ts +++ b/packages/core/src/common/index.ts @@ -34,6 +34,7 @@ export * from './message-service'; export * from './message-service-protocol'; export * from './progress-service'; export * from './progress-service-protocol'; +export * from './quick-pick-service'; export * from './selection'; export * from './strings'; export * from './application-error'; diff --git a/packages/core/src/electron-main/theia-electron-window.ts b/packages/core/src/electron-main/theia-electron-window.ts index 8494ac75d720b..9ac8e7c9a2acd 100644 --- a/packages/core/src/electron-main/theia-electron-window.ts +++ b/packages/core/src/electron-main/theia-electron-window.ts @@ -20,8 +20,10 @@ import { APPLICATION_STATE_CHANGE_SIGNAL, CLOSE_REQUESTED_SIGNAL, RELOAD_REQUEST import { BrowserWindow, BrowserWindowConstructorOptions, ipcMain, IpcMainEvent } from '../../electron-shared/electron'; import { inject, injectable, postConstruct } from '../../shared/inversify'; import { ElectronMainApplicationGlobals } from './electron-main-constants'; -import { DisposableCollection, Emitter, Event, isWindows } from '../common'; +import { DisposableCollection, Emitter, Event } from '../common'; import { createDisposableListener } from './event-utils'; +import { URI } from '../common/uri'; +import { FileUri } from '../node/file-uri'; /** * Theia tracks the maximized state of Electron Browser Windows. @@ -114,14 +116,15 @@ export class TheiaElectronWindow { } protected async handleStopRequest(onSafeCallback: () => unknown, reason: StopReason): Promise { - // Only confirm close to windows that have loaded our front end. - let currentUrl = this.window.webContents.getURL(); - let frontendUri = this.globals.THEIA_FRONTEND_HTML_PATH; - // Since our resolved frontend HTML path might contain backward slashes on Windows, we normalize everything first. - if (isWindows) { - currentUrl = currentUrl.replace(/\\/g, '/'); - frontendUri = frontendUri.replace(/\\/g, '/'); - } + // Only confirm close to windows that have loaded our frontend. + // Both the windows's URL and the FS path of the `index.html` should be converted to the "same" format to be able to compare them. (#11226) + // Notes: + // - Windows: file:///C:/path/to/somewhere vs file:///c%3A/path/to/somewhere + // - macOS: file:///Applications/App%20Name.app/Contents vs /Applications/App Name.app/Contents + // This URL string comes from electron, we can expect that this is properly encoded URL. For example, a space is `%20` + const currentUrl = new URI(this.window.webContents.getURL()).toString(); + // THEIA_FRONTEND_HTML_PATH is an FS path, we have to covert to an encoded URI string. + const frontendUri = FileUri.create(this.globals.THEIA_FRONTEND_HTML_PATH).toString(); const safeToClose = !currentUrl.includes(frontendUri) || await this.checkSafeToStop(reason); if (safeToClose) { try { diff --git a/packages/debug/src/browser/debug-contribution.ts b/packages/debug/src/browser/debug-contribution.ts index 882cb4d5c489d..48af1c8be8378 100644 --- a/packages/debug/src/browser/debug-contribution.ts +++ b/packages/debug/src/browser/debug-contribution.ts @@ -23,12 +23,6 @@ export interface DebugContribution { register(configType: string, connection: DebugSessionConnection): void; } -export interface DebugPluginConfiguration { - debugMode?: string; - pluginLocation?: string; - debugPort?: string; -} - // copied from https://github.com/microsoft/vscode-node-debug2/blob/bcd333ef87642b817ac96d28fde7ab96fee3f6a9/src/nodeDebugInterfaces.d.ts export interface LaunchVSCodeRequest extends DebugProtocol.Request { arguments: LaunchVSCodeArguments; diff --git a/packages/plugin-dev/src/browser/hosted-plugin-manager-client.ts b/packages/plugin-dev/src/browser/hosted-plugin-manager-client.ts index 2cd28677e734d..95ff873e7b9f2 100644 --- a/packages/plugin-dev/src/browser/hosted-plugin-manager-client.ts +++ b/packages/plugin-dev/src/browser/hosted-plugin-manager-client.ts @@ -22,8 +22,8 @@ import { LabelProvider, isNative, AbstractDialog } from '@theia/core/lib/browser import { WindowService } from '@theia/core/lib/browser/window/window-service'; import { WorkspaceService } from '@theia/workspace/lib/browser'; import { FileDialogService } from '@theia/filesystem/lib/browser'; -import { PluginDevServer } from '../common/plugin-dev-protocol'; -import { DebugPluginConfiguration, LaunchVSCodeArgument, LaunchVSCodeRequest, LaunchVSCodeResult } from '@theia/debug/lib/browser/debug-contribution'; +import { PluginDebugConfiguration, PluginDevServer } from '../common/plugin-dev-protocol'; +import { LaunchVSCodeArgument, LaunchVSCodeRequest, LaunchVSCodeResult } from '@theia/debug/lib/browser/debug-contribution'; import { DebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager'; import { HostedPluginPreferences } from './hosted-plugin-preferences'; import { FileService } from '@theia/filesystem/lib/browser/file-service'; @@ -145,7 +145,7 @@ export class HostedPluginManagerClient { return undefined; } - async start(debugConfig?: DebugPluginConfiguration): Promise { + async start(debugConfig?: PluginDebugConfiguration): Promise { if (await this.hostedPluginServer.isHostedPluginInstanceRunning()) { this.messageService.warn(nls.localize('theia/plugin-dev/alreadyRunning', 'Hosted instance is already running.')); return; @@ -181,7 +181,7 @@ export class HostedPluginManagerClient { } } - async debug(config?: DebugPluginConfiguration): Promise { + async debug(config?: PluginDebugConfiguration): Promise { await this.start(this.setDebugConfig(config)); await this.startDebugSessionManager(); @@ -361,7 +361,7 @@ export class HostedPluginManagerClient { return error?.message?.substring(error.message.indexOf(':') + 1) || ''; } - private setDebugConfig(config?: DebugPluginConfiguration): DebugPluginConfiguration { + private setDebugConfig(config?: PluginDebugConfiguration): PluginDebugConfiguration { config = Object.assign(config || {}, { debugMode: this.hostedPluginPreferences['hosted-plugin.debugMode'] }); if (config.pluginLocation) { this.pluginLocation = new URI((!config.pluginLocation.startsWith('/') ? '/' : '') + config.pluginLocation.replace(/\\/g, '/')).withScheme('file'); @@ -369,7 +369,7 @@ export class HostedPluginManagerClient { return config; } - private getDebugPluginConfig(args: LaunchVSCodeArgument[]): DebugPluginConfiguration { + private getDebugPluginConfig(args: LaunchVSCodeArgument[]): PluginDebugConfiguration { let pluginLocation; for (const arg of args) { if (arg?.prefix === '--extensionDevelopmentPath=') { diff --git a/packages/plugin-dev/src/common/plugin-dev-protocol.ts b/packages/plugin-dev/src/common/plugin-dev-protocol.ts index 18a5924b8f0a6..dc69da104e5fa 100644 --- a/packages/plugin-dev/src/common/plugin-dev-protocol.ts +++ b/packages/plugin-dev/src/common/plugin-dev-protocol.ts @@ -15,8 +15,6 @@ // ***************************************************************************** import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory'; -// eslint-disable-next-line @theia/runtime-import-check -import { DebugPluginConfiguration } from '@theia/debug/lib/browser/debug-contribution'; import { PluginMetadata } from '@theia/plugin-ext/lib/common/plugin-protocol'; export const pluginDevServicePath = '/services/plugin-dev'; @@ -24,7 +22,7 @@ export const PluginDevServer = Symbol('PluginDevServer'); export interface PluginDevServer extends JsonRpcServer { getHostedPlugin(): Promise; runHostedPluginInstance(uri: string): Promise; - runDebugHostedPluginInstance(uri: string, debugConfig: DebugPluginConfiguration): Promise; + runDebugHostedPluginInstance(uri: string, debugConfig: PluginDebugConfiguration): Promise; terminateHostedPluginInstance(): Promise; isHostedPluginInstanceRunning(): Promise; getHostedPluginInstanceURI(): Promise; @@ -39,3 +37,9 @@ export interface PluginDevServer extends JsonRpcServer { export interface PluginDevClient { } + +export interface PluginDebugConfiguration { + debugMode?: string; + pluginLocation?: string; + debugPort?: string; +} diff --git a/packages/plugin-dev/src/node/hosted-instance-manager.ts b/packages/plugin-dev/src/node/hosted-instance-manager.ts index c540d21fed6f4..c86deb06d9aa2 100644 --- a/packages/plugin-dev/src/node/hosted-instance-manager.ts +++ b/packages/plugin-dev/src/node/hosted-instance-manager.ts @@ -29,8 +29,7 @@ import { FileUri } from '@theia/core/lib/node/file-uri'; import { LogType } from '@theia/plugin-ext/lib/common/types'; import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin'; import { MetadataScanner } from '@theia/plugin-ext/lib/hosted/node/metadata-scanner'; -// eslint-disable-next-line @theia/runtime-import-check -import { DebugPluginConfiguration } from '@theia/debug/lib/browser/debug-contribution'; +import { PluginDebugConfiguration } from '../common/plugin-dev-protocol'; import { HostedPluginProcess } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin-process'; const DEFAULT_HOSTED_PLUGIN_PORT = 3030; @@ -61,7 +60,7 @@ export interface HostedInstanceManager { * @param debugConfig debug configuration * @returns uri where new Theia instance is run */ - debug(pluginUri: URI, debugConfig: DebugPluginConfiguration): Promise; + debug(pluginUri: URI, debugConfig: PluginDebugConfiguration): Promise; /** * Terminates hosted plugin instance. @@ -121,11 +120,11 @@ export abstract class AbstractHostedInstanceManager implements HostedInstanceMan return this.doRun(pluginUri, port); } - async debug(pluginUri: URI, debugConfig: DebugPluginConfiguration): Promise { + async debug(pluginUri: URI, debugConfig: PluginDebugConfiguration): Promise { return this.doRun(pluginUri, undefined, debugConfig); } - private async doRun(pluginUri: URI, port?: number, debugConfig?: DebugPluginConfiguration): Promise { + private async doRun(pluginUri: URI, port?: number, debugConfig?: PluginDebugConfiguration): Promise { if (this.isPluginRunning) { this.hostedPluginSupport.sendLog({ data: 'Hosted plugin instance is already running.', type: LogType.Info }); throw new Error('Hosted instance is already running.'); @@ -239,7 +238,7 @@ export abstract class AbstractHostedInstanceManager implements HostedInstanceMan return false; } - protected async getStartCommand(port?: number, debugConfig?: DebugPluginConfiguration): Promise { + protected async getStartCommand(port?: number, debugConfig?: PluginDebugConfiguration): Promise { const processArguments = process.argv; let command: string[]; @@ -366,7 +365,7 @@ export class NodeHostedPluginRunner extends AbstractHostedInstanceManager { return options; } - protected override async getStartCommand(port?: number, debugConfig?: DebugPluginConfiguration): Promise { + protected override async getStartCommand(port?: number, debugConfig?: PluginDebugConfiguration): Promise { if (!port) { port = process.env.HOSTED_PLUGIN_PORT ? Number(process.env.HOSTED_PLUGIN_PORT) : diff --git a/packages/plugin-dev/src/node/plugin-dev-service.ts b/packages/plugin-dev/src/node/plugin-dev-service.ts index 5d8f346854e4a..58c0ecf566523 100644 --- a/packages/plugin-dev/src/node/plugin-dev-service.ts +++ b/packages/plugin-dev/src/node/plugin-dev-service.ts @@ -14,7 +14,7 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** -import { PluginDevServer, PluginDevClient } from '../common/plugin-dev-protocol'; +import { PluginDebugConfiguration, PluginDevServer, PluginDevClient } from '../common/plugin-dev-protocol'; import { injectable, inject } from '@theia/core/shared/inversify'; import { HostedInstanceManager } from './hosted-instance-manager'; import { PluginMetadata } from '@theia/plugin-ext/lib/common/plugin-protocol'; @@ -22,8 +22,6 @@ import URI from '@theia/core/lib/common/uri'; import { HostedPluginReader } from './hosted-plugin-reader'; import { HostedPluginsManager } from './hosted-plugins-manager'; import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin'; -// eslint-disable-next-line @theia/runtime-import-check -import { DebugPluginConfiguration } from '@theia/debug/lib/browser/debug-contribution'; @injectable() export class PluginDevServerImpl implements PluginDevServer { @@ -66,7 +64,7 @@ export class PluginDevServerImpl implements PluginDevServer { return this.uriToStrPromise(this.hostedInstanceManager.run(new URI(uri))); } - runDebugHostedPluginInstance(uri: string, debugConfig: DebugPluginConfiguration): Promise { + runDebugHostedPluginInstance(uri: string, debugConfig: PluginDebugConfiguration): Promise { return this.uriToStrPromise(this.hostedInstanceManager.debug(new URI(uri), debugConfig)); } diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index d533974845a91..abff12eabe343 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -99,8 +99,7 @@ import type { import { SerializableEnvironmentVariableCollection } from '@theia/terminal/lib/common/base-terminal-protocol'; import { ThemeType } from '@theia/core/lib/common/theme'; import { Disposable } from '@theia/core/lib/common/disposable'; -// eslint-disable-next-line @theia/runtime-import-check -import { PickOptions, QuickInputButtonHandle, QuickPickItem, WidgetOpenerOptions } from '@theia/core/lib/browser'; +import { PickOptions, QuickInputButtonHandle, QuickPickItem } from '@theia/core/lib/common'; import { Severity } from '@theia/core/lib/common/severity'; export interface PreferenceData { @@ -1620,12 +1619,12 @@ export interface WebviewViewsMain extends Disposable { } export interface CustomEditorsExt { - $resolveWebviewEditor( + $resolveWebviewEditor( resource: UriComponents, newWebviewHandle: string, viewType: string, title: string, - widgetOpenerOptions: WidgetOpenerOptions | undefined, + widgetOpenerOptions: T | undefined, options: theia.WebviewPanelOptions, cancellation: CancellationToken): Promise; $createCustomDocument(resource: UriComponents, viewType: string, openContext: theia.CustomDocumentOpenContext, cancellation: CancellationToken): Promise<{ editable: boolean }>; @@ -1648,7 +1647,7 @@ export interface CustomEditorsMain { $registerTextEditorProvider(viewType: string, options: theia.WebviewPanelOptions, capabilities: CustomTextEditorCapabilities): void; $registerCustomEditorProvider(viewType: string, options: theia.WebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void; $unregisterEditorProvider(viewType: string): void; - $createCustomEditorPanel(handle: string, title: string, widgetOpenerOptions: WidgetOpenerOptions | undefined, options: theia.WebviewPanelOptions & theia.WebviewOptions): Promise; + $createCustomEditorPanel(handle: string, title: string, widgetOpenerOptions: T | undefined, options: theia.WebviewPanelOptions & theia.WebviewOptions): Promise; $onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void; $onContentChange(resource: UriComponents, viewType: string): void; } diff --git a/packages/plugin-ext/src/plugin/custom-editors.ts b/packages/plugin-ext/src/plugin/custom-editors.ts index a1f956c5f5658..ae961bc294ee6 100644 --- a/packages/plugin-ext/src/plugin/custom-editors.ts +++ b/packages/plugin-ext/src/plugin/custom-editors.ts @@ -29,7 +29,6 @@ import { WebviewImpl, WebviewsExtImpl } from './webviews'; import { CancellationToken, CancellationTokenSource } from '@theia/core/lib/common/cancellation'; import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { WorkspaceExtImpl } from './workspace'; -import { WidgetOpenerOptions } from '@theia/core/lib/browser'; export class CustomEditorsExtImpl implements CustomEditorsExt { private readonly proxy: CustomEditorsMain; @@ -116,12 +115,12 @@ export class CustomEditorsExtImpl implements CustomEditorsExt { document.dispose(); } - async $resolveWebviewEditor( + async $resolveWebviewEditor( resource: UriComponents, handler: string, viewType: string, title: string, - widgetOpenerOptions: WidgetOpenerOptions | undefined, + widgetOpenerOptions: T | undefined, options: theia.WebviewPanelOptions & theia.WebviewOptions, cancellation: CancellationToken ): Promise {