turn language status API proposal into push model, https://github.com/microsoft/vscode/issues/129037

This commit is contained in:
Johannes Rieken 2021-07-21 12:51:02 +02:00
parent ee4740005e
commit e30d70f9f5
No known key found for this signature in database
GPG key ID: 96634B5AF12F8798
9 changed files with 106 additions and 105 deletions

View file

@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { 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';
@ -17,6 +16,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
export interface ILanguageStatus {
selector: LanguageSelector,
severity: Severity;
text: string;
message: string | IMarkdownString;
@ -34,41 +34,26 @@ export interface ILanguageStatusService {
onDidChange: Event<void>;
registerLanguageStatusProvider(selector: LanguageSelector, provider: ILanguageStatusProvider): IDisposable;
addStatus(status: ILanguageStatus): IDisposable;
getLanguageStatus(model: ITextModel): Promise<ILanguageStatus[]>;
}
class LanguageStatusServiceImpl implements ILanguageStatusService {
declare _serviceBrand: undefined;
private readonly _provider = new LanguageFeatureRegistry<ILanguageStatusProvider>();
private readonly _provider = new LanguageFeatureRegistry<ILanguageStatus>();
private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = Event.any(this._onDidChange.event, this._provider.onDidChange);
readonly onDidChange: Event<any> = this._provider.onDidChange;
dispose() {
this._onDidChange.dispose();
}
registerLanguageStatusProvider(selector: LanguageSelector, provider: ILanguageStatusProvider): IDisposable {
return this._provider.register(selector, provider);
addStatus(status: ILanguageStatus): IDisposable {
return this._provider.register(status.selector, status);
}
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);
return this._provider.ordered(model).sort((a, b) => b.severity - a.severity);
}
}

View file

@ -3166,19 +3166,16 @@ declare module 'vscode' {
Error = 2
}
class LanguageStatus {
interface LanguageStatusItem {
selector: DocumentSelector;
text: string;
detail: string | MarkdownString;
detail: string | MarkdownString
severity: LanguageStatusSeverity;
constructor(text: string);
}
export interface LanguageStatusProvider {
provideLanguageStatus(token: CancellationToken): ProviderResult<LanguageStatus>;
dispose(): void;
}
namespace languages {
export function registerLanguageStatusProvider(selector: DocumentSelector, provider: LanguageStatusProvider): Disposable;
export function createLanguageStatusItem(selector: DocumentSelector): LanguageStatusItem;
}
//#endregion

View file

@ -23,7 +23,6 @@ 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 {
@ -35,7 +34,6 @@ 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;
@ -159,16 +157,6 @@ 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 {

View file

@ -12,6 +12,8 @@ import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { StandardTokenType } from 'vs/editor/common/modes';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ILanguageStatus, ILanguageStatusService } from 'vs/editor/common/services/languageStatusService';
import { IDisposable } from 'vs/base/common/lifecycle';
@extHostNamedCustomer(MainContext.MainThreadLanguages)
export class MainThreadLanguages implements MainThreadLanguagesShape {
@ -21,8 +23,8 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService,
@ITextModelService private _resolverService: ITextModelService,
) {
}
@ILanguageStatusService private readonly _languageStatusService: ILanguageStatusService,
) { }
dispose(): void {
// nothing
@ -62,4 +64,17 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
range: new Range(position.lineNumber, 1 + tokens.getStartOffset(idx), position.lineNumber, 1 + tokens.getEndOffset(idx))
};
}
// --- language status
private readonly _status = new Map<number, IDisposable>();
$setLanguageStatus(handle: number, status: ILanguageStatus): void {
this._status.get(handle)?.dispose();
this._status.set(handle, this._languageStatusService.addStatus(status));
}
$removeLanguageStatus(handle: number): void {
this._status.get(handle)?.dispose();
}
}

View file

@ -507,9 +507,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerTypeHierarchyProvider(extension, selector, provider);
},
registerLanguageStatusProvider(selector: vscode.DocumentSelector, provider: vscode.LanguageStatusProvider): vscode.Disposable {
createLanguageStatusItem(selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerLanguageStatusProvider(extension, selector, provider);
return extHostLanguages.createLanguageStatusItem(selector);
}
};
@ -1284,7 +1284,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
BranchCoverage: extHostTypes.BranchCoverage,
FunctionCoverage: extHostTypes.FunctionCoverage,
WorkspaceTrustState: extHostTypes.WorkspaceTrustState,
LanguageStatus: extHostTypes.LanguageStatus,
LanguageStatusSeverity: extHostTypes.LanguageStatusSeverity,
};
};

View file

@ -383,7 +383,6 @@ 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;
@ -426,6 +425,8 @@ export interface MainThreadLanguagesShape extends IDisposable {
$getLanguages(): Promise<string[]>;
$changeLanguage(resource: UriComponents, languageId: string): Promise<void>;
$tokensAtPosition(resource: UriComponents, position: IPosition): Promise<undefined | { type: modes.StandardTokenType, range: IRange }>;
$setLanguageStatus(handle: number, status: ILanguageStatus): void;
$removeLanguageStatus(handle: number): void;
}
export interface MainThreadMessageOptions {
@ -1641,7 +1642,6 @@ 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>;

View file

@ -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, LanguageStatusSeverity } from 'vs/workbench/api/common/extHostTypes';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit } 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';
@ -33,37 +33,9 @@ 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;
@ -1520,7 +1492,7 @@ class TypeHierarchyAdapter {
return map?.get(itemId);
}
}
type Adapter = LanguageStatusAdapter | DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
@ -1652,18 +1624,6 @@ 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 {

View file

@ -7,7 +7,10 @@ import { MainContext, MainThreadLanguagesShape, IMainContext } from './extHost.p
import type * as vscode from 'vscode';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { StandardTokenType, Range, Position } from 'vs/workbench/api/common/extHostTypes';
import { StandardTokenType, Range, Position, LanguageStatusSeverity } from 'vs/workbench/api/common/extHostTypes';
import Severity from 'vs/base/common/severity';
import { disposableTimeout } from 'vs/base/common/async';
import { IDisposable } from 'vs/base/common/lifecycle';
export class ExtHostLanguages {
@ -61,4 +64,69 @@ export class ExtHostLanguages {
}
return result;
}
private _handlePool: number = 0;
createLanguageStatusItem(selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
const handle = this._handlePool++;
const proxy = this._proxy;
const data: { selector: any, text: string, detail: string | vscode.MarkdownString, severity: vscode.LanguageStatusSeverity } = {
selector,
text: '',
detail: '',
severity: LanguageStatusSeverity.Information,
};
let soonHandle: IDisposable | undefined;
const updateAsync = () => {
soonHandle?.dispose();
soonHandle = disposableTimeout(() => {
this._proxy.$setLanguageStatus(handle, {
selector: data.selector,
text: data.text,
message: typeof data.detail === 'string' ? data.detail : typeConvert.MarkdownString.from(data.detail),
severity: data.severity === LanguageStatusSeverity.Error ? Severity.Error : data.severity === LanguageStatusSeverity.Warning ? Severity.Warning : Severity.Info
});
}, 0);
};
const result: vscode.LanguageStatusItem = {
get selector() {
return data.selector;
},
set selector(value) {
data.selector = value;
updateAsync();
},
get text() {
return data.text;
},
set text(value) {
data.text = value;
updateAsync();
},
get detail() {
return data.detail;
},
set detail(value) {
data.detail = value;
updateAsync();
},
get severity() {
return data.severity;
},
set severity(value) {
data.severity = value;
updateAsync();
},
dispose() {
soonHandle?.dispose();
proxy.$removeLanguageStatus(handle);
}
};
updateAsync();
return result;
}
}

View file

@ -1286,18 +1286,7 @@ export enum LanguageStatusSeverity {
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 {