diff --git a/extensions/positron-python/python_files/positron/positron_ipykernel/ui_comm.py b/extensions/positron-python/python_files/positron/positron_ipykernel/ui_comm.py index dda73094a4e..4ace3d0e8ec 100644 --- a/extensions/positron-python/python_files/positron/positron_ipykernel/ui_comm.py +++ b/extensions/positron-python/python_files/positron/positron_ipykernel/ui_comm.py @@ -355,6 +355,16 @@ class ExecuteCommandParams(BaseModel): ) +class EvaluateWhenClauseParams(BaseModel): + """ + Get a logical for a `when` clause (a set of context keys) + """ + + when_clause: StrictStr = Field( + description="The values for context keys, as a `when` clause", + ) + + class ExecuteCodeParams(BaseModel): """ Execute code in a Positron runtime @@ -481,6 +491,8 @@ class ShowHtmlFileParams(BaseModel): ExecuteCommandParams.update_forward_refs() +EvaluateWhenClauseParams.update_forward_refs() + ExecuteCodeParams.update_forward_refs() OpenWorkspaceParams.update_forward_refs() diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index fd34acde7f0..c152a0a713e 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -606,7 +606,7 @@ }, "positron": { "binaryDependencies": { - "ark": "0.1.119" + "ark": "0.1.120" }, "minimumRVersion": "4.2.0", "minimumRenvVersion": "1.0.7" diff --git a/positron/comms/ui-frontend-openrpc.json b/positron/comms/ui-frontend-openrpc.json index eb748374af7..012b782f5ff 100644 --- a/positron/comms/ui-frontend-openrpc.json +++ b/positron/comms/ui-frontend-openrpc.json @@ -216,6 +216,26 @@ } ] }, + { + "name": "evaluate_when_clause", + "summary": "Get a logical for a `when` clause (a set of context keys)", + "description": "Use this to evaluate a `when` clause of context keys in the frontend", + "params": [ + { + "name": "when_clause", + "description": "The values for context keys, as a `when` clause", + "schema": { + "type": "string" + } + } + ], + "result": { + "schema": { + "type": "boolean", + "description": "Whether the `when` clause evaluates as true or false" + } + } + }, { "name": "execute_code", "summary": "Execute code in a Positron runtime", diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index a49081a78f1..6f1c8c57525 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -94,6 +94,7 @@ import './positron/mainThreadLanguageRuntime'; import './positron/mainThreadPreviewPanel'; import './positron/mainThreadModalDialogs'; import './positron/mainThreadConsoleService'; +import './positron/mainThreadContextKeyService'; // --- End Positron --- export class ExtensionPoints implements IWorkbenchContribution { diff --git a/src/vs/workbench/api/browser/positron/mainThreadContextKeyService.ts b/src/vs/workbench/api/browser/positron/mainThreadContextKeyService.ts new file mode 100644 index 00000000000..c9d77b3670e --- /dev/null +++ b/src/vs/workbench/api/browser/positron/mainThreadContextKeyService.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. + *--------------------------------------------------------------------------------------------*/ + +import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; +import { MainPositronContext, MainThreadContextKeyServiceShape } from '../../common/positron/extHost.positron.protocol'; +import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { DisposableStore } from 'vs/base/common/lifecycle'; + +@extHostNamedCustomer(MainPositronContext.MainThreadContextKeyService) +export class MainThreadContextKeyService implements MainThreadContextKeyServiceShape { + + private readonly _disposables = new DisposableStore(); + + constructor( + extHostContext: IExtHostContext, + @IContextKeyService private readonly contextKeyService: IContextKeyService + ) { + } + + $evaluateWhenClause(whenClause: string): Promise { + const precondition = ContextKeyExpr.deserialize(whenClause); + if (precondition === undefined) { + throw new Error(`Cannot evaluate when clause '${whenClause}'`); + } + return Promise.resolve(this.contextKeyService.contextMatchesRules(precondition)); + } + + public dispose(): void { + this._disposables.dispose(); + } + +} diff --git a/src/vs/workbench/api/common/positron/extHost.positron.api.impl.ts b/src/vs/workbench/api/common/positron/extHost.positron.api.impl.ts index 9128ad2052a..c4410d13acf 100644 --- a/src/vs/workbench/api/common/positron/extHost.positron.api.impl.ts +++ b/src/vs/workbench/api/common/positron/extHost.positron.api.impl.ts @@ -17,6 +17,7 @@ import * as extHostTypes from 'vs/workbench/api/common/positron/extHostTypes.pos import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { ExtHostPreviewPanels } from 'vs/workbench/api/common/positron/extHostPreviewPanels'; import { ExtHostModalDialogs } from 'vs/workbench/api/common/positron/extHostModalDialogs'; +import { ExtHostContextKeyService } from 'vs/workbench/api/common/positron/extHostContextKeyService'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; @@ -63,8 +64,10 @@ export function createPositronApiFactoryAndRegisterActors(accessor: ServicesAcce const extHostLanguageRuntime = rpcProtocol.set(ExtHostPositronContext.ExtHostLanguageRuntime, new ExtHostLanguageRuntime(rpcProtocol, extHostLogService)); const extHostPreviewPanels = rpcProtocol.set(ExtHostPositronContext.ExtHostPreviewPanel, new ExtHostPreviewPanels(rpcProtocol, extHostWebviews, extHostWorkspace)); const extHostModalDialogs = rpcProtocol.set(ExtHostPositronContext.ExtHostModalDialogs, new ExtHostModalDialogs(rpcProtocol)); + const extHostContextKeyService = rpcProtocol.set(ExtHostPositronContext.ExtHostContextKeyService, new ExtHostContextKeyService(rpcProtocol)); const extHostConsoleService = rpcProtocol.set(ExtHostPositronContext.ExtHostConsoleService, new ExtHostConsoleService(rpcProtocol, extHostLogService)); - const extHostMethods = rpcProtocol.set(ExtHostPositronContext.ExtHostMethods, new ExtHostMethods(rpcProtocol, extHostEditors, extHostDocuments, extHostModalDialogs, extHostLanguageRuntime, extHostWorkspace)); + const extHostMethods = rpcProtocol.set(ExtHostPositronContext.ExtHostMethods, + new ExtHostMethods(rpcProtocol, extHostEditors, extHostDocuments, extHostModalDialogs, extHostLanguageRuntime, extHostWorkspace, extHostContextKeyService)); return function (extension: IExtensionDescription, extensionInfo: IExtensionRegistries, configProvider: ExtHostConfigProvider): typeof positron { diff --git a/src/vs/workbench/api/common/positron/extHost.positron.protocol.ts b/src/vs/workbench/api/common/positron/extHost.positron.protocol.ts index 5f7e760bfeb..eafea6fbc66 100644 --- a/src/vs/workbench/api/common/positron/extHost.positron.protocol.ts +++ b/src/vs/workbench/api/common/positron/extHost.positron.protocol.ts @@ -79,6 +79,14 @@ export interface MainThreadModalDialogsShape extends IDisposable { // The interface to the main thread exposed by the extension host export interface ExtHostModalDialogsShape { } +// Interface that the main process exposes to the extension host +export interface MainThreadContextKeyServiceShape { + $evaluateWhenClause(whenClause: string): Promise; +} + +// Interface to the main thread exposed by the extension host +export interface ExtHostContextKeyServiceShape { } + export interface MainThreadConsoleServiceShape { $getConsoleWidth(): Promise; $tryPasteText(id: string, text: string): void; @@ -168,6 +176,7 @@ export const ExtHostPositronContext = { ExtHostPreviewPanel: createProxyIdentifier('ExtHostPreviewPanel'), ExtHostModalDialogs: createProxyIdentifier('ExtHostModalDialogs'), ExtHostConsoleService: createProxyIdentifier('ExtHostConsoleService'), + ExtHostContextKeyService: createProxyIdentifier('ExtHostContextKeyService'), ExtHostMethods: createProxyIdentifier('ExtHostMethods'), }; @@ -176,5 +185,6 @@ export const MainPositronContext = { MainThreadPreviewPanel: createProxyIdentifier('MainThreadPreviewPanel'), MainThreadModalDialogs: createProxyIdentifier('MainThreadModalDialogs'), MainThreadConsoleService: createProxyIdentifier('MainThreadConsoleService'), + MainThreadContextKeyService: createProxyIdentifier('MainThreadContextKeyService'), MainThreadMethods: createProxyIdentifier('MainThreadMethods'), }; diff --git a/src/vs/workbench/api/common/positron/extHostContextKeyService.ts b/src/vs/workbench/api/common/positron/extHostContextKeyService.ts new file mode 100644 index 00000000000..61278749ca7 --- /dev/null +++ b/src/vs/workbench/api/common/positron/extHostContextKeyService.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as extHostProtocol from './extHost.positron.protocol'; + +export class ExtHostContextKeyService implements extHostProtocol.ExtHostContextKeyServiceShape { + + private readonly _proxy: extHostProtocol.MainThreadContextKeyServiceShape; + + constructor( + mainContext: extHostProtocol.IMainPositronContext, + ) { + // Trigger creation of the proxy + this._proxy = mainContext.getProxy(extHostProtocol.MainPositronContext.MainThreadContextKeyService); + } + + /** + * Queries the main thread with a `when` clause. + * + * @returns If the `when` clause evaluates to true or false. + */ + public evaluateWhenClause(whenClause: string): Promise { + return this._proxy.$evaluateWhenClause(whenClause); + } + +} + diff --git a/src/vs/workbench/api/common/positron/extHostMethods.ts b/src/vs/workbench/api/common/positron/extHostMethods.ts index 7237a298dbe..36b8adf92dc 100644 --- a/src/vs/workbench/api/common/positron/extHostMethods.ts +++ b/src/vs/workbench/api/common/positron/extHostMethods.ts @@ -8,6 +8,7 @@ import { ExtHostEditors } from '../extHostTextEditors'; import { ExtHostDocuments } from '../extHostDocuments'; import { ExtHostWorkspace } from '../extHostWorkspace'; import { ExtHostModalDialogs } from '../positron/extHostModalDialogs'; +import { ExtHostContextKeyService } from '../positron/extHostContextKeyService'; import { ExtHostLanguageRuntime } from '../positron/extHostLanguageRuntime'; import { UiFrontendRequest, EditorContext, Range as UIRange } from 'vs/workbench/services/languageRuntime/common/positronUiComm'; import { JsonRpcErrorCode } from 'vs/workbench/services/languageRuntime/common/positronBaseComm'; @@ -41,7 +42,8 @@ export class ExtHostMethods implements extHostProtocol.ExtHostMethodsShape { private readonly documents: ExtHostDocuments, private readonly dialogs: ExtHostModalDialogs, private readonly runtime: ExtHostLanguageRuntime, - private readonly workspace: ExtHostWorkspace + private readonly workspace: ExtHostWorkspace, + private readonly contextKeys: ExtHostContextKeyService ) { } @@ -137,6 +139,13 @@ export class ExtHostMethods implements extHostProtocol.ExtHostMethodsShape { params.allow_incomplete as boolean); break; } + case UiFrontendRequest.EvaluateWhenClause: { + if (!params || !Object.keys(params).includes('when_clause')) { + return newInvalidParamsError(method); + } + result = await this.evaluateWhenClause(params.when_clause as string); + break; + } case UiFrontendRequest.DebugSleep: { if (!params || !Object.keys(params).includes('ms')) { return newInvalidParamsError(method); @@ -270,6 +279,10 @@ export class ExtHostMethods implements extHostProtocol.ExtHostMethodsShape { return this.runtime.executeCode(languageId, code, focus, allowIncomplete); } + async evaluateWhenClause(whenClause: string): Promise { + return this.contextKeys.evaluateWhenClause(whenClause); + } + async debugSleep(ms: number): Promise { await delay(ms); return null; diff --git a/src/vs/workbench/services/languageRuntime/common/positronUiComm.ts b/src/vs/workbench/services/languageRuntime/common/positronUiComm.ts index 18a816a6def..5ab75d31225 100644 --- a/src/vs/workbench/services/languageRuntime/common/positronUiComm.ts +++ b/src/vs/workbench/services/languageRuntime/common/positronUiComm.ts @@ -387,6 +387,19 @@ export interface DebugSleepRequest { } +/** + * Request: Get a logical for a `when` clause (a set of context keys) + * + * Use this to evaluate a `when` clause of context keys in the frontend + */ +export interface EvaluateWhenClauseRequest { + /** + * The values for context keys, as a `when` clause + */ + when_clause: string; + +} + /** * Request: Execute code in a Positron runtime * @@ -470,6 +483,7 @@ export enum UiFrontendRequest { ShowQuestion = 'show_question', ShowDialog = 'show_dialog', DebugSleep = 'debug_sleep', + EvaluateWhenClause = 'evaluate_when_clause', ExecuteCode = 'execute_code', WorkspaceFolder = 'workspace_folder', ModifyEditorSelections = 'modify_editor_selections',