1
>
/*---------------------------------------------------------------------------------------------
opener.ts
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 { IDisposable } from '../../../base/common/lifecycle.js';
8
>
import { URI } from '../../../base/common/uri.js';
9
>
import { IEditorOptions, ITextEditorSelection } from '../../editor/common/editor.js';
10
>
import { createDecorator } from '../../instantiation/common/instantiation.js';
11
>
12
>
export const IOpenerService = createDecorator<IOpenerService>('openerService');
13
>
14
>
export type OpenInternalOptions = {
15
>
16
>
/**
17
>
* Signals that the intent is to open an editor to the side
18
>
* of the currently active editor.
19
>
*/
20
>
readonly openToSide?: boolean;
21
>
22
>
/**
23
>
* Extra editor options to apply in case an editor is used to open.
24
>
*/
25
>
readonly editorOptions?: IEditorOptions;
26
>
27
>
/**
28
>
* Signals that the editor to open was triggered through a user
29
>
* action, such as keyboard or mouse usage.
30
>
*/
31
>
readonly fromUserGesture?: boolean;
32
>
33
>
/**
34
>
* Allow command links to be handled.
35
>
*
36
>
* If this is an array, then only the commands included in the array can be run.
37
>
*/
38
>
readonly allowCommands?: boolean | readonly string[];
39
>
};
40
>
41
>
export type OpenExternalOptions = {
42
>
readonly openExternal?: boolean;
43
>
readonly allowTunneling?: boolean;
44
>
readonly allowContributedOpeners?: boolean | string;
45
>
readonly fromWorkspace?: boolean;
46
>
readonly skipValidation?: boolean;
47
>
};
48
>
49
>
export type OpenOptions = OpenInternalOptions & OpenExternalOptions;
50
>
51
>
export type ResolveExternalUriOptions = { readonly allowTunneling?: boolean };
52
>
53
>
export interface IResolvedExternalUri extends IDisposable {
54
>
resolved: URI;
55
>
}
56
>
57
>
export interface IOpener {
58
>
open(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise<boolean>;
59
>
}
60
>
61
>
export interface IExternalOpener {
62
>
openExternal(href: string, ctx: { sourceUri: URI; preferredOpenerId?: string }, token: CancellationToken): Promise<boolean>;
63
>
dispose?(): void;
64
>
}
65
>
66
>
export interface IValidator {
67
>
shouldOpen(resource: URI | string, openOptions?: OpenOptions): Promise<boolean>;
68
>
}
69
>
70
>
export interface IExternalUriResolver {
71
>
resolveExternalUri(resource: URI, options?: OpenOptions): Promise<{ resolved: URI; dispose(): void } | undefined>;
72
>
}
73
>
74
>
export interface IOpenerService {
75
>
76
>
readonly _serviceBrand: undefined;
77
>
78
>
/**
79
>
* Register a participant that can handle the open() call.
80
>
*/
81
>
registerOpener(opener: IOpener): IDisposable;
82
>
83
>
/**
84
>
* Register a participant that can validate if the URI resource be opened.
85
>
* Validators are run before openers.
86
>
*/
87
>
registerValidator(validator: IValidator): IDisposable;
88
>
89
>
/**
90
>
* Register a participant that can resolve an external URI resource to be opened.
91
>
*/
92
>
registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable;
93
>
94
>
/**
95
>
* Sets the handler for opening externally. If not provided,
96
>
* a default handler will be used.
97
>
*/
98
>
setDefaultExternalOpener(opener: IExternalOpener): void;
99
>
100
>
/**
101
>
* Registers a new opener external resources openers.
102
>
*/
103
>
registerExternalOpener(opener: IExternalOpener): IDisposable;
104
>
105
>
/**
106
>
* Opens a resource, like a webaddress, a document uri, or executes command.
107
>
*
108
>
* @param resource A resource
109
>
* @return A promise that resolves when the opening is done.
110
>
*/
111
>
open(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise<boolean>;
112
>
113
>
/**
114
>
* Resolve a resource to its external form.
115
>
* @throws whenever resolvers couldn't resolve this resource externally.
116
>
*/
117
>
resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise<IResolvedExternalUri>;
118
>
}
119
>
120
>
/**
121
>
* Encodes selection into the `URI`.
122
>
*
123
>
* IMPORTANT: you MUST use `extractSelection` to separate the selection
124
>
* again from the original `URI` before passing the `URI` into any
125
>
* component that is not aware of selections.
126
>
*/
127
>
export function withSelection(uri: URI, selection: ITextEditorSelection): URI {
128
return uri.with({ fragment: `${selection.startLineNumber},${selection.startColumn}${selection.endLineNumber ? `-${selection.endLineNumber}${selection.endColumn ? `,${selection.endColumn}` : ''}` : ''}` });
129
}
131
>
/**
132
>
* file:///some/file.js#73
133
>
* file:///some/file.js#L73
134
>
* file:///some/file.js#73,84
135
>
* file:///some/file.js#L73,84
136
>
* file:///some/file.js#73-83
137
>
* file:///some/file.js#L73-L83
138
>
* file:///some/file.js#73,84-83,52
139
>
* file:///some/file.js#L73,84-L83,52
140
>
*/
141
>
export function extractSelection(uri: URI): { selection: ITextEditorSelection | undefined; uri: URI } {
142
let selection: ITextEditorSelection | undefined = undefined;
143
const match = /^L?(\d+)(?:,(\d+))?(-L?(\d+)(?:,(\d+))?)?/.exec(uri.fragment);