Path: blob/main/src/vs/workbench/contrib/output/browser/outputLinkProvider.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 { 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 { createWebWorker } from '../../../../base/browser/webWorkerFactory.js';15import { IWebWorkerClient } from '../../../../base/common/worker/webWorker.js';16import { WorkerTextModelSyncClient } from '../../../../editor/common/services/textModelSync/textModelSync.impl.js';17import { FileAccess } from '../../../../base/common/network.js';1819export class OutputLinkProvider extends Disposable {2021private static readonly DISPOSE_WORKER_TIME = 3 * 60 * 1000; // dispose worker after 3 minutes of inactivity2223private worker?: OutputLinkWorkerClient;24private disposeWorkerScheduler: RunOnceScheduler;25private linkProviderRegistration: IDisposable | undefined;2627constructor(28@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,29@IModelService private readonly modelService: IModelService,30@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,31) {32super();3334this.disposeWorkerScheduler = new RunOnceScheduler(() => this.disposeWorker(), OutputLinkProvider.DISPOSE_WORKER_TIME);3536this.registerListeners();37this.updateLinkProviderWorker();38}3940private registerListeners(): void {41this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.updateLinkProviderWorker()));42}4344private updateLinkProviderWorker(): void {4546// Setup link provider depending on folders being opened or not47const folders = this.contextService.getWorkspace().folders;48if (folders.length > 0) {49if (!this.linkProviderRegistration) {50this.linkProviderRegistration = this.languageFeaturesService.linkProvider.register([{ language: OUTPUT_MODE_ID, scheme: '*' }, { language: LOG_MODE_ID, scheme: '*' }], {51provideLinks: async model => {52const links = await this.provideLinks(model.uri);5354return links && { links };55}56});57}58} else {59dispose(this.linkProviderRegistration);60this.linkProviderRegistration = undefined;61}6263// Dispose worker to recreate with folders on next provideLinks request64this.disposeWorker();65this.disposeWorkerScheduler.cancel();66}6768private getOrCreateWorker(): OutputLinkWorkerClient {69this.disposeWorkerScheduler.schedule();7071if (!this.worker) {72this.worker = new OutputLinkWorkerClient(this.contextService, this.modelService);73}7475return this.worker;76}7778private async provideLinks(modelUri: URI): Promise<ILink[]> {79return this.getOrCreateWorker().provideLinks(modelUri);80}8182private disposeWorker(): void {83if (this.worker) {84this.worker.dispose();85this.worker = undefined;86}87}88}8990class OutputLinkWorkerClient extends Disposable {91private readonly _workerClient: IWebWorkerClient<OutputLinkComputer>;92private readonly _workerTextModelSyncClient: WorkerTextModelSyncClient;93private readonly _initializeBarrier: Promise<void>;9495constructor(96@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,97@IModelService modelService: IModelService,98) {99super();100this._workerClient = this._register(createWebWorker<OutputLinkComputer>(101FileAccess.asBrowserUri('vs/workbench/contrib/output/common/outputLinkComputerMain.js'),102'OutputLinkDetectionWorker'103));104this._workerTextModelSyncClient = this._register(WorkerTextModelSyncClient.create(this._workerClient, modelService));105this._initializeBarrier = this._ensureWorkspaceFolders();106}107108private async _ensureWorkspaceFolders(): Promise<void> {109await this._workerClient.proxy.$setWorkspaceFolders(this.contextService.getWorkspace().folders.map(folder => folder.uri.toString()));110}111112public async provideLinks(modelUri: URI): Promise<ILink[]> {113await this._initializeBarrier;114this._workerTextModelSyncClient.ensureSyncedResources([modelUri]);115return this._workerClient.proxy.$computeLinks(modelUri.toString());116}117}118119120