Merge from vscode 1b314ab317fbff7d799b21754326b7d849889ceb

This commit is contained in:
ADS Merger
2020-07-15 23:51:18 +00:00
parent aae013d498
commit 9d3f12d0b7
554 changed files with 15159 additions and 8223 deletions

View File

@@ -76,6 +76,7 @@ import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentica
import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline';
import { ExtHostNotebookConcatDocument } from 'vs/workbench/api/common/extHostNotebookConcatDocument';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
@@ -88,6 +89,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// services
const initData = accessor.get(IExtHostInitDataService);
const extHostConsumerFileSystem = accessor.get(IExtHostConsumerFileSystem);
const extensionService = accessor.get(IExtHostExtensionService);
const extHostWorkspace = accessor.get(IExtHostWorkspace);
const extHostConfiguration = accessor.get(IExtHostConfiguration);
@@ -203,6 +205,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get providerIds(): string[] {
return extHostAuthentication.providerIds;
},
get providers(): ReadonlyArray<vscode.AuthenticationProviderInformation> {
return extHostAuthentication.providers;
},
hasSessions(providerId: string, scopes: string[]): Thenable<boolean> {
return extHostAuthentication.hasSessions(providerId, scopes);
},
@@ -212,7 +217,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
logout(providerId: string, sessionId: string): Thenable<void> {
return extHostAuthentication.logout(providerId, sessionId);
},
get onDidChangeSessions(): Event<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }> {
get onDidChangeSessions(): Event<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent> {
return extHostAuthentication.onDidChangeSessions;
},
};
@@ -269,7 +274,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get sessionId() { return initData.telemetryInfo.sessionId; },
get language() { return initData.environment.appLanguage; },
get appName() { return initData.environment.appName; },
get appRoot() { return initData.environment.appRoot?.fsPath ?? '<UNKNOWN_APP_ROOT>'; },
get appRoot() { return initData.environment.appRoot?.fsPath ?? ''; },
get uriScheme() { return initData.environment.appUriScheme; },
get logLevel() {
checkProposedApiEnabled(extension);
@@ -746,7 +751,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
},
get fs() {
return extHostFileSystem.fileSystem;
return extHostConsumerFileSystem;
},
registerFileSearchProvider: (scheme: string, provider: vscode.FileSearchProvider) => {
checkProposedApiEnabled(extension);
@@ -878,6 +883,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
},
stopDebugging(session: vscode.DebugSession | undefined) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
},
addBreakpoints(breakpoints: vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;

View File

@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtHostOutputService, ExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostWorkspace, ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { IExtHostDecorations, ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
import { IExtHostConfiguration, ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
// import { IExtHostTask, WorkerExtHostTask } from 'vs/workbench/api/common/extHostTask';
// import { IExtHostDebugService, WorkerExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostSearch, ExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { IExtensionStoragePaths, ExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { ExtHostConsumerFileSystem, IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
registerSingleton(IExtHostCommands, ExtHostCommands);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostConsumerFileSystem, ExtHostConsumerFileSystem);
// registerSingleton(IExtHostDebugService, WorkerExtHostDebugService);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostOutputService, ExtHostOutputService);
registerSingleton(IExtHostSearch, ExtHostSearch);
registerSingleton(IExtHostStorage, ExtHostStorage);
// registerSingleton(IExtHostTask, WorkerExtHostTask);
registerSingleton(IExtHostTerminalService, WorkerExtHostTerminalService);
registerSingleton(IExtHostTunnelService, ExtHostTunnelService);
registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);

View File

@@ -67,11 +67,10 @@ export interface IEnvironment {
appRoot?: URI;
appLanguage: string;
appUriScheme: string;
appSettingsHome?: URI;
extensionDevelopmentLocationURI?: URI[];
extensionTestsLocationURI?: URI;
globalStorageHome: URI;
userHome: URI;
workspaceStorageHome: URI;
webviewResourceRoot: string;
webviewCspSource: string;
useHostProxy?: boolean;
@@ -162,7 +161,7 @@ export interface MainThreadCommentsShape extends IDisposable {
}
export interface MainThreadAuthenticationShape extends IDisposable {
$registerAuthenticationProvider(id: string, displayName: string, supportsMultipleAccounts: boolean): void;
$registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): void;
$unregisterAuthenticationProvider(id: string): void;
$getProviderIds(): Promise<string[]>;
$sendDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
@@ -206,8 +205,8 @@ export interface MainThreadDialogSaveOptions {
}
export interface MainThreadDiaglogsShape extends IDisposable {
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<UriComponents[] | undefined>;
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<UriComponents | undefined>;
$showOpenDialog(options?: MainThreadDialogOpenOptions): Promise<UriComponents[] | undefined>;
$showSaveDialog(options?: MainThreadDialogSaveOptions): Promise<UriComponents | undefined>;
}
export interface MainThreadDecorationsShape extends IDisposable {
@@ -738,7 +737,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>;
@@ -784,7 +783,7 @@ export interface MainThreadTaskShape extends IDisposable {
$unregisterTaskProvider(handle: number): Promise<void>;
$fetchTasks(filter?: tasks.TaskFilterDTO): Promise<tasks.TaskDTO[]>;
$getTaskExecution(value: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
$executeTask(task: tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
$executeTask(task: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
$terminateTask(id: string): Promise<void>;
$registerTaskSystem(scheme: string, info: tasks.TaskSystemInfoDTO): void;
$customExecutionComplete(id: string, result?: number): Promise<void>;
@@ -862,7 +861,7 @@ export interface IStartDebuggingOptions {
parentSessionID?: DebugSessionUUID;
repl?: IDebugSessionReplMode;
noDebug?: boolean;
noCompact?: boolean;
compact?: boolean;
}
export interface MainThreadDebugServiceShape extends IDisposable {
@@ -876,8 +875,10 @@ export interface MainThreadDebugServiceShape extends IDisposable {
$unregisterDebugConfigurationProvider(handle: number): void;
$unregisterDebugAdapterDescriptorFactory(handle: number): void;
$startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, options: IStartDebuggingOptions): Promise<boolean>;
$stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void>;
$setDebugSessionName(id: DebugSessionUUID, name: string): void;
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
$terminateDebugSession(id: DebugSessionUUID): Promise<void>;
$appendDebugConsole(value: string): void;
$startBreakpointEvents(): void;
$registerBreakpoints(breakpoints: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>): Promise<void>;
@@ -1029,8 +1030,8 @@ export interface ExtHostAuthenticationShape {
$getSessionAccessToken(id: string, sessionId: string): Promise<string>;
$login(id: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$logout(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): Promise<void>;
$onDidChangeAuthenticationProviders(added: string[], removed: string[]): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise<void>;
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]): Promise<void>;
}
export interface ExtHostSearchShape {
@@ -1455,6 +1456,7 @@ export interface ExtHostTaskShape {
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string; }, variables: string[]; }): Promise<{ process?: string; variables: { [key: string]: string; }; }>;
$getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined; }>;
$jsonTasksSupported(): Thenable<boolean>;
$findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string | undefined>;
}
export interface IBreakpointDto {

View File

@@ -14,11 +14,15 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private _proxy: MainThreadAuthenticationShape;
private _authenticationProviders: Map<string, vscode.AuthenticationProvider> = new Map<string, vscode.AuthenticationProvider>();
private _providerIds: string[] = [];
private _providers: vscode.AuthenticationProviderInformation[] = [];
private _onDidChangeAuthenticationProviders = new Emitter<vscode.AuthenticationProvidersChangeEvent>();
readonly onDidChangeAuthenticationProviders: Event<vscode.AuthenticationProvidersChangeEvent> = this._onDidChangeAuthenticationProviders.event;
private _onDidChangeSessions = new Emitter<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }>();
readonly onDidChangeSessions: Event<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }> = this._onDidChangeSessions.event;
private _onDidChangeSessions = new Emitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
readonly onDidChangeSessions: Event<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent> = this._onDidChangeSessions.event;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.getProxy(MainContext.MainThreadAuthentication);
@@ -29,12 +33,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
get providerIds(): string[] {
const ids: string[] = [];
this._authenticationProviders.forEach(provider => {
ids.push(provider.id);
});
return this._providerIds;
}
return ids;
get providers(): ReadonlyArray<vscode.AuthenticationProviderInformation> {
return Object.freeze(this._providers);
}
private async resolveSessions(providerId: string): Promise<ReadonlyArray<modes.AuthenticationSession>> {
@@ -53,7 +56,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
async hasSessions(providerId: string, scopes: string[]): Promise<boolean> {
const orderedScopes = scopes.sort().join(' ');
const sessions = await this.resolveSessions(providerId);
return !!(sessions.filter(session => session.scopes.sort().join(' ') === orderedScopes).length);
return !!(sessions.filter(session => session.scopes.slice().sort().join(' ') === orderedScopes).length);
}
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession>;
@@ -67,12 +70,12 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
const orderedScopes = scopes.sort().join(' ');
const sessions = (await provider.getSessions()).filter(session => session.scopes.sort().join(' ') === orderedScopes);
const sessions = (await provider.getSessions()).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
if (sessions.length) {
if (!provider.supportsMultipleAccounts) {
const session = sessions[0];
const allowed = await this._proxy.$getSessionsPrompt(providerId, session.account.displayName, provider.displayName, extensionId, extensionName);
const allowed = await this._proxy.$getSessionsPrompt(providerId, session.account.label, provider.label, extensionId, extensionName);
if (allowed) {
return session;
} else {
@@ -81,17 +84,17 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
// On renderer side, confirm consent, ask user to choose between accounts if multiple sessions are valid
const selected = await this._proxy.$selectSession(providerId, provider.displayName, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
const selected = await this._proxy.$selectSession(providerId, provider.label, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
return sessions.find(session => session.id === selected.id);
} else {
if (options.createIfNone) {
const isAllowed = await this._proxy.$loginPrompt(provider.displayName, extensionName);
const isAllowed = await this._proxy.$loginPrompt(provider.label, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
const session = await provider.login(scopes);
await this._proxy.$setTrustedExtension(providerId, session.account.displayName, extensionId, extensionName);
await this._proxy.$setTrustedExtension(providerId, session.account.label, extensionId, extensionName);
return session;
} else {
await this._proxy.$requestNewSession(providerId, scopes, extensionId, extensionName);
@@ -115,16 +118,36 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
this._authenticationProviders.set(provider.id, provider);
if (!this._providerIds.includes(provider.id)) {
this._providerIds.push(provider.id);
}
if (!this._providers.find(p => p.id === provider.id)) {
this._providers.push({
id: provider.id,
label: provider.label
});
}
const listener = provider.onDidChangeSessions(e => {
this._proxy.$sendDidChangeSessions(provider.id, e);
});
this._proxy.$registerAuthenticationProvider(provider.id, provider.displayName, provider.supportsMultipleAccounts);
this._proxy.$registerAuthenticationProvider(provider.id, provider.label, provider.supportsMultipleAccounts);
return new Disposable(() => {
listener.dispose();
this._authenticationProviders.delete(provider.id);
const index = this._providerIds.findIndex(id => id === provider.id);
if (index > -1) {
this._providerIds.splice(index);
}
const i = this._providers.findIndex(p => p.id === provider.id);
if (i > -1) {
this._providers.splice(i);
}
this._proxy.$unregisterAuthenticationProvider(provider.id);
});
}
@@ -171,12 +194,25 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$onDidChangeAuthenticationSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent) {
this._onDidChangeSessions.fire({ [providerId]: event });
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent) {
this._onDidChangeSessions.fire({ provider: { id, label }, ...event });
return Promise.resolve();
}
$onDidChangeAuthenticationProviders(added: string[], removed: string[]) {
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]) {
added.forEach(id => {
if (!this._providers.includes(id)) {
this._providers.push(id);
}
});
removed.forEach(p => {
const index = this._providers.findIndex(provider => provider.id === p.id);
if (index > -1) {
this._providers.splice(index);
}
});
this._onDidChangeAuthenticationProviders.fire({ added, removed });
return Promise.resolve();
}

View File

@@ -51,6 +51,7 @@ export interface IExtHostDebugService extends ExtHostDebugServiceShape {
addBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void>;
removeBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void>;
startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean>;
stopDebugging(session: vscode.DebugSession | undefined): Promise<void>;
registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable;
registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable;
registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable;
@@ -297,10 +298,14 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
parentSessionID: options.parentSession ? options.parentSession.id : undefined,
repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate',
noDebug: options.noDebug,
noCompact: options.noCompact
compact: options.compact
});
}
public stopDebugging(session: vscode.DebugSession | undefined): Promise<void> {
return this._debugServiceProxy.$stopDebugging(session ? session.id : undefined);
}
public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable {
if (!provider) {
@@ -952,6 +957,10 @@ export class ExtHostDebugSession implements vscode.DebugSession {
public customRequest(command: string, args: any): Promise<any> {
return this._debugServiceProxy.$customDebugAdapterRequest(this._id, command, args);
}
public terminate(): Promise<void> {
return this._debugServiceProxy.$terminateDebugSession(this._id);
}
}
export class ExtHostDebugConsole implements vscode.DebugConsole {

View File

@@ -15,13 +15,13 @@ export class ExtHostDialogs {
this._proxy = mainContext.getProxy(MainContext.MainThreadDialogs);
}
showOpenDialog(options: vscode.OpenDialogOptions): Promise<URI[] | undefined> {
showOpenDialog(options?: vscode.OpenDialogOptions): Promise<URI[] | undefined> {
return this._proxy.$showOpenDialog(options).then(filepaths => {
return filepaths ? filepaths.map(p => URI.revive(p)) : undefined;
});
}
showSaveDialog(options: vscode.SaveDialogOptions): Promise<URI | undefined> {
showSaveDialog(options?: vscode.SaveDialogOptions): Promise<URI | undefined> {
return this._proxy.$showSaveDialog(options).then(filepath => {
return filepath ? URI.revive(filepath) : undefined;
});

View File

@@ -16,9 +16,8 @@ import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/co
import { ActivatedExtension, EmptyExtension, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionActivationError, checkProposedApiEnabled } 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;
@@ -387,10 +386,22 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
subscriptions: [],
get extensionUri() { return extensionDescription.extensionLocation; },
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
asAbsolutePath(relativePath: string) { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
get storagePath() { return that._storagePath.workspaceValue(extensionDescription)?.fsPath; },
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription).fsPath; },
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
get logUri() {
checkProposedApiEnabled(extensionDescription);
return URI.joinPath(that._initData.logsLocation, extensionDescription.identifier.value);
},
get storageUri() {
checkProposedApiEnabled(extensionDescription);
return that._storagePath.workspaceValue(extensionDescription);
},
get globalStorageUri() {
checkProposedApiEnabled(extensionDescription);
return that._storagePath.globalValue(extensionDescription);
},
get extensionMode() { return extensionMode; },
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
});
@@ -486,94 +497,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> {

View File

@@ -8,7 +8,7 @@ import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystem
import type * as vscode from 'vscode';
import * as files from 'vs/platform/files/common/files';
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
import { FileChangeType, FileSystemError } from 'vs/workbench/api/common/extHostTypes';
import { FileChangeType } from 'vs/workbench/api/common/extHostTypes';
import * as typeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { Schemas } from 'vs/base/common/network';
@@ -108,59 +108,6 @@ class FsLinkProvider {
}
}
class ConsumerFileSystem implements vscode.FileSystem {
constructor(private _proxy: MainThreadFileSystemShape) { }
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
return this._proxy.$stat(uri).catch(ConsumerFileSystem._handleError);
}
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
return this._proxy.$readdir(uri).catch(ConsumerFileSystem._handleError);
}
createDirectory(uri: vscode.Uri): Promise<void> {
return this._proxy.$mkdir(uri).catch(ConsumerFileSystem._handleError);
}
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
return this._proxy.$readFile(uri).then(buff => buff.buffer).catch(ConsumerFileSystem._handleError);
}
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
return this._proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ConsumerFileSystem._handleError);
}
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
return this._proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ConsumerFileSystem._handleError);
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return this._proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ConsumerFileSystem._handleError);
}
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean }): Promise<void> {
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ConsumerFileSystem._handleError);
}
private static _handleError(err: any): never {
// generic error
if (!(err instanceof Error)) {
throw new FileSystemError(String(err));
}
// no provider (unknown scheme) error
if (err.name === 'ENOPRO') {
throw FileSystemError.Unavailable(err.message);
}
// file system error
switch (err.name) {
case files.FileSystemProviderErrorCode.FileExists: throw FileSystemError.FileExists(err.message);
case files.FileSystemProviderErrorCode.FileNotFound: throw FileSystemError.FileNotFound(err.message);
case files.FileSystemProviderErrorCode.FileNotADirectory: throw FileSystemError.FileNotADirectory(err.message);
case files.FileSystemProviderErrorCode.FileIsADirectory: throw FileSystemError.FileIsADirectory(err.message);
case files.FileSystemProviderErrorCode.NoPermissions: throw FileSystemError.NoPermissions(err.message);
case files.FileSystemProviderErrorCode.Unavailable: throw FileSystemError.Unavailable(err.message);
default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
}
}
}
export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
@@ -172,11 +119,8 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
private _linkProviderRegistration?: IDisposable;
private _handlePool: number = 0;
readonly fileSystem: vscode.FileSystem;
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) {
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
this.fileSystem = new ConsumerFileSystem(this._proxy);
// register used schemes
Object.keys(Schemas).forEach(scheme => this._usedSchemes.add(scheme));

View File

@@ -0,0 +1,74 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MainThreadFileSystemShape, MainContext } from './extHost.protocol';
import * as vscode from 'vscode';
import * as files from 'vs/platform/files/common/files';
import { FileSystemError } from 'vs/workbench/api/common/extHostTypes';
import { VSBuffer } from 'vs/base/common/buffer';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
export class ExtHostConsumerFileSystem implements vscode.FileSystem {
readonly _serviceBrand: undefined;
private readonly _proxy: MainThreadFileSystemShape;
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem);
}
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
return this._proxy.$stat(uri).catch(ExtHostConsumerFileSystem._handleError);
}
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
return this._proxy.$readdir(uri).catch(ExtHostConsumerFileSystem._handleError);
}
createDirectory(uri: vscode.Uri): Promise<void> {
return this._proxy.$mkdir(uri).catch(ExtHostConsumerFileSystem._handleError);
}
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
return this._proxy.$readFile(uri).then(buff => buff.buffer).catch(ExtHostConsumerFileSystem._handleError);
}
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
return this._proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ExtHostConsumerFileSystem._handleError);
}
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
return this._proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return this._proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
private static _handleError(err: any): never {
// generic error
if (!(err instanceof Error)) {
throw new FileSystemError(String(err));
}
// no provider (unknown scheme) error
if (err.name === 'ENOPRO') {
throw FileSystemError.Unavailable(err.message);
}
// file system error
switch (err.name) {
case files.FileSystemProviderErrorCode.FileExists: throw FileSystemError.FileExists(err.message);
case files.FileSystemProviderErrorCode.FileNotFound: throw FileSystemError.FileNotFound(err.message);
case files.FileSystemProviderErrorCode.FileNotADirectory: throw FileSystemError.FileNotADirectory(err.message);
case files.FileSystemProviderErrorCode.FileIsADirectory: throw FileSystemError.FileIsADirectory(err.message);
case files.FileSystemProviderErrorCode.NoPermissions: throw FileSystemError.NoPermissions(err.message);
case files.FileSystemProviderErrorCode.Unavailable: throw FileSystemError.Unavailable(err.message);
default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
}
}
}
export interface IExtHostConsumerFileSystem extends ExtHostConsumerFileSystem { }
export const IExtHostConsumerFileSystem = createDecorator<IExtHostConsumerFileSystem>('IExtHostConsumerFileSystem');

View File

@@ -1020,7 +1020,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
if (provider) {
let storageRoot: URI | undefined;
if (this._extensionStoragePaths) {
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension));
storageRoot = this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension);
}
let document = this._documents.get(URI.revive(uri).toString());
@@ -1330,7 +1330,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const entry = this._notebookContentProviders.get(viewType);
let storageRoot: URI | undefined;
if (entry && this._extensionStoragePaths) {
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension);
}
if (!this._documents.has(revivedUriStr)) {

View File

@@ -117,6 +117,11 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
this.update();
}
public set accessibilityInformation(accessibilityInformation: vscode.AccessibilityInformation | undefined) {
this._accessibilityInformation = accessibilityInformation;
this.update();
}
public show(): void {
this._visible = true;
this.update();

View File

@@ -5,12 +5,83 @@
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironment, IStaticWorkspaceData } from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { URI } from 'vs/base/common/uri';
export const IExtensionStoragePaths = createDecorator<IExtensionStoragePaths>('IExtensionStoragePaths');
export interface IExtensionStoragePaths {
readonly _serviceBrand: undefined;
whenReady: Promise<any>;
workspaceValue(extension: IExtensionDescription): string | undefined;
globalValue(extension: IExtensionDescription): string;
workspaceValue(extension: IExtensionDescription): URI | undefined;
globalValue(extension: IExtensionDescription): URI;
}
export class ExtensionStoragePaths implements IExtensionStoragePaths {
readonly _serviceBrand: undefined;
private readonly _workspace?: IStaticWorkspaceData;
private readonly _environment: IEnvironment;
readonly whenReady: Promise<URI | undefined>;
private _value?: URI;
constructor(
@IExtHostInitDataService initData: IExtHostInitDataService,
@ILogService private readonly _logService: ILogService,
@IExtHostConsumerFileSystem private readonly _extHostFileSystem: IExtHostConsumerFileSystem
) {
this._workspace = initData.workspace ?? undefined;
this._environment = initData.environment;
this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
}
private async _getOrCreateWorkspaceStoragePath(): Promise<URI | undefined> {
if (!this._workspace) {
return Promise.resolve(undefined);
}
const storageName = this._workspace.id;
const storageUri = URI.joinPath(this._environment.workspaceStorageHome, storageName);
try {
await this._extHostFileSystem.stat(storageUri);
this._logService.trace('[ExtHostStorage] storage dir already exists', storageUri);
return storageUri;
} catch {
// doesn't exist, that's OK
}
try {
this._logService.trace('[ExtHostStorage] creating dir and metadata-file', storageUri);
await this._extHostFileSystem.createDirectory(storageUri);
await this._extHostFileSystem.writeFile(
URI.joinPath(storageUri, 'meta.json'),
new TextEncoder().encode(JSON.stringify({
id: this._workspace.id,
configuration: URI.revive(this._workspace.configuration)?.toString(),
name: this._workspace.name
}, undefined, 2))
);
return storageUri;
} catch (e) {
this._logService.error('[ExtHostStorage]', e);
return undefined;
}
}
workspaceValue(extension: IExtensionDescription): URI | undefined {
if (this._value) {
return URI.joinPath(this._value, extension.identifier.value);
}
return undefined;
}
globalValue(extension: IExtensionDescription): URI {
return URI.joinPath(this._environment.globalStorageHome, extension.identifier.value.toLowerCase());
}
}

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { URI, UriComponents } from 'vs/base/common/uri';
import * as Objects from 'vs/base/common/objects';
import { asPromise } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
@@ -27,6 +26,7 @@ import * as Platform from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { USER_TASKS_GROUP_KEY } from 'vs/workbench/contrib/tasks/common/taskService';
import { NotSupportedError } from 'vs/base/common/errors';
export interface IExtHostTask extends ExtHostTaskShape {
@@ -325,7 +325,7 @@ export namespace TaskFilterDTO {
if (!value) {
return undefined;
}
return Objects.assign(Object.create(null), value);
return Object.assign(Object.create(null), value);
}
}
@@ -371,7 +371,7 @@ export interface HandlerData {
extension: IExtensionDescription;
}
export abstract class ExtHostTaskBase implements ExtHostTaskShape {
export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask {
readonly _serviceBrand: undefined;
protected readonly _proxy: MainThreadTaskShape;
@@ -679,7 +679,9 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape {
}
}
public abstract async $jsonTasksSupported(): Promise<boolean>;
public abstract $jsonTasksSupported(): Promise<boolean>;
public abstract $findExecutable(command: string, cwd?: string | undefined, paths?: string[] | undefined): Promise<string | undefined>;
}
export class WorkerExtHostTask extends ExtHostTaskBase {
@@ -715,7 +717,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
if (CustomExecutionDTO.is(dto.execution)) {
await this.addCustomExecution(dto, task, false);
} else {
throw new Error('Not implemented');
throw new NotSupportedError();
}
// Always get the task execution first to prevent timing issues when retrieving it later
@@ -775,6 +777,10 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
public async $jsonTasksSupported(): Promise<boolean> {
return false;
}
public async $findExecutable(command: string, cwd?: string | undefined, paths?: string[] | undefined): Promise<string | undefined> {
return undefined;
}
}
export const IExtHostTask = createDecorator<IExtHostTask>('IExtHostTask');

View File

@@ -18,6 +18,8 @@ import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from '
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { localize } from 'vs/nls';
import { NotSupportedError } from 'vs/base/common/errors';
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
@@ -312,6 +314,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
protected _terminalProcessDisposables: { [id: number]: IDisposable } = {};
protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
private readonly _bufferer: TerminalDataBufferer;
private readonly _linkHandlers: Set<vscode.TerminalLinkHandler> = new Set();
@@ -351,8 +354,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
public abstract $getAvailableShells(): Promise<IShellDefinitionDto[]>;
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
public abstract getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
public abstract $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options, options.name);
@@ -625,11 +626,10 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
for (const provideResult of provideResults) {
if (provideResult && provideResult.links.length > 0) {
result.push(...provideResult.links.map(providerLink => {
const endIndex = Math.max(providerLink.endIndex, providerLink.startIndex + 1);
const link = {
id: nextLinkId++,
startIndex: providerLink.startIndex,
length: endIndex - providerLink.startIndex,
length: providerLink.length,
label: providerLink.tooltip
};
cacheLinkMap.set(link.id, {
@@ -719,6 +719,39 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
});
return index;
}
public getEnvironmentVariableCollection(extension: IExtensionDescription): vscode.EnvironmentVariableCollection {
let collection = this._environmentVariableCollections.get(extension.identifier.value);
if (!collection) {
collection = new EnvironmentVariableCollection();
this._setEnvironmentVariableCollection(extension.identifier.value, collection);
}
return collection;
}
private _syncEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
const serialized = serializeEnvironmentVariableCollection(collection.map);
this._proxy.$setEnvironmentVariableCollection(extensionIdentifier, collection.persistent, serialized.length === 0 ? undefined : serialized);
}
public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
collections.forEach(entry => {
const extensionIdentifier = entry[0];
const collection = new EnvironmentVariableCollection(entry[1]);
this._setEnvironmentVariableCollection(extensionIdentifier, collection);
});
}
private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
this._environmentVariableCollections.set(extensionIdentifier, collection);
collection.onDidChangeCollection(() => {
// When any collection value changes send this immediately, this is done to ensure
// following calls to createTerminal will be created with the new environment. It will
// result in more noise by sending multiple updates when called but collections are
// expected to be small.
this._syncEnvironmentVariableCollection(extensionIdentifier, collection!);
});
}
}
export class EnvironmentVariableCollection implements vscode.EnvironmentVariableCollection {
@@ -785,43 +818,35 @@ export class EnvironmentVariableCollection implements vscode.EnvironmentVariable
export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
throw new Error('Not implemented');
throw new NotSupportedError();
}
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
throw new Error('Not implemented');
throw new NotSupportedError();
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
throw new Error('Not implemented');
// Return the empty string to avoid throwing
return '';
}
public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
throw new Error('Not implemented');
throw new NotSupportedError();
}
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined> {
throw new Error('Not implemented');
throw new NotSupportedError();
}
public $getAvailableShells(): Promise<IShellDefinitionDto[]> {
throw new Error('Not implemented');
throw new NotSupportedError();
}
public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
throw new Error('Not implemented');
throw new NotSupportedError();
}
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
// No-op for web worker ext host as workspace permissions aren't used
}
public getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection {
// This is not implemented so worker ext host extensions cannot influence terminal envs
throw new Error('Not implemented');
}
public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
// No-op for web worker ext host as collections aren't used
}
}

View File

@@ -78,9 +78,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
}
const result = await provider.provideTimeline(uri, options, token);
// Intentional == we don't know how a provider will respond
// eslint-disable-next-line eqeqeq
if (result == null) {
if (result === undefined || result === null) {
return undefined;
}

View File

@@ -13,7 +13,7 @@ import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.proto
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions } from 'vs/workbench/common/views';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { asPromise } from 'vs/base/common/async';
import { TreeItemCollapsibleState, ThemeIcon } from 'vs/workbench/api/common/extHostTypes';
import { TreeItemCollapsibleState, ThemeIcon, MarkdownString as MarkdownStringType } from 'vs/workbench/api/common/extHostTypes';
import { isUndefinedOrNull, isString } from 'vs/base/common/types';
import { equals, coalesce } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
@@ -367,7 +367,7 @@ export class ExtHostTreeView<T> extends Disposable {
if (node) {
const resolve = await this.dataProvider.resolveTreeItem(element, node.extensionItem);
// Resolvable elements. Currently only tooltip.
node.item.tooltip = resolve.tooltip;
node.item.tooltip = this.getTooltip(resolve.tooltip);
return node.item;
}
}
@@ -538,14 +538,11 @@ export class ExtHostTreeView<T> extends Disposable {
}
private getTooltip(tooltip?: string | vscode.MarkdownString): string | IMarkdownString | undefined {
if (typeof tooltip === 'string') {
return tooltip;
} else if (tooltip === undefined) {
return undefined;
} else {
if (MarkdownStringType.isMarkdownString(tooltip)) {
checkProposedApiEnabled(this.extension);
return MarkdownString.from(tooltip);
}
return tooltip;
}
protected createTreeNode(element: T, extensionTreeItem: azdata.TreeItem2, parent: TreeNode | Root): TreeNode { // {{SQL CARBON EDIT}} change to protected, change to azdata.TreeItem

View File

@@ -1271,6 +1271,13 @@ export class MarkdownString {
this.value += '\n```\n';
return this;
}
static isMarkdownString(thing: any): thing is vscode.MarkdownString {
if (thing instanceof MarkdownString) {
return true;
}
return thing && thing.appendCodeblock && thing.appendMarkdown && thing.appendText && (thing.value !== undefined);
}
}
@es5ClassCompat
@@ -2770,7 +2777,7 @@ export enum ExtensionMode {
//#region Authentication
export class AuthenticationSession implements vscode.AuthenticationSession {
constructor(public id: string, public accessToken: string, public account: { displayName: string, id: string }, public scopes: string[]) { }
constructor(public id: string, public accessToken: string, public account: { label: string, id: string }, public scopes: string[]) { }
}
//#endregion Authentication

View File

@@ -598,7 +598,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
let storageRoot: URI | undefined;
if (this.supportEditing(entry.provider) && this._extensionStoragePaths) {
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension);
}
this._documents.add(viewType, document, storageRoot);

View File

@@ -345,7 +345,7 @@ namespace schema {
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `$(zap)`'),
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
anyOf: [{
type: 'string'
},

View File

@@ -0,0 +1,138 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. 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';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ISearchService } from 'vs/workbench/services/search/common/search';
import { toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
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(',')}`);
}
}
export function checkGlobFileExists(
accessor: ServicesAccessor,
folders: readonly UriComponents[],
includes: string[],
token: CancellationToken,
): Promise<boolean> {
const instantiationService = accessor.get(IInstantiationService);
const searchService = accessor.get(ISearchService);
const queryBuilder = instantiationService.createInstance(QueryBuilder);
const query = queryBuilder.file(folders.map(folder => toWorkspaceFolder(URI.revive(folder))), {
_reason: 'checkExists',
includePattern: includes.join(', '),
expandPatterns: true,
exists: true
});
return searchService.fileSearch(query, token).then(
result => {
return !!result.limitHit;
},
err => {
if (!errors.isPromiseCanceledError(err)) {
return Promise.reject(err);
}
return false;
});
}