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 { CancellationToken } from '../../../../base/common/cancellation.js';
7
>
import { Iterable } from '../../../../base/common/iterator.js';
8
>
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
9
>
import { LinkedList } from '../../../../base/common/linkedList.js';
10
>
import { isWeb } from '../../../../base/common/platform.js';
11
>
import { URI } from '../../../../base/common/uri.js';
12
>
import * as languages from '../../../../editor/common/languages.js';
13
>
import * as nls from '../../../../nls.js';
14
>
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
15
>
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
16
>
import { ILogService } from '../../../../platform/log/common/log.js';
17
>
import { IExternalOpener, IOpenerService } from '../../../../platform/opener/common/opener.js';
18
>
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js';
19
>
import { defaultExternalUriOpenerId, ExternalUriOpenersConfiguration, externalUriOpenersSettingId } from './configuration.js';
20
>
import { testUrlMatchesGlob } from '../../../../platform/url/common/urlGlob.js';
21
>
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
22
>
23
>
24
>
export const IExternalUriOpenerService = createDecorator<IExternalUriOpenerService>('externalUriOpenerService');
25
>
26
>
27
>
export interface IExternalOpenerProvider {
28
>
getOpeners(targetUri: URI): AsyncIterable<IExternalUriOpener>;
29
>
}
30
>
31
>
export interface IExternalUriOpener {
32
>
readonly id: string;
33
>
readonly label: string;
34
>
35
>
canOpen(uri: URI, token: CancellationToken): Promise<languages.ExternalUriOpenerPriority>;
36
>
openExternalUri(uri: URI, ctx: { sourceUri: URI }, token: CancellationToken): Promise<boolean>;
37
>
}
38
>
39
>
export interface IExternalUriOpenerService {
40
>
readonly _serviceBrand: undefined;
41
>
42
>
/**
43
>
* Registers a provider for external resources openers.
44
>
*/
45
>
registerExternalOpenerProvider(provider: IExternalOpenerProvider): IDisposable;
46
>
47
>
/**
48
>
* Get the configured IExternalUriOpener for the uri.
49
>
* If there is no opener configured, then returns the first opener that can handle the uri.
50
>
*/
51
>
getOpener(uri: URI, ctx: { sourceUri: URI; preferredOpenerId?: string }, token: CancellationToken): Promise<IExternalUriOpener | undefined>;
52
>
}
53
>
54
>
export class ExternalUriOpenerService extends Disposable implements IExternalUriOpenerService, IExternalOpener {
55
>
56
>
public readonly _serviceBrand: undefined;
57
>
58
>
private readonly _providers = new LinkedList<IExternalOpenerProvider>();
59
>
60
>
constructor(
61
>
@IOpenerService openerService: IOpenerService,
62
>
@IConfigurationService private readonly configurationService: IConfigurationService,
63
>
@ILogService private readonly logService: ILogService,
64
>
@IPreferencesService private readonly preferencesService: IPreferencesService,
65
>
@IQuickInputService private readonly quickInputService: IQuickInputService,
66
>
) {
67
>
super();
68
>
this._register(openerService.registerExternalOpener(this));
69
>
}
70
>
71
>
registerExternalOpenerProvider(provider: IExternalOpenerProvider): IDisposable {
72
>
const remove = this._providers.push(provider);
73
>
return { dispose: remove };
74
>
}
75
>
76
>
private async getOpeners(targetUri: URI, allowOptional: boolean, ctx: { sourceUri: URI; preferredOpenerId?: string }, token: CancellationToken): Promise<IExternalUriOpener[]> {
77
>
const allOpeners = await this.getAllOpenersForUri(targetUri);
78
>
79
>
if (allOpeners.size === 0) {
80
return [];
81
}