Path: blob/main/src/vs/workbench/api/common/extHostLanguages.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { MainContext, MainThreadLanguagesShape, IMainContext, ExtHostLanguagesShape } from './extHost.protocol.js';6import type * as vscode from 'vscode';7import { ExtHostDocuments } from './extHostDocuments.js';8import * as typeConvert from './extHostTypeConverters.js';9import { StandardTokenType, Range, Position, LanguageStatusSeverity } from './extHostTypes.js';10import Severity from '../../../base/common/severity.js';11import { disposableTimeout } from '../../../base/common/async.js';12import { DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';13import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';14import { CommandsConverter } from './extHostCommands.js';15import { IURITransformer } from '../../../base/common/uriIpc.js';16import { checkProposedApiEnabled } from '../../services/extensions/common/extensions.js';1718export class ExtHostLanguages implements ExtHostLanguagesShape {1920private readonly _proxy: MainThreadLanguagesShape;2122private _languageIds: string[] = [];2324constructor(25mainContext: IMainContext,26private readonly _documents: ExtHostDocuments,27private readonly _commands: CommandsConverter,28private readonly _uriTransformer: IURITransformer | undefined29) {30this._proxy = mainContext.getProxy(MainContext.MainThreadLanguages);31}3233$acceptLanguageIds(ids: string[]): void {34this._languageIds = ids;35}3637async getLanguages(): Promise<string[]> {38return this._languageIds.slice(0);39}4041async changeLanguage(uri: vscode.Uri, languageId: string): Promise<vscode.TextDocument> {42await this._proxy.$changeLanguage(uri, languageId);43const data = this._documents.getDocumentData(uri);44if (!data) {45throw new Error(`document '${uri.toString()}' NOT found`);46}47return data.document;48}4950async tokenAtPosition(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.TokenInformation> {51const versionNow = document.version;52const pos = typeConvert.Position.from(position);53const info = await this._proxy.$tokensAtPosition(document.uri, pos);54const defaultRange = {55type: StandardTokenType.Other,56range: document.getWordRangeAtPosition(position) ?? new Range(position.line, position.character, position.line, position.character)57};58if (!info) {59// no result60return defaultRange;61}62const result = {63range: typeConvert.Range.to(info.range),64type: typeConvert.TokenType.to(info.type)65};66if (!result.range.contains(<Position>position)) {67// bogous result68return defaultRange;69}70if (versionNow !== document.version) {71// concurrent change72return defaultRange;73}74return result;75}7677private _handlePool: number = 0;78private _ids = new Set<string>();7980createLanguageStatusItem(extension: IExtensionDescription, id: string, selector: vscode.DocumentSelector): vscode.LanguageStatusItem {8182const handle = this._handlePool++;83const proxy = this._proxy;84const ids = this._ids;8586// enforce extension unique identifier87const fullyQualifiedId = `${extension.identifier.value}/${id}`;88if (ids.has(fullyQualifiedId)) {89throw new Error(`LanguageStatusItem with id '${id}' ALREADY exists`);90}91ids.add(fullyQualifiedId);9293const data: Omit<vscode.LanguageStatusItem, 'dispose' | 'text2'> = {94selector,95id,96name: extension.displayName ?? extension.name,97severity: LanguageStatusSeverity.Information,98command: undefined,99text: '',100detail: '',101busy: false102};103104105let soonHandle: IDisposable | undefined;106const commandDisposables = new DisposableStore();107const updateAsync = () => {108soonHandle?.dispose();109110if (!ids.has(fullyQualifiedId)) {111console.warn(`LanguageStatusItem (${id}) from ${extension.identifier.value} has been disposed and CANNOT be updated anymore`);112return; // disposed in the meantime113}114115soonHandle = disposableTimeout(() => {116commandDisposables.clear();117this._proxy.$setLanguageStatus(handle, {118id: fullyQualifiedId,119name: data.name ?? extension.displayName ?? extension.name,120source: extension.displayName ?? extension.name,121selector: typeConvert.DocumentSelector.from(data.selector, this._uriTransformer),122label: data.text,123detail: data.detail ?? '',124severity: data.severity === LanguageStatusSeverity.Error ? Severity.Error : data.severity === LanguageStatusSeverity.Warning ? Severity.Warning : Severity.Info,125command: data.command && this._commands.toInternal(data.command, commandDisposables),126accessibilityInfo: data.accessibilityInformation,127busy: data.busy128});129}, 0);130};131132const result: vscode.LanguageStatusItem = {133dispose() {134commandDisposables.dispose();135soonHandle?.dispose();136proxy.$removeLanguageStatus(handle);137ids.delete(fullyQualifiedId);138},139get id() {140return data.id;141},142get name() {143return data.name;144},145set name(value) {146data.name = value;147updateAsync();148},149get selector() {150return data.selector;151},152set selector(value) {153data.selector = value;154updateAsync();155},156get text() {157return data.text;158},159set text(value) {160data.text = value;161updateAsync();162},163set text2(value) {164checkProposedApiEnabled(extension, 'languageStatusText');165data.text = value;166updateAsync();167},168get text2() {169checkProposedApiEnabled(extension, 'languageStatusText');170return data.text;171},172get detail() {173return data.detail;174},175set detail(value) {176data.detail = value;177updateAsync();178},179get severity() {180return data.severity;181},182set severity(value) {183data.severity = value;184updateAsync();185},186get accessibilityInformation() {187return data.accessibilityInformation;188},189set accessibilityInformation(value) {190data.accessibilityInformation = value;191updateAsync();192},193get command() {194return data.command;195},196set command(value) {197data.command = value;198updateAsync();199},200get busy() {201return data.busy;202},203set busy(value: boolean) {204data.busy = value;205updateAsync();206}207};208updateAsync();209return result;210}211}212213214