extHostWorkspace.ts ×67

Frontier kind: Code frontier

unlabeled · c_204b7bc56904

71 tests · 76111 LOC · 258 files · introduces 0 tests · 478 LOC · 4 files

Introduces — evidence that enters the hierarchy at this concept

Code
93 ranges478 lines · 4 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
4951 ranges76111 lines · 258 files · Browse complete extent
All tests (intent)
71 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

4 files ranked by introduced lines: 478 introduced LOC across 93 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/api/common/extHostWorkspace.ts 322 introduced LOC · 67 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostWorkspace.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 { delta as arrayDelta, mapArrayOrNot } from '../../../base/common/arrays.js';
7 > import { AsyncIterableProducer, Barrier } from '../../../base/common/async.js';
8 > import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
9 > import { AsyncEmitter, Emitter, Event } from '../../../base/common/event.js';
10 > import { DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
11 > import { StopWatch } from '../../../base/common/stopwatch.js';
12 > import { TernarySearchTree } from '../../../base/common/ternarySearchTree.js';
13 > import { Schemas } from '../../../base/common/network.js';
14 > import { Counter } from '../../../base/common/numbers.js';
15 > import { basename, basenameOrAuthority, dirname, ExtUri, relativePath } from '../../../base/common/resources.js';
16 > import { compare } from '../../../base/common/strings.js';
17 > import { isUriComponents, URI, UriComponents } from '../../../base/common/uri.js';
18 > import { localize } from '../../../nls.js';
19 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
20 > import { FileSystemProviderCapabilities } from '../../../platform/files/common/files.js';
21 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
22 > import { ILogService } from '../../../platform/log/common/log.js';
23 > import { Severity } from '../../../platform/notification/common/notification.js';
24 > import { EditSessionIdentityMatch } from '../../../platform/workspace/common/editSessions.js';
25 > import { Workspace, WorkspaceFolder } from '../../../platform/workspace/common/workspace.js';
26 > import { IExtHostFileSystemInfo } from './extHostFileSystemInfo.js';
27 > import { IExtHostInitDataService } from './extHostInitDataService.js';
28 > import { IExtHostRpcService } from './extHostRpcService.js';
29 > import { GlobPattern } from './extHostTypeConverters.js';
30 > import { Range } from './extHostTypes.js';
31 > import { IURITransformerService } from './extHostUriTransformerService.js';
32 > import { IFileQueryBuilderOptions, ISearchPatternBuilder, ITextQueryBuilderOptions } from '../../services/search/common/queryBuilder.js';
33 > import { IRawFileMatch2, ITextSearchResult, resultIsMatch } from '../../services/search/common/search.js';
34 > import type * as vscode from 'vscode';
35 > import { ExtHostWorkspaceShape, IRelativePatternDto, IWorkspaceData, MainContext, MainThreadMessageOptions, MainThreadMessageServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from './extHost.protocol.js';
36 > import { revive } from '../../../base/common/marshalling.js';
37 > import { AuthInfo, Credentials } from '../../../platform/request/common/request.js';
38 > import { ExcludeSettingOptions, TextSearchContext2, TextSearchMatch2 } from '../../services/search/common/searchExtTypes.js';
39 > import { bufferToStream, readableToBuffer, VSBuffer } from '../../../base/common/buffer.js';
40 > import { toDecodeStream, toEncodeReadable, UTF8 } from '../../services/textfile/common/encoding.js';
41 > import { consumeStream } from '../../../base/common/stream.js';
42 > import { stringToSnapshot } from '../../services/textfile/common/textfiles.js';
43 > // Type-only import to avoid a runtime cycle with extHostConfiguration.ts.
44 > import type { ExtHostConfigProvider } from './extHostConfiguration.js';
45 >
46 > export interface IExtHostWorkspaceProvider {
47 > getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise<vscode.WorkspaceFolder | undefined>;
48 > resolveWorkspaceFolder(uri: vscode.Uri): Promise<vscode.WorkspaceFolder | undefined>;
49 > getWorkspaceFolders2(): Promise<vscode.WorkspaceFolder[] | undefined>;
50 > resolveProxy(url: string): Promise<string | undefined>;
51 > lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined>;
52 > lookupKerberosAuthorization(url: string): Promise<string | undefined>;
53 > loadCertificates(): Promise<string[]>;
54 > }
55 >
56 function isFolderEqual(folderA: URI, folderB: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): boolean {
57 return new ExtUri(uri => ignorePathCasing(uri, extHostFileSystemInfo)).isEqual(folderA, folderB);
58 }
60 function compareWorkspaceFolderByUri(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder, extHostFileSystemInfo: IExtHostFileSystemInfo): number {
61 return isFolderEqual(a.uri, b.uri, extHostFileSystemInfo) ? 0 : compare(a.uri.toString(), b.uri.toString());
62 }
64 function compareWorkspaceFolderByUriAndNameAndIndex(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder, extHostFileSystemInfo: IExtHostFileSystemInfo): number {
65 if (a.index !== b.index) {
69 return isFolderEqual(a.uri, b.uri, extHostFileSystemInfo) ? compare(a.name, b.name) : compare(a.uri.toString(), b.uri.toString());
70 }
72 function delta(oldFolders: vscode.WorkspaceFolder[], newFolders: vscode.WorkspaceFolder[], compare: (a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder, extHostFileSystemInfo: IExtHostFileSystemInfo) => number, extHostFileSystemInfo: IExtHostFileSystemInfo): { removed: vscode.WorkspaceFolder[]; added: vscode.WorkspaceFolder[] } {
73 const oldSortedFolders = oldFolders.slice(0).sort((a, b) => compare(a, b, extHostFileSystemInfo));
76 return arrayDelta(oldSortedFolders, newSortedFolders, (a, b) => compare(a, b, extHostFileSystemInfo));
77 }
79 function ignorePathCasing(uri: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): boolean {
80 const capabilities = extHostFileSystemInfo.getCapabilities(uri.scheme);
81 return !(capabilities && (capabilities & FileSystemProviderCapabilities.PathCaseSensitive));
82 }
84 > interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
85 > name: string;
86 > index: number;
87 > }
88 >
89 > interface QueryOptions<T> {
90 > options: T;
91 > folder: URI | undefined;
92 > }
93 >
94 > type FindFilesApiKind = 'findFiles' | 'findFiles2';
95 >
96 > interface FindFilesCallIntent {
97 > /** Value the extension explicitly passed for `useIgnoreFiles.local` (findFiles2); `undefined` if not specified or N/A for legacy `findFiles`. */
98 > readonly useIgnoreFilesLocal: boolean | undefined;
99 > /** Whether the extension passed `null` as the `exclude` argument to legacy `findFiles` (the documented escape hatch). Always `false` for findFiles2. */
100 > readonly excludeWasNull: boolean;
101 > }
102 >
103 > class ExtHostWorkspaceImpl extends Workspace {
104 >
105 > static toExtHostWorkspace(data: IWorkspaceData | null, previousConfirmedWorkspace: ExtHostWorkspaceImpl | undefined, previousUnconfirmedWorkspace: ExtHostWorkspaceImpl | undefined, extHostFileSystemInfo: IExtHostFileSystemInfo): { workspace: ExtHostWorkspaceImpl | null; added: vscode.WorkspaceFolder[]; removed: vscode.WorkspaceFolder[] } {
106 > if (!data) {
107 > return { workspace: null, added: [], removed: [] };
108 > }
109 >
110 > const { id, name, folders, configuration, transient, isUntitled } = data;
111 > const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
112 >
113 > // If we have an existing workspace, we try to find the folders that match our
114 > // data and update their properties. It could be that an extension stored them
115 > // for later use and we want to keep them "live" if they are still present.
116 > const oldWorkspace = previousConfirmedWorkspace;
117 > if (previousConfirmedWorkspace) {
118 > folders.forEach((folderData, index) => {
119 > const folderUri = URI.revive(folderData.uri);
120 > const existingFolder = ExtHostWorkspaceImpl._findFolder(previousUnconfirmedWorkspace || previousConfirmedWorkspace, folderUri, extHostFileSystemInfo);
121 >
122 > if (existingFolder) {
123 > existingFolder.name = folderData.name;
124 > existingFolder.index = folderData.index;
125 >
126 > newWorkspaceFolders.push(existingFolder);
127 > } else {
128 > newWorkspaceFolders.push({ uri: folderUri, name: folderData.name, index });
129 > }
130 > });
131 > } else {
132 > newWorkspaceFolders.push(...folders.map(({ uri, name, index }) => ({ uri: URI.revive(uri), name, index })));
133 > }
134 >
135 > // make sure to restore sort order based on index
136 > newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
137 >
138 > const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, !!transient, configuration ? URI.revive(configuration) : null, !!isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo));
139 > const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri, extHostFileSystemInfo);
140 >
141 > return { workspace, added, removed };
142 > }
143 >
144 > private static _findFolder(workspace: ExtHostWorkspaceImpl, folderUriToFind: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): MutableWorkspaceFolder | undefined {
145 for (let i = 0; i < workspace.folders.length; i++) {
146 const folder = workspace.workspaceFolders[i];
152 return undefined;
153 }
155 > private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
156 > private readonly _structure: TernarySearchTree<URI, vscode.WorkspaceFolder>;
157 >
158 > constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], transient: boolean, configuration: URI | null, private _isUntitled: boolean, ignorePathCasing: (key: URI) => boolean) {
159 super(id, folders.map(f => new WorkspaceFolder(f)), transient, configuration, ignorePathCasing);
160 this._structure = TernarySearchTree.forUris<vscode.WorkspaceFolder>(ignorePathCasing, () => true);
166 });
167 }
169 > override get name(): string {
170 return this._name;
171 }
173 > get isUntitled(): boolean {
174 return this._isUntitled;
175 }
177 > get workspaceFolders(): vscode.WorkspaceFolder[] {
178 return this._workspaceFolders.slice(0);
179 }
181 > getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder | undefined {
182 if (resolveParent && this._structure.get(uri)) {
183 // `uri` is a workspace folder so we check for its parent
186 return this._structure.findSubstr(uri);
187 }
189 > resolveWorkspaceFolder(uri: URI): vscode.WorkspaceFolder | undefined {
190 return this._structure.get(uri);
191 }
193 >
194 > export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspaceProvider {
195 >
196 > readonly _serviceBrand: undefined;
197 >
198 > private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
199 > readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
200 >
201 > private readonly _onDidGrantWorkspaceTrust = new Emitter<void>();
202 > readonly onDidGrantWorkspaceTrust: Event<void> = this._onDidGrantWorkspaceTrust.event;
203 >
204 > private readonly _onDidChangeWorkspaceTrustedFolders = new Emitter<void>();
205 > readonly onDidChangeWorkspaceTrustedFolders: Event<void> = this._onDidChangeWorkspaceTrustedFolders.event;
206 >
207 > private readonly _logService: ILogService;
208 > private readonly _requestIdProvider: Counter;
209 > private readonly _barrier: Barrier;
210 >
211 > private _confirmedWorkspace?: ExtHostWorkspaceImpl;
212 > private _unconfirmedWorkspace?: ExtHostWorkspaceImpl;
213 >
214 > private readonly _proxy: MainThreadWorkspaceShape;
215 > private readonly _messageService: MainThreadMessageServiceShape;
216 > private readonly _telemetryProxy: MainThreadTelemetryShape;
217 > private readonly _extHostFileSystemInfo: IExtHostFileSystemInfo;
218 > private readonly _uriTransformerService: IURITransformerService;
219 >
220 > private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = [];
221 >
222 > private _trusted: boolean = false;
223 >
224 > private readonly _editSessionIdentityProviders = new Map<string, vscode.EditSessionIdentityProvider>();
225 >
226 > // Pushed in by ExtHostConfiguration after init (see `$setConfigProvider`).
227 > private _configProvider?: ExtHostConfigProvider;
228 >
229 > constructor(
230 @IExtHostRpcService extHostRpc: IExtHostRpcService,
231 @IExtHostInitDataService initData: IExtHostInitDataService,
246 this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], !!data.transient, data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
247 }
249 > /**
250 > * Receives the configuration provider from ExtHostConfiguration after init. We cannot inject
251 > * IExtHostConfiguration directly because it creates a DI cycle (ExtHostConfiguration already
252 > * depends on IExtHostWorkspace). Once set, settings reads in findFiles become synchronous.
253 > */
254 > $setConfigProvider(provider: ExtHostConfigProvider): void {
255 this._configProvider = provider;
256 }
258 > private _useIgnoreFilesInFindFiles(): boolean {
259 return this._configProvider?.getConfiguration('search').get<boolean>('experimental.useIgnoreFilesInFindFiles') ?? false;
260 }
262 > private _userIgnoreFilesSetting(): boolean {
263 // Default in `search.useIgnoreFiles` is `true`; mirror that here so telemetry computed against
264 // an unset config still reflects the fallback the query builder will apply.
265 return this._configProvider?.getConfiguration('search').get<boolean>('useIgnoreFiles') ?? true;
266 }
268 > $initializeWorkspace(data: IWorkspaceData | null, trusted: boolean): void {
269 this._trusted = trusted;
270 this.$acceptWorkspaceData(data);
271 this._barrier.open();
272 }
274 > waitForInitializeCall(): Promise<boolean> {
275 return this._barrier.wait();
276 }
278 > // --- workspace ---
279 >
280 > get workspace(): Workspace | undefined {
281 return this._actualWorkspace;
282 }
284 > get name(): string | undefined {
285 return this._actualWorkspace ? this._actualWorkspace.name : undefined;
286 }
288 > get workspaceFile(): vscode.Uri | undefined {
289 if (this._actualWorkspace) {
290 if (this._actualWorkspace.configuration) {
299 return undefined;
300 }
302 > private get _actualWorkspace(): ExtHostWorkspaceImpl | undefined {
303 return this._unconfirmedWorkspace || this._confirmedWorkspace;
304 }
306 > getWorkspaceFolders(): vscode.WorkspaceFolder[] | undefined {
307 if (!this._actualWorkspace) {
308 return undefined;
310 return this._actualWorkspace.workspaceFolders.slice(0);
311 }
313 > async getWorkspaceFolders2(): Promise<vscode.WorkspaceFolder[] | undefined> {
314 await this._barrier.wait();
315 if (!this._actualWorkspace) {
318 return this._actualWorkspace.workspaceFolders.slice(0);
319 }
321 > updateWorkspaceFolders(extension: IExtensionDescription, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: vscode.Uri; name?: string }[]): boolean {
322 const validatedDistinctWorkspaceFoldersToAdd: { uri: vscode.Uri; name?: string }[] = [];
323 if (Array.isArray(workspaceFoldersToAdd)) {
383 return true;
384 }
386 > getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder | undefined {
387 if (!this._actualWorkspace) {
388 return undefined;
390 return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent);
391 }
393 > async getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise<vscode.WorkspaceFolder | undefined> {
394 await this._barrier.wait();
395 if (!this._actualWorkspace) {
398 return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent);
399 }
401 > async resolveWorkspaceFolder(uri: vscode.Uri): Promise<vscode.WorkspaceFolder | undefined> {
402 await this._barrier.wait();
403 if (!this._actualWorkspace) {
406 return this._actualWorkspace.resolveWorkspaceFolder(uri);
407 }
409 > getPath(): string | undefined {
410
411 // this is legacy from the days before having
423 return folders[0].uri.fsPath;
424 }
426 > getRelativePath(pathOrUri: string | vscode.Uri, includeWorkspace?: boolean): string {
427
428 let resource: URI | undefined;
459 return result!;
460 }
462 > private trySetWorkspaceFolders(folders: vscode.WorkspaceFolder[]): void {
463
464 // Update directly here. The workspace is unconfirmed as long as we did not get an
474 }
475 }
477 > $acceptWorkspaceData(data: IWorkspaceData | null): void {
478
479 const { workspace, added, removed } = ExtHostWorkspaceImpl.toExtHostWorkspace(data, this._confirmedWorkspace, this._unconfirmedWorkspace, this._extHostFileSystemInfo);
490 }));
491 }
493 > // --- search ---
494 >
495 > /**
496 > * Note, null/undefined have different and important meanings for "exclude"
497 > */
498 > findFiles(include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | null | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
499 this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`);
500
528 }, extensionId, 'findFiles', { useIgnoreFilesLocal: undefined, excludeWasNull: exclude === null }, token);
529 }
531 >
532 > findFiles2(filePatterns: readonly vscode.GlobPattern[],
533 options: vscode.FindFiles2Options = {},
534 extensionId: ExtensionIdentifier,
537 return this._findFilesImpl({ type: 'filePatterns', value: filePatterns }, options, extensionId, 'findFiles2', { useIgnoreFilesLocal: options.useIgnoreFiles?.local, excludeWasNull: false }, token);
538 }
540 > private async _findFilesImpl(
541 // the old `findFiles` used `include` to query, but the new `findFiles2` uses `filePattern` to query.
542 // `filePattern` is the proper way to handle this, since it takes less precedence than the ignore files.
635 }
636 }
638 > private async _findFilesBase(
639 queryOptions: QueryOptions<IFileQueryBuilderOptions>[] | undefined,
640 token: CancellationToken
677 return Array.from(uriMap.values());
678 }
680 > private _reportFindFilesTelemetry(event: {
681 extensionId: string;
682 apiKind: FindFilesApiKind;
718 this._telemetryProxy.$publicLog2<FindFilesEvent, FindFilesEventClassification>('extHostFindFiles', event);
719 }
721 > findTextInFiles2(query: vscode.TextSearchQuery2, options: vscode.FindTextInFilesOptions2 | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): vscode.FindTextInFilesResponse {
722 this._logService.trace(`extHostWorkspace#findTextInFiles2: textSearch, extension: ${extensionId.value}, entryPoint: findTextInFiles2`);
723
808 };
809 }
811 >
812 > async findTextInFilesBase(query: vscode.TextSearchQuery, queryOptions: QueryOptions<ITextQueryBuilderOptions>[] | undefined, callback: (result: ITextSearchResult<URI>, uri: URI) => void, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete> {
813 const requestId = this._requestIdProvider.getNext();
814
855 }
856 }
858 > async findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions & { useSearchExclude?: boolean }, callback: (result: vscode.TextSearchResult) => void, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete> {
859 this._logService.trace(`extHostWorkspace#findTextInFiles: textSearch, extension: ${extensionId.value}, entryPoint: findTextInFiles`);
860
911 return this.findTextInFilesBase(query, [{ options: queryOptions, folder: parsedInclude?.folder }], progress, token);
912 }
914 > $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void {
915 this._activeSearchCallbacks[requestId]?.(result);
916 }
918 > async save(uri: URI): Promise<URI | undefined> {
919 const result = await this._proxy.$save(uri, { saveAs: false });
920
921 return URI.revive(result);
922 }
924 > async saveAs(uri: URI): Promise<URI | undefined> {
925 const result = await this._proxy.$save(uri, { saveAs: true });
926
927 return URI.revive(result);
928 }
930 > saveAll(includeUntitled?: boolean): Promise<boolean> {
931 return this._proxy.$saveAll(includeUntitled);
932 }
934 > resolveProxy(url: string): Promise<string | undefined> {
935 return this._proxy.$resolveProxy(url);
936 }
938 > lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined> {
939 return this._proxy.$lookupAuthorization(authInfo);
940 }
942 > lookupKerberosAuthorization(url: string): Promise<string | undefined> {
943 return this._proxy.$lookupKerberosAuthorization(url);
944 }
946 > loadCertificates(): Promise<string[]> {
947 return this._proxy.$loadCertificates();
948 }
950 > // --- trust ---
951 >
952 > get trusted(): boolean {
953 return this._trusted;
954 }
956 > requestResourceTrust(options: vscode.ResourceTrustRequestOptions): Promise<boolean | undefined> {
957 return this._proxy.$requestResourceTrust(options);
958 }
960 > requestWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise<boolean | undefined> {
961 return this._proxy.$requestWorkspaceTrust(options);
962 }
964 > $onDidGrantWorkspaceTrust(): void {
965 if (!this._trusted) {
966 this._trusted = true;
968 }
969 }
971 > $onDidChangeWorkspaceTrustedFolders(): void {
972 this._onDidChangeWorkspaceTrustedFolders.fire();
973 }
975 > isResourceTrusted(resource: vscode.Uri): Promise<boolean> {
976 return this._proxy.$isResourceTrusted(resource);
977 }
979 > // --- edit sessions ---
980 >
981 > private _providerHandlePool = 0;
982 >
983 > // called by ext host
984 > registerEditSessionIdentityProvider(scheme: string, provider: vscode.EditSessionIdentityProvider) {
985 if (this._editSessionIdentityProviders.has(scheme)) {
986 throw new Error(`A provider has already been registered for scheme ${scheme}`);
997 });
998 }
1000 > // called by main thread
1001 > async $getEditSessionIdentifier(workspaceFolder: UriComponents, cancellationToken: CancellationToken): Promise<string | undefined> {
1002 this._logService.info('Getting edit session identifier for workspaceFolder', workspaceFolder);
1003 const folder = await this.resolveWorkspaceFolder(URI.revive(workspaceFolder));
1023 return result;
1024 }
1026 > async $provideEditSessionIdentityMatch(workspaceFolder: UriComponents, identity1: string, identity2: string, cancellationToken: CancellationToken): Promise<EditSessionIdentityMatch | undefined> {
1027 this._logService.info('Getting edit session identifier for workspaceFolder', workspaceFolder);
1028 const folder = await this.resolveWorkspaceFolder(URI.revive(workspaceFolder));
1048 return result;
1049 }
1051 > private readonly _onWillCreateEditSessionIdentityEvent = new AsyncEmitter<vscode.EditSessionIdentityWillCreateEvent>();
1052 >
1053 > getOnWillCreateEditSessionIdentityEvent(extension: IExtensionDescription): Event<vscode.EditSessionIdentityWillCreateEvent> {
1054 return (listener, thisArg, disposables) => {
1055 const wrappedListener: IExtensionListener<vscode.EditSessionIdentityWillCreateEvent> = function wrapped(e) { listener.call(thisArg, e); };
1058 };
1059 }
1061 > // main thread calls this to trigger participants
1062 > async $onWillCreateEditSessionIdentity(workspaceFolder: UriComponents, token: CancellationToken, timeout: number): Promise<void> {
1063 const folder = await this.resolveWorkspaceFolder(URI.revive(workspaceFolder));
1064
1079 }
1080 }
1082 > // --- canonical uri identity ---
1083 >
1084 > private readonly _canonicalUriProviders = new Map<string, vscode.CanonicalUriProvider>();
1085 >
1086 > // called by ext host
1087 > registerCanonicalUriProvider(scheme: string, provider: vscode.CanonicalUriProvider) {
1088 if (this._canonicalUriProviders.has(scheme)) {
1089 throw new Error(`A provider has already been registered for scheme ${scheme}`);
1100 });
1101 }
1103 > async provideCanonicalUri(uri: URI, options: vscode.CanonicalUriRequestOptions, cancellationToken: CancellationToken): Promise<URI | undefined> {
1104 const provider = this._canonicalUriProviders.get(uri.scheme);
1105 if (!provider) {
1114 return result;
1115 }
1117 > // called by main thread
1118 > async $provideCanonicalUri(uri: UriComponents, targetScheme: string, cancellationToken: CancellationToken): Promise<UriComponents | undefined> {
1119 return this.provideCanonicalUri(URI.revive(uri), { targetScheme }, cancellationToken);
1120 }
1122 > // --- encodings ---
1123 >
1124 > async decode(content: Uint8Array, args?: { uri?: vscode.Uri; encoding?: string }): Promise<string> {
1125 const [uri, opts] = this.toEncodeDecodeParameters(args);
1126 const options = await this._proxy.$resolveDecoding(uri, opts);
1143 return consumeStream(stream, chunks => chunks.join(''));
1144 }
1146 > async encode(content: string, args?: { uri?: vscode.Uri; encoding?: string }): Promise<Uint8Array> {
1147 const [uri, options] = this.toEncodeDecodeParameters(args);
1148 const { encoding, addBOM } = await this._proxy.$resolveEncoding(uri, options);
1157 return readableToBuffer(res).buffer;
1158 }
1160 > private toEncodeDecodeParameters(opts?: { uri?: vscode.Uri; encoding?: string }): [UriComponents | undefined, { encoding: string } | undefined] {
1161 const uri = isUriComponents(opts?.uri) ? opts.uri : undefined;
1162 const encoding = typeof opts?.encoding === 'string' ? opts.encoding : undefined;
1164 return [uri, encoding ? { encoding } : undefined];
1165 }
1167 >
1168 > export const IExtHostWorkspace = createDecorator<IExtHostWorkspace>('IExtHostWorkspace');
1169 > export interface IExtHostWorkspace extends ExtHostWorkspace, ExtHostWorkspaceShape, IExtHostWorkspaceProvider { }
1170 >
1171 function parseSearchExcludeInclude(include: string | IRelativePatternDto | undefined | null): { pattern: string; folder?: URI } | undefined {
1172 let pattern: string | undefined;
1187 return undefined;
1188 }
1190 > interface IExtensionListener<E> {
1191 > extension: IExtensionDescription;
1192 > (e: E): any;
1193 > }
1194 >
1195 function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined): ISearchPatternBuilder<URI>[] {
1196 return (
src/vs/workbench/api/common/extHostConfiguration.ts 97 introduced LOC · 19 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostConfiguration.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 { mixin, deepClone } from '../../../base/common/objects.js';
7 > import { Event, Emitter } from '../../../base/common/event.js';
8 > import type * as vscode from 'vscode';
9 > import { ExtHostWorkspace, IExtHostWorkspace } from './extHostWorkspace.js';
10 > import { ExtHostConfigurationShape, MainThreadConfigurationShape, IConfigurationInitData, MainContext } from './extHost.protocol.js';
11 > import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes.js';
12 > import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from '../../../platform/configuration/common/configuration.js';
13 > import { Configuration, ConfigurationChangeEvent } from '../../../platform/configuration/common/configurationModels.js';
14 > import { ConfigurationScope, OVERRIDE_PROPERTY_REGEX } from '../../../platform/configuration/common/configurationRegistry.js';
15 > import { isObject } from '../../../base/common/types.js';
16 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
17 > import { Barrier } from '../../../base/common/async.js';
18 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
19 > import { IExtHostRpcService } from './extHostRpcService.js';
20 > import { ILogService } from '../../../platform/log/common/log.js';
21 > import { Workspace } from '../../../platform/workspace/common/workspace.js';
22 > import { URI } from '../../../base/common/uri.js';
23 >
24 function lookUp(tree: unknown, key: string) {
25 if (key) {
33 return undefined;
34 }
36 > export type ConfigurationInspect<T> = {
37 > key: string;
38 >
39 > defaultValue?: T;
40 > globalLocalValue?: T;
41 > globalRemoteValue?: T;
42 > globalValue?: T;
43 > workspaceValue?: T;
44 > workspaceFolderValue?: T;
45 >
46 > defaultLanguageValue?: T;
47 > globalLocalLanguageValue?: T;
48 > globalRemoteLanguageValue?: T;
49 > globalLanguageValue?: T;
50 > workspaceLanguageValue?: T;
51 > workspaceFolderLanguageValue?: T;
52 >
53 > languageIds?: string[];
54 > };
55 >
56 function isUri(thing: unknown): thing is vscode.Uri {
57 return thing instanceof URI;
58 }
60 function isResourceLanguage(thing: unknown): thing is { uri: URI; languageId: string } {
61 return isObject(thing)
64 && typeof (thing as Record<string, unknown>).languageId === 'string';
65 }
67 function isLanguage(thing: unknown): thing is { languageId: string } {
68 return isObject(thing)
71 && typeof (thing as Record<string, unknown>).languageId === 'string';
72 }
74 function isWorkspaceFolder(thing: unknown): thing is vscode.WorkspaceFolder {
75 return isObject(thing)
78 && (!(thing as Record<string, unknown>).index || typeof (thing as Record<string, unknown>).index === 'number');
79 }
81 function scopeToOverrides(scope: vscode.ConfigurationScope | undefined | null): IConfigurationOverrides | undefined {
82 if (isUri(scope)) {
97 return undefined;
98 }
100 > export class ExtHostConfiguration implements ExtHostConfigurationShape {
101 >
102 > readonly _serviceBrand: undefined;
103 >
104 > private readonly _proxy: MainThreadConfigurationShape;
105 > private readonly _logService: ILogService;
106 > private readonly _extHostWorkspace: ExtHostWorkspace;
107 > private readonly _barrier: Barrier;
108 > private _actual: ExtHostConfigProvider | null;
109 >
110 > constructor(
111 @IExtHostRpcService extHostRpc: IExtHostRpcService,
112 @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace,
119 this._actual = null;
120 }
122 > public getConfigProvider(): Promise<ExtHostConfigProvider> {
123 return this._barrier.wait().then(_ => this._actual!);
124 }
126 > $initializeConfiguration(data: IConfigurationInitData): void {
127 this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data, this._logService);
128 // Push the config provider into ExtHostWorkspace so it can read settings synchronously
131 this._barrier.open();
132 }
134 > $acceptConfigurationChanged(data: IConfigurationInitData, change: IConfigurationChange): void {
135 this.getConfigProvider().then(provider => provider.$acceptConfigurationChanged(data, change));
136 }
138 >
139 > export class ExtHostConfigProvider {
140 >
141 > private readonly _onDidChangeConfiguration = new Emitter<vscode.ConfigurationChangeEvent>();
142 > private readonly _proxy: MainThreadConfigurationShape;
143 > private readonly _extHostWorkspace: ExtHostWorkspace;
144 > private _configurationScopes: Map<string, ConfigurationScope | undefined>;
145 > private _configuration: Configuration;
146 > private _logService: ILogService;
147 >
148 > constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData, logService: ILogService) {
149 this._proxy = proxy;
150 this._logService = logService;
153 this._configurationScopes = this._toMap(data.configurationScopes);
154 }
156 > get onDidChangeConfiguration(): Event<vscode.ConfigurationChangeEvent> {
157 return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event;
158 }
160 > $acceptConfigurationChanged(data: IConfigurationInitData, change: IConfigurationChange) {
161 const previous = { data: this._configuration.toData(), workspace: this._extHostWorkspace.workspace };
162 this._configuration = Configuration.parse(data, this._logService);
164 this._onDidChangeConfiguration.fire(this._toConfigurationChangeEvent(change, previous));
165 }
167 > getConfiguration(section?: string, scope?: vscode.ConfigurationScope | null, extensionDescription?: IExtensionDescription): vscode.WorkspaceConfiguration {
168 const overrides = scopeToOverrides(scope) || {};
169 const config = this._toReadonlyValue(this._configuration.getValue(section, overrides, this._extHostWorkspace.workspace));
297 return Object.freeze(result);
298 }
300 > private _toReadonlyValue(result: unknown): unknown {
301 const readonlyProxy = (target: unknown): unknown => {
302 return isObject(target) ?
313 return readonlyProxy(result);
314 }
316 > private _validateConfigurationAccess(key: string, overrides?: IConfigurationOverrides, extensionId?: ExtensionIdentifier): void {
317 const scope = OVERRIDE_PROPERTY_REGEX.test(key) ? ConfigurationScope.RESOURCE : this._configurationScopes.get(key);
318 const extensionIdText = extensionId ? `[${extensionId.value}] ` : '';
330 }
331 }
333 > private _toConfigurationChangeEvent(change: IConfigurationChange, previous: { data: IConfigurationData; workspace: Workspace | undefined }): vscode.ConfigurationChangeEvent {
334 const event = new ConfigurationChangeEvent(change, previous, this._configuration, this._extHostWorkspace.workspace, this._logService);
335 return Object.freeze({
337 });
338 }
340 > private _toMap(scopes: [string, ConfigurationScope | undefined][]): Map<string, ConfigurationScope | undefined> {
341 return scopes.reduce((result, scope) => { result.set(scope[0], scope[1]); return result; }, new Map<string, ConfigurationScope | undefined>());
342 }
344 > }
345 >
346 > export const IExtHostConfiguration = createDecorator<IExtHostConfiguration>('IExtHostConfiguration');
347 > export interface IExtHostConfiguration extends ExtHostConfiguration { }
src/vs/workbench/api/common/extHostFileSystemInfo.ts 34 introduced LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostFileSystemInfo.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 { Schemas } from '../../../base/common/network.js';
7 > import { ExtUri, IExtUri } from '../../../base/common/resources.js';
8 > import { UriComponents } from '../../../base/common/uri.js';
9 > import { FileSystemProviderCapabilities } from '../../../platform/files/common/files.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 > import { ExtHostFileSystemInfoShape } from './extHost.protocol.js';
12 >
13 > export class ExtHostFileSystemInfo implements ExtHostFileSystemInfoShape {
14 >
15 > declare readonly _serviceBrand: undefined;
16 >
17 > private readonly _systemSchemes = new Set(Object.keys(Schemas));
18 > private readonly _providerInfo = new Map<string, number>();
19 >
20 > readonly extUri: IExtUri;
21 >
22 > constructor() {
23 this.extUri = new ExtUri(uri => {
24 const capabilities = this._providerInfo.get(uri.scheme);
34 });
35 }
37 > $acceptProviderInfos(uri: UriComponents, capabilities: number | null): void {
38 if (capabilities === null) {
39 this._providerInfo.delete(uri.scheme);
42 }
43 }
45 > isFreeScheme(scheme: string): boolean {
46 return !this._providerInfo.has(scheme) && !this._systemSchemes.has(scheme);
47 }
49 > getCapabilities(scheme: string): number | undefined {
50 return this._providerInfo.get(scheme);
51 }
53 >
54 > export interface IExtHostFileSystemInfo extends ExtHostFileSystemInfo {
55 > readonly extUri: IExtUri;
56 > }
57 > export const IExtHostFileSystemInfo = createDecorator<IExtHostFileSystemInfo>('IExtHostFileSystemInfo');
src/vs/workbench/api/common/extHostUriTransformerService.ts 25 introduced LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostUriTransformerService.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 { IURITransformer } from '../../../base/common/uriIpc.js';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 > import { URI, UriComponents } from '../../../base/common/uri.js';
9 >
10 > export interface IURITransformerService extends IURITransformer {
11 > readonly _serviceBrand: undefined;
12 > }
13 >
14 > export const IURITransformerService = createDecorator<IURITransformerService>('IURITransformerService');
15 >
16 > export class URITransformerService implements IURITransformerService {
17 > declare readonly _serviceBrand: undefined;
18 >
19 > transformIncoming: (uri: UriComponents) => UriComponents;
20 > transformOutgoing: (uri: UriComponents) => UriComponents;
21 > transformOutgoingURI: (uri: URI) => URI;
22 > transformOutgoingScheme: (scheme: string) => string;
23 >
24 > constructor(delegate: IURITransformer | null) {
25 if (!delegate) {
26 this.transformIncoming = arg => arg;