Path: blob/main/extensions/copilot/src/extension/linkify/common/linkifyService.ts
13399 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 { IEnvService } from '../../../platform/env/common/envService';6import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService';7import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';8import { createServiceIdentifier } from '../../../util/common/services';9import { CancellationToken } from '../../../util/vs/base/common/cancellation';10import { IDisposable } from '../../../util/vs/base/common/lifecycle';11import { PromptReference } from '../../prompt/common/conversation';12import { FilePathLinkifier } from './filePathLinkifier';13import { LinkifiedText } from './linkifiedText';14import { Linkifier } from './linkifier';15import { ModelFilePathLinkifier } from './modelFilePathLinkifier';16import { StatCache } from './statCache';1718/**19* A stateful linkifier.20*/21export interface ILinkifier {22/**23* The total number of links that have been added.24*25* This may not be up to date if there are any ongoing `append` or `flush` calls.26*/27readonly totalAddedLinkCount: number;2829/**30* Add new text to the linkifier.31*32* @returns The new text that has been linkified. This may include parts of text that was previously passed to `.append`.33* It also may be empty if we are still accumulating text for linkification.34*/35append(newText: string, token: CancellationToken): Promise<LinkifiedText>;3637/**38* Complete the current linkification. If there is any pending text, it will be linkified and returned.39*/40flush(token: CancellationToken): Promise<LinkifiedText | undefined>;41}4243export interface IContributedLinkifierFactory {44create(): IContributedLinkifier;45}4647export interface IContributedLinkifier {48linkify(49text: string,50context: LinkifierContext,51token: CancellationToken52): Promise<LinkifiedText | undefined>;53}5455export interface LinkifierContext {56readonly requestId: string | undefined;57readonly references: readonly PromptReference[];58}5960export const ILinkifyService = createServiceIdentifier<ILinkifyService>('ILinkifyService');6162export interface ILinkifyService {63readonly _serviceBrand: undefined;6465/**66* Register a new global linkifier that is run for all text.67*/68registerGlobalLinkifier(linkifier: IContributedLinkifierFactory): IDisposable;6970/**71* Create a new {@link ILinkifier stateful linkifier}.72*/73createLinkifier(74context: LinkifierContext,75additionalLinkifiers?: readonly IContributedLinkifierFactory[],76): ILinkifier;77}7879export class LinkifyService implements ILinkifyService {8081declare readonly _serviceBrand: undefined;8283private readonly globalLinkifiers = new Set<IContributedLinkifierFactory>();8485constructor(86@IFileSystemService private readonly fileSystem: IFileSystemService,87@IWorkspaceService private readonly workspaceService: IWorkspaceService,88@IEnvService private readonly envService: IEnvService,89) {90}9192registerGlobalLinkifier(linkifier: IContributedLinkifierFactory): IDisposable {93if (this.globalLinkifiers.has(linkifier)) {94throw new Error('Linkifier already registered');95}9697this.globalLinkifiers.add(linkifier);98return { dispose: () => this.globalLinkifiers.delete(linkifier) };99}100101createLinkifier(102context: LinkifierContext,103additionalLinkifiers?: readonly IContributedLinkifierFactory[],104): ILinkifier {105// Model and file path linkifiers share a stat cache per linkifier instance106// so that filesystem lookups are not duplicated across them.107const statCache = new StatCache(this.fileSystem);108const builtInLinkifiers: IContributedLinkifier[] = [109new ModelFilePathLinkifier(this.workspaceService, statCache),110new FilePathLinkifier(this.workspaceService, statCache),111];112const additional = (additionalLinkifiers || []).map(x => x.create());113const global = [...this.globalLinkifiers].map(x => x.create());114return new Linkifier(context, this.envService.uriScheme, [...additional, ...builtInLinkifiers, ...global]);115}116}117118119