Skip to content

Commit

Permalink
first cut for language status API proposal, #129037
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Jul 21, 2021
1 parent 5fb3fbf commit 4508c29
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 5 deletions.
75 changes: 75 additions & 0 deletions src/vs/editor/common/services/languageStatusService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { CancellationToken } from 'vs/base/common/cancellation';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { ITextModel } from 'vs/editor/common/model';
import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry';
import { LanguageSelector } from 'vs/editor/common/modes/languageSelector';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';


export interface ILanguageStatus {
severity: Severity;
text: string;
message: string | IMarkdownString;
}

export interface ILanguageStatusProvider {
provideLanguageStatus(langId: string, token: CancellationToken): Promise<ILanguageStatus | undefined>
}

export const ILanguageStatusService = createDecorator<ILanguageStatusService>('ILanguageStatusService');

export interface ILanguageStatusService {

_serviceBrand: undefined;

onDidChange: Event<void>;

registerLanguageStatusProvider(selector: LanguageSelector, provider: ILanguageStatusProvider): IDisposable;

getLanguageStatus(model: ITextModel): Promise<ILanguageStatus[]>;
}


class LanguageStatusServiceImpl implements ILanguageStatusService {
declare _serviceBrand: undefined;

private readonly _provider = new LanguageFeatureRegistry<ILanguageStatusProvider>();

private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = Event.any(this._onDidChange.event, this._provider.onDidChange);

dispose() {
this._onDidChange.dispose();
}

registerLanguageStatusProvider(selector: LanguageSelector, provider: ILanguageStatusProvider): IDisposable {
return this._provider.register(selector, provider);
}

async getLanguageStatus(model: ITextModel): Promise<ILanguageStatus[]> {
const all: ILanguageStatus[] = [];
for (const provider of this._provider.ordered(model)) {
try {
const status = await provider.provideLanguageStatus(model.getLanguageIdentifier().language, CancellationToken.None);
if (status) {
all.push(status);
}
} catch (err) {
onUnexpectedExternalError(err);
}
}
return all.sort((a, b) => b.severity - a.severity);
}
}

registerSingleton(ILanguageStatusService, LanguageStatusServiceImpl, true);
24 changes: 24 additions & 0 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3158,4 +3158,28 @@ declare module 'vscode' {
}
//#endregion

//#region https://github.com/microsoft/vscode/issues/129037

enum LanguageStatusSeverity {
Information = 0,
Warning = 1,
Error = 2
}

class LanguageStatus {
text: string;
detail: string | MarkdownString;
severity: LanguageStatusSeverity;
constructor(text: string);
}

export interface LanguageStatusProvider {
provideLanguageStatus(token: CancellationToken): ProviderResult<LanguageStatus>;
}

namespace languages {
export function registerLanguageStatusProvider(selector: DocumentSelector, provider: LanguageStatusProvider): Disposable;
}

//#endregion
}
12 changes: 12 additions & 0 deletions src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
import { mixin } from 'vs/base/common/objects';
import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
import { ILanguageStatus, ILanguageStatusService } from 'vs/editor/common/services/languageStatusService';

@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
Expand All @@ -34,6 +35,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
constructor(
extHostContext: IExtHostContext,
@IModeService modeService: IModeService,
@ILanguageStatusService private readonly _languageStatusService: ILanguageStatusService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures);
this._modeService = modeService;
Expand Down Expand Up @@ -157,6 +159,16 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha

//#endregion

// --- language status

$registerLanguageStatusProvider(handle: number, selector: IDocumentFilterDto[]): void {
this._registrations.set(handle, this._languageStatusService.registerLanguageStatusProvider(selector, {
provideLanguageStatus: (_langId: string, token: CancellationToken): Promise<ILanguageStatus | undefined> => {
return this._proxy.$provideLanguageStatus(handle, token);
}
}));
}

// --- outline

$registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], displayName: string): void {
Expand Down
8 changes: 7 additions & 1 deletion src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerTypeHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.TypeHierarchyProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerTypeHierarchyProvider(extension, selector, provider);
},
registerLanguageStatusProvider(selector: vscode.DocumentSelector, provider: vscode.LanguageStatusProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerLanguageStatusProvider(extension, selector, provider);
}
};

Expand Down Expand Up @@ -1279,7 +1283,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
StatementCoverage: extHostTypes.StatementCoverage,
BranchCoverage: extHostTypes.BranchCoverage,
FunctionCoverage: extHostTypes.FunctionCoverage,
WorkspaceTrustState: extHostTypes.WorkspaceTrustState
WorkspaceTrustState: extHostTypes.WorkspaceTrustState,
LanguageStatus: extHostTypes.LanguageStatus,
LanguageStatusSeverity: extHostTypes.LanguageStatusSeverity,
};
};
}
3 changes: 3 additions & 0 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { createExtHostContextProxyIdentifier as createExtId, createMainContextPr
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
import * as search from 'vs/workbench/services/search/common/search';
import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar';
import { ILanguageStatus } from 'vs/editor/common/services/languageStatusService';

export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
Expand Down Expand Up @@ -382,6 +383,7 @@ export interface IdentifiableInlineCompletion extends modes.InlineCompletion {

export interface MainThreadLanguageFeaturesShape extends IDisposable {
$unregister(handle: number): void;
$registerLanguageStatusProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], label: string): void;
$registerCodeLensSupport(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
$emitCodeLensEvent(eventHandle: number, event?: any): void;
Expand Down Expand Up @@ -1639,6 +1641,7 @@ export interface IInlineValueContextDto {
export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;

export interface ExtHostLanguageFeaturesShape {
$provideLanguageStatus(handle: number, token: CancellationToken): Promise<ILanguageStatus | undefined>;
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
$resolveCodeLens(handle: number, symbol: ICodeLensDto, token: CancellationToken): Promise<ICodeLensDto | undefined>;
Expand Down
44 changes: 42 additions & 2 deletions src/vs/workbench/api/common/extHostLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { mixin } from 'vs/base/common/objects';
import type * as vscode from 'vscode';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit } from 'vs/workbench/api/common/extHostTypes';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, LanguageStatusSeverity } from 'vs/workbench/api/common/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
Expand All @@ -33,9 +33,37 @@ import { Cache } from './cache';
import { StopWatch } from 'vs/base/common/stopwatch';
import { CancellationError } from 'vs/base/common/errors';
import { Emitter } from 'vs/base/common/event';
import { ILanguageStatus } from 'vs/editor/common/services/languageStatusService';
import Severity from 'vs/base/common/severity';

// --- adapter

class LanguageStatusAdapter {

constructor(private readonly _provider: vscode.LanguageStatusProvider) { }

async provideLanguageStatus(token: CancellationToken): Promise<ILanguageStatus | undefined> {

const value = await this._provider.provideLanguageStatus(token);
if (!value) {
return;
}

let severity = Severity.Info;
if (value.severity === LanguageStatusSeverity.Error) {
severity = Severity.Error;
} else if (value.severity === LanguageStatusSeverity.Warning) {
severity = Severity.Warning;
}

return {
text: value.text,
message: typeConvert.MarkdownString.from(value.detail),
severity
};
}
}

class DocumentSymbolAdapter {

private _documents: ExtHostDocuments;
Expand Down Expand Up @@ -1492,7 +1520,7 @@ class TypeHierarchyAdapter {
return map?.get(itemId);
}
}
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
type Adapter = LanguageStatusAdapter | DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
Expand Down Expand Up @@ -1624,6 +1652,18 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return ext.displayName || ext.name;
}

// --- language status

registerLanguageStatusProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.LanguageStatusProvider): vscode.Disposable {
const handle = this._addNewAdapter(new LanguageStatusAdapter(provider), extension);
this._proxy.$registerLanguageStatusProvider(handle, this._transformDocumentSelector(selector));
return this._createDisposable(handle);
}

$provideLanguageStatus(handle: number, token: CancellationToken): Promise<ILanguageStatus | undefined> {
return this._withAdapter(handle, LanguageStatusAdapter, adapter => adapter.provideLanguageStatus(token), undefined);
}

// --- outline

registerDocumentSymbolProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider, metadata?: vscode.DocumentSymbolProviderMetadata): vscode.Disposable {
Expand Down
18 changes: 18 additions & 0 deletions src/vs/workbench/api/common/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,24 @@ export class CallHierarchyOutgoingCall {
}
}

export enum LanguageStatusSeverity {
Information = 0,
Warning = 1,
Error = 2
}

export class LanguageStatus {

text: string;
detail: string | MarkdownString;
severity: LanguageStatusSeverity;

constructor(text: string) {
this.text = text;
this.detail = '';
this.severity = LanguageStatusSeverity.Information;
}
}
@es5ClassCompat
export class CodeLens {

Expand Down
Loading

0 comments on commit 4508c29

Please sign in to comment.