Path: blob/main/src/vs/workbench/contrib/output/browser/outputLinkProvider.ts
5263 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 { URI } from '../../../../base/common/uri.js';6import { RunOnceScheduler } from '../../../../base/common/async.js';7import { IModelService } from '../../../../editor/common/services/model.js';8import { ILink } from '../../../../editor/common/languages.js';9import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';10import { OUTPUT_MODE_ID, LOG_MODE_ID } from '../../../services/output/common/output.js';11import { OutputLinkComputer } from '../common/outputLinkComputer.js';12import { IDisposable, dispose, Disposable } from '../../../../base/common/lifecycle.js';13import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';14import { WebWorkerDescriptor } from '../../../../platform/webWorker/browser/webWorkerDescriptor.js';15import { IWebWorkerService } from '../../../../platform/webWorker/browser/webWorkerService.js';16import { IWebWorkerClient } from '../../../../base/common/worker/webWorker.js';17import { WorkerTextModelSyncClient } from '../../../../editor/common/services/textModelSync/textModelSync.impl.js';18import { FileAccess } from '../../../../base/common/network.js';1920export class OutputLinkProvider extends Disposable {2122private static readonly DISPOSE_WORKER_TIME = 3 * 60 * 1000; // dispose worker after 3 minutes of inactivity2324private worker?: OutputLinkWorkerClient;25private disposeWorkerScheduler: RunOnceScheduler;26private linkProviderRegistration: IDisposable | undefined;2728constructor(29@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,30@IModelService private readonly modelService: IModelService,31@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,32@IWebWorkerService private readonly webWorkerService: IWebWorkerService,33) {34super();3536this.disposeWorkerScheduler = this._register(new RunOnceScheduler(() => this.disposeWorker(), OutputLinkProvider.DISPOSE_WORKER_TIME));3738this.registerListeners();39this.updateLinkProviderWorker();40}4142private registerListeners(): void {43this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.updateLinkProviderWorker()));44}4546private updateLinkProviderWorker(): void {4748// Setup link provider depending on folders being opened or not49const folders = this.contextService.getWorkspace().folders;50if (folders.length > 0) {51if (!this.linkProviderRegistration) {52this.linkProviderRegistration = this.languageFeaturesService.linkProvider.register([{ language: OUTPUT_MODE_ID, scheme: '*' }, { language: LOG_MODE_ID, scheme: '*' }], {53provideLinks: async model => {54const links = await this.provideLinks(model.uri);5556return links && { links };57}58});59}60} else {61dispose(this.linkProviderRegistration);62this.linkProviderRegistration = undefined;63}6465// Dispose worker to recreate with folders on next provideLinks request66this.disposeWorker();67this.disposeWorkerScheduler.cancel();68}6970private getOrCreateWorker(): OutputLinkWorkerClient {71this.disposeWorkerScheduler.schedule();7273if (!this.worker) {74this.worker = new OutputLinkWorkerClient(this.contextService, this.modelService, this.webWorkerService);75}7677return this.worker;78}7980private async provideLinks(modelUri: URI): Promise<ILink[]> {81return this.getOrCreateWorker().provideLinks(modelUri);82}8384private disposeWorker(): void {85if (this.worker) {86this.worker.dispose();87this.worker = undefined;88}89}90}9192class OutputLinkWorkerClient extends Disposable {93private readonly _workerClient: IWebWorkerClient<OutputLinkComputer>;94private readonly _workerTextModelSyncClient: WorkerTextModelSyncClient;95private readonly _initializeBarrier: Promise<void>;9697constructor(98@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,99@IModelService modelService: IModelService,100@IWebWorkerService webWorkerService: IWebWorkerService,101) {102super();103this._workerClient = this._register(webWorkerService.createWorkerClient<OutputLinkComputer>(104new WebWorkerDescriptor({105esmModuleLocation: FileAccess.asBrowserUri('vs/workbench/contrib/output/common/outputLinkComputerMain.js'),106label: 'OutputLinkDetectionWorker'107})108));109this._workerTextModelSyncClient = this._register(WorkerTextModelSyncClient.create(this._workerClient, modelService));110this._initializeBarrier = this._ensureWorkspaceFolders();111}112113private async _ensureWorkspaceFolders(): Promise<void> {114await this._workerClient.proxy.$setWorkspaceFolders(this.contextService.getWorkspace().folders.map(folder => folder.uri.toString()));115}116117public async provideLinks(modelUri: URI): Promise<ILink[]> {118await this._initializeBarrier;119this._workerTextModelSyncClient.ensureSyncedResources([modelUri]);120return this._workerClient.proxy.$computeLinks(modelUri.toString());121}122}123124125