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

@@ -75,7 +75,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
constructor(
private readonly _proxy: ExtHostAuthenticationShape,
public readonly id: string,
public readonly displayName: string,
public readonly label: string,
public readonly supportsMultipleAccounts: boolean,
private readonly notificationService: INotificationService,
private readonly storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
@@ -135,17 +135,17 @@ export class MainThreadAuthenticationProvider extends Disposable {
}
private registerSession(session: modes.AuthenticationSession) {
this._sessions.set(session.id, session.account.displayName);
this._sessions.set(session.id, session.account.label);
const existingSessionsForAccount = this._accounts.get(session.account.displayName);
const existingSessionsForAccount = this._accounts.get(session.account.label);
if (existingSessionsForAccount) {
this._accounts.set(session.account.displayName, existingSessionsForAccount.concat(session.id));
this._accounts.set(session.account.label, existingSessionsForAccount.concat(session.id));
return;
} else {
this._accounts.set(session.account.displayName, [session.id]);
this._accounts.set(session.account.label, [session.id]);
}
this.storageKeysSyncRegistryService.registerStorageKey({ key: `${this.id}-${session.account.displayName}`, version: 1 });
this.storageKeysSyncRegistryService.registerStorageKey({ key: `${this.id}-${session.account.label}`, version: 1 });
}
async signOut(accountName: string): Promise<void> {
@@ -219,15 +219,15 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostAuthentication);
this._register(this.authenticationService.onDidChangeSessions(e => {
this._proxy.$onDidChangeAuthenticationSessions(e.providerId, e.event);
this._proxy.$onDidChangeAuthenticationSessions(e.providerId, e.label, e.event);
}));
this._register(this.authenticationService.onDidRegisterAuthenticationProvider(providerId => {
this._proxy.$onDidChangeAuthenticationProviders([providerId], []);
this._register(this.authenticationService.onDidRegisterAuthenticationProvider(info => {
this._proxy.$onDidChangeAuthenticationProviders([info], []);
}));
this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(providerId => {
this._proxy.$onDidChangeAuthenticationProviders([], [providerId]);
this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(info => {
this._proxy.$onDidChangeAuthenticationProviders([], [info]);
}));
}
@@ -235,8 +235,8 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
return Promise.resolve(this.authenticationService.getProviderIds());
}
async $registerAuthenticationProvider(id: string, displayName: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new MainThreadAuthenticationProvider(this._proxy, id, displayName, supportsMultipleAccounts, this.notificationService, this.storageKeysSyncRegistryService, this.storageService, this.quickInputService, this.dialogService);
async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new MainThreadAuthenticationProvider(this._proxy, id, label, supportsMultipleAccounts, this.notificationService, this.storageKeysSyncRegistryService, this.storageService, this.quickInputService, this.dialogService);
await provider.initialize();
this.authenticationService.registerAuthenticationProvider(id, provider);
}
@@ -267,13 +267,13 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
const orderedScopes = scopes.sort().join(' ');
const sessions = (await this.$getSessions(providerId)).filter(session => session.scopes.sort().join(' ') === orderedScopes);
const displayName = this.authenticationService.getDisplayName(providerId);
const sessions = (await this.$getSessions(providerId)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
const label = this.authenticationService.getLabel(providerId);
if (sessions.length) {
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
const session = sessions[0];
const allowed = await this.$getSessionsPrompt(providerId, session.account.displayName, displayName, extensionId, extensionName);
const allowed = await this.$getSessionsPrompt(providerId, session.account.label, label, extensionId, extensionName);
if (allowed) {
return session;
} else {
@@ -282,17 +282,17 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
// On renderer side, confirm consent, ask user to choose between accounts if multiple sessions are valid
const selected = await this.$selectSession(providerId, displayName, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
const selected = await this.$selectSession(providerId, label, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
return sessions.find(session => session.id === selected.id);
} else {
if (options.createIfNone) {
const isAllowed = await this.$loginPrompt(displayName, extensionName);
const isAllowed = await this.$loginPrompt(label, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
const session = await this.authenticationService.login(providerId, scopes);
await this.$setTrustedExtension(providerId, session.account.displayName, extensionId, extensionName);
await this.$setTrustedExtension(providerId, session.account.label, extensionId, extensionName);
return session;
} else {
await this.$requestNewSession(providerId, scopes, extensionId, extensionName);
@@ -313,7 +313,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
if (existingSessionPreference) {
const matchingSession = potentialSessions.find(session => session.id === existingSessionPreference);
if (matchingSession) {
const allowed = await this.$getSessionsPrompt(providerId, matchingSession.account.displayName, providerName, extensionId, extensionName);
const allowed = await this.$getSessionsPrompt(providerId, matchingSession.account.label, providerName, extensionId, extensionName);
if (allowed) {
return matchingSession;
}
@@ -326,7 +326,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
quickPick.ignoreFocusOut = true;
const items: { label: string, session?: modes.AuthenticationSession }[] = potentialSessions.map(session => {
return {
label: session.account.displayName,
label: session.account.label,
session
};
});
@@ -351,7 +351,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
const session = selected.session ?? await this.authenticationService.login(providerId, scopes);
const accountName = session.account.displayName;
const accountName = session.account.label;
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {

View File

@@ -232,7 +232,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
noDebug: options.noDebug,
parentSession: this.getSession(options.parentSessionID),
repl: options.repl,
noCompact: options.noCompact
compact: options.compact
};
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions).then(success => {
return success;
@@ -262,6 +262,26 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return Promise.reject(new Error('debug session not found'));
}
public $terminateDebugSession(sessionId: DebugSessionUUID): Promise<void> {
const session = this.debugService.getModel().getSession(sessionId, true);
if (session) {
return session.terminate();
}
return Promise.reject(new Error('debug session not found'));
}
public $stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void> {
if (sessionId) {
const session = this.debugService.getModel().getSession(sessionId, true);
if (session) {
return this.debugService.stopSession(session);
}
} else { // stop all
return this.debugService.stopSession(undefined);
}
return Promise.reject(new Error('debug session not found'));
}
public $appendDebugConsole(value: string): void {
// Use warning as severity to get the orange color for messages coming from the debug extension
const session = this.debugService.getViewModel().focusedSession;

View File

@@ -23,37 +23,37 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
//
}
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<URI[] | undefined> {
$showOpenDialog(options?: MainThreadDialogOpenOptions): Promise<URI[] | undefined> {
return Promise.resolve(this._fileDialogService.showOpenDialog(MainThreadDialogs._convertOpenOptions(options)));
}
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<URI | undefined> {
$showSaveDialog(options?: MainThreadDialogSaveOptions): Promise<URI | undefined> {
return Promise.resolve(this._fileDialogService.showSaveDialog(MainThreadDialogs._convertSaveOptions(options)));
}
private static _convertOpenOptions(options: MainThreadDialogOpenOptions): IOpenDialogOptions {
private static _convertOpenOptions(options?: MainThreadDialogOpenOptions): IOpenDialogOptions {
const result: IOpenDialogOptions = {
openLabel: options.openLabel || undefined,
canSelectFiles: options.canSelectFiles || (!options.canSelectFiles && !options.canSelectFolders),
canSelectFolders: options.canSelectFolders,
canSelectMany: options.canSelectMany,
defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined,
title: options.title || undefined
openLabel: options?.openLabel || undefined,
canSelectFiles: options?.canSelectFiles || (!options?.canSelectFiles && !options?.canSelectFolders),
canSelectFolders: options?.canSelectFolders,
canSelectMany: options?.canSelectMany,
defaultUri: options?.defaultUri ? URI.revive(options.defaultUri) : undefined,
title: options?.title || undefined
};
if (options.filters) {
if (options?.filters) {
result.filters = [];
forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value }));
}
return result;
}
private static _convertSaveOptions(options: MainThreadDialogSaveOptions): ISaveDialogOptions {
private static _convertSaveOptions(options?: MainThreadDialogSaveOptions): ISaveDialogOptions {
const result: ISaveDialogOptions = {
defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined,
saveLabel: options.saveLabel || undefined,
title: options.title || undefined
defaultUri: options?.defaultUri ? URI.revive(options.defaultUri) : undefined,
saveLabel: options?.saveLabel || undefined,
title: options?.title || undefined
};
if (options.filters) {
if (options?.filters) {
result.filters = [];
forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value }));
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { IDisposable, IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { IReference, dispose, Disposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ITextModel } from 'vs/editor/common/model';
@@ -19,6 +19,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { toLocalResource, extUri, IExtUri } from 'vs/base/common/resources';
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { Emitter } from 'vs/base/common/event';
export class BoundModelReferenceCollection {
@@ -73,7 +74,36 @@ export class BoundModelReferenceCollection {
}
}
export class MainThreadDocuments implements MainThreadDocumentsShape {
class ModelTracker extends Disposable {
private _knownVersionId: number;
constructor(
private readonly _model: ITextModel,
private readonly _onIsCaughtUpWithContentChanges: Emitter<URI>,
private readonly _proxy: ExtHostDocumentsShape,
private readonly _textFileService: ITextFileService,
) {
super();
this._knownVersionId = this._model.getVersionId();
this._register(this._model.onDidChangeContent((e) => {
this._knownVersionId = e.versionId;
this._proxy.$acceptModelChanged(this._model.uri, e, this._textFileService.isDirty(this._model.uri));
if (this.isCaughtUpWithContentChanges()) {
this._onIsCaughtUpWithContentChanges.fire(this._model.uri);
}
}));
}
public isCaughtUpWithContentChanges(): boolean {
return (this._model.getVersionId() === this._knownVersionId);
}
}
export class MainThreadDocuments extends Disposable implements MainThreadDocumentsShape {
private _onIsCaughtUpWithContentChanges = this._register(new Emitter<URI>());
public readonly onIsCaughtUpWithContentChanges = this._onIsCaughtUpWithContentChanges.event;
private readonly _modelService: IModelService;
private readonly _textModelResolverService: ITextModelService;
@@ -82,8 +112,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
private readonly _environmentService: IWorkbenchEnvironmentService;
private readonly _uriIdentityService: IUriIdentityService;
private readonly _toDispose = new DisposableStore();
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
private _modelTrackers: { [modelUrl: string]: ModelTracker; };
private readonly _proxy: ExtHostDocumentsShape;
private readonly _modelIsSynced = new Set<string>();
private readonly _modelReferenceCollection: BoundModelReferenceCollection;
@@ -99,6 +128,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
@IUriIdentityService uriIdentityService: IUriIdentityService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService
) {
super();
this._modelService = modelService;
this._textModelResolverService = textModelResolverService;
this._textFileService = textFileService;
@@ -106,26 +136,26 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
this._environmentService = environmentService;
this._uriIdentityService = uriIdentityService;
this._modelReferenceCollection = this._toDispose.add(new BoundModelReferenceCollection(uriIdentityService.extUri));
this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(uriIdentityService.extUri));
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
this._toDispose.add(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
this._toDispose.add(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
this._toDispose.add(modelService.onModelModeChanged(this._onModelModeChanged, this));
this._register(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
this._register(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
this._register(modelService.onModelModeChanged(this._onModelModeChanged, this));
this._toDispose.add(textFileService.files.onDidSave(e => {
this._register(textFileService.files.onDidSave(e => {
if (this._shouldHandleFileEvent(e.model.resource)) {
this._proxy.$acceptModelSaved(e.model.resource);
}
}));
this._toDispose.add(textFileService.files.onDidChangeDirty(m => {
this._register(textFileService.files.onDidChangeDirty(m => {
if (this._shouldHandleFileEvent(m.resource)) {
this._proxy.$acceptDirtyStateChanged(m.resource, m.isDirty());
}
}));
this._toDispose.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => {
this._register(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => {
if (e.operation === FileOperation.MOVE || e.operation === FileOperation.DELETE) {
for (const { source } of e.files) {
if (source) {
@@ -135,15 +165,23 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
}
}));
this._modelToDisposeMap = Object.create(null);
this._modelTrackers = Object.create(null);
}
public dispose(): void {
Object.keys(this._modelToDisposeMap).forEach((modelUrl) => {
this._modelToDisposeMap[modelUrl].dispose();
Object.keys(this._modelTrackers).forEach((modelUrl) => {
this._modelTrackers[modelUrl].dispose();
});
this._modelToDisposeMap = Object.create(null);
this._toDispose.dispose();
this._modelTrackers = Object.create(null);
super.dispose();
}
public isCaughtUpWithContentChanges(resource: URI): boolean {
const modelUrl = resource.toString();
if (this._modelTrackers[modelUrl]) {
return this._modelTrackers[modelUrl].isCaughtUpWithContentChanges();
}
return true;
}
private _shouldHandleFileEvent(resource: URI): boolean {
@@ -159,9 +197,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
}
const modelUrl = model.uri;
this._modelIsSynced.add(modelUrl.toString());
this._modelToDisposeMap[modelUrl.toString()] = model.onDidChangeContent((e) => {
this._proxy.$acceptModelChanged(modelUrl, e, this._textFileService.isDirty(modelUrl));
});
this._modelTrackers[modelUrl.toString()] = new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService);
}
private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void {
@@ -179,8 +215,8 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
return;
}
this._modelIsSynced.delete(strModelUrl);
this._modelToDisposeMap[strModelUrl].dispose();
delete this._modelToDisposeMap[strModelUrl];
this._modelTrackers[strModelUrl].dispose();
delete this._modelTrackers[strModelUrl];
}
// --- from extension host process

View File

@@ -306,6 +306,7 @@ export class MainThreadDocumentsAndEditors {
private readonly _toDispose = new DisposableStore();
private readonly _proxy: ExtHostDocumentsAndEditorsShape;
private readonly _mainThreadDocuments: MainThreadDocuments;
private readonly _textEditors = new Map<string, MainThreadTextEditor>();
private readonly _onTextEditorAdd = new Emitter<MainThreadTextEditor[]>();
@@ -336,8 +337,8 @@ export class MainThreadDocumentsAndEditors {
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
const mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, this._textFileService, fileService, textModelResolverService, environmentService, uriIdentityService, workingCopyFileService));
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
this._mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, this._textFileService, fileService, textModelResolverService, environmentService, uriIdentityService, workingCopyFileService));
extHostContext.set(MainContext.MainThreadDocuments, this._mainThreadDocuments);
const mainThreadTextEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService));
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
@@ -367,7 +368,7 @@ export class MainThreadDocumentsAndEditors {
// added editors
for (const apiEditor of delta.addedEditors) {
const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.editor.getModel(),
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService, this._clipboardService);
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._mainThreadDocuments, this._modelService, this._clipboardService);
this._textEditors.set(apiEditor.id, mainThreadEditor);
addedEditors.push(mainThreadEditor);

View File

@@ -20,6 +20,7 @@ import { equals } from 'vs/base/common/arrays';
import { CodeEditorStateFlag, EditorState } from 'vs/editor/browser/core/editorState';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
import { MainThreadDocuments } from 'vs/workbench/api/browser/mainThreadDocuments';
export interface IFocusTracker {
onGainedFocus(): void;
@@ -160,7 +161,8 @@ export class MainThreadTextEditorProperties {
export class MainThreadTextEditor {
private readonly _id: string;
private _model: ITextModel;
private readonly _model: ITextModel;
private readonly _mainThreadDocuments: MainThreadDocuments;
private readonly _modelService: IModelService;
private readonly _clipboardService: IClipboardService;
private readonly _modelListeners = new DisposableStore();
@@ -176,6 +178,7 @@ export class MainThreadTextEditor {
model: ITextModel,
codeEditor: ICodeEditor,
focusTracker: IFocusTracker,
mainThreadDocuments: MainThreadDocuments,
modelService: IModelService,
clipboardService: IClipboardService,
) {
@@ -184,6 +187,7 @@ export class MainThreadTextEditor {
this._codeEditor = null;
this._properties = null;
this._focusTracker = focusTracker;
this._mainThreadDocuments = mainThreadDocuments;
this._modelService = modelService;
this._clipboardService = clipboardService;
@@ -198,7 +202,6 @@ export class MainThreadTextEditor {
}
public dispose(): void {
this._model = null!;
this._modelListeners.dispose();
this._codeEditor = null;
this._codeEditorListeners.dispose();
@@ -257,21 +260,46 @@ export class MainThreadTextEditor {
this._focusTracker.onLostFocus();
}));
let nextSelectionChangeSource: string | null = null;
this._codeEditorListeners.add(this._mainThreadDocuments.onIsCaughtUpWithContentChanges((uri) => {
if (uri.toString() === this._model.uri.toString()) {
const selectionChangeSource = nextSelectionChangeSource;
nextSelectionChangeSource = null;
this._updatePropertiesNow(selectionChangeSource);
}
}));
const updateProperties = (selectionChangeSource: string | null) => {
// Some editor events get delivered faster than model content changes. This is
// problematic, as this leads to editor properties reaching the extension host
// too soon, before the model content change that was the root cause.
//
// If this case is identified, then let's update editor properties on the next model
// content change instead.
if (this._mainThreadDocuments.isCaughtUpWithContentChanges(this._model.uri)) {
nextSelectionChangeSource = null;
this._updatePropertiesNow(selectionChangeSource);
} else {
// update editor properties on the next model content change
nextSelectionChangeSource = selectionChangeSource;
}
};
this._codeEditorListeners.add(this._codeEditor.onDidChangeCursorSelection((e) => {
// selection
this._updatePropertiesNow(e.source);
updateProperties(e.source);
}));
this._codeEditorListeners.add(this._codeEditor.onDidChangeConfiguration(() => {
// options
this._updatePropertiesNow(null);
updateProperties(null);
}));
this._codeEditorListeners.add(this._codeEditor.onDidLayoutChange(() => {
// visibleRanges
this._updatePropertiesNow(null);
updateProperties(null);
}));
this._codeEditorListeners.add(this._codeEditor.onDidScrollChange(() => {
// visibleRanges
this._updatePropertiesNow(null);
updateProperties(null);
}));
this._updatePropertiesNow(null);
}

View File

@@ -27,6 +27,8 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
@@ -276,7 +278,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
// --- commands
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn, string?]) {
CommandsRegistry.registerCommand('_workbench.open', async function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn, string?]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
@@ -285,16 +287,17 @@ CommandsRegistry.registerCommand('_workbench.open', function (accessor: Services
if (options || typeof position === 'number') {
// use editor options or editor view column as a hint to use the editor service for opening
return editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, position)).then(_ => undefined);
await editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, position));
return;
}
if (resource && resource.scheme === 'command') {
// do not allow to execute commands from here
return Promise.resolve(undefined);
return;
}
// finally, delegate to opener service
return openerService.open(resource).then(_ => undefined);
await openerService.open(resource);
});
CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAccessor, args: [URI, string, ITextEditorOptions | undefined, EditorViewColumn | undefined]) => {
@@ -313,7 +316,7 @@ CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAcces
});
CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string, string, IEditorOptions, EditorViewColumn]) {
CommandsRegistry.registerCommand('_workbench.diff', async function (accessor: ServicesAccessor, args: [URI, URI, string, string, IEditorOptions, EditorViewColumn]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -329,5 +332,17 @@ CommandsRegistry.registerCommand('_workbench.diff', function (accessor: Services
label = localize('diffLeftRightLabel', "{0} ⟷ {1}", leftResource.toString(true), rightResource.toString(true));
}
return editorService.openEditor({ leftResource, rightResource, label, description, options }, viewColumnToEditorGroup(editorGroupService, position)).then(() => undefined);
await editorService.openEditor({ leftResource, rightResource, label, description, options }, viewColumnToEditorGroup(editorGroupService, position));
});
CommandsRegistry.registerCommand('_workbench.revertAllDirty', async function (accessor: ServicesAccessor) {
const environmentService = accessor.get(IEnvironmentService);
if (!environmentService.extensionTestsLocationURI) {
throw new Error('Command is only available when running extension tests.');
}
const workingCopyService = accessor.get(IWorkingCopyService);
for (const workingCopy of workingCopyService.dirtyWorkingCopies) {
await workingCopy.revert({ soft: true });
}
});

View File

@@ -30,12 +30,14 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
// if there are icons in the text use the tooltip for the aria label
let ariaLabel: string;
let role: string | undefined = undefined;
if (accessibilityInformation) {
ariaLabel = accessibilityInformation.label;
role = accessibilityInformation.role;
} else {
ariaLabel = text ? text.replace(MainThreadStatusBar.CODICON_REGEXP, (_match, codiconName) => codiconName) : '';
}
const entry: IStatusbarEntry = { text, tooltip, command, color, ariaLabel };
const entry: IStatusbarEntry = { text, tooltip, command, color, ariaLabel, role };
if (typeof priority === 'undefined') {
priority = 0;

View File

@@ -7,7 +7,6 @@ import * as nls from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as Objects from 'vs/base/common/objects';
import * as Types from 'vs/base/common/types';
import * as Platform from 'vs/base/common/platform';
import { IStringDictionary, forEach } from 'vs/base/common/collections';
@@ -64,7 +63,7 @@ namespace TaskProcessEndedDTO {
namespace TaskDefinitionDTO {
export function from(value: KeyedTaskIdentifier): TaskDefinitionDTO {
const result = Objects.assign(Object.create(null), value);
const result = Object.assign(Object.create(null), value);
delete result._key;
return result;
}
@@ -85,13 +84,13 @@ namespace TaskPresentationOptionsDTO {
if (value === undefined || value === null) {
return undefined;
}
return Objects.assign(Object.create(null), value);
return Object.assign(Object.create(null), value);
}
export function to(value: TaskPresentationOptionsDTO | undefined): PresentationOptions {
if (value === undefined || value === null) {
return PresentationOptions.defaults;
}
return Objects.assign(Object.create(null), PresentationOptions.defaults, value);
return Object.assign(Object.create(null), PresentationOptions.defaults, value);
}
}
@@ -100,13 +99,13 @@ namespace RunOptionsDTO {
if (value === undefined || value === null) {
return undefined;
}
return Objects.assign(Object.create(null), value);
return Object.assign(Object.create(null), value);
}
export function to(value: RunOptionsDTO | undefined): RunOptions {
if (value === undefined || value === null) {
return RunOptions.defaults;
}
return Objects.assign(Object.create(null), RunOptions.defaults, value);
return Object.assign(Object.create(null), RunOptions.defaults, value);
}
}
@@ -368,7 +367,7 @@ namespace TaskDTO {
const label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
const definition = TaskDefinitionDTO.to(task.definition, executeOnly)!;
const id = `${task.source.extensionId}.${definition._key}`;
const id = (CustomExecutionDTO.is(task.execution!) && task._id) ? task._id : `${task.source.extensionId}.${definition._key}`;
const result: ContributedTask = new ContributedTask(
id, // uuidMap.getUUID(identifier)
source,
@@ -534,20 +533,47 @@ export class MainThreadTask implements MainThreadTaskShape {
}
}
public $executeTask(value: TaskDTO): Promise<TaskExecutionDTO> {
// Passing in a TaskHandleDTO will cause the task to get re-resolved, which is important for tasks are coming from the core,
// such as those gotten from a fetchTasks, since they can have missing configuration properties.
public $executeTask(value: TaskHandleDTO | TaskDTO): Promise<TaskExecutionDTO> {
return new Promise<TaskExecutionDTO>((resolve, reject) => {
const task = TaskDTO.to(value, this._workspaceContextServer, true)!;
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
const result: TaskExecutionDTO = {
id: task._id,
task: TaskDTO.from(task)
};
resolve(result);
if (TaskHandleDTO.is(value)) {
const workspaceFolder = typeof value.workspaceFolder === 'string' ? value.workspaceFolder : this._workspaceContextServer.getWorkspaceFolder(URI.revive(value.workspaceFolder));
if (workspaceFolder) {
this._taskService.getTask(workspaceFolder, value.id, true).then((task: Task | undefined) => {
if (!task) {
reject(new Error('Task not found'));
} else {
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
const result: TaskExecutionDTO = {
id: value.id,
task: TaskDTO.from(task)
};
resolve(result);
}
}, (_error) => {
reject(new Error('Task not found'));
});
} else {
reject(new Error('No workspace folder'));
}
} else {
const task = TaskDTO.to(value, this._workspaceContextServer, true)!;
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
const result: TaskExecutionDTO = {
id: task._id,
task: TaskDTO.from(task)
};
resolve(result);
}
});
}
public $customExecutionComplete(id: string, result?: number): Promise<void> {
return new Promise<void>((resolve, reject) => {
this._taskService.getActiveTasks().then((tasks) => {
@@ -642,6 +668,9 @@ export class MainThreadTask implements MainThreadTaskShape {
},
getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => {
return Promise.resolve(this._proxy.$getDefaultShellAndArgs());
},
findExecutable: (command: string, cwd?: string, paths?: string[]): Promise<string | undefined> => {
return this._proxy.$findExecutable(command, cwd, paths);
}
});
}

View File

@@ -24,6 +24,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { withNullAsUndefined } from 'vs/base/common/types';
import { IFileService } from 'vs/platform/files/common/files';
import { IRequestService } from 'vs/platform/request/common/request';
import { checkGlobFileExists } from 'vs/workbench/api/common/shared/workspaceContains';
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@@ -188,26 +189,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
return search;
}
$checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise<boolean> {
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
const query = queryBuilder.file(folders.map(folder => toWorkspaceFolder(URI.revive(folder))), {
_reason: 'checkExists',
includePattern: includes.join(', '),
expandPatterns: true,
exists: true
});
return this._searchService.fileSearch(query, token).then(
result => {
return !!result.limitHit;
},
err => {
if (!isPromiseCanceledError(err)) {
return Promise.reject(err);
}
return false;
});
$checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean> {
return this._instantiationService.invokeFunction((accessor) => checkGlobFileExists(accessor, folders, includes, token));
}
// --- save & edit resources ---

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;
});
}

View File

@@ -4,48 +4,35 @@
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { ExtHostOutputService2 } from 'vs/workbench/api/node/extHostOutputService';
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 { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
// import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
// import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
// import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
// import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { NativeExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { ExtHostTunnelService } from 'vs/workbench/api/node/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
// import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
// import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { ILogService } from 'vs/platform/log/common/log';
// #########################################################################
// ### ###
// ### !!! PLEASE ADD COMMON IMPORTS INTO extHost.common.services.ts !!! ###
// ### ###
// #########################################################################
// register singleton services
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostCommands, ExtHostCommands);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostTerminalService, ExtHostTerminalService);
// registerSingleton(IExtHostTask, ExtHostTask); {{SQL CABON EDIT}} disable exthost tasks
// registerSingleton(IExtHostDebugService, ExtHostDebugService); {{SQL CARBON EDIT}} remove debug service
registerSingleton(IExtHostSearch, NativeExtHostSearch);
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
registerSingleton(IExtHostStorage, ExtHostStorage);
registerSingleton(ILogService, ExtHostLogService);
// registerSingleton(IExtHostDebugService, ExtHostDebugService);
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
registerSingleton(IExtHostSearch, NativeExtHostSearch);
// registerSingleton(IExtHostTask, ExtHostTask);
registerSingleton(IExtHostTerminalService, ExtHostTerminalService);
registerSingleton(IExtHostTunnelService, ExtHostTunnelService);

View File

@@ -1,80 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 } from 'vs/base/common/uri';
import * as pfs from 'vs/base/node/pfs';
import { IEnvironment, IStaticWorkspaceData } from 'vs/workbench/api/common/extHost.protocol';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { ILogService } from 'vs/platform/log/common/log';
export class ExtensionStoragePaths implements IExtensionStoragePaths {
readonly _serviceBrand: undefined;
private readonly _workspace?: IStaticWorkspaceData;
private readonly _environment: IEnvironment;
readonly whenReady: Promise<string | undefined>;
private _value?: string;
constructor(
@IExtHostInitDataService initData: IExtHostInitDataService,
@ILogService private readonly _logService: ILogService,
) {
this._workspace = withNullAsUndefined(initData.workspace);
this._environment = initData.environment;
this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
}
workspaceValue(extension: IExtensionDescription): string | undefined {
if (this._value) {
return path.join(this._value, extension.identifier.value);
}
return undefined;
}
globalValue(extension: IExtensionDescription): string {
return path.join(this._environment.globalStorageHome.fsPath, extension.identifier.value.toLowerCase());
}
private async _getOrCreateWorkspaceStoragePath(): Promise<string | undefined> {
if (!this._workspace) {
return Promise.resolve(undefined);
}
if (!this._environment.appSettingsHome) {
return undefined;
}
const storageName = this._workspace.id;
const storagePath = path.join(this._environment.appSettingsHome.fsPath, 'workspaceStorage', storageName);
const exists = await pfs.dirExists(storagePath);
if (exists) {
return storagePath;
}
try {
await pfs.mkdirp(storagePath);
await pfs.writeFile(
path.join(storagePath, 'meta.json'),
JSON.stringify({
id: this._workspace.id,
configuration: this._workspace.configuration && URI.revive(this._workspace.configuration).toString(),
name: this._workspace.name
}, undefined, 2)
);
return storagePath;
} catch (e) {
this._logService.error(e);
return undefined;
}
}
}

View File

@@ -6,7 +6,7 @@
// import * as path from 'vs/base/common/path';
import { URI, UriComponents } from 'vs/base/common/uri';
// import { win32 } from 'vs/base/node/processes';
import { win32 } from 'vs/base/node/processes';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import type * as vscode from 'vscode';
@@ -54,12 +54,13 @@ export class ExtHostTask extends ExtHostTaskBase {
// We have a preserved ID. So the task didn't change.
if (tTask._id !== undefined) {
// Always get the task execution first to prevent timing issues when retrieving it later
const executionDTO = await this._proxy.$getTaskExecution(TaskHandleDTO.from(tTask));
const handleDto = TaskHandleDTO.from(tTask);
const executionDTO = await this._proxy.$getTaskExecution(handleDto);
if (executionDTO.task === undefined) {
throw new Error('Task from execution DTO is undefined');
}
const execution = await this.getTaskExecution(executionDTO, task);
this._proxy.$executeTask(executionDTO.task).catch(() => { /* The error here isn't actionable. */ });
this._proxy.$executeTask(handleDto).catch(() => { /* The error here isn't actionable. */ });
return execution;
} else {
const dto = TaskDTO.from(task, extension);
@@ -195,4 +196,8 @@ export class ExtHostTask extends ExtHostTaskBase {
public async $jsonTasksSupported(): Promise<boolean> {
return true;
}
public async $findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string> {
return win32.findExecutable(command, cwd, paths);
}
}

View File

@@ -20,11 +20,8 @@ import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostD
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
import { BaseExtHostTerminalService, ExtHostTerminal, EnvironmentVariableCollection } from 'vs/workbench/api/common/extHostTerminalService';
import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
export class ExtHostTerminalService extends BaseExtHostTerminalService {
@@ -32,8 +29,6 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
private _variableResolver: ExtHostVariableResolverService | undefined;
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
private _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
// TODO: Pull this from main side
private _isWorkspaceShellAllowed: boolean = false;
@@ -235,37 +230,4 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
this._isWorkspaceShellAllowed = isAllowed;
}
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!);
});
}
}

View File

@@ -0,0 +1,19 @@
/*---------------------------------------------------------------------------------------------
* 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 { ILogService } from 'vs/platform/log/common/log';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensionService';
import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
// #########################################################################
// ### ###
// ### !!! PLEASE ADD COMMON IMPORTS INTO extHost.common.services.ts !!! ###
// ### ###
// #########################################################################
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
registerSingleton(ILogService, ExtHostLogService);