mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-23 18:19:12 +01:00
Extract workspaceContains related logic to a separate file (#75284)
This commit is contained in:
@@ -734,7 +734,7 @@ export interface ITextSearchComplete {
|
||||
export interface MainThreadWorkspaceShape extends IDisposable {
|
||||
$startFileSearch(includePattern: string | null, includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise<UriComponents[] | null>;
|
||||
$startTextSearch(query: search.IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null>;
|
||||
$checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
|
||||
$checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
|
||||
$saveAll(includeUntitled?: boolean): Promise<boolean>;
|
||||
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string; }[]): Promise<void>;
|
||||
$resolveProxy(url: string): Promise<string | undefined>;
|
||||
|
||||
@@ -18,7 +18,6 @@ import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHost
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import type * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -35,6 +34,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IExtensionActivationHost, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains';
|
||||
|
||||
interface ITestRunner {
|
||||
/** Old test runner API, as exported from `vscode/lib/testrunner` */
|
||||
@@ -70,7 +70,6 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
|
||||
private readonly _onDidChangeRemoteConnectionData = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeRemoteConnectionData = this._onDidChangeRemoteConnectionData.event;
|
||||
@@ -486,94 +485,28 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
).then(() => { });
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtension(folders: ReadonlyArray<vscode.WorkspaceFolder>, desc: IExtensionDescription): Promise<void> {
|
||||
const activationEvents = desc.activationEvents;
|
||||
if (!activationEvents) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private async _handleWorkspaceContainsEagerExtension(folders: ReadonlyArray<vscode.WorkspaceFolder>, desc: IExtensionDescription): Promise<void> {
|
||||
if (this.isActivated(desc.identifier)) {
|
||||
return Promise.resolve(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
const globPatterns: string[] = [];
|
||||
|
||||
const localWithRemote = !this._initData.remote.isRemote && !!this._initData.remote.authority;
|
||||
for (const activationEvent of activationEvents) {
|
||||
if (/^workspaceContains:/.test(activationEvent)) {
|
||||
const fileNameOrGlob = activationEvent.substr('workspaceContains:'.length);
|
||||
if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0 || localWithRemote) {
|
||||
globPatterns.push(fileNameOrGlob);
|
||||
} else {
|
||||
fileNames.push(fileNameOrGlob);
|
||||
}
|
||||
}
|
||||
const host: IExtensionActivationHost = {
|
||||
folders: folders.map(folder => folder.uri),
|
||||
forceUsingSearch: localWithRemote,
|
||||
exists: (path) => this._hostUtils.exists(path),
|
||||
checkExists: (folders, includes, token) => this._mainThreadWorkspaceProxy.$checkExists(folders, includes, token)
|
||||
};
|
||||
|
||||
const result = await checkActivateWorkspaceContainsExtension(host, desc);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileNames.length === 0 && globPatterns.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(folders, desc.identifier, fileName))).then(() => { });
|
||||
const globPatternPromise = this._activateIfGlobPatterns(folders, desc.identifier, globPatterns);
|
||||
|
||||
return Promise.all([fileNamePromise, globPatternPromise]).then(() => { });
|
||||
}
|
||||
|
||||
private async _activateIfFileName(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, fileName: string): Promise<void> {
|
||||
|
||||
// find exact path
|
||||
for (const { uri } of folders) {
|
||||
if (await this._hostUtils.exists(path.join(URI.revive(uri).fsPath, fileName))) {
|
||||
// the file was found
|
||||
return (
|
||||
this._activateById(extensionId, { startup: true, extensionId, activationEvent: `workspaceContains:${fileName}` })
|
||||
.then(undefined, err => this._logService.error(err))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async _activateIfGlobPatterns(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, globPatterns: string[]): Promise<void> {
|
||||
this._logService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId.value}, entryPoint: workspaceContains`);
|
||||
|
||||
if (globPatterns.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const searchP = this._mainThreadWorkspaceProxy.$checkExists(folders.map(folder => folder.uri), globPatterns, tokenSource.token);
|
||||
|
||||
const timer = setTimeout(async () => {
|
||||
tokenSource.cancel();
|
||||
this._activateById(extensionId, { startup: true, extensionId, activationEvent: `workspaceContainsTimeout:${globPatterns.join(',')}` })
|
||||
.then(undefined, err => this._logService.error(err));
|
||||
}, AbstractExtHostExtensionService.WORKSPACE_CONTAINS_TIMEOUT);
|
||||
|
||||
let exists: boolean = false;
|
||||
try {
|
||||
exists = await searchP;
|
||||
} catch (err) {
|
||||
if (!errors.isPromiseCanceledError(err)) {
|
||||
this._logService.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
clearTimeout(timer);
|
||||
|
||||
if (exists) {
|
||||
// a file was found matching one of the glob patterns
|
||||
return (
|
||||
this._activateById(extensionId, { startup: true, extensionId, activationEvent: `workspaceContains:${globPatterns.join(',')}` })
|
||||
.then(undefined, err => this._logService.error(err))
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
return (
|
||||
this._activateById(desc.identifier, { startup: true, extensionId: desc.identifier, activationEvent: result.activationEvent })
|
||||
.then(undefined, err => this._logService.error(err))
|
||||
);
|
||||
}
|
||||
|
||||
private _handleExtensionTests(): Promise<void> {
|
||||
|
||||
105
src/vs/workbench/api/common/shared/workspaceContains.ts
Normal file
105
src/vs/workbench/api/common/shared/workspaceContains.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
const WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
|
||||
export interface IExtensionActivationHost {
|
||||
readonly folders: readonly UriComponents[];
|
||||
readonly forceUsingSearch: boolean;
|
||||
|
||||
exists(path: string): Promise<boolean>;
|
||||
checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface IExtensionActivationResult {
|
||||
activationEvent: string;
|
||||
}
|
||||
|
||||
export function checkActivateWorkspaceContainsExtension(host: IExtensionActivationHost, desc: IExtensionDescription): Promise<IExtensionActivationResult | undefined> {
|
||||
const activationEvents = desc.activationEvents;
|
||||
if (!activationEvents) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
const globPatterns: string[] = [];
|
||||
|
||||
for (const activationEvent of activationEvents) {
|
||||
if (/^workspaceContains:/.test(activationEvent)) {
|
||||
const fileNameOrGlob = activationEvent.substr('workspaceContains:'.length);
|
||||
if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0 || host.forceUsingSearch) {
|
||||
globPatterns.push(fileNameOrGlob);
|
||||
} else {
|
||||
fileNames.push(fileNameOrGlob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileNames.length === 0 && globPatterns.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
let resolveResult: (value: IExtensionActivationResult | undefined) => void;
|
||||
const result = new Promise<IExtensionActivationResult | undefined>((resolve, reject) => { resolveResult = resolve; });
|
||||
const activate = (activationEvent: string) => resolveResult({ activationEvent });
|
||||
|
||||
const fileNamePromise = Promise.all(fileNames.map((fileName) => _activateIfFileName(host, fileName, activate))).then(() => { });
|
||||
const globPatternPromise = _activateIfGlobPatterns(host, desc.identifier, globPatterns, activate);
|
||||
|
||||
Promise.all([fileNamePromise, globPatternPromise]).then(() => {
|
||||
// when all are done, resolve with undefined (relevant only if it was not activated so far)
|
||||
resolveResult(undefined);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function _activateIfFileName(host: IExtensionActivationHost, fileName: string, activate: (activationEvent: string) => void): Promise<void> {
|
||||
// find exact path
|
||||
for (const uri of host.folders) {
|
||||
if (await host.exists(path.join(URI.revive(uri).fsPath, fileName))) {
|
||||
// the file was found
|
||||
activate(`workspaceContains:${fileName}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function _activateIfGlobPatterns(host: IExtensionActivationHost, extensionId: ExtensionIdentifier, globPatterns: string[], activate: (activationEvent: string) => void): Promise<void> {
|
||||
if (globPatterns.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const searchP = host.checkExists(host.folders, globPatterns, tokenSource.token);
|
||||
|
||||
const timer = setTimeout(async () => {
|
||||
tokenSource.cancel();
|
||||
activate(`workspaceContainsTimeout:${globPatterns.join(',')}`);
|
||||
}, WORKSPACE_CONTAINS_TIMEOUT);
|
||||
|
||||
let exists: boolean = false;
|
||||
try {
|
||||
exists = await searchP;
|
||||
} catch (err) {
|
||||
if (!errors.isPromiseCanceledError(err)) {
|
||||
errors.onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
clearTimeout(timer);
|
||||
|
||||
if (exists) {
|
||||
// a file was found matching one of the glob patterns
|
||||
activate(`workspaceContains:${globPatterns.join(',')}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user