Merge from vscode 0fde6619172c9f04c41f2e816479e432cc974b8b (#5199)

This commit is contained in:
Anthony Dresser
2019-04-24 22:26:02 -07:00
committed by GitHub
parent d63f07d29a
commit 34457880c7
86 changed files with 1254 additions and 702 deletions

View File

@@ -11,6 +11,8 @@ import { IResourceInput } from 'vs/platform/editor/common/editor';
import { Schemas } from 'vs/base/common/network';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IUntitledResourceInput } from 'vs/workbench/common/editor';
import { toLocalResource } from 'vs/base/common/resources';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export class BackupRestorer implements IWorkbenchContribution {
@@ -21,7 +23,8 @@ export class BackupRestorer implements IWorkbenchContribution {
constructor(
@IEditorService private readonly editorService: IEditorService,
@IBackupFileService private readonly backupFileService: IBackupFileService,
@ILifecycleService private readonly lifecycleService: ILifecycleService
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
) {
this.restoreBackups();
}
@@ -79,9 +82,9 @@ export class BackupRestorer implements IWorkbenchContribution {
if (resource.scheme === Schemas.untitled
&& !BackupRestorer.UNTITLED_REGEX.test(resource.fsPath)
&& !BackupRestorer.SQLQUERY_REGEX.test(resource.fsPath)) {
return { filePath: resource.fsPath, options };
return { resource: toLocalResource(resource, this.environmentService.configuration.remoteAuthority), options, forceUntitled: true };
}
return { resource, options };
}
}
}

View File

@@ -85,6 +85,7 @@ export interface IExtensionsWorkbenchService {
_serviceBrand: any;
onChange: Event<IExtension | undefined>;
local: IExtension[];
installed: IExtension[];
outdated: IExtension[];
queryLocal(server?: IExtensionManagementServer): Promise<IExtension[]>;
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;

View File

@@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
import { EditorOptions } from 'vs/workbench/common/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
@@ -300,7 +300,7 @@ export class ExtensionEditor extends BaseEditor {
this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token)));
this.extensionDependencies = new Cache(() => createCancelablePromise(token => this.extensionsWorkbenchService.loadDependencies(extension, token)));
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer);
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer, true);
const onError = Event.once(domEvent(this.icon, 'error'));
onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables);
this.icon.src = extension.iconUrl;
@@ -393,6 +393,7 @@ export class ExtensionEditor extends BaseEditor {
this.instantiationService.createInstance(EnableDropDownAction),
this.instantiationService.createInstance(DisableDropDownAction, runningExtensions),
this.instantiationService.createInstance(RemoteInstallAction),
this.instantiationService.createInstance(LocalInstallAction),
combinedInstallAction,
systemDisabledWarningAction,
this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction),

View File

@@ -316,12 +316,14 @@ export class RemoteInstallAction extends ExtensionAction {
private updateLabel(): void {
if (this.installing) {
this.label = RemoteInstallAction.INSTALLING_LABEL;
this.tooltip = this.label;
return;
}
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
if (remoteAuthority) {
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote");
this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${host}`;
this.tooltip = this.label;
return;
}
}
@@ -339,9 +341,9 @@ export class RemoteInstallAction extends ExtensionAction {
// Installed User Extension
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
// Local Workspace Extension
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.configurationService))
// Extension does not exist in remote
&& !this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
&& !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
&& this.extensionsWorkbenchService.canInstall(this.extension)
) {
this.enabled = true;
@@ -370,6 +372,85 @@ export class RemoteInstallAction extends ExtensionAction {
}
}
export class LocalInstallAction extends ExtensionAction {
private static INSTALL_LABEL = localize('install locally', "Install Locally");
private static INSTALLING_LABEL = localize('installing', "Installing");
private static readonly Class = 'extension-action prominent install';
private static readonly InstallingClass = 'extension-action install installing';
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private installing: boolean = false;
constructor(
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@ILabelService private readonly labelService: ILabelService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super(`extensions.localinstall`, LocalInstallAction.INSTALL_LABEL, LocalInstallAction.Class, false);
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
this.updateLabel();
this.update();
}
private updateLabel(): void {
if (this.installing) {
this.label = LocalInstallAction.INSTALLING_LABEL;
this.tooltip = this.label;
return;
}
this.label = `${LocalInstallAction.INSTALL_LABEL}`;
this.tooltip = this.label;
}
update(): void {
this.enabled = false;
this.class = LocalInstallAction.Class;
if (this.installing) {
this.enabled = true;
this.class = LocalInstallAction.InstallingClass;
this.updateLabel();
return;
}
if (this.environmentService.configuration.remoteAuthority
// Installed User Extension
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
// Remote UI or Language pack Extension
&& this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.configurationService))
// Extension does not exist in local
&& !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)
&& this.extensionsWorkbenchService.canInstall(this.extension)
) {
this.enabled = true;
this.updateLabel();
return;
}
}
async run(): Promise<void> {
if (!this.installing) {
this.installing = true;
this.update();
this.extensionsWorkbenchService.open(this.extension);
alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));
if (this.extension.gallery) {
await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery);
this.installing = false;
this.update();
}
}
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class UninstallAction extends ExtensionAction {
private static readonly UninstallLabel = localize('uninstallAction', "Uninstall");
@@ -1265,23 +1346,34 @@ export class ReloadAction extends ExtensionAction {
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
return;
}
if (this.workbenchEnvironmentService.configuration.remoteAuthority
if (this.workbenchEnvironmentService.configuration.remoteAuthority) {
const uiExtension = isUIExtension(this.extension.local.manifest, this.configurationService);
// Local Workspace Extension
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
) {
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
// Extension exist in remote and enabled
if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName));
return;
if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
// Extension exist in remote and enabled
if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
return;
}
}
// Remote UI Extension
if (uiExtension && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)[0];
// Extension exist in local and enabled
if (localExtension && localExtension.local && this.extensionEnablementService.isEnabled(localExtension.local)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
return;
}
}
}
}
@@ -2464,7 +2556,8 @@ export class StatusLabelAction extends Action implements IExtensionContainer {
}
constructor(
@IExtensionService private readonly extensionService: IExtensionService
@IExtensionService private readonly extensionService: IExtensionService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
) {
super('extensions.action.statusLabel', '', StatusLabelAction.DISABLED_CLASS, false);
}
@@ -2503,7 +2596,7 @@ export class StatusLabelAction extends Action implements IExtensionContainer {
};
const canRemoveExtension = () => {
if (this.extension.local) {
if (runningExtensions.every(e => !areSameExtensions({ id: e.identifier.value }, this.extension.identifier))) {
if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value }, this.extension.identifier) && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) {
return true;
}
return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension.local));
@@ -2592,21 +2685,18 @@ export class DisabledLabelAction extends ExtensionAction {
update(): void {
this.class = `${DisabledLabelAction.Class} hide`;
this.label = '';
this.enabled = false;
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
return;
}
if (this.warningAction.enabled) {
this.enabled = true;
if (this.warningAction.tooltip) {
this.class = DisabledLabelAction.Class;
this.label = this.warningAction.tooltip;
return;
}
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
return;
}
if (this.extension && this.extension.local && this._runningExtensions) {
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
const isExtensionRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier));
if (!isExtensionRunning && !isEnabled) {
this.enabled = true;
if (!isExtensionRunning && !isEnabled && this.extensionEnablementService.canChangeEnablement(this.extension.local)) {
this.class = DisabledLabelAction.Class;
this.label = localize('disabled by user', "This extension is disabled by the user.");
return;
@@ -2626,7 +2716,9 @@ export class DisabledLabelAction extends ExtensionAction {
export class SystemDisabledWarningAction extends ExtensionAction {
private static readonly Class = 'disable-warning';
private static readonly CLASS = 'system-disable';
private static readonly WARNING_CLASS = `${SystemDisabledWarningAction.CLASS} warning`;
private static readonly INFO_CLASS = `${SystemDisabledWarningAction.CLASS} info`;
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
@@ -2640,7 +2732,7 @@ export class SystemDisabledWarningAction extends ExtensionAction {
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionService private readonly extensionService: IExtensionService,
) {
super('extensions.install', '', `${SystemDisabledWarningAction.Class} hide`, false);
super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false);
this.labelService.onDidChangeFormatters(() => this.update(), this, this.disposables);
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
this.updateRunningExtensions();
@@ -2652,44 +2744,54 @@ export class SystemDisabledWarningAction extends ExtensionAction {
}
update(): void {
this.enabled = false;
this.class = `${SystemDisabledWarningAction.Class} hide`;
this.class = `${SystemDisabledWarningAction.CLASS} hide`;
this.tooltip = '';
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
if (
!this.extension ||
!this.extension.local ||
!this.extension.server ||
!this._runningExtensions ||
!this.workbenchEnvironmentService.configuration.remoteAuthority ||
!this.extensionManagementServerService.remoteExtensionManagementServer ||
this.extension.state !== ExtensionState.Installed
) {
return;
}
if (this.extension && this.extension.local && this.extension.server && this._runningExtensions && this.workbenchEnvironmentService.configuration.remoteAuthority && this.extensionManagementServerService.remoteExtensionManagementServer) {
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
const localExtensionServer = localExtension ? localExtension.server : null;
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (isLanguagePackExtension(this.extension.local.manifest)) {
if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) {
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
this.tooltip = this.extension.server === this.extensionManagementServerService.localExtensionManagementServer
? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer))
: localize('Install language pack also locally', "Install the language pack extension locally to enable it also there.");
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
return;
}
return;
}
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
const localExtensionServer = localExtension ? localExtension.server : null;
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
return;
}
}
}

View File

@@ -13,7 +13,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -67,7 +67,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const element = append(root, $('.extension'));
const iconContainer = append(element, $('.icon-container'));
const icon = append(iconContainer, $<HTMLImageElement>('img.icon'));
const iconRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
const iconRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer, false);
const details = append(element, $('.details'));
const headerContainer = append(details, $('.header-container'));
const header = append(headerContainer, $('.header'));
@@ -75,7 +75,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const version = append(header, $('span.version'));
const installCount = append(header, $('span.install-count'));
const ratings = append(header, $('span.ratings'));
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header);
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header, false);
const description = append(details, $('.description.ellipsis'));
const footer = append(details, $('.footer'));
const author = append(footer, $('.author.ellipsis'));
@@ -98,6 +98,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
reloadAction,
this.instantiationService.createInstance(InstallAction),
this.instantiationService.createInstance(RemoteInstallAction),
this.instantiationService.createInstance(LocalInstallAction),
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
systemDisabledWarningAction,
this.instantiationService.createInstance(ManageExtensionAction)

View File

@@ -55,6 +55,9 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { Registry } from 'vs/platform/registry/common/platform';
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { ILabelService } from 'vs/platform/label/common/label';
interface SearchInputEvent extends Event {
target: HTMLInputElement;
@@ -91,7 +94,9 @@ const viewIdNameMappings: { [id: string]: string } = {
export class ExtensionsViewletViewsContribution implements IWorkbenchContribution {
constructor(
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@ILabelService private readonly labelService: ILabelService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
) {
this.registerViews();
}
@@ -180,22 +185,32 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
*/
private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] {
const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => {
const serverLabel = this.workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? this.labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label;
if (viewTitle && this.workbenchEnvironmentService.configuration.remoteAuthority) {
return `${serverLabel} - ${viewTitle}`;
}
return viewTitle ? viewTitle : serverLabel;
};
const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server);
const getOutdatedViewName = (): string => getViewName(localize('outdated', "Outdated"), server);
const onDidChangeServerLabel: EventOf<void> = this.workbenchEnvironmentService.configuration.remoteAuthority ? EventOf.map(this.labelService.onDidChangeFormatters, () => undefined) : EventOf.None;
return [{
id: `extensions.${server.authority}.installed`,
name: localize('installed', "Installed"),
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
get name() { return getInstalledViewName(); },
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())] },
when: ContextKeyExpr.and(ContextKeyExpr.has('searchInstalledExtensions')),
weight: 100
}, {
id: `extensions.${server.authority}.outdated`,
name: localize('outdated', "Outdated"),
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
get name() { return getOutdatedViewName(); },
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getOutdatedViewName())] },
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
weight: 100
}, {
id: `extensions.${server.authority}.default`,
name: localize('installed', "Installed"),
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
get name() { return getInstalledViewName(); },
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())] },
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')),
weight: 40,
order: 1
@@ -228,7 +243,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
ctorDescriptor: { ctor: RecommendedExtensionsView },
when: ContextKeyExpr.has('recommendedExtensions'),
weight: 50,
canToggleVisibility: true,
order: 2
};
}
@@ -243,7 +257,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
ctorDescriptor: { ctor: WorkspaceRecommendedExtensionsView },
when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')),
weight: 50,
canToggleVisibility: true,
order: 1
};
}
@@ -256,7 +269,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
ctorDescriptor: { ctor: EnabledExtensionsView },
when: ContextKeyExpr.and(ContextKeyExpr.has('searchEnabledExtensions')),
weight: 40,
canToggleVisibility: true,
order: 1
};
}
@@ -269,7 +281,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
ctorDescriptor: { ctor: DisabledExtensionsView },
when: ContextKeyExpr.and(ContextKeyExpr.has('searchDisabledExtensions')),
weight: 10,
canToggleVisibility: true,
order: 3,
collapsed: true
};
@@ -282,8 +293,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
name: viewIdNameMappings[id],
ctorDescriptor: { ctor: BuiltInExtensionsView },
when: ContextKeyExpr.has('searchBuiltInExtensions'),
weight: 100,
canToggleVisibility: true
weight: 100
};
}
@@ -294,8 +304,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
name: viewIdNameMappings[id],
ctorDescriptor: { ctor: BuiltInThemesExtensionsView },
when: ContextKeyExpr.has('searchBuiltInExtensions'),
weight: 100,
canToggleVisibility: true
weight: 100
};
}
@@ -306,8 +315,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
name: viewIdNameMappings[id],
ctorDescriptor: { ctor: BuiltInBasicsExtensionsView },
when: ContextKeyExpr.has('searchBuiltInExtensions'),
weight: 100,
canToggleVisibility: true
weight: 100
};
}
}

View File

@@ -16,7 +16,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { append, $, toggleClass } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/electron-browser/extensionsList';
import { IExtension, IExtensionsWorkbenchService } from '../common/extensions';
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions';
import { Query } from '../common/extensionQuery';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -45,9 +45,7 @@ import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePa
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import product from 'vs/platform/product/node/product';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { ILabelService } from 'vs/platform/label/common/label';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
class ExtensionsViewState extends Disposable implements IExtensionsViewState {
@@ -97,7 +95,7 @@ export class ExtensionsListView extends ViewletPanel {
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
@IExperimentService private readonly experimentService: IExperimentService,
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService
) {
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
this.server = options.server;
@@ -340,11 +338,20 @@ export class ExtensionsListView extends ViewletPanel {
const isE1Running = running1 && this.extensionManagementServerService.getExtensionManagementServer(running1.extensionLocation) === e1.server;
const running2 = runningExtensionsById.get(ExtensionIdentifier.toKey(e2.identifier.id));
const isE2Running = running2 && this.extensionManagementServerService.getExtensionManagementServer(running2.extensionLocation) === e2.server;
if ((isE1Running && isE2Running) || (!isE1Running && !isE2Running)) {
if ((isE1Running && isE2Running)) {
return e1.displayName.localeCompare(e2.displayName);
}
const isE1LanguagePackExtension = e1.local && isLanguagePackExtension(e1.local.manifest);
const isE2LanguagePackExtension = e2.local && isLanguagePackExtension(e2.local.manifest);
if (!isE1Running && !isE2Running) {
if (isE1LanguagePackExtension) {
return -1;
}
if (isE2LanguagePackExtension) {
return 1;
}
return e1.displayName.localeCompare(e2.displayName);
}
if ((isE1Running && isE2LanguagePackExtension) || (isE2Running && isE1LanguagePackExtension)) {
return e1.displayName.localeCompare(e2.displayName);
}
@@ -865,18 +872,11 @@ export class ExtensionsListView extends ViewletPanel {
}
}
function getViewTitleForServer(viewTitle: string, server: IExtensionManagementServer, labelService: ILabelService, workbenchEnvironmentService: IWorkbenchEnvironmentService): string {
const serverLabel = workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label;
if (viewTitle && workbenchEnvironmentService.configuration.remoteAuthority) {
return `${serverLabel} - ${viewTitle}`;
}
return viewTitle ? viewTitle : serverLabel;
}
export class ServerExtensionsView extends ExtensionsListView {
constructor(
server: IExtensionManagementServer,
onDidChangeTitle: Event<string>,
options: ExtensionsListViewOptions,
@INotificationService notificationService: INotificationService,
@IKeybindingService keybindingService: IKeybindingService,
@@ -893,15 +893,11 @@ export class ServerExtensionsView extends ExtensionsListView {
@IExperimentService experimentService: IExperimentService,
@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
@ILabelService labelService: ILabelService,
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
) {
const viewTitle = options.title;
options.title = getViewTitleForServer(viewTitle, server, labelService, workbenchEnvironmentService);
options.server = server;
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, modeService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService);
this.disposables.push(labelService.onDidChangeFormatters(() => this.updateTitle(getViewTitleForServer(viewTitle, server, labelService, workbenchEnvironmentService))));
this.disposables.push(onDidChangeTitle(title => this.updateTitle(title)));
}
async show(query: string): Promise<IPagedModel<IExtension>> {
@@ -1044,6 +1040,12 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
private getRecommendationsToInstall(): Promise<IExtensionRecommendation[]> {
return this.tipsService.getWorkspaceRecommendations()
.then(recommendations => recommendations.filter(({ extensionId }) => !this.extensionsWorkbenchService.local.some(i => areSameExtensions({ id: extensionId }, i.identifier))));
.then(recommendations => recommendations.filter(({ extensionId }) => {
const extension = this.extensionsWorkbenchService.local.filter(i => areSameExtensions({ id: extensionId }, i.identifier))[0];
if (!extension || !extension.local || extension.state !== ExtensionState.Installed) {
return true;
}
return isUIExtension(extension.local.manifest, this.configurationService) ? extension.server !== this.extensionManagementServerService.localExtensionManagementServer : extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer;
}));
}
}

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/extensionsWidgets';
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer } from '../common/extensions';
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState } from '../common/extensions';
import { append, $, addClass } from 'vs/base/browser/dom';
import * as platform from 'vs/base/common/platform';
import { localize } from 'vs/nls';
@@ -148,34 +148,46 @@ export class TooltipWidget extends ExtensionWidget {
constructor(
private readonly parent: HTMLElement,
private readonly extensionLabelAction: DisabledLabelAction,
private readonly disabledLabelAction: DisabledLabelAction,
private readonly recommendationWidget: RecommendationWidget,
private readonly reloadAction: ReloadAction
private readonly reloadAction: ReloadAction,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@ILabelService private readonly labelService: ILabelService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
) {
super();
this._register(Event.any<any>(
this.extensionLabelAction.onDidChange,
this.disabledLabelAction.onDidChange,
this.reloadAction.onDidChange,
this.recommendationWidget.onDidChangeTooltip
this.recommendationWidget.onDidChangeTooltip,
this.labelService.onDidChangeFormatters
)(() => this.render()));
}
render(): void {
this.parent.title = '';
this.parent.removeAttribute('aria-label');
this.parent.title = this.getTooltip();
if (this.extension) {
const title = this.getTitle();
this.parent.title = title;
this.parent.setAttribute('aria-label', localize('extension-arialabel', "{0}. {1} Press enter for extension details.", this.extension.displayName));
}
}
private getTitle(): string {
private getTooltip(): string {
if (!this.extension) {
return '';
}
if (this.reloadAction.enabled) {
return this.reloadAction.tooltip;
}
if (this.extensionLabelAction.enabled) {
return this.extensionLabelAction.label;
if (this.disabledLabelAction.label) {
return this.disabledLabelAction.label;
}
if (this.extension.local && this.extension.state === ExtensionState.Installed) {
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority));
}
return localize('extension enabled locally', "Extension is enabled locally.");
}
return this.recommendationWidget.tooltip;
}
@@ -252,6 +264,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
constructor(
parent: HTMLElement,
private readonly tooltip: boolean,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
@@ -276,7 +289,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
return;
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge);
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
append(this.element, this.remoteBadge.element);
}
}
@@ -294,6 +307,7 @@ class RemoteBadge extends Disposable {
readonly element: HTMLElement;
constructor(
private readonly tooltip: boolean,
@ILabelService private readonly labelService: ILabelService,
@IThemeService private readonly themeService: IThemeService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@@ -320,12 +334,14 @@ class RemoteBadge extends Disposable {
this._register(this.themeService.onThemeChange(() => applyBadgeStyle()));
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => applyBadgeStyle()));
const updateTitle = () => {
if (this.element) {
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
}
};
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));
updateTitle();
if (this.tooltip) {
const updateTitle = () => {
if (this.element) {
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
}
};
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));
updateTitle();
}
}
}

View File

@@ -7,6 +7,9 @@
padding: 0 5px;
outline-offset: 2px;
line-height: initial;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.monaco-action-bar .action-item .action-label.clear-extensions {
@@ -35,7 +38,7 @@
.monaco-action-bar .action-item.disabled .action-label.extension-action.extension-editor-dropdown-action,
.monaco-action-bar .action-item.disabled .action-label.extension-action.reload,
.monaco-action-bar .action-item.disabled .action-label.disable-status.hide,
.monaco-action-bar .action-item.disabled .action-label.disable-warning.hide,
.monaco-action-bar .action-item.disabled .action-label.system-disable.hide,
.monaco-action-bar .action-item.disabled .action-label.extension-status-label.hide,
.monaco-action-bar .action-item.disabled .action-label.malicious-status.not-malicious {
display: none;
@@ -67,24 +70,33 @@
padding-left: 0;
}
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .action-label.disable-warning,
.extensions-viewlet>.extensions .extension>.details>.footer>.monaco-action-bar .action-item .action-label.disable-warning {
cursor: default;
margin: 0.1em;
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .action-label.system-disable,
.extensions-viewlet>.extensions .extension>.details>.footer>.monaco-action-bar .action-item .action-label.system-disable {
margin: 0.15em;
}
.monaco-action-bar .action-item .action-label.disable-warning.icon {
.monaco-action-bar .action-item .action-label.system-disable.icon {
opacity: 1;
height: 18px;
width: 10px;
background: url('status-warning.svg') center center no-repeat;
margin-top: 0.15em
}
.vs-dark .monaco-action-bar .action-item .action-label.disable-warning.icon {
.monaco-action-bar .action-item .action-label.system-disable.warning.icon {
background: url('status-warning.svg') center center no-repeat;
}
.vs-dark .monaco-action-bar .action-item .action-label.system-disable.warning.icon {
background: url('status-warning-inverse.svg') center center no-repeat;
}
.monaco-action-bar .action-item .action-label.system-disable.info.icon {
background: url('status-info.svg') center center no-repeat;
}
.vs-dark .monaco-action-bar .action-item .action-label.system-disable.info.icon {
background: url('status-info-inverse.svg') center center no-repeat;
}
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.extension-status-label,
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.disable-status,
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status {

View File

@@ -41,11 +41,13 @@
line-height: 38px;
border-radius: 20px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.extension-editor > .header > .icon-container .extension-remote-badge .octicon {
font-size: 32px;
vertical-align: middle;
font-size: 28px;
}
.extension-editor > .header > .details {
@@ -145,6 +147,9 @@
padding: 1px 6px;
}
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .extension-action {
max-width: 300px;
}
.extension-editor > .header > .details > .subtext-container {
display: block;

View File

@@ -113,6 +113,10 @@
text-align: center;
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container .extension-remote-badge > .octicon {
vertical-align: middle
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header > .extension-remote-badge-container {
margin-left: 6px;
}
@@ -123,11 +127,13 @@
line-height: 14px;
border-radius: 20px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge > .octicon {
font-size: 13px;
vertical-align: middle;
font-size: 12px;
}
.extensions-viewlet.narrow > .extensions .extension > .icon-container,
@@ -224,6 +230,14 @@
flex-wrap: wrap-reverse;
}
.extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar > .actions-container .extension-action {
max-width: 150px;
}
.extensions-viewlet.narrow > .extensions .extension > .details > .footer > .monaco-action-bar > .actions-container .extension-action {
max-width: 100px;
}
.extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-label {
margin-top: 0.3em;
margin-left: 0.3em;

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8.5" cy="7.5" r="5.5" fill="#1E1E1E"/><path d="M8.5 3C6.015 3 4 5.015 4 7.5S6.015 12 8.5 12 13 9.985 13 7.5 10.985 3 8.5 3zm.5 8H8V6h1v5zm0-6H8V4h1v1z" fill="#1BA1E2"/><path d="M8 6h1v5H8V6zm0-2v1h1V4H8z" fill="#252526"/></svg>

After

Width:  |  Height:  |  Size: 356 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8.5" cy="7.5" r="5.5" fill="#F6F6F6"/><path d="M8.5 3C6.015 3 4 5.015 4 7.5S6.015 12 8.5 12 13 9.985 13 7.5 10.985 3 8.5 3zm.5 8H8V6h1v5zm0-6H8V4h1v1z" fill="#1BA1E2"/><path d="M8 6h1v5H8V6zm0-2v1h1V4H8z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 353 B

View File

@@ -379,12 +379,12 @@ export class RuntimeExtensionsEditor extends BaseEditor {
if (element.description.extensionLocation.scheme !== 'file') {
const el = $('span');
el.innerHTML = renderOcticons(`$(rss) ${element.description.extensionLocation.authority}`);
el.innerHTML = renderOcticons(`$(remote) ${element.description.extensionLocation.authority}`);
data.msgContainer.appendChild(el);
const hostLabel = this._labelService.getHostLabel(REMOTE_HOST_SCHEME, this._environmentService.configuration.remoteAuthority);
if (hostLabel) {
el.innerHTML = renderOcticons(`$(rss) ${hostLabel}`);
el.innerHTML = renderOcticons(`$(remote) ${hostLabel}`);
}
}

View File

@@ -36,7 +36,7 @@ import * as resources from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension } from 'vs/platform/extensions/common/extensions';
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
// {{SQL CARBON EDIT}}
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
@@ -605,15 +605,19 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
get local(): IExtension[] {
const result = [...this.localExtensions.local];
if (!this.remoteExtensions) {
return result;
}
result.push(...this.remoteExtensions.local);
const result = [...this.installed];
const byId = groupByExtension(result, r => r.identifier);
return byId.reduce((result, extensions) => { result.push(this.getPrimaryExtension(extensions)); return result; }, []);
}
get installed(): IExtension[] {
const result = [...this.localExtensions.local];
if (this.remoteExtensions) {
result.push(...this.remoteExtensions.local);
}
return result;
}
get outdated(): IExtension[] {
const allLocal = [...this.localExtensions.local];
if (this.remoteExtensions) {
@@ -855,7 +859,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
return this.installWithProgress(async () => {
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}} remove extensionservice install from gallery
if (extensionPolicy === ExtensionsPolicy.allowMicrosoft) {
if (extension.publisherDisplayName === 'Microsoft') {
await this.downloadOrBrowse(extension).then(() => this.checkAndEnableDisabledDependencies(gallery.identifier));
@@ -916,7 +920,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' with version '{1}' as it is not compatible with Azure Data Studio.", extension.gallery!.identifier.id, version)));
}
return this.installWithProgress(async () => {
await this.extensionService.installFromGallery(gallery);
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService;
await extensionService.installFromGallery(gallery);
if (extension.latestVersion !== version) {
this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(gallery.identifier, version));
}

View File

@@ -15,6 +15,7 @@ import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
/**
* An implementation of editor for binary files like images.
@@ -29,7 +30,8 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
@IWindowsService private readonly windowsService: IWindowsService,
@IEditorService private readonly editorService: IEditorService,
@IStorageService storageService: IStorageService,
@ITextFileService textFileService: ITextFileService
@ITextFileService textFileService: ITextFileService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
) {
super(
BinaryFileEditor.ID,
@@ -40,7 +42,8 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
telemetryService,
themeService,
textFileService,
storageService
environmentService,
storageService,
);
}

View File

@@ -38,6 +38,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerService';
import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles';
import { Schemas } from 'vs/base/common/network';
// Viewlet Action
export class OpenExplorerViewletAction extends ShowViewletAction {
@@ -59,7 +60,7 @@ class FileUriLabelContribution implements IWorkbenchContribution {
constructor(@ILabelService labelService: ILabelService) {
labelService.registerFormatter({
scheme: 'file',
scheme: Schemas.file,
formatting: {
label: '${authority}${path}',
separator: sep,
@@ -307,6 +308,7 @@ configurationRegistry.registerConfiguration({
},
'files.hotExit': {
'type': 'string',
'scope': ConfigurationScope.APPLICATION,
'enum': [HotExitConfiguration.OFF, HotExitConfiguration.ON_EXIT, HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE],
'default': HotExitConfiguration.ON_EXIT,
'markdownEnumDescriptions': [

View File

@@ -136,14 +136,15 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
const isReadonly = fileOperationError.fileOperationResult === FileOperationResult.FILE_READ_ONLY;
const triedToMakeWriteable = isReadonly && fileOperationError.options && (fileOperationError.options as IWriteTextFileOptions).overwriteReadonly;
const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED;
const canHandlePermissionOrReadonlyErrors = resource.scheme === Schemas.file; // https://github.com/Microsoft/vscode/issues/48659
// Save Elevated (cannot write elevated https://github.com/Microsoft/vscode/issues/48659)
if (resource.scheme === Schemas.file && (isPermissionDenied || triedToMakeWriteable)) {
// Save Elevated
if (canHandlePermissionOrReadonlyErrors && (isPermissionDenied || triedToMakeWriteable)) {
actions.primary!.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable));
}
// Overwrite (cannot overwrite readonly https://github.com/Microsoft/vscode/issues/48659)
else if (resource.scheme === Schemas.file && isReadonly) {
// Overwrite
else if (canHandlePermissionOrReadonlyErrors && isReadonly) {
actions.primary!.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model));
}
@@ -158,13 +159,14 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
// Discard
actions.primary!.push(this.instantiationService.createInstance(ExecuteCommandAction, REVERT_FILE_COMMAND_ID, nls.localize('discard', "Discard")));
if (isReadonly) {
// Message
if (canHandlePermissionOrReadonlyErrors && isReadonly) {
if (triedToMakeWriteable) {
message = isWindows ? nls.localize('readonlySaveErrorAdmin', "Failed to save '{0}': File is read-only. Select 'Overwrite as Admin' to retry as administrator.", basename(resource)) : nls.localize('readonlySaveErrorSudo', "Failed to save '{0}': File is read-only. Select 'Overwrite as Sudo' to retry as superuser.", basename(resource));
} else {
message = nls.localize('readonlySaveError', "Failed to save '{0}': File is read-only. Select 'Overwrite' to attempt to make it writeable.", basename(resource));
}
} else if (isPermissionDenied) {
} else if (canHandlePermissionOrReadonlyErrors && isPermissionDenied) {
message = isWindows ? nls.localize('permissionDeniedSaveError', "Failed to save '{0}': Insufficient permissions. Select 'Retry as Admin' to retry as administrator.", basename(resource)) : nls.localize('permissionDeniedSaveErrorSudo', "Failed to save '{0}': Insufficient permissions. Select 'Retry as Sudo' to retry as superuser.", basename(resource));
} else {
message = nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(resource), toErrorMessage(error, false));
@@ -246,7 +248,7 @@ class ResolveSaveConflictAction extends Action {
return this.editorService.openEditor(
{
leftResource: URI.from({ scheme: CONFLICT_RESOLUTION_SCHEME, path: resource.fsPath }),
leftResource: resource.with({ scheme: CONFLICT_RESOLUTION_SCHEME }),
rightResource: resource,
label: editorLabel,
options: { pinned: true }

View File

@@ -50,7 +50,7 @@ registerEditorAction(class FormatDocumentMultipleAction extends EditorAction {
return commandService.executeCommand('editor.action.formatDocument');
} else {
const langName = model.getLanguageIdentifier().language;
const message = nls.localize('no.rovider', "There is no formatter for '{0}'-files installed.", langName);
const message = nls.localize('no.provider', "There is no formatter for '{0}'-files installed.", langName);
const choice = {
label: nls.localize('install.formatter', "Install Formatter..."),
run: () => showExtensionQuery(viewletService, `category:formatters ${langName}`)

View File

@@ -159,6 +159,11 @@ export const tocData: ITOCEntry = {
id: 'features/comments',
label: localize('comments', "Comments"),
settings: ['comments.*']
},
{
id: 'features/remote',
label: localize('remote', "Remote"),
settings: ['remote.*']
}
]
},

View File

@@ -418,14 +418,14 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
.then(() => {
const remoteAuthority = environmentService.configuration.remoteAuthority;
const hostLabel = labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority) || remoteAuthority;
const label = nls.localize('openRemoteSettings', "Open User Settings ({0})", hostLabel);
const label = nls.localize('openRemoteSettings', "Open Remote Settings ({0})", hostLabel);
CommandsRegistry.registerCommand(OpenRemoteSettingsAction.ID, serviceAccessor => {
serviceAccessor.get(IInstantiationService).createInstance(OpenRemoteSettingsAction, OpenRemoteSettingsAction.ID, label).run();
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: OpenRemoteSettingsAction.ID,
title: { value: label, original: `Preferences: Open User Settings (${hostLabel})` },
title: { value: label, original: `Preferences: Open Remote Settings (${hostLabel})` },
category: nls.localize('preferencesCategory', "Preferences")
},
when: RemoteAuthorityContext.notEqualsTo('')

View File

@@ -205,7 +205,7 @@ export class SettingsEditor2 extends BaseEditor {
this.updateStyles();
}
setInput(input: SettingsEditor2Input, options: SettingsEditorOptions, token: CancellationToken): Promise<void> {
setInput(input: SettingsEditor2Input, options: SettingsEditorOptions | null, token: CancellationToken): Promise<void> {
this.inSettingsEditorContextKey.set(true);
return super.setInput(input, options, token)
.then(() => new Promise(process.nextTick)) // Force setInput to be async
@@ -213,10 +213,10 @@ export class SettingsEditor2 extends BaseEditor {
return this.render(token);
})
.then(() => {
options = options || SettingsEditorOptions.create({});
if (!this.viewState.settingsTarget) {
if (!options) {
options = SettingsEditorOptions.create({ target: ConfigurationTarget.USER_LOCAL });
} else if (!options.target) {
if (!options.target) {
options.target = ConfigurationTarget.USER_LOCAL;
}
}
@@ -1065,7 +1065,7 @@ export class SettingsEditor2 extends BaseEditor {
this.searchInProgress = null;
}
this.viewState.filterToCategory = undefined;
this.tocTree.setFocus([]);
this.tocTreeModel.currentSearchModel = this.searchResultModel;
this.onSearchModeToggled();
@@ -1206,8 +1206,7 @@ export class SettingsEditor2 extends BaseEditor {
this.tocTreeModel.update();
}
this.tocTree.setSelection([]);
this.viewState.filterToCategory = undefined;
this.tocTree.setFocus([]);
this.tocTree.expandAll();
this.renderTree(undefined, true);

View File

@@ -26,12 +26,12 @@ const id = 'workbench.action.openSnippets';
namespace ISnippetPick {
export function is(thing: object): thing is ISnippetPick {
return thing && typeof (<ISnippetPick>thing).filepath === 'string';
return thing && URI.isUri((<ISnippetPick>thing).filepath);
}
}
interface ISnippetPick extends IQuickPickItem {
filepath: string;
filepath: URI;
hint?: true;
}
@@ -71,7 +71,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
existing.push({
label: basename(file.location.fsPath),
filepath: file.location.fsPath,
filepath: file.location,
description: names.size === 0
? nls.localize('global.scope', "(global)")
: nls.localize('global.1', "({0})", values(names).join(', '))
@@ -83,7 +83,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
existing.push({
label: basename(file.location.fsPath),
description: `(${modeService.getLanguageName(mode)})`,
filepath: file.location.fsPath
filepath: file.location
});
seen.add(mode);
}
@@ -96,15 +96,15 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
future.push({
label: mode,
description: `(${label})`,
filepath: join(dir, `${mode}.json`),
filepath: URI.file(join(dir, `${mode}.json`)),
hint: true
});
}
}
existing.sort((a, b) => {
let a_ext = extname(a.filepath);
let b_ext = extname(b.filepath);
let a_ext = extname(a.filepath.path);
let b_ext = extname(b.filepath.path);
if (a_ext === b_ext) {
return a.label.localeCompare(b.label);
} else if (a_ext === '.code-snippets') {
@@ -165,7 +165,7 @@ async function createSnippetFile(scope: string, defaultPath: URI, windowService:
}
async function createLanguageSnippetFile(pick: ISnippetPick, fileService: IFileService, textFileService: ITextFileService) {
if (await fileService.exists(URI.file(pick.filepath))) {
if (await fileService.exists(pick.filepath)) {
return;
}
const contents = [
@@ -185,7 +185,7 @@ async function createLanguageSnippetFile(pick: ISnippetPick, fileService: IFileS
'\t// }',
'}'
].join('\n');
await textFileService.write(URI.file(pick.filepath), contents);
await textFileService.write(pick.filepath, contents);
}
CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
@@ -240,7 +240,7 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
if (pick.hint) {
await createLanguageSnippetFile(pick, fileService, textFileService);
}
return opener.open(URI.file(pick.filepath));
return opener.open(pick.filepath);
}
});

View File

@@ -246,8 +246,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
/* __GDPR__FRAGMENT__
"WorkspaceTags" : {
"workbench.filesToOpen" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workspace.id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"workspace.roots" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
@@ -352,9 +351,8 @@ export class WorkspaceStats implements IWorkbenchContribution {
tags['workspace.id'] = workspaceId;
const { filesToOpen, filesToCreate, filesToDiff } = configuration;
tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || 0;
tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || 0;
const { filesToOpenOrCreate, filesToDiff } = configuration;
tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0;
tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0;
const isEmpty = state === WorkbenchState.EMPTY;
@@ -586,11 +584,9 @@ export class WorkspaceStats implements IWorkbenchContribution {
return folder && [folder];
}
private findFolder({ filesToOpen, filesToCreate, filesToDiff }: IWindowConfiguration): URI | undefined {
if (filesToOpen && filesToOpen.length) {
return this.parentURI(filesToOpen[0].fileUri);
} else if (filesToCreate && filesToCreate.length) {
return this.parentURI(filesToCreate[0].fileUri);
private findFolder({ filesToOpenOrCreate, filesToDiff }: IWindowConfiguration): URI | undefined {
if (filesToOpenOrCreate && filesToOpenOrCreate.length) {
return this.parentURI(filesToOpenOrCreate[0].fileUri);
} else if (filesToDiff && filesToDiff.length) {
return this.parentURI(filesToDiff[0].fileUri);
}

View File

@@ -36,7 +36,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
) {
super();
const { filesToOpen, filesToCreate, filesToDiff } = environmentService.configuration;
const { filesToOpenOrCreate, filesToDiff } = environmentService.configuration;
const activeViewlet = viewletService.getActiveViewlet();
/* __GDPR__
@@ -47,8 +47,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
"windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToOpenOrCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
@@ -64,8 +63,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
userAgent: navigator.userAgent,
windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth },
emptyWorkbench: contextService.getWorkbenchState() === WorkbenchState.EMPTY,
'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0,
'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0,
'workbench.filesToOpenOrCreate': filesToOpenOrCreate && filesToOpenOrCreate.length || 0,
'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0,
customKeybindingsCount: keybindingsService.customKeybindingsCount(),
theme: themeService.getColorTheme().id,

View File

@@ -339,7 +339,7 @@ export class CreateNewTerminalAction extends Action {
// Don't create the instance if the workspace picker was canceled
return null;
}
return this.terminalService.createTerminal({ cwd: workspace.uri.fsPath }, true);
return this.terminalService.createTerminal({ cwd: workspace.uri }, true);
});
}

View File

@@ -15,7 +15,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { Schemas } from 'vs/base/common/network';
import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IProductService } from 'vs/platform/product/common/product';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
@@ -131,7 +131,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
});
}
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(hasRemoteAuthority ? REMOTE_HOST_SCHEME : undefined);
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
} else {
this._process = this._launchProcess(shellLaunchConfig, cols, rows);

View File

@@ -34,24 +34,26 @@ export function registerFileProtocol(
getRoots: () => ReadonlyArray<URI>
) {
contents.session.protocol.registerBufferProtocol(protocol, (request, callback: any) => {
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const requestUri = URI.parse(request.url);
const redirectedUri = URI.from({
scheme: REMOTE_HOST_SCHEME,
authority: extensionLocation.authority,
path: '/vscode-resource',
query: JSON.stringify({
requestResourcePath: requestUri.path
})
});
resolveContent(textFileService, redirectedUri, getMimeType(requestUri), callback);
return;
}
const requestPath = URI.parse(request.url).path;
const normalizedPath = URI.file(requestPath);
for (const root of getRoots()) {
if (startsWith(normalizedPath.fsPath, root.fsPath + sep)) {
if (!startsWith(normalizedPath.fsPath, root.fsPath + sep)) {
continue;
}
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const requestUri = URI.parse(request.url);
const redirectedUri = URI.from({
scheme: REMOTE_HOST_SCHEME,
authority: extensionLocation.authority,
path: '/vscode-resource',
query: JSON.stringify({
requestResourcePath: requestUri.path
})
});
resolveContent(textFileService, redirectedUri, getMimeType(requestUri), callback);
return;
} else {
resolveContent(textFileService, normalizedPath, getMimeType(normalizedPath), callback);
return;
}