Skip to content

Commit

Permalink
eclipse-theia#10027 WIP Support EvaluatableExpressions
Browse files Browse the repository at this point in the history
- Implement support for plugins providing evalutable epressions

Awaiting uplift of monaco
- PR: theia-ide/vscode#1

Contributed on behalf of STMicroelectronics

Signed-off-by: Nina Doschek <[email protected]>

Fixes eclipse-theia#10027
  • Loading branch information
ndoschek committed Jun 30, 2022
1 parent 907d769 commit 01987a7
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,7 @@ export interface LanguagesExt {
): Promise<SignatureHelp | undefined>;
$releaseSignatureHelp(handle: number, id: number): void;
$provideHover(handle: number, resource: UriComponents, position: Position, token: CancellationToken): Promise<Hover | undefined>;
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: theia.Position, token?: theia.CancellationToken): Promise<theia.EvaluatableExpression | undefined>;
$provideDocumentHighlights(handle: number, resource: UriComponents, position: Position, token: CancellationToken): Promise<DocumentHighlight[] | undefined>;
$provideDocumentFormattingEdits(handle: number, resource: UriComponents,
options: FormattingOptions, token: CancellationToken): Promise<TextEdit[] | undefined>;
Expand Down Expand Up @@ -1538,6 +1539,7 @@ export interface LanguagesMain {
$registerReferenceProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void;
$registerSignatureHelpProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[], metadata: theia.SignatureHelpProviderMetadata): void;
$registerHoverProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void;
$registerEvaluatableExpressionProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void;
$registerDocumentHighlightProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void;
$registerQuickFixProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[], codeActionKinds?: string[], documentation?: CodeActionProviderDocumentation): void;
$clearDiagnostics(id: string): void;
Expand Down
20 changes: 19 additions & 1 deletion packages/plugin-ext/src/main/browser/languages-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,25 @@ export class LanguagesMainImpl implements LanguagesMain, Disposable {
return this.proxy.$provideHover(handle, model.uri, position, token);
}

$registerDocumentHighlightProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void {
$registerEvaluatableExpressionProvider(handle: number, pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void {
// const languageSelector = this.toLanguageSelector(selector);
// const evaluatableExpressionProvider = this.createEvaluatableExpressionProvider(handle);
// this.register(handle, (monaco.languages.registerEvaluatableExpressionProvider as RegistrationFunction<monaco.languages.EvaluatableExpressionProvider>)
// (languageSelector, evaluatableExpressionProvider));
}

// protected createEvaluatableExpressionProvider(handle: number): theia.EvaluatableExpressionProvider {
// return {
// provideEvaluatableExpression: (model, position, token) => this.provideEvaluatableExpression(handle, model, position, token)
// };
// }

// protected provideEvaluatableExpression(handle: number, model: theia.TextDocument, position: theia.Position,
// token?: theia.CancellationToken): monaco.languages.ProviderResult<monaco.languages.EvaluatableExpression | undefined> {
// return this.proxy.$provideEvaluatableExpression(handle, model.uri, position, token);
// }

$registerDocumentHighlightProvider(handle: number, _pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void {
const languageSelector = this.toLanguageSelector(selector);
const documentHighlightProvider = this.createDocumentHighlightProvider(handle);
this.register(handle, (monaco.languages.registerDocumentHighlightProvider as RegistrationFunction<monaco.languages.DocumentHighlightProvider>)
Expand Down
17 changes: 16 additions & 1 deletion packages/plugin-ext/src/plugin/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ import {
CallHierarchyItem,
CallHierarchyIncomingCall,
CallHierarchyOutgoingCall,
LinkedEditingRanges,
LinkedEditingRanges
} from '../common/plugin-api-rpc-model';
import { CompletionAdapter } from './languages/completion';
import { Diagnostics } from './languages/diagnostics';
import { SignatureHelpAdapter } from './languages/signature';
import { HoverAdapter } from './languages/hover';
import { EvaluatableExpressionAdapter } from './languages/evaluatable-expression';
import { DocumentHighlightAdapter } from './languages/document-highlight';
import { DocumentFormattingAdapter } from './languages/document-formatting';
import { RangeFormattingAdapter } from './languages/range-formatting';
Expand Down Expand Up @@ -100,6 +101,7 @@ import { serializeEnterRules, serializeIndentation, serializeRegExp } from './la
type Adapter = CompletionAdapter |
SignatureHelpAdapter |
HoverAdapter |
EvaluatableExpressionAdapter |
DocumentHighlightAdapter |
DocumentFormattingAdapter |
RangeFormattingAdapter |
Expand Down Expand Up @@ -350,6 +352,19 @@ export class LanguagesExtImpl implements LanguagesExt {
}
// ### Hover Provider end

// ### EvaluatableExpression Provider begin
registerEvaluatableExpressionProvider(selector: theia.DocumentSelector, provider: theia.EvaluatableExpressionProvider, pluginInfo: PluginInfo): theia.Disposable {
const callId = this.addNewAdapter(new EvaluatableExpressionAdapter(provider, this.documents));
this.proxy.$registerEvaluatableExpressionProvider(callId, pluginInfo, this.transformDocumentSelector(selector));
return this.createDisposable(callId);
}

$provideEvaluatableExpression(handle: number, resource: UriComponents, position: theia.Position,
token?: theia.CancellationToken): Promise<theia.EvaluatableExpression | undefined> {
return this.withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined);
}
// ### EvaluatableExpression Provider end

// ### Document Highlight Provider begin
registerDocumentHighlightProvider(selector: theia.DocumentSelector, provider: theia.DocumentHighlightProvider, pluginInfo: PluginInfo): theia.Disposable {
const callId = this.addNewAdapter(new DocumentHighlightAdapter(provider, this.documents));
Expand Down
41 changes: 41 additions & 0 deletions packages/plugin-ext/src/plugin/languages/evaluatable-expression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// *****************************************************************************
// Copyright (C) 2022 STMicroelectronics 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 WITH Classpath-exception-2.0
// *****************************************************************************

import { URI } from '@theia/core/shared/vscode-uri';
import * as theia from '@theia/plugin';
import { DocumentsExtImpl } from '../documents';

export class EvaluatableExpressionAdapter {

constructor(
private readonly provider: theia.EvaluatableExpressionProvider,
private readonly documents: DocumentsExtImpl
) { }

async provideEvaluatableExpression(resource: URI, position: theia.Position, token?: theia.CancellationToken): Promise<theia.EvaluatableExpression | undefined> {
const document = this.documents.getDocument(resource);
if (!document) {
return Promise.reject(new Error(`There are no documents for ${resource}`));
}

return Promise.resolve(this.provider.provideEvaluatableExpression(document, position, token)).then(expression => {
if (!expression) {
return undefined;
}
return expression;
});
}
}
5 changes: 5 additions & 0 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import {
SignatureHelp,
SignatureHelpTriggerKind,
Hover,
EvaluatableExpression,
DocumentHighlightKind,
DocumentHighlight,
DocumentLink,
Expand Down Expand Up @@ -724,6 +725,9 @@ export function createAPIFactory(
registerHoverProvider(selector: theia.DocumentSelector, provider: theia.HoverProvider): theia.Disposable {
return languagesExt.registerHoverProvider(selector, provider, pluginToPluginInfo(plugin));
},
registerEvaluatableExpressionProvider(selector: theia.DocumentSelector, provider: theia.EvaluatableExpressionProvider): theia.Disposable {
return languagesExt.registerEvaluatableExpressionProvider(selector, provider, pluginToPluginInfo(plugin));
},
registerDocumentHighlightProvider(selector: theia.DocumentSelector, provider: theia.DocumentHighlightProvider): theia.Disposable {
return languagesExt.registerDocumentHighlightProvider(selector, provider, pluginToPluginInfo(plugin));
},
Expand Down Expand Up @@ -981,6 +985,7 @@ export function createAPIFactory(
SignatureHelp,
SignatureHelpTriggerKind,
Hover,
EvaluatableExpression,
DocumentHighlightKind,
DocumentHighlight,
DocumentLink,
Expand Down
18 changes: 18 additions & 0 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,24 @@ export class Hover {
}
}

@es5ClassCompat
export class EvaluatableExpression {

public range: theia.Range;
public expression?: string;

constructor(
range: theia.Range,
expression?: string
) {
if (!range) {
illegalArgument('range must be defined');
}
this.range = range;
this.expression = expression;
}
}

export enum DocumentHighlightKind {
Text = 0,
Read = 1,
Expand Down
60 changes: 60 additions & 0 deletions packages/plugin/src/theia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9209,6 +9209,18 @@ export module '@theia/plugin' {
*/
export function registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Disposable;

/**
* Register a provider that locates evaluatable expressions in text documents.
* The editor will evaluate the expression in the active debug session and will show the result in the debug hover.
*
* If multiple providers are registered for a language an arbitrary provider will be used.
*
* @param selector A selector that defines the documents this provider is applicable to.
* @param provider An evaluatable expression provider.
* @return A {@link Disposable} that unregisters this provider when being disposed.
*/
export function registerEvaluatableExpressionProvider(selector: DocumentSelector, provider: EvaluatableExpressionProvider): Disposable;

/**
* Register a workspace symbol provider.
*
Expand Down Expand Up @@ -9522,6 +9534,54 @@ export module '@theia/plugin' {
provideHover(document: TextDocument, position: Position, token: CancellationToken | undefined): ProviderResult<Hover>;
}

/**
* An EvaluatableExpression represents an expression in a document that can be evaluated by an active debugger or runtime.
* The result of this evaluation is shown in a tooltip-like widget.
* If only a range is specified, the expression will be extracted from the underlying document.
* An optional expression can be used to override the extracted expression.
* In this case the range is still used to highlight the range in the document.
*/
export class EvaluatableExpression {

/*
* The range is used to extract the evaluatable expression from the underlying document and to highlight it.
*/
readonly range: Range;

/*
* If specified the expression overrides the extracted expression.
*/
readonly expression?: string | undefined;

/**
* Creates a new evaluatable expression object.
*
* @param range The range in the underlying document from which the evaluatable expression is extracted.
* @param expression If specified overrides the extracted expression.
*/
constructor(range: Range, expression?: string);
}

/**
* The evaluatable expression provider interface defines the contract between extensions and
* the debug hover. In this contract the provider returns an evaluatable expression for a given position
* in a document and the editor evaluates this expression in the active debug session and shows the result in a debug hover.
*/
export interface EvaluatableExpressionProvider {
/**
* Provide an evaluatable expression for the given document and position.
* The editor will evaluate this expression in the active debug session and will show the result in the debug hover.
* The expression can be implicitly specified by the range in the underlying document or by explicitly returning an expression.
*
* @param document The document for which the debug hover is about to appear.
* @param position The line and character position in the document where the debug hover is about to appear.
* @param token A cancellation token.
* @return An EvaluatableExpression or a thenable that resolves to such. The lack of a result can be
* signaled by returning `undefined` or `null`.
*/
provideEvaluatableExpression(document: TextDocument, position: Position, token: CancellationToken | undefined): ProviderResult<EvaluatableExpression>;
}

/**
* A document highlight kind.
*/
Expand Down

0 comments on commit 01987a7

Please sign in to comment.