diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts index 2dc28f72b501b..4367992efd925 100644 --- a/packages/plugin-ext/src/plugin/plugin-context.ts +++ b/packages/plugin-ext/src/plugin/plugin-context.ts @@ -225,7 +225,10 @@ import { ChatResultFeedbackKind, LanguageModelChatMessage, LanguageModelChatMessageRole, - LanguageModelError + LanguageModelError, + PortAutoForwardAction, + PortAttributes, + DebugVisualization } from './types-impl'; import { AuthenticationExtImpl } from './authentication-ext'; import { SymbolKind } from '../common/plugin-api-rpc-model'; @@ -814,7 +817,13 @@ export function createAPIFactory( }, getCanonicalUri(uri: theia.Uri, options: theia.CanonicalUriRequestOptions, token: CancellationToken): theia.ProviderResult { return workspaceExt.getCanonicalUri(uri, options, token); - } + }, + /** + * @stubbed + * This is a stub implementation, that should minimally satisfy vscode extensions + * that currently use this proposed API. + */ + registerPortAttributesProvider: () => Disposable.NULL }; const onDidChangeLogLevel = new Emitter(); @@ -1134,7 +1143,11 @@ export function createAPIFactory( }, asDebugSourceUri(source: theia.DebugProtocolSource, session?: theia.DebugSession): theia.Uri { return debugExt.asDebugSourceUri(source, session); - } + }, + /** @stubbed Due to proposed API */ + registerDebugVisualizationProvider: () => Disposable.NULL, + /** @stubbed Due to proposed API */ + registerDebugVisualizationTreeProvider: () => Disposable.NULL }; const tasks: typeof theia.tasks = { @@ -1241,7 +1254,7 @@ export function createAPIFactory( } }; - const chat: typeof theia.chat = { + const chat: typeof theia.chat = { /** @stubbed MappedEditsProvider */ registerMappedEditsProvider(documentSelector: theia.DocumentSelector, provider: theia.MappedEditsProvider): Disposable { return Disposable.NULL; @@ -1251,7 +1264,7 @@ export function createAPIFactory( return { id, requestHandler: handler, - dispose() {}, + dispose() { }, onDidReceiveFeedback: (listener, thisArgs?, disposables?) => Event.None(listener, thisArgs, disposables) }; } @@ -1481,7 +1494,10 @@ export function createAPIFactory( ChatResultFeedbackKind, LanguageModelChatMessage, LanguageModelChatMessageRole, - LanguageModelError + LanguageModelError, + PortAutoForwardAction, + PortAttributes, + DebugVisualization }; }; } diff --git a/packages/plugin-ext/src/plugin/types-impl.ts b/packages/plugin-ext/src/plugin/types-impl.ts index b0c4f0a8cd1a2..3b9a28057432c 100644 --- a/packages/plugin-ext/src/plugin/types-impl.ts +++ b/packages/plugin-ext/src/plugin/types-impl.ts @@ -3036,7 +3036,7 @@ export class DebugThread { } export class DebugStackFrame { - private constructor(readonly session: theia.DebugSession, readonly threadId: number, readonly frameId: number) { } + private constructor(readonly session: theia.DebugSession, readonly threadId: number, readonly frameId: number) { } } @es5ClassCompat @@ -3363,7 +3363,7 @@ export class TestMessage implements theia.TestMessage { @es5ClassCompat export class TestCoverageCount { - constructor( public covered: number, public total: number) { } + constructor(public covered: number, public total: number) { } } @es5ClassCompat @@ -3922,7 +3922,7 @@ export class ChatResponseFileTreePart { } export type ChatResponsePart = ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart -| ChatResponseProgressPart | ChatResponseReferencePart | ChatResponseCommandButtonPart; + | ChatResponseProgressPart | ChatResponseReferencePart | ChatResponseCommandButtonPart; export enum ChatResultFeedbackKind { Unhelpful = 0, @@ -3970,3 +3970,32 @@ export class LanguageModelError extends Error { } } // #endregion + +// #region Port Attributes + +export enum PortAutoForwardAction { + Notify = 1, + OpenBrowser = 2, + OpenPreview = 3, + Silent = 4, + Ignore = 5 +} + +export class PortAttributes { + constructor(public autoForwardAction: PortAutoForwardAction) { + } +} + +// #endregion + +// #region Debug Visualization + +export class DebugVisualization { + iconPath?: URI | { light: URI; dark: URI } | ThemeIcon; + visualization?: theia.Command | { treeId: string }; + + constructor(public name: string) { + } +} + +// #endregion diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 98a0f69b3ca0f..a712b59b05b16 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -24,18 +24,20 @@ import './theia-extra'; import './theia.proposed.canonicalUriProvider'; import './theia.proposed.customEditorMove'; +import './theia.proposed.debugVisualization'; import './theia.proposed.diffCommand'; import './theia.proposed.documentPaste'; import './theia.proposed.editSessionIdentityProvider'; import './theia.proposed.extensionsAny'; import './theia.proposed.externalUriOpener'; +import './theia.proposed.findTextInFiles'; +import './theia.proposed.fsChunks'; import './theia.proposed.mappedEditsProvider'; +import './theia.proposed.multiDocumentHighlightProvider'; import './theia.proposed.notebookCellExecutionState'; import './theia.proposed.notebookKernelSource'; import './theia.proposed.notebookMessaging'; -import './theia.proposed.findTextInFiles'; -import './theia.proposed.fsChunks'; -import './theia.proposed.multiDocumentHighlightProvider'; +import './theia.proposed.portsAttributes'; import './theia.proposed.profileContentHandlers'; import './theia.proposed.resolvers'; import './theia.proposed.scmValidation'; diff --git a/packages/plugin/src/theia.proposed.debugVisualization.d.ts b/packages/plugin/src/theia.proposed.debugVisualization.d.ts new file mode 100644 index 0000000000000..181fda82930bf --- /dev/null +++ b/packages/plugin/src/theia.proposed.debugVisualization.d.ts @@ -0,0 +1,189 @@ +// ***************************************************************************** +// Copyright (C) 2024 Typefox and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +declare module '@theia/plugin' { + export namespace debug { + /** + * Registers a custom data visualization for variables when debugging. + * + * @param id The corresponding ID in the package.json `debugVisualizers` contribution point. + * @param provider The {@link DebugVisualizationProvider} to register + * @stubbed + */ + export function registerDebugVisualizationProvider( + id: string, + provider: DebugVisualizationProvider + ): Disposable; + + /** + * Registers a tree that can be referenced by {@link DebugVisualization.visualization}. + * @param id + * @param provider + * @stubbed + */ + export function registerDebugVisualizationTreeProvider( + id: string, + provider: DebugVisualizationTree + ): Disposable; + } + + /** + * An item from the {@link DebugVisualizationTree} + */ + export interface DebugTreeItem { + /** + * A human-readable string describing this item. + */ + label: string; + + /** + * A human-readable string which is rendered less prominent. + */ + description?: string; + + /** + * {@link TreeItemCollapsibleState} of the tree item. + */ + collapsibleState?: TreeItemCollapsibleState; + + /** + * Context value of the tree item. This can be used to contribute item specific actions in the tree. + * For example, a tree item is given a context value as `folder`. When contributing actions to `view/item/context` + * using `menus` extension point, you can specify context value for key `viewItem` in `when` expression like `viewItem == folder`. + * ```json + * "contributes": { + * "menus": { + * "view/item/context": [ + * { + * "command": "extension.deleteFolder", + * "when": "viewItem == folder" + * } + * ] + * } + * } + * ``` + * This will show action `extension.deleteFolder` only for items with `contextValue` is `folder`. + */ + contextValue?: string; + + /** + * Whether this item can be edited by the user. + */ + canEdit?: boolean; + } + + /** + * Provides a tree that can be referenced in debug visualizations. + */ + export interface DebugVisualizationTree { + /** + * Gets the tree item for an element or the base context item. + */ + getTreeItem(context: DebugVisualizationContext): ProviderResult; + /** + * Gets children for the tree item or the best context item. + */ + getChildren(element: T): ProviderResult; + /** + * Handles the user editing an item. + */ + editItem?(item: T, value: string): ProviderResult; + } + + export class DebugVisualization { + /** + * The name of the visualization to show to the user. + */ + name: string; + + /** + * An icon for the view when it's show in inline actions. + */ + iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + + /** + * Visualization to use for the variable. This may be either: + * - A command to run when the visualization is selected for a variable. + * - A reference to a previously-registered {@link DebugVisualizationTree} + */ + visualization?: Command | { treeId: string }; + + /** + * Creates a new debug visualization object. + * @param name Name of the visualization to show to the user. + */ + constructor(name: string); + } + + export interface DebugVisualizationProvider { + /** + * Called for each variable when the debug session stops. It should return + * any visualizations the extension wishes to show to the user. + * + * Note that this is only called when its `when` clause defined under the + * `debugVisualizers` contribution point in the `package.json` evaluates + * to true. + */ + provideDebugVisualization(context: DebugVisualizationContext, token: CancellationToken): ProviderResult; + + /** + * Invoked for a variable when a user picks the visualizer. + * + * It may return a {@link TreeView} that's shown in the Debug Console or + * inline in a hover. A visualizer may choose to return `undefined` from + * this function and instead trigger other actions in the UI, such as opening + * a custom {@link WebviewView}. + */ + resolveDebugVisualization?(visualization: T, token: CancellationToken): ProviderResult; + } + + export interface DebugVisualizationContext { + /** + * The Debug Adapter Protocol Variable to be visualized. + * @see https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable + */ + variable: any; + /** + * The Debug Adapter Protocol variable reference the type (such as a scope + * or another variable) that contained this one. Empty for variables + * that came from user evaluations in the Debug Console. + * @see https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable + */ + containerId?: number; + /** + * The ID of the Debug Adapter Protocol StackFrame in which the variable was found, + * for variables that came from scopes in a stack frame. + * @see https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame + */ + frameId?: number; + /** + * The ID of the Debug Adapter Protocol Thread in which the variable was found. + * @see https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame + */ + threadId: number; + /** + * The debug session the variable belongs to. + */ + session: DebugSession; + } +} diff --git a/packages/plugin/src/theia.proposed.portsAttributes.d.ts b/packages/plugin/src/theia.proposed.portsAttributes.d.ts new file mode 100644 index 0000000000000..b67d15c900342 --- /dev/null +++ b/packages/plugin/src/theia.proposed.portsAttributes.d.ts @@ -0,0 +1,115 @@ +// ***************************************************************************** +// Copyright (C) 2024 Typefox and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module '@theia/plugin' { + + /** + * The action that should be taken when a port is discovered through automatic port forwarding discovery. + */ + export enum PortAutoForwardAction { + /** + * Notify the user that the port is being forwarded. This is the default action. + */ + Notify = 1, + /** + * Once the port is forwarded, open the user's web browser to the forwarded port. + */ + OpenBrowser = 2, + /** + * Once the port is forwarded, open the preview browser to the forwarded port. + */ + OpenPreview = 3, + /** + * Forward the port silently. + */ + Silent = 4, + /** + * Do not forward the port. + */ + Ignore = 5 + } + + /** + * The attributes that a forwarded port can have. + */ + export class PortAttributes { + /** + * The action to be taken when this port is detected for auto forwarding. + */ + autoForwardAction: PortAutoForwardAction; + + /** + * Creates a new PortAttributes object + * @param port the port number + * @param autoForwardAction the action to take when this port is detected + */ + constructor(autoForwardAction: PortAutoForwardAction); + } + + /** + * A provider of port attributes. Port attributes are used to determine what action should be taken when a port is discovered. + */ + export interface PortAttributesProvider { + /** + * Provides attributes for the given port. For ports that your extension doesn't know about, simply + * return undefined. For example, if `providePortAttributes` is called with ports 3000 but your + * extension doesn't know anything about 3000 you should return undefined. + * @param port The port number of the port that attributes are being requested for. + * @param pid The pid of the process that is listening on the port. If the pid is unknown, undefined will be passed. + * @param commandLine The command line of the process that is listening on the port. If the command line is unknown, undefined will be passed. + * @param token A cancellation token that indicates the result is no longer needed. + */ + providePortAttributes(attributes: { port: number; pid?: number; commandLine?: string }, token: CancellationToken): ProviderResult; + } + + /** + * A selector that will be used to filter which {@link PortAttributesProvider} should be called for each port. + */ + export interface PortAttributesSelector { + /** + * Specifying a port range will cause your provider to only be called for ports within the range. + * The start is inclusive and the end is exclusive. + */ + portRange?: [number, number] | number; + + /** + * Specifying a command pattern will cause your provider to only be called for processes whose command line matches the pattern. + */ + commandPattern?: RegExp; + } + + export namespace workspace { + /** + * If your extension listens on ports, consider registering a PortAttributesProvider to provide information + * about the ports. For example, a debug extension may know about debug ports in it's debuggee. By providing + * this information with a PortAttributesProvider the extension can tell the editor that these ports should be + * ignored, since they don't need to be user facing. + * + * The results of the PortAttributesProvider are merged with the user setting `remote.portsAttributes`. If the values conflict, the user setting takes precedence. + * + * @param portSelector It is best practice to specify a port selector to avoid unnecessary calls to your provider. + * If you don't specify a port selector your provider will be called for every port, which will result in slower port forwarding for the user. + * @param provider The {@link PortAttributesProvider PortAttributesProvider}. + * @stubbed + */ + export function registerPortAttributesProvider(portSelector: PortAttributesSelector, provider: PortAttributesProvider): Disposable; + } +}