Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/linkify/common/linkifyService.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IEnvService } from '../../../platform/env/common/envService';
7
import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService';
8
import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';
9
import { createServiceIdentifier } from '../../../util/common/services';
10
import { CancellationToken } from '../../../util/vs/base/common/cancellation';
11
import { IDisposable } from '../../../util/vs/base/common/lifecycle';
12
import { PromptReference } from '../../prompt/common/conversation';
13
import { FilePathLinkifier } from './filePathLinkifier';
14
import { LinkifiedText } from './linkifiedText';
15
import { Linkifier } from './linkifier';
16
import { ModelFilePathLinkifier } from './modelFilePathLinkifier';
17
import { StatCache } from './statCache';
18
19
/**
20
* A stateful linkifier.
21
*/
22
export interface ILinkifier {
23
/**
24
* The total number of links that have been added.
25
*
26
* This may not be up to date if there are any ongoing `append` or `flush` calls.
27
*/
28
readonly totalAddedLinkCount: number;
29
30
/**
31
* Add new text to the linkifier.
32
*
33
* @returns The new text that has been linkified. This may include parts of text that was previously passed to `.append`.
34
* It also may be empty if we are still accumulating text for linkification.
35
*/
36
append(newText: string, token: CancellationToken): Promise<LinkifiedText>;
37
38
/**
39
* Complete the current linkification. If there is any pending text, it will be linkified and returned.
40
*/
41
flush(token: CancellationToken): Promise<LinkifiedText | undefined>;
42
}
43
44
export interface IContributedLinkifierFactory {
45
create(): IContributedLinkifier;
46
}
47
48
export interface IContributedLinkifier {
49
linkify(
50
text: string,
51
context: LinkifierContext,
52
token: CancellationToken
53
): Promise<LinkifiedText | undefined>;
54
}
55
56
export interface LinkifierContext {
57
readonly requestId: string | undefined;
58
readonly references: readonly PromptReference[];
59
}
60
61
export const ILinkifyService = createServiceIdentifier<ILinkifyService>('ILinkifyService');
62
63
export interface ILinkifyService {
64
readonly _serviceBrand: undefined;
65
66
/**
67
* Register a new global linkifier that is run for all text.
68
*/
69
registerGlobalLinkifier(linkifier: IContributedLinkifierFactory): IDisposable;
70
71
/**
72
* Create a new {@link ILinkifier stateful linkifier}.
73
*/
74
createLinkifier(
75
context: LinkifierContext,
76
additionalLinkifiers?: readonly IContributedLinkifierFactory[],
77
): ILinkifier;
78
}
79
80
export class LinkifyService implements ILinkifyService {
81
82
declare readonly _serviceBrand: undefined;
83
84
private readonly globalLinkifiers = new Set<IContributedLinkifierFactory>();
85
86
constructor(
87
@IFileSystemService private readonly fileSystem: IFileSystemService,
88
@IWorkspaceService private readonly workspaceService: IWorkspaceService,
89
@IEnvService private readonly envService: IEnvService,
90
) {
91
}
92
93
registerGlobalLinkifier(linkifier: IContributedLinkifierFactory): IDisposable {
94
if (this.globalLinkifiers.has(linkifier)) {
95
throw new Error('Linkifier already registered');
96
}
97
98
this.globalLinkifiers.add(linkifier);
99
return { dispose: () => this.globalLinkifiers.delete(linkifier) };
100
}
101
102
createLinkifier(
103
context: LinkifierContext,
104
additionalLinkifiers?: readonly IContributedLinkifierFactory[],
105
): ILinkifier {
106
// Model and file path linkifiers share a stat cache per linkifier instance
107
// so that filesystem lookups are not duplicated across them.
108
const statCache = new StatCache(this.fileSystem);
109
const builtInLinkifiers: IContributedLinkifier[] = [
110
new ModelFilePathLinkifier(this.workspaceService, statCache),
111
new FilePathLinkifier(this.workspaceService, statCache),
112
];
113
const additional = (additionalLinkifiers || []).map(x => x.create());
114
const global = [...this.globalLinkifiers].map(x => x.create());
115
return new Linkifier(context, this.envService.uriScheme, [...additional, ...builtInLinkifiers, ...global]);
116
}
117
}
118
119