Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import * as nls from 'vs/nls';
import {
ExtensionManagementError, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementParticipant, IGalleryExtension, ILocalExtension, InstallOperation,
IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode,
InstallOptions, InstallVSIXOptions, UninstallOptions, Metadata, InstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, IExtensionManagementService, InstallExtensionInfo, EXTENSION_INSTALL_DEP_PACK_CONTEXT, ExtensionGalleryError
InstallOptions, UninstallOptions, Metadata, InstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, IExtensionManagementService, InstallExtensionInfo, EXTENSION_INSTALL_DEP_PACK_CONTEXT, ExtensionGalleryError
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions, ExtensionKey, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType, IExtensionManifest, isApplicationScopedExtension, TargetPlatform } from 'vs/platform/extensions/common/extensions';
Expand All @@ -27,9 +27,9 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';

export type ExtensionVerificationStatus = boolean | string;
export type InstallableExtension = { readonly manifest: IExtensionManifest; extension: IGalleryExtension | URI; options: InstallOptions & InstallVSIXOptions };
export type InstallableExtension = { readonly manifest: IExtensionManifest; extension: IGalleryExtension | URI; options: InstallOptions };

export type InstallExtensionTaskOptions = InstallOptions & InstallVSIXOptions & { readonly profileLocation: URI };
export type InstallExtensionTaskOptions = InstallOptions & { readonly profileLocation: URI };
export interface IInstallExtensionTask {
readonly identifier: IExtensionIdentifier;
readonly source: IGalleryExtension | URI;
Expand Down Expand Up @@ -228,7 +228,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
const isApplicationScoped = options.isApplicationScoped || options.isBuiltin || isApplicationScopedExtension(manifest);
const installExtensionTaskOptions: InstallExtensionTaskOptions = {
...options,
installOnlyNewlyAddedFromExtensionPack: URI.isUri(extension) ? options.installOnlyNewlyAddedFromExtensionPack : true, /* always true for gallery extensions */
installOnlyNewlyAddedFromExtensionPack: options.installOnlyNewlyAddedFromExtensionPack ?? !URI.isUri(extension) /* always true for gallery extensions */,
isApplicationScoped,
profileLocation: isApplicationScoped ? this.userDataProfilesService.defaultProfile.extensionsResource : options.profileLocation ?? this.getCurrentExtensionsManifestLocation()
};
Expand Down Expand Up @@ -715,7 +715,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
abstract zip(extension: ILocalExtension): Promise<URI>;
abstract unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
abstract getManifest(vsix: URI): Promise<IExtensionManifest>;
abstract install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension>;
abstract install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
abstract installFromLocation(location: URI, profileLocation: URI): Promise<ILocalExtension>;
abstract installExtensionsFromProfile(extensions: IExtensionIdentifier[], fromProfileLocation: URI, toProfileLocation: URI): Promise<ILocalExtension[]>;
abstract getInstalled(type?: ExtensionType, profileLocation?: URI): Promise<ILocalExtension[]>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,16 +453,16 @@ export type InstallOptions = {
donotVerifySignature?: boolean;
operation?: InstallOperation;
profileLocation?: URI;
installOnlyNewlyAddedFromExtensionPack?: boolean;
/**
* Context passed through to InstallExtensionResult
*/
context?: IStringDictionary<any>;
};
export type InstallVSIXOptions = InstallOptions & { installOnlyNewlyAddedFromExtensionPack?: boolean };
export type UninstallOptions = { readonly donotIncludePack?: boolean; readonly donotCheckDependents?: boolean; readonly versionOnly?: boolean; readonly remove?: boolean; readonly profileLocation?: URI };

export interface IExtensionManagementParticipant {
postInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions | InstallVSIXOptions, token: CancellationToken): Promise<void>;
postInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions, token: CancellationToken): Promise<void>;
postUninstall(local: ILocalExtension, options: UninstallOptions, token: CancellationToken): Promise<void>;
}

Expand All @@ -481,7 +481,7 @@ export interface IExtensionManagementService {
zip(extension: ILocalExtension): Promise<URI>;
unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
getManifest(vsix: URI): Promise<IExtensionManifest>;
install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension>;
install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
canInstall(extension: IGalleryExtension): Promise<boolean>;
installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise<ILocalExtension>;
installGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<InstallExtensionResult[]>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { cloneAndChange } from 'vs/base/common/objects';
import { URI, UriComponents } from 'vs/base/common/uri';
import { DefaultURITransformer, IURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionIdentifier, IExtensionTipsService, IGalleryExtension, ILocalExtension, IExtensionsControlManifest, isTargetPlatformCompatible, InstallOptions, InstallVSIXOptions, UninstallOptions, Metadata, IExtensionManagementService, DidUninstallExtensionEvent, InstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, InstallOperation, InstallExtensionInfo } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionIdentifier, IExtensionTipsService, IGalleryExtension, ILocalExtension, IExtensionsControlManifest, isTargetPlatformCompatible, InstallOptions, UninstallOptions, Metadata, IExtensionManagementService, DidUninstallExtensionEvent, InstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, InstallOperation, InstallExtensionInfo } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';

function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI;
Expand Down Expand Up @@ -237,7 +237,7 @@ export class ExtensionManagementChannelClient extends Disposable implements IExt
return Promise.resolve(this.channel.call<IExtensionIdentifier>('unzip', [zipLocation]));
}

install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix, options])).then(local => transformIncomingExtension(local, null));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { INativeEnvironmentService } from 'vs/platform/environment/common/enviro
import { AbstractExtensionManagementService, AbstractExtensionTask, ExtensionVerificationStatus, IInstallExtensionTask, InstallExtensionTaskOptions, IUninstallExtensionTask, joinErrors, toExtensionManagementError, UninstallExtensionTaskOptions } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService';
import {
ExtensionManagementError, ExtensionManagementErrorCode, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService, IGalleryExtension, ILocalExtension, InstallOperation,
Metadata, InstallVSIXOptions
Metadata, InstallOptions
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions, computeTargetPlatform, ExtensionKey, getGalleryExtensionId, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionsProfileScannerService, IScannedProfileExtension } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
Expand Down Expand Up @@ -140,7 +140,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
return this.extensionsScanner.scanUserExtensionAtLocation(location);
}

async install(vsix: URI, options: InstallVSIXOptions = {}): Promise<ILocalExtension> {
async install(vsix: URI, options: InstallOptions = {}): Promise<ILocalExtension> {
this.logService.trace('ExtensionManagementService#install', vsix.toString());

const { location, cleanup } = await this.downloadVsix(vsix);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import 'vs/css!./media/voiceChatActions';
import { Event } from 'vs/base/common/event';
import { firstOrDefault } from 'vs/base/common/arrays';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Codicon } from 'vs/base/common/codicons';
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { localize, localize2 } from 'vs/nls';
Expand Down Expand Up @@ -46,13 +46,12 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ProgressLocation } from 'vs/platform/progress/common/progress';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { IVoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ThemeIcon } from 'vs/base/common/themables';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ProgressLocation } from 'vs/platform/progress/common/progress';

const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey<boolean>('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") });
const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") });
Expand Down Expand Up @@ -634,36 +633,13 @@ export class InstallVoiceChatAction extends Action2 {

async run(accessor: ServicesAccessor): Promise<void> {
const contextKeyService = accessor.get(IContextKeyService);
const dialogService = accessor.get(IDialogService);
const extensionManagementService = accessor.get(IExtensionsWorkbenchService);

const extension = firstOrDefault((await extensionManagementService.getExtensions([{ id: InstallVoiceChatAction.SPEECH_EXTENSION_ID }], CancellationToken.None)));
if (!extension) {
return;
}

if (extension.state === ExtensionState.Installed) {
await dialogService.info(
localize('enableExtensionMessage', "Microphone support requires an extension. Please enable it."),
localize('enableExtensionDetail', "Extension '{0}' is currently disabled.", InstallVoiceChatAction.SPEECH_EXTENSION_ID),
);

return extensionManagementService.open(extension);
}

const { confirmed } = await dialogService.confirm({
message: localize('confirmInstallMessage', "Microphone support requires an extension. Would you like to install it now?"),
detail: localize('confirmInstallDetail', "This will install the '{0}' extension.", InstallVoiceChatAction.SPEECH_EXTENSION_ID),
primaryButton: localize({ key: 'installButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Install")
});

if (!confirmed) {
return;
}

const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
try {
InstallingSpeechProvider.bindTo(contextKeyService).set(true);
await extensionManagementService.install(extension, undefined, ProgressLocation.Notification);
await extensionsWorkbenchService.install(InstallVoiceChatAction.SPEECH_EXTENSION_ID, {
justification: localize('confirmInstallDetail', "Microphone support requires this extension."),
enable: true
}, ProgressLocation.Notification);
} finally {
InstallingSpeechProvider.bindTo(contextKeyService).set(false);
}
Expand Down
74 changes: 19 additions & 55 deletions src/vs/workbench/contrib/debug/browser/variablesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { AsyncDataTree, IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/
import { ITreeContextMenuEvent, ITreeMouseEvent, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
import { Action, IAction } from 'vs/base/common/actions';
import { coalesce } from 'vs/base/common/arrays';
import { RunOnceScheduler, timeout } from 'vs/base/common/async';
import { RunOnceScheduler } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Codicon } from 'vs/base/common/codicons';
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
Expand All @@ -22,16 +22,16 @@ import { localize } from 'vs/nls';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuService, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { ProgressLocation } from 'vs/platform/progress/common/progress';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ViewAction, ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
Expand All @@ -43,6 +43,7 @@ import { CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS
import { getContextForVariable } from 'vs/workbench/contrib/debug/common/debugContext';
import { ErrorScope, Expression, Scope, StackFrame, Variable, VisualizedExpression, getUriForDebugMemory } from 'vs/workbench/contrib/debug/common/debugModel';
import { DebugVisualizer, IDebugVisualizerService } from 'vs/workbench/contrib/debug/common/debugVisualizers';
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';

Expand Down Expand Up @@ -717,15 +718,14 @@ CommandsRegistry.registerCommand({
memoryReference = arg.memoryReference;
}

const commandService = accessor.get(ICommandService);
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
const editorService = accessor.get(IEditorService);
const notifications = accessor.get(INotificationService);
const progressService = accessor.get(IProgressService);
const notificationService = accessor.get(INotificationService);
const extensionService = accessor.get(IExtensionService);
const telemetryService = accessor.get(ITelemetryService);

const ext = await extensionService.getExtension(HEX_EDITOR_EXTENSION_ID);
if (ext || await tryInstallHexEditor(notifications, progressService, extensionService, commandService)) {
if (ext || await tryInstallHexEditor(extensionsWorkbenchService, notificationService)) {
/* __GDPR__
"debug/didViewMemory" : {
"owner": "connor4312",
Expand All @@ -747,53 +747,17 @@ CommandsRegistry.registerCommand({
}
});

function tryInstallHexEditor(notifications: INotificationService, progressService: IProgressService, extensionService: IExtensionService, commandService: ICommandService) {
return new Promise<boolean>(resolve => {
let installing = false;

const handle = notifications.prompt(
Severity.Info,
localize("viewMemory.prompt", "Inspecting binary data requires the Hex Editor extension. Would you like to install it now?"), [
{
label: localize("cancel", "Cancel"),
run: () => resolve(false),
},
{
label: localize("install", "Install"),
run: async () => {
installing = true;
try {
await progressService.withProgress(
{
location: ProgressLocation.Notification,
title: localize("viewMemory.install.progress", "Installing the Hex Editor..."),
},
async () => {
await commandService.executeCommand('workbench.extensions.installExtension', HEX_EDITOR_EXTENSION_ID);
// it seems like the extension is not registered immediately on install --
// wait for it to appear before returning.
while (!(await extensionService.getExtension(HEX_EDITOR_EXTENSION_ID))) {
await timeout(30);
}
},
);
resolve(true);
} catch (e) {
notifications.error(e as Error);
resolve(false);
}
}
},
],
{ sticky: true },
);

handle.onDidClose(e => {
if (!installing) {
resolve(false);
}
});
});
async function tryInstallHexEditor(extensionsWorkbenchService: IExtensionsWorkbenchService, notificationService: INotificationService): Promise<boolean> {
try {
await extensionsWorkbenchService.install(HEX_EDITOR_EXTENSION_ID, {
justification: localize("viewMemory.prompt", "Inspecting binary data requires this extension."),
enable: true
}, ProgressLocation.Notification);
return true;
} catch (error) {
notificationService.error(error);
return false;
}
}

export const BREAK_WHEN_VALUE_CHANGES_ID = 'debug.breakWhenValueChanges';
Expand Down
Loading