mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 08:40:29 -04:00
Merge from vscode 3d67364fbfcf676d93be64f949e9b33e7f1b969e (#5028)
This commit is contained in:
@@ -250,7 +250,8 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
}
|
||||
|
||||
private layoutTreeAndContainer(): void {
|
||||
const treeHeight = Math.min(MAX_TREE_HEIGHT, this.tree.contentHeight);
|
||||
const scrollBarHeight = 8;
|
||||
const treeHeight = Math.min(MAX_TREE_HEIGHT, this.tree.contentHeight + scrollBarHeight);
|
||||
this.treeContainer.style.height = `${treeHeight}px`;
|
||||
this.tree.layout(treeHeight, 324);
|
||||
}
|
||||
|
||||
@@ -720,11 +720,25 @@ class ReplDelegate implements IListVirtualDelegate<IReplElement> {
|
||||
getHeight(element: IReplElement): number {
|
||||
// Give approximate heights. Repl has dynamic height so the tree will measure the actual height on its own.
|
||||
const fontSize = this.configurationService.getValue<IDebugConfiguration>('debug').console.fontSize;
|
||||
const rowHeight = Math.ceil(1.4 * fontSize);
|
||||
if (element instanceof Expression && element.hasChildren) {
|
||||
return Math.ceil(2 * 1.4 * fontSize);
|
||||
return 2 * rowHeight;
|
||||
}
|
||||
|
||||
return Math.ceil(1.4 * fontSize);
|
||||
// In order to keep scroll position we need to give a good approximation to the tree
|
||||
if (element instanceof SimpleReplElement) {
|
||||
// For every 150 characters increase the number of lines needed
|
||||
let count = Math.ceil(element.value.length / 150);
|
||||
for (let i = 0; i < element.value.length; i++) {
|
||||
if (element.value[i] === '\n' || element.value[i] === '\r\n') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return Math.max(1, count) * rowHeight;
|
||||
}
|
||||
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
getTemplateId(element: IReplElement): string {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbenc
|
||||
import { isUndefinedOrNull, isObject } from 'vs/base/common/types';
|
||||
import { basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
|
||||
const MAX_REPL_LENGTH = 10000;
|
||||
let topReplElementCounter = 0;
|
||||
@@ -39,8 +40,13 @@ export class ReplModel {
|
||||
}
|
||||
|
||||
if (typeof data === 'string') {
|
||||
const element = new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, data.trimRight(), sev, source);
|
||||
this.addReplElement(element);
|
||||
const previousElement = this.replElements.length ? this.replElements[this.replElements.length - 1] : undefined;
|
||||
if (previousElement instanceof SimpleReplElement && previousElement.severity === sev && !endsWith(previousElement.value, '\n') && !endsWith(previousElement.value, '\r\n')) {
|
||||
previousElement.value += data;
|
||||
} else {
|
||||
const element = new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, data, sev, source);
|
||||
this.addReplElement(element);
|
||||
}
|
||||
} else {
|
||||
// TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression
|
||||
(<any>data).severity = sev;
|
||||
|
||||
@@ -509,7 +509,7 @@ export class DebugService implements IDebugService {
|
||||
|
||||
// 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905
|
||||
if (isExtensionHostDebugging(session.configuration) && session.state === State.Running && session.configuration.noDebug) {
|
||||
this.extensionHostDebugService.close(session.root.uri);
|
||||
this.extensionHostDebugService.close(session.getId());
|
||||
}
|
||||
|
||||
this.telemetryDebugSessionStop(session, adapterExitEvent);
|
||||
@@ -556,8 +556,8 @@ export class DebugService implements IDebugService {
|
||||
return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? session.restart() : undefined);
|
||||
}
|
||||
|
||||
if (isExtensionHostDebugging(session.configuration) && session.root) {
|
||||
return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.root.uri) : undefined);
|
||||
if (isExtensionHostDebugging(session.configuration)) {
|
||||
return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.getId()) : undefined);
|
||||
}
|
||||
|
||||
const shouldFocus = this.viewModel.focusedSession && session.getId() === this.viewModel.focusedSession.getId();
|
||||
|
||||
@@ -423,34 +423,41 @@ suite('Debug - Model', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const repl = new ReplModel(session);
|
||||
repl.appendToRepl('first line\n', severity.Error);
|
||||
repl.appendToRepl('second line', severity.Error);
|
||||
repl.appendToRepl('third line', severity.Warning);
|
||||
repl.appendToRepl('second line ', severity.Error);
|
||||
repl.appendToRepl('third line ', severity.Error);
|
||||
repl.appendToRepl('fourth line', severity.Error);
|
||||
|
||||
let elements = <SimpleReplElement[]>repl.getReplElements();
|
||||
assert.equal(elements.length, 4);
|
||||
assert.equal(elements[0].value, 'first line');
|
||||
assert.equal(elements.length, 2);
|
||||
assert.equal(elements[0].value, 'first line\n');
|
||||
assert.equal(elements[0].severity, severity.Error);
|
||||
assert.equal(elements[1].value, 'second line');
|
||||
assert.equal(elements[1].value, 'second line third line fourth line');
|
||||
assert.equal(elements[1].severity, severity.Error);
|
||||
assert.equal(elements[2].value, 'third line');
|
||||
assert.equal(elements[2].severity, severity.Warning);
|
||||
assert.equal(elements[3].value, 'fourth line');
|
||||
assert.equal(elements[3].severity, severity.Error);
|
||||
|
||||
repl.appendToRepl('1', severity.Warning);
|
||||
elements = <SimpleReplElement[]>repl.getReplElements();
|
||||
assert.equal(elements.length, 5);
|
||||
assert.equal(elements[4].value, '1');
|
||||
assert.equal(elements[4].severity, severity.Warning);
|
||||
assert.equal(elements.length, 3);
|
||||
assert.equal(elements[2].value, '1');
|
||||
assert.equal(elements[2].severity, severity.Warning);
|
||||
|
||||
const keyValueObject = { 'key1': 2, 'key2': 'value' };
|
||||
repl.appendToRepl(new RawObjectReplElement('fakeid', 'fake', keyValueObject), severity.Info);
|
||||
const element = <RawObjectReplElement>repl.getReplElements()[5];
|
||||
const element = <RawObjectReplElement>repl.getReplElements()[3];
|
||||
assert.equal(element.value, 'Object');
|
||||
assert.deepEqual(element.valueObj, keyValueObject);
|
||||
|
||||
repl.removeReplExpressions();
|
||||
assert.equal(repl.getReplElements().length, 0);
|
||||
|
||||
repl.appendToRepl('1\n', severity.Info);
|
||||
repl.appendToRepl('2', severity.Info);
|
||||
repl.appendToRepl('3\n4', severity.Info);
|
||||
repl.appendToRepl('5\n', severity.Info);
|
||||
repl.appendToRepl('6', severity.Info);
|
||||
elements = <SimpleReplElement[]>repl.getReplElements();
|
||||
assert.equal(elements.length, 3);
|
||||
assert.equal(elements[0], '1\n');
|
||||
assert.equal(elements[1], '23\n45\n');
|
||||
assert.equal(elements[2], '6');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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, SystemDisabledLabelAction, 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 } 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';
|
||||
@@ -395,7 +395,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.instantiationService.createInstance(RemoteInstallAction),
|
||||
combinedInstallAction,
|
||||
systemDisabledWarningAction,
|
||||
this.instantiationService.createInstance(SystemDisabledLabelAction, systemDisabledWarningAction),
|
||||
this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction),
|
||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, true),
|
||||
];
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
@@ -623,9 +623,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
renderDashboardContributions(content, manifest, layout)
|
||||
];
|
||||
|
||||
const isEmpty = !renders.reduce((v, r) => r || v, false);
|
||||
scrollableContent.scanDomNode();
|
||||
|
||||
const isEmpty = !renders.some(x => x);
|
||||
if (isEmpty) {
|
||||
append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions");
|
||||
append(this.content, content);
|
||||
|
||||
@@ -21,6 +21,7 @@ import { randomPort } from 'vs/base/node/ports';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
|
||||
|
||||
export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService {
|
||||
|
||||
@@ -76,7 +77,8 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._extensionService.canProfileExtensionHost()) {
|
||||
const inspectPort = this._extensionService.getInspectPort();
|
||||
if (!inspectPort) {
|
||||
return this._dialogService.confirm({
|
||||
type: 'info',
|
||||
message: nls.localize('restart1', "Profile Extensions"),
|
||||
@@ -92,7 +94,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
|
||||
|
||||
this._setState(ProfileSessionState.Starting);
|
||||
|
||||
return this._extensionService.startExtensionHostProfile().then((value) => {
|
||||
return this._instantiationService.createInstance(ExtensionHostProfiler, inspectPort).start().then((value) => {
|
||||
this._profileSession = value;
|
||||
this._setState(ProfileSessionState.Running);
|
||||
}, (err) => {
|
||||
|
||||
@@ -251,6 +251,11 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
||||
description: localize('extensionsPolicy', "Sets the security policy for downloading extensions."),
|
||||
scope: ConfigurationScope.APPLICATION,
|
||||
default: ExtensionsPolicy.allowAll
|
||||
},
|
||||
'extensions.showInstalledExtensionsByDefault': {
|
||||
type: 'boolean',
|
||||
description: localize('extensions.showInstalledExtensionsByDefault', "When enabled, extensions view shows installed extensions view by default."),
|
||||
default: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -60,6 +60,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -183,7 +184,7 @@ export class InstallAction extends ExtensionAction {
|
||||
return;
|
||||
}
|
||||
|
||||
this.enabled = this.extensionsWorkbenchService.canInstall(this.extension) && this.extension.state === ExtensionState.Uninstalled;
|
||||
this.enabled = this.extensionsWorkbenchService.canInstall(this.extension) && !this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier));
|
||||
this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
|
||||
this.updateLabel();
|
||||
}
|
||||
@@ -720,7 +721,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
||||
]);
|
||||
groups.push([this.instantiationService.createInstance(UninstallAction)]);
|
||||
groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]);
|
||||
groups.push([this.instantiationService.createInstance(ExtensionInfoAction)]);
|
||||
groups.push([this.instantiationService.createInstance(ExtensionInfoAction), this.instantiationService.createInstance(ExtensionSettingsAction)]);
|
||||
|
||||
groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension));
|
||||
|
||||
@@ -829,6 +830,27 @@ export class ExtensionInfoAction extends ExtensionAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtensionSettingsAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'extensions.extensionSettings';
|
||||
static readonly LABEL = localize('extensionSettingsAction', "Configure Extension Settings");
|
||||
|
||||
constructor(
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService
|
||||
) {
|
||||
super(ExtensionSettingsAction.ID, ExtensionSettingsAction.LABEL);
|
||||
this.update();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = !!this.extension;
|
||||
}
|
||||
run(): Promise<any> {
|
||||
this.preferencesService.openSettings(false, `@ext:${this.extension.identifier.id}`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export class EnableForWorkspaceAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'extensions.enableForWorkspace';
|
||||
@@ -1195,9 +1217,10 @@ export class ReloadAction extends ExtensionAction {
|
||||
}
|
||||
const isUninstalled = this.extension.state === ExtensionState.Uninstalled;
|
||||
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
||||
const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
|
||||
|
||||
if (isUninstalled) {
|
||||
if (runningExtension) {
|
||||
if (isSameExtensionRunning) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
@@ -1210,7 +1233,6 @@ export class ReloadAction extends ExtensionAction {
|
||||
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||
if (runningExtension) {
|
||||
// Extension is running
|
||||
const isSameExtensionRunning = this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
|
||||
const isSameVersionRunning = isSameExtensionRunning && this.extension.version === runningExtension.version;
|
||||
if (isEnabled) {
|
||||
if (!isSameVersionRunning && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||
@@ -2484,6 +2506,7 @@ export class StatusLabelAction extends Action implements IExtensionContainer {
|
||||
return canAddExtension() ? this.initialStatus === ExtensionState.Installed ? localize('updated', "Updated") : localize('installed', "Installed") : null;
|
||||
}
|
||||
if (currentStatus === ExtensionState.Uninstalling && this.status === ExtensionState.Uninstalled) {
|
||||
this.initialStatus = this.status;
|
||||
return canRemoveExtension() ? localize('uninstalled', "Uninstalled") : null;
|
||||
}
|
||||
}
|
||||
@@ -2533,7 +2556,7 @@ export class MaliciousStatusLabelAction extends ExtensionAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class SystemDisabledLabelAction extends ExtensionAction {
|
||||
export class DisabledLabelAction extends ExtensionAction {
|
||||
|
||||
private static readonly Class = 'disable-status';
|
||||
|
||||
@@ -2542,19 +2565,26 @@ export class SystemDisabledLabelAction extends ExtensionAction {
|
||||
|
||||
constructor(
|
||||
private readonly warningAction: SystemDisabledWarningAction,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||
) {
|
||||
super('extensions.systemDisabledLabel', warningAction.tooltip, `${SystemDisabledLabelAction.Class} hide`, false);
|
||||
super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false);
|
||||
warningAction.onDidChange(() => this.update(), this, this.disposables);
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = this.warningAction.enabled;
|
||||
if (this.enabled) {
|
||||
this.class = SystemDisabledLabelAction.Class;
|
||||
this.class = `${DisabledLabelAction.Class} hide`;
|
||||
this.label = '';
|
||||
if (this.warningAction.enabled) {
|
||||
this.enabled = true;
|
||||
this.class = DisabledLabelAction.Class;
|
||||
this.label = this.warningAction.tooltip;
|
||||
} else {
|
||||
this.class = `${SystemDisabledLabelAction.Class} hide`;
|
||||
this.label = '';
|
||||
return;
|
||||
}
|
||||
if (this.extension && this.extension.local && !this.extensionEnablementService.isEnabled(this.extension.local)) {
|
||||
this.enabled = true;
|
||||
this.class = DisabledLabelAction.Class;
|
||||
this.label = localize('disabled by user', "This extension is disabled by the user.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2599,27 +2629,42 @@ export class SystemDisabledWarningAction extends ExtensionAction {
|
||||
this.enabled = false;
|
||||
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
||||
this.tooltip = '';
|
||||
if (this.extension && this.extension.local && this._runningExtensions) {
|
||||
if (this.extension && this.extension.local && this.extension.server && this._runningExtensions && this.workbenchEnvironmentService.configuration.remoteAuthority && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
if (
|
||||
// Remote Window
|
||||
this.workbenchEnvironmentService.configuration.remoteAuthority
|
||||
// Local Workspace Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !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.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
||||
) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||
this.tooltip = localize('disabled workspace Extension', "This extension is disabled because it cannot run in a window connected to the remote server.", host, host);
|
||||
if (this.extensionsWorkbenchService.canInstall(this.extension)) {
|
||||
this.tooltip = `${this.tooltip} ${localize('Install in remote server', "Install it in '{0}' server to enable.", host)}`;
|
||||
this.tooltip = localize('disabled workspace Extension', "This extension from {0} server is disabled because it cannot run in a window connected to the remote server.", this.getServerLabel(this.extensionManagementServerService.localExtensionManagementServer));
|
||||
if (!this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
|
||||
&& this.extensionsWorkbenchService.canInstall(this.extension)
|
||||
) {
|
||||
// Extension does not exist in remote
|
||||
this.tooltip = `${this.tooltip} ${localize('Install in remote server', "Install it in {0} server to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer))}`;
|
||||
}
|
||||
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;
|
||||
if (
|
||||
// Not same as running extension
|
||||
runningExtensionServer && this.extension.server !== runningExtensionServer
|
||||
) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
this.tooltip = localize('disabled because running in another server', "This extension from {0} server is disabled because another instance of same extension from {1} server is enabled.", this.getServerLabel(this.extension.server), this.getServerLabel(runningExtensionServer));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getServerLabel(server: IExtensionManagementServer): string {
|
||||
if (server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||
}
|
||||
return server.label;
|
||||
}
|
||||
run(): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IExtensionService, IResponsiveStateChangeEvent, ICpuProfilerTarget, IExtensionHostProfile, ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IResponsiveStateChangeEvent, IExtensionHostProfile, ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -21,11 +21,12 @@ import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { createSlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions';
|
||||
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
|
||||
|
||||
export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private readonly _session = new Map<ICpuProfilerTarget, CancellationTokenSource>();
|
||||
private readonly _blame = new Set<string>();
|
||||
private _session: CancellationTokenSource | undefined;
|
||||
|
||||
constructor(
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@@ -41,26 +42,29 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
||||
}
|
||||
|
||||
private async _onDidChangeResponsiveChange(event: IResponsiveStateChangeEvent): Promise<void> {
|
||||
const { target } = event;
|
||||
|
||||
if (!target.canProfileExtensionHost()) {
|
||||
const port = this._extensionService.getInspectPort();
|
||||
|
||||
if (!port) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isResponsive && this._session.has(target)) {
|
||||
if (event.isResponsive && this._session) {
|
||||
// stop profiling when responsive again
|
||||
this._session.get(target)!.cancel();
|
||||
this._session.cancel();
|
||||
|
||||
} else if (!event.isResponsive && !this._session.has(target)) {
|
||||
} else if (!event.isResponsive && !this._session) {
|
||||
// start profiling if not yet profiling
|
||||
const token = new CancellationTokenSource();
|
||||
this._session.set(target, token);
|
||||
const cts = new CancellationTokenSource();
|
||||
this._session = cts;
|
||||
|
||||
|
||||
let session: ProfileSession;
|
||||
try {
|
||||
session = await target.startExtensionHostProfile();
|
||||
session = await this._instantiationService.createInstance(ExtensionHostProfiler, port).start();
|
||||
|
||||
} catch (err) {
|
||||
this._session.delete(target);
|
||||
this._session = undefined;
|
||||
// fail silent as this is often
|
||||
// caused by another party being
|
||||
// connected already
|
||||
@@ -69,7 +73,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
||||
|
||||
// wait 5 seconds or until responsive again
|
||||
await new Promise(resolve => {
|
||||
token.token.onCancellationRequested(resolve);
|
||||
cts.token.onCancellationRequested(resolve);
|
||||
setTimeout(resolve, 5e3);
|
||||
});
|
||||
|
||||
@@ -79,7 +83,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
||||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
} finally {
|
||||
this._session.delete(target);
|
||||
this._session = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ 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 } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
@@ -88,13 +88,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
});
|
||||
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
|
||||
|
||||
const widgets = [
|
||||
recommendationWidget,
|
||||
badgeWidget,
|
||||
this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version),
|
||||
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
||||
this.instantiationService.createInstance(RatingsWidget, ratings, true)
|
||||
];
|
||||
const systemDisabledWarningAction = this.instantiationService.createInstance(SystemDisabledWarningAction);
|
||||
const actions = [
|
||||
this.instantiationService.createInstance(StatusLabelAction),
|
||||
this.instantiationService.createInstance(UpdateAction),
|
||||
@@ -102,10 +96,20 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
this.instantiationService.createInstance(InstallAction),
|
||||
this.instantiationService.createInstance(RemoteInstallAction),
|
||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
|
||||
this.instantiationService.createInstance(SystemDisabledWarningAction),
|
||||
systemDisabledWarningAction,
|
||||
this.instantiationService.createInstance(ManageExtensionAction)
|
||||
];
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
const disabledLabelAction = this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction);
|
||||
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget);
|
||||
const widgets = [
|
||||
recommendationWidget,
|
||||
badgeWidget,
|
||||
tooltipWidget,
|
||||
this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version),
|
||||
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
||||
this.instantiationService.createInstance(RatingsWidget, ratings, true)
|
||||
];
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, disabledLabelAction]);
|
||||
|
||||
actionbar.push(actions, actionOptions);
|
||||
const disposables = [...actions, ...widgets, actionbar, extensionContainers];
|
||||
|
||||
@@ -53,7 +53,6 @@ import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { RemoteAuthorityContext as RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
|
||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
|
||||
interface SearchInputEvent extends Event {
|
||||
@@ -64,7 +63,10 @@ interface SearchInputEvent extends Event {
|
||||
const NonEmptyWorkspaceContext = new RawContextKey<boolean>('nonEmptyWorkspace', false);
|
||||
const DefaultViewsContext = new RawContextKey<boolean>('defaultExtensionViews', true);
|
||||
const SearchMarketplaceExtensionsContext = new RawContextKey<boolean>('searchMarketplaceExtensions', false);
|
||||
const SearchServerExtensionsContext = new RawContextKey<boolean>('searchServerExtensions', false);
|
||||
const SearchIntalledExtensionsContext = new RawContextKey<boolean>('searchInstalledExtensions', false);
|
||||
const SearchOutdatedExtensionsContext = new RawContextKey<boolean>('searchOutdatedExtensions', false);
|
||||
const SearchEnabledExtensionsContext = new RawContextKey<boolean>('searchEnabledExtensions', false);
|
||||
const SearchDisabledExtensionsContext = new RawContextKey<boolean>('searchDisabledExtensions', false);
|
||||
const HasInstalledExtensionsContext = new RawContextKey<boolean>('hasInstalledExtensions', true);
|
||||
const SearchBuiltInExtensionsContext = new RawContextKey<boolean>('searchBuiltInExtensions', false);
|
||||
const RecommendedExtensionsContext = new RawContextKey<boolean>('recommendedExtensions', false);
|
||||
@@ -72,10 +74,12 @@ const DefaultRecommendedExtensionsContext = new RawContextKey<boolean>('defaultR
|
||||
const viewIdNameMappings: { [id: string]: string } = {
|
||||
'extensions.listView': localize('marketPlace', "Marketplace"),
|
||||
'extensions.enabledExtensionList': localize('enabledExtensions', "Enabled"),
|
||||
'extensions.enabledExtensionList2': localize('enabledExtensions', "Enabled"),
|
||||
'extensions.disabledExtensionList': localize('disabledExtensions', "Disabled"),
|
||||
'extensions.disabledExtensionList2': localize('disabledExtensions', "Disabled"),
|
||||
// {{SQL CARBON EDIT}}
|
||||
// 'extensions.popularExtensionsList': localize('popularExtensions', "Popular"),
|
||||
'extensions.recommendedList': localize('recommendedExtensions', "Marketplace"),
|
||||
'extensions.recommendedList': localize('recommendedExtensions', "Recommended"),
|
||||
'extensions.otherrecommendedList': localize('otherRecommendedExtensions', "Other Recommendations"),
|
||||
'extensions.workspaceRecommendedList': localize('workspaceRecommendedExtensions', "Workspace Recommendations"),
|
||||
'extensions.builtInExtensionsList': localize('builtInExtensions', "Features"),
|
||||
@@ -98,6 +102,8 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
viewDescriptors.push(this.createDefaultDisabledExtensionsListViewDescriptor());
|
||||
// {{SQL CARBON EDIT}}
|
||||
// viewDescriptors.push(this.createDefaultPopularExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDisabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInBasicsExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInThemesExtensionsListViewDescriptor());
|
||||
@@ -133,7 +139,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: EnabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), ContextKeyExpr.not('config.extensions.showInstalledExtensionsByDefault')),
|
||||
weight: 40,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
@@ -148,7 +154,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: DisabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), ContextKeyExpr.not('config.extensions.showInstalledExtensionsByDefault')),
|
||||
weight: 10,
|
||||
canToggleVisibility: true,
|
||||
order: 3,
|
||||
@@ -175,15 +181,21 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] {
|
||||
return [{
|
||||
id: `extensions.${server.authority}.installed`,
|
||||
name: server.label,
|
||||
name: localize('installed', "Installed"),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchServerExtensions')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchInstalledExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.authority}.outdated`,
|
||||
name: localize('outdated', "Outdated"),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.authority}.default`,
|
||||
name: server.label,
|
||||
name: localize('installed', "Installed"),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), ContextKeyExpr.has('config.extensions.showInstalledExtensionsByDefault')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
}];
|
||||
@@ -235,6 +247,33 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
};
|
||||
}
|
||||
|
||||
private createEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.enabledExtensionList2';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: EnabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchEnabledExtensions')),
|
||||
weight: 40,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
|
||||
private createDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.disabledExtensionList2';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: DisabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchDisabledExtensions')),
|
||||
weight: 10,
|
||||
canToggleVisibility: true,
|
||||
order: 3,
|
||||
collapsed: true
|
||||
};
|
||||
}
|
||||
|
||||
private createBuiltInExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInExtensionsList';
|
||||
return {
|
||||
@@ -278,7 +317,10 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
private nonEmptyWorkspaceContextKey: IContextKey<boolean>;
|
||||
private defaultViewsContextKey: IContextKey<boolean>;
|
||||
private searchMarketplaceExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchServerExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchInstalledExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchOutdatedExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchEnabledExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchDisabledExtensionsContextKey: IContextKey<boolean>;
|
||||
private hasInstalledExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchBuiltInExtensionsContextKey: IContextKey<boolean>;
|
||||
private recommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
@@ -317,7 +359,10 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
this.nonEmptyWorkspaceContextKey = NonEmptyWorkspaceContext.bindTo(contextKeyService);
|
||||
this.defaultViewsContextKey = DefaultViewsContext.bindTo(contextKeyService);
|
||||
this.searchMarketplaceExtensionsContextKey = SearchMarketplaceExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchServerExtensionsContextKey = SearchServerExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchInstalledExtensionsContextKey = SearchIntalledExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchOutdatedExtensionsContextKey = SearchOutdatedExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchEnabledExtensionsContextKey = SearchEnabledExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchDisabledExtensionsContextKey = SearchDisabledExtensionsContext.bindTo(contextKeyService);
|
||||
this.hasInstalledExtensionsContextKey = HasInstalledExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchBuiltInExtensionsContextKey = SearchBuiltInExtensionsContext.bindTo(contextKeyService);
|
||||
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
@@ -457,7 +502,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
|
||||
protected saveState(): void {
|
||||
const value = this.searchBox.getValue();
|
||||
if (ExtensionsListView.isInstalledExtensionsQuery(value)) {
|
||||
if (ExtensionsListView.isLocalExtensionsQuery(value)) {
|
||||
this.searchViewletState['query.value'] = value;
|
||||
} else {
|
||||
this.searchViewletState['query.value'] = '';
|
||||
@@ -468,13 +513,14 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
private doSearch(): Promise<void> {
|
||||
const value = this.normalizedQuery();
|
||||
this.defaultViewsContextKey.set(!value);
|
||||
const isServerExtensionsQuery = ExtensionsListView.isServerExtensionsQuery(value);
|
||||
const isBuiltInExtensionsQuery = ExtensionsListView.isBuiltInExtensionsQuery(value);
|
||||
const isRecommendedExtensionsQuery = ExtensionsListView.isRecommendedExtensionsQuery(value);
|
||||
this.searchServerExtensionsContextKey.set(isServerExtensionsQuery);
|
||||
this.searchBuiltInExtensionsContextKey.set(isBuiltInExtensionsQuery);
|
||||
this.searchInstalledExtensionsContextKey.set(ExtensionsListView.isInstalledExtensionsQuery(value));
|
||||
this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value));
|
||||
this.searchEnabledExtensionsContextKey.set(ExtensionsListView.isEnabledExtensionsQuery(value));
|
||||
this.searchDisabledExtensionsContextKey.set(ExtensionsListView.isDisabledExtensionsQuery(value));
|
||||
this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value));
|
||||
this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery);
|
||||
this.searchMarketplaceExtensionsContextKey.set(!!value && !isServerExtensionsQuery && !isBuiltInExtensionsQuery && !isRecommendedExtensionsQuery);
|
||||
this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery);
|
||||
this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY);
|
||||
|
||||
return this.progress(Promise.all(this.panels.map(view =>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { assign } from 'vs/base/common/objects';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { PagedModel, IPagedModel, IPager, DelayedPagedModel } from 'vs/base/common/paging';
|
||||
import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -41,7 +41,7 @@ import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
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';
|
||||
@@ -96,7 +96,8 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
|
||||
@IExperimentService private readonly experimentService: IExperimentService,
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
|
||||
this.server = options.server;
|
||||
@@ -234,7 +235,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
if (ids.length) {
|
||||
return this.queryByIds(ids, options, token);
|
||||
}
|
||||
if (ExtensionsListView.isInstalledExtensionsQuery(query.value) || /@builtin/.test(query.value)) {
|
||||
if (ExtensionsListView.isLocalExtensionsQuery(query.value) || /@builtin/.test(query.value)) {
|
||||
return this.queryLocal(query, options);
|
||||
}
|
||||
return this.queryGallery(query, options, token);
|
||||
@@ -329,7 +330,23 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
&& (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
||||
&& (!categories.length || categories.some(category => (e.local && e.local.manifest.categories || []).some(c => c.toLowerCase() === category))));
|
||||
|
||||
return this.getPagedModel(this.sortExtensions(result, options));
|
||||
if (options.sortBy !== undefined) {
|
||||
result = this.sortExtensions(result, options);
|
||||
} else {
|
||||
const runningExtensions = await this.extensionService.getExtensions();
|
||||
const runningExtensionsById = runningExtensions.reduce((result, e) => { result.set(ExtensionIdentifier.toKey(e.identifier.value), e); return result; }, new Map<string, IExtensionDescription>());
|
||||
result = result.sort((e1, e2) => {
|
||||
const running1 = runningExtensionsById.get(ExtensionIdentifier.toKey(e1.identifier.id));
|
||||
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)) {
|
||||
return e1.displayName.localeCompare(e2.displayName);
|
||||
}
|
||||
return isE1Running ? -1 : 1;
|
||||
});
|
||||
}
|
||||
return this.getPagedModel(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -785,12 +802,28 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return /^\s*@builtin\s*$/i.test(query);
|
||||
}
|
||||
|
||||
static isInstalledExtensionsQuery(query: string): boolean {
|
||||
return /@installed|@outdated|@enabled|@disabled/i.test(query);
|
||||
static isLocalExtensionsQuery(query: string): boolean {
|
||||
return this.isInstalledExtensionsQuery(query)
|
||||
|| this.isOutdatedExtensionsQuery(query)
|
||||
|| this.isEnabledExtensionsQuery(query)
|
||||
|| this.isDisabledExtensionsQuery(query)
|
||||
|| this.isBuiltInExtensionsQuery(query);
|
||||
}
|
||||
|
||||
static isServerExtensionsQuery(query: string): boolean {
|
||||
return /@installed|@outdated/i.test(query);
|
||||
static isInstalledExtensionsQuery(query: string): boolean {
|
||||
return /@installed/i.test(query);
|
||||
}
|
||||
|
||||
static isOutdatedExtensionsQuery(query: string): boolean {
|
||||
return /@outdated/i.test(query);
|
||||
}
|
||||
|
||||
static isEnabledExtensionsQuery(query: string): boolean {
|
||||
return /@enabled/i.test(query);
|
||||
}
|
||||
|
||||
static isDisabledExtensionsQuery(query: string): boolean {
|
||||
return /@disabled/i.test(query);
|
||||
}
|
||||
|
||||
static isRecommendedExtensionsQuery(query: string): boolean {
|
||||
@@ -827,8 +860,12 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
}
|
||||
|
||||
function getServerLabel(server: IExtensionManagementServer, labelService: ILabelService, workbenchEnvironmentService: IWorkbenchEnvironmentService): string {
|
||||
return workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label;
|
||||
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 {
|
||||
@@ -852,17 +889,19 @@ export class ServerExtensionsView extends ExtensionsListView {
|
||||
@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService
|
||||
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
options.title = getServerLabel(server, labelService, workbenchEnvironmentService);
|
||||
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);
|
||||
this.disposables.push(labelService.onDidChangeFormatters(() => this.updateTitle(getServerLabel(server, labelService, workbenchEnvironmentService))));
|
||||
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))));
|
||||
}
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query ? query : '@installed';
|
||||
if (!ExtensionsListView.isInstalledExtensionsQuery(query) && !ExtensionsListView.isBuiltInExtensionsQuery(query)) {
|
||||
if (!ExtensionsListView.isLocalExtensionsQuery(query) && !ExtensionsListView.isBuiltInExtensionsQuery(query)) {
|
||||
query = query += ' @installed';
|
||||
}
|
||||
return super.show(query.trim());
|
||||
|
||||
@@ -11,12 +11,13 @@ import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
||||
private _extension: IExtension;
|
||||
@@ -142,11 +143,53 @@ export class RatingsWidget extends ExtensionWidget {
|
||||
}
|
||||
}
|
||||
|
||||
export class TooltipWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private readonly parent: HTMLElement,
|
||||
private readonly extensionLabelAction: DisabledLabelAction,
|
||||
private readonly recommendationWidget: RecommendationWidget
|
||||
) {
|
||||
super();
|
||||
this._register(this.extensionLabelAction.onDidChange(() => this.render()));
|
||||
this._register(this.recommendationWidget.onDidChangeTooltip(() => this.render()));
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.parent.title = '';
|
||||
this.parent.removeAttribute('aria-label');
|
||||
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 {
|
||||
if (this.extensionLabelAction.enabled) {
|
||||
return this.extensionLabelAction.label;
|
||||
}
|
||||
return this.recommendationWidget.tooltip;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class RecommendationWidget extends ExtensionWidget {
|
||||
|
||||
private element?: HTMLElement;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
private _tooltip: string;
|
||||
get tooltip(): string { return this._tooltip; }
|
||||
set tooltip(tooltip: string) {
|
||||
if (this._tooltip !== tooltip) {
|
||||
this._tooltip = tooltip;
|
||||
this._onDidChangeTooltip.fire();
|
||||
}
|
||||
}
|
||||
private _onDidChangeTooltip: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeTooltip: Event<void> = this._onDidChangeTooltip.event;
|
||||
|
||||
constructor(
|
||||
private parent: HTMLElement,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@@ -159,7 +202,7 @@ export class RecommendationWidget extends ExtensionWidget {
|
||||
}
|
||||
|
||||
private clear(): void {
|
||||
this.parent.title = '';
|
||||
this.tooltip = '';
|
||||
this.parent.setAttribute('aria-label', this.extension ? localize('viewExtensionDetailsAria', "{0}. Press enter for extension details.", this.extension.displayName) : '');
|
||||
if (this.element) {
|
||||
this.parent.removeChild(this.element);
|
||||
@@ -186,8 +229,7 @@ export class RecommendationWidget extends ExtensionWidget {
|
||||
};
|
||||
applyBookmarkStyle(this.themeService.getTheme());
|
||||
this.themeService.onThemeChange(applyBookmarkStyle, this, this.disposables);
|
||||
this.parent.title = extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText;
|
||||
this.parent.setAttribute('aria-label', localize('viewRecommendedExtensionDetailsAria', "{0}. {1} Press enter for extension details.", this.extension.displayName, extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText));
|
||||
this.tooltip = extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +269,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
}
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.element = append(this.parent, $('div.extension-remote-badge'));
|
||||
append(this.element, $('span.octicon.octicon-file-symlink-directory'));
|
||||
append(this.element, $('span.octicon.octicon-remote'));
|
||||
|
||||
const applyBadgeStyle = () => {
|
||||
if (!this.element) {
|
||||
|
||||
@@ -700,7 +700,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||
}
|
||||
|
||||
private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): IExtension {
|
||||
Promise.all([this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet), this.remoteExtensions ? this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false)])
|
||||
Promise.all([this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet), this.remoteExtensions ? this.remoteExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false)])
|
||||
.then(result => {
|
||||
if (result[0] || result[1]) {
|
||||
this.eventuallyAutoUpdateExtensions();
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/com
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension, IQueryOptions,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, IExtensionManagementServerService, EnablementState, ExtensionRecommendationReason, SortBy
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, IExtensionManagementServerService, EnablementState, ExtensionRecommendationReason, SortBy, IExtensionManagementServer
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
@@ -39,6 +39,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService';
|
||||
|
||||
|
||||
suite('ExtensionsListView Tests', () => {
|
||||
@@ -89,11 +90,14 @@ suite('ExtensionsListView Tests', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, <IExtensionManagementServerService>{
|
||||
localExtensionManagementServer: {
|
||||
extensionManagementService: instantiationService.get(IExtensionManagementService)
|
||||
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
|
||||
private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' };
|
||||
constructor() {
|
||||
super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService));
|
||||
}
|
||||
});
|
||||
get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; }
|
||||
set localExtensionManagementServer(server: IExtensionManagementServer) { }
|
||||
}());
|
||||
|
||||
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
|
||||
@@ -151,14 +155,14 @@ suite('ExtensionsListView Tests', () => {
|
||||
|
||||
test('Test query types', () => {
|
||||
assert.equal(ExtensionsListView.isBuiltInExtensionsQuery('@builtin'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@installed'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@enabled'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@disabled'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@outdated'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@installed searchText'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@enabled searchText'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@disabled searchText'), true);
|
||||
assert.equal(ExtensionsListView.isInstalledExtensionsQuery('@outdated searchText'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@installed'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@enabled'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@disabled'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@outdated'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@installed searchText'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@enabled searchText'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@disabled searchText'), true);
|
||||
assert.equal(ExtensionsListView.isLocalExtensionsQuery('@outdated searchText'), true);
|
||||
});
|
||||
|
||||
test('Test empty query equates to sort by install count', () => {
|
||||
@@ -200,8 +204,8 @@ suite('ExtensionsListView Tests', () => {
|
||||
|
||||
await testableView.show('@installed first').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with search text.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with search text.');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with search text.');
|
||||
assert.equal(result.get(1).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with search text.');
|
||||
});
|
||||
|
||||
await testableView.show('@disabled').then(result => {
|
||||
@@ -242,27 +246,27 @@ suite('ExtensionsListView Tests', () => {
|
||||
test('Test installed query with category', async () => {
|
||||
await testableView.show('@installed category:themes').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query with category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with category.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with category.');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with category.');
|
||||
assert.equal(result.get(1).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with category.');
|
||||
});
|
||||
|
||||
await testableView.show('@installed category:"themes"').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query with quoted category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with quoted category.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with quoted category.');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with quoted category.');
|
||||
assert.equal(result.get(1).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with quoted category.');
|
||||
});
|
||||
|
||||
await testableView.show('@installed category:"programming languages"').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query with quoted category including space');
|
||||
assert.equal(result.get(0).name, localDisabledLanguage.manifest.name, 'Unexpected extension for @installed query with quoted category inlcuding space.');
|
||||
assert.equal(result.get(1).name, localEnabledLanguage.manifest.name, 'Unexpected extension for @installed query with quoted category including space.');
|
||||
assert.equal(result.get(0).name, localEnabledLanguage.manifest.name, 'Unexpected extension for @installed query with quoted category including space.');
|
||||
assert.equal(result.get(1).name, localDisabledLanguage.manifest.name, 'Unexpected extension for @installed query with quoted category inlcuding space.');
|
||||
});
|
||||
|
||||
await testableView.show('@installed category:themes category:random').then(result => {
|
||||
assert.equal(result.length, 3, 'Unexpected number of results for @installed query with multiple category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(2).name, localRandom.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(1).name, localRandom.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(2).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
});
|
||||
|
||||
await testableView.show('@enabled category:themes').then(result => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||
import * as nls from 'vs/nls';
|
||||
import { sep } from 'vs/base/common/path';
|
||||
@@ -159,7 +159,7 @@ class FileEditorInputFactory implements IEditorInputFactory {
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput {
|
||||
return instantiationService.invokeFunction<FileEditorInput>(accessor => {
|
||||
const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput);
|
||||
const resource = !!fileInput.resourceJSON ? URI.revive(fileInput.resourceJSON) : URI.parse(fileInput.resource);
|
||||
const resource = !!fileInput.resourceJSON ? URI.revive(<UriComponents>fileInput.resourceJSON) : URI.parse(fileInput.resource);
|
||||
const encoding = fileInput.encoding;
|
||||
|
||||
return accessor.get(IEditorService).createInput({ resource, encoding, forceFile: true }) as FileEditorInput;
|
||||
|
||||
@@ -160,9 +160,9 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
|
||||
|
||||
if (isReadonly) {
|
||||
if (triedToMakeWriteable) {
|
||||
message = isWindows ? nls.localize('readonlySaveErrorAdmin', "Failed to save '{0}': File is write protected. Select 'Overwrite as Admin' to retry as administrator.", basename(resource)) : nls.localize('readonlySaveErrorSudo', "Failed to save '{0}': File is write protected. Select 'Overwrite as Sudo' to retry as superuser.", basename(resource));
|
||||
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 write protected. Select 'Overwrite' to attempt to remove protection.", basename(resource));
|
||||
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) {
|
||||
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));
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import * as nls from 'vs/nls';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { SyncActionDescriptor, ICommandAction, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { OpenIssueReporterAction, ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-browser/issueActions';
|
||||
import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-browser/issueActions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue';
|
||||
import { WorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issueService';
|
||||
@@ -19,8 +19,27 @@ const helpCategory = nls.localize('help', "Help");
|
||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
|
||||
if (!!product.reportIssueUrl) {
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIssueReporterAction, OpenIssueReporterAction.ID, OpenIssueReporterAction.LABEL), 'Help: Open Issue Reporter', helpCategory);
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueUsingReporterAction, ReportPerformanceIssueUsingReporterAction.ID, ReportPerformanceIssueUsingReporterAction.LABEL), 'Help: Report Performance Issue', helpCategory);
|
||||
|
||||
const OpenIssueReporterActionId = 'workbench.action.openIssueReporter';
|
||||
const OpenIssueReporterActionLabel = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue");
|
||||
|
||||
CommandsRegistry.registerCommand(OpenIssueReporterActionId, function (accessor, args?: [string]) {
|
||||
let extensionId: string | undefined;
|
||||
if (args && Array.isArray(args)) {
|
||||
[extensionId] = args;
|
||||
}
|
||||
|
||||
return accessor.get(IWorkbenchIssueService).openReporter({ extensionId });
|
||||
});
|
||||
|
||||
const command: ICommandAction = {
|
||||
id: OpenIssueReporterActionId,
|
||||
title: { value: OpenIssueReporterActionLabel, original: 'Help: Open Issue Reporter' },
|
||||
category: helpCategory
|
||||
};
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command });
|
||||
}
|
||||
|
||||
const developerCategory = nls.localize('developer', "Developer");
|
||||
|
||||
@@ -8,23 +8,6 @@ import * as nls from 'vs/nls';
|
||||
import { IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue';
|
||||
|
||||
export class OpenIssueReporterAction extends Action {
|
||||
static readonly ID = 'workbench.action.openIssueReporter';
|
||||
static readonly LABEL = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<boolean> {
|
||||
return this.issueService.openReporter().then(() => true);
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenProcessExplorer extends Action {
|
||||
static readonly ID = 'workbench.action.openProcessExplorer';
|
||||
static readonly LABEL = nls.localize('openProcessExplorer', "Open Process Explorer");
|
||||
|
||||
@@ -48,7 +48,7 @@ export class OpenSettings2Action extends Action {
|
||||
}
|
||||
|
||||
run(event?: any): Promise<any> {
|
||||
return this.preferencesService.openSettings(false);
|
||||
return this.preferencesService.openSettings(false, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export class OpenSettingsJsonAction extends Action {
|
||||
}
|
||||
|
||||
run(event?: any): Promise<any> {
|
||||
return this.preferencesService.openSettings(true);
|
||||
return this.preferencesService.openSettings(true, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -256,8 +256,8 @@ export class PreferencesEditor extends BaseEditor {
|
||||
}
|
||||
const promise: Promise<boolean> = this.input && this.input.isDirty() ? this.input.save() : Promise.resolve(true);
|
||||
promise.then(() => {
|
||||
if (target === ConfigurationTarget.USER) {
|
||||
this.preferencesService.switchSettings(ConfigurationTarget.USER, this.preferencesService.userSettingsResource, true);
|
||||
if (target === ConfigurationTarget.USER_LOCAL) {
|
||||
this.preferencesService.switchSettings(ConfigurationTarget.USER_LOCAL, this.preferencesService.userSettingsResource, true);
|
||||
} else if (target === ConfigurationTarget.WORKSPACE) {
|
||||
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE, this.preferencesService.workspaceSettingsResource!, true);
|
||||
} else if (target instanceof URI) {
|
||||
@@ -507,7 +507,7 @@ class PreferencesRenderersController extends Disposable {
|
||||
private searchAllSettingsTargets(query: string, searchProvider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number, token?: CancellationToken): Promise<void> {
|
||||
const searchPs = [
|
||||
this.searchSettingsTarget(query, searchProvider, ConfigurationTarget.WORKSPACE, groupId, groupLabel, groupOrder, token),
|
||||
this.searchSettingsTarget(query, searchProvider, ConfigurationTarget.USER, groupId, groupLabel, groupOrder, token)
|
||||
this.searchSettingsTarget(query, searchProvider, ConfigurationTarget.USER_LOCAL, groupId, groupLabel, groupOrder, token)
|
||||
];
|
||||
|
||||
for (const folder of this.workspaceContextService.getWorkspace().folders) {
|
||||
@@ -541,9 +541,10 @@ class PreferencesRenderersController extends Disposable {
|
||||
}
|
||||
|
||||
private async getPreferencesEditorModel(target: SettingsTarget | undefined): Promise<ISettingsEditorModel | undefined> {
|
||||
const resource = target === ConfigurationTarget.USER ? this.preferencesService.userSettingsResource :
|
||||
target === ConfigurationTarget.WORKSPACE ? this.preferencesService.workspaceSettingsResource :
|
||||
target;
|
||||
const resource = target === ConfigurationTarget.USER_LOCAL ? this.preferencesService.userSettingsResource :
|
||||
target === ConfigurationTarget.USER_REMOTE ? this.preferencesService.userSettingsResource :
|
||||
target === ConfigurationTarget.WORKSPACE ? this.preferencesService.workspaceSettingsResource :
|
||||
target;
|
||||
|
||||
if (!resource) {
|
||||
return undefined;
|
||||
@@ -821,7 +822,7 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
this.editablePreferencesEditorContainer = DOM.$('.editable-preferences-editor-container');
|
||||
const editablePreferencesHeaderContainer = DOM.append(this.editablePreferencesEditorContainer, DOM.$('.preferences-header-container'));
|
||||
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, editablePreferencesHeaderContainer));
|
||||
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, editablePreferencesHeaderContainer, undefined));
|
||||
this._register(this.settingsTargetsWidget.onDidTargetChange(target => this._onDidSettingsTargetChange.fire(target)));
|
||||
|
||||
this._register(attachStylerCallback(this.themeService, { scrollbarShadow }, colors => {
|
||||
@@ -865,7 +866,7 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
private getDefaultPreferencesHeaderText(target: ConfigurationTarget): string {
|
||||
switch (target) {
|
||||
case ConfigurationTarget.USER:
|
||||
case ConfigurationTarget.USER_LOCAL:
|
||||
return nls.localize('defaultUserSettings', "Default User Settings");
|
||||
case ConfigurationTarget.WORKSPACE:
|
||||
return nls.localize('defaultWorkspaceSettings', "Default Workspace Settings");
|
||||
@@ -942,7 +943,7 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
private getSettingsTarget(resource: URI): SettingsTarget {
|
||||
if (this.preferencesService.userSettingsResource.toString() === resource.toString()) {
|
||||
return ConfigurationTarget.USER;
|
||||
return ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
|
||||
const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource;
|
||||
@@ -955,7 +956,7 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
return folder.uri;
|
||||
}
|
||||
|
||||
return ConfigurationTarget.USER;
|
||||
return ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
|
||||
private disposeEditors(): void {
|
||||
@@ -1202,7 +1203,7 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl
|
||||
.then<any>(settingsModel => {
|
||||
if (settingsModel instanceof SettingsEditorModel && this.editor.getModel()) {
|
||||
switch (settingsModel.configurationTarget) {
|
||||
case ConfigurationTarget.USER:
|
||||
case ConfigurationTarget.USER_LOCAL:
|
||||
return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel);
|
||||
case ConfigurationTarget.WORKSPACE:
|
||||
return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel);
|
||||
|
||||
@@ -24,11 +24,14 @@ import { ConfigurationTarget } from 'vs/platform/configuration/common/configurat
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { activeContrastBorder, badgeBackground, badgeForeground, contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
|
||||
|
||||
export class SettingsHeaderWidget extends Widget implements IViewZone {
|
||||
@@ -464,14 +467,20 @@ export class FolderSettingsActionItem extends BaseActionItem {
|
||||
}
|
||||
}
|
||||
|
||||
export type SettingsTarget = ConfigurationTarget.USER | ConfigurationTarget.WORKSPACE | URI;
|
||||
export type SettingsTarget = ConfigurationTarget.USER_LOCAL | ConfigurationTarget.USER_REMOTE | ConfigurationTarget.WORKSPACE | URI;
|
||||
|
||||
export interface ISettingsTargetsWidgetOptions {
|
||||
enableRemoteSettings?: boolean;
|
||||
}
|
||||
|
||||
export class SettingsTargetsWidget extends Widget {
|
||||
|
||||
private settingsSwitcherBar: ActionBar;
|
||||
private userSettings: Action;
|
||||
private userLocalSettings: Action;
|
||||
private userRemoteSettings: Action;
|
||||
private workspaceSettings: Action;
|
||||
private folderSettings: FolderSettingsActionItem;
|
||||
private options: ISettingsTargetsWidgetOptions;
|
||||
|
||||
private _settingsTarget: SettingsTarget;
|
||||
|
||||
@@ -480,10 +489,14 @@ export class SettingsTargetsWidget extends Widget {
|
||||
|
||||
constructor(
|
||||
parent: HTMLElement,
|
||||
options: ISettingsTargetsWidgetOptions | undefined,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super();
|
||||
this.options = options || {};
|
||||
this.create(parent);
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged()));
|
||||
this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update()));
|
||||
@@ -498,18 +511,25 @@ export class SettingsTargetsWidget extends Widget {
|
||||
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined
|
||||
}));
|
||||
|
||||
this.userSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER));
|
||||
this.userSettings.tooltip = this.userSettings.label;
|
||||
this.userLocalSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL));
|
||||
this.userLocalSettings.tooltip = this.userLocalSettings.label;
|
||||
|
||||
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||
const hostLabel = remoteAuthority && this.labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority);
|
||||
const remoteSettingsLabel = localize('userSettingsRemote', "Remote Settings") +
|
||||
(hostLabel ? ` (${hostLabel})` : '');
|
||||
this.userRemoteSettings = new Action('userSettingsRemote', remoteSettingsLabel, '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE));
|
||||
this.userRemoteSettings.tooltip = this.userRemoteSettings.label;
|
||||
|
||||
this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace Settings"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE));
|
||||
this.workspaceSettings.tooltip = this.workspaceSettings.label;
|
||||
|
||||
const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder Settings"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder ? folder.uri : ConfigurationTarget.USER));
|
||||
const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder Settings"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri));
|
||||
this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction);
|
||||
|
||||
this.update();
|
||||
|
||||
this.settingsSwitcherBar.push([this.userSettings, this.workspaceSettings, folderSettingsAction]);
|
||||
this.settingsSwitcherBar.push([this.userLocalSettings, this.userRemoteSettings, this.workspaceSettings, folderSettingsAction]);
|
||||
}
|
||||
|
||||
get settingsTarget(): SettingsTarget {
|
||||
@@ -518,7 +538,8 @@ export class SettingsTargetsWidget extends Widget {
|
||||
|
||||
set settingsTarget(settingsTarget: SettingsTarget) {
|
||||
this._settingsTarget = settingsTarget;
|
||||
this.userSettings.checked = ConfigurationTarget.USER === this.settingsTarget;
|
||||
this.userLocalSettings.checked = ConfigurationTarget.USER_LOCAL === this.settingsTarget;
|
||||
this.userRemoteSettings.checked = ConfigurationTarget.USER_REMOTE === this.settingsTarget;
|
||||
this.workspaceSettings.checked = ConfigurationTarget.WORKSPACE === this.settingsTarget;
|
||||
if (this.settingsTarget instanceof URI) {
|
||||
this.folderSettings.getAction().checked = true;
|
||||
@@ -536,13 +557,13 @@ export class SettingsTargetsWidget extends Widget {
|
||||
}
|
||||
|
||||
this.workspaceSettings.label = label;
|
||||
} else if (settingsTarget === ConfigurationTarget.USER) {
|
||||
} else if (settingsTarget === ConfigurationTarget.USER_LOCAL) {
|
||||
let label = localize('userSettings', "User Settings");
|
||||
if (count) {
|
||||
label += ` (${count})`;
|
||||
}
|
||||
|
||||
this.userSettings.label = label;
|
||||
this.userLocalSettings.label = label;
|
||||
} else if (settingsTarget instanceof URI) {
|
||||
this.folderSettings.setCount(settingsTarget, count);
|
||||
}
|
||||
@@ -552,21 +573,27 @@ export class SettingsTargetsWidget extends Widget {
|
||||
this.folderSettings.folder = null;
|
||||
this.update();
|
||||
if (this.settingsTarget === ConfigurationTarget.WORKSPACE && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
this.updateTarget(ConfigurationTarget.USER);
|
||||
this.updateTarget(ConfigurationTarget.USER_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
updateTarget(settingsTarget: SettingsTarget): Promise<void> {
|
||||
const isSameTarget = this.settingsTarget === settingsTarget || settingsTarget instanceof URI && this.settingsTarget instanceof URI && this.settingsTarget.toString() === settingsTarget.toString();
|
||||
const isSameTarget = this.settingsTarget === settingsTarget ||
|
||||
settingsTarget instanceof URI &&
|
||||
this.settingsTarget instanceof URI &&
|
||||
this.settingsTarget.toString() === settingsTarget.toString();
|
||||
|
||||
if (!isSameTarget) {
|
||||
this.settingsTarget = settingsTarget;
|
||||
this._onDidTargetChange.fire(this.settingsTarget);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
DOM.toggleClass(this.settingsSwitcherBar.domNode, 'empty-workbench', this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
|
||||
this.userRemoteSettings.enabled = !!(this.options.enableRemoteSettings && this.environmentService.configuration.remoteAuthority);
|
||||
this.workspaceSettings.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY;
|
||||
this.folderSettings.getAction().enabled = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.contextService.getWorkspace().folders.length > 0;
|
||||
}
|
||||
|
||||
@@ -1174,7 +1174,7 @@ export class SettingsTreeFilter implements ITreeFilter<SettingsTreeElement> {
|
||||
}
|
||||
|
||||
// Non-user scope selected
|
||||
if (element instanceof SettingsTreeSettingElement && this.viewState.settingsTarget !== ConfigurationTarget.USER) {
|
||||
if (element instanceof SettingsTreeSettingElement && this.viewState.settingsTarget !== ConfigurationTarget.USER_LOCAL) {
|
||||
if (!element.matchesScope(this.viewState.settingsTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||
import { isArray, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -19,6 +20,7 @@ export const ONLINE_SERVICES_SETTING_TAG = 'usesOnlineServices';
|
||||
export interface ISettingsEditorViewState {
|
||||
settingsTarget: SettingsTarget;
|
||||
tagFilters?: Set<string>;
|
||||
extensionFilters?: Set<string>;
|
||||
filterToCategory?: SettingsTreeGroupElement;
|
||||
}
|
||||
|
||||
@@ -228,6 +230,24 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
matchesAnyExtension(extensionFilters?: Set<string>): boolean {
|
||||
if (!extensionFilters || !extensionFilters.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.setting.extensionInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let extensionId of extensionFilters) {
|
||||
if (extensionId.toLowerCase() === this.setting.extensionInfo.id.toLowerCase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingsTreeModel {
|
||||
@@ -337,9 +357,10 @@ interface IInspectResult {
|
||||
function inspectSetting(key: string, target: SettingsTarget, configurationService: IConfigurationService): IInspectResult {
|
||||
const inspectOverrides = URI.isUri(target) ? { resource: target } : undefined;
|
||||
const inspected = configurationService.inspect(key, inspectOverrides);
|
||||
const targetSelector = target === ConfigurationTarget.USER ? 'user' :
|
||||
target === ConfigurationTarget.WORKSPACE ? 'workspace' :
|
||||
'workspaceFolder';
|
||||
const targetSelector = target === ConfigurationTarget.USER_LOCAL ? 'userLocal' :
|
||||
target === ConfigurationTarget.USER_REMOTE ? 'userRemote' :
|
||||
target === ConfigurationTarget.WORKSPACE ? 'workspace' :
|
||||
'workspaceFolder';
|
||||
const isConfigured = typeof inspected[targetSelector] !== 'undefined';
|
||||
|
||||
return { isConfigured, inspected, targetSelector };
|
||||
@@ -494,7 +515,7 @@ export class SearchResultModel extends SettingsTreeModel {
|
||||
|
||||
// Save time, filter children in the search model instead of relying on the tree filter, which still requires heights to be calculated.
|
||||
this.root.children = this.root.children
|
||||
.filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget));
|
||||
.filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget) && child.matchesAnyExtension(this._viewState.extensionFilters));
|
||||
|
||||
if (this.newExtensionSearchResults && this.newExtensionSearchResults.filterMatches.length) {
|
||||
const newExtElement = new SettingsTreeNewExtensionsElement();
|
||||
@@ -527,11 +548,14 @@ export class SearchResultModel extends SettingsTreeModel {
|
||||
export interface IParsedQuery {
|
||||
tags: string[];
|
||||
query: string;
|
||||
extensionFilters: string[];
|
||||
}
|
||||
|
||||
const tagRegex = /(^|\s)@tag:("([^"]*)"|[^"]\S*)/g;
|
||||
const extensionRegex = /(^|\s)@ext:("([^"]*)"|[^"]\S*)?/g;
|
||||
export function parseQuery(query: string): IParsedQuery {
|
||||
const tags: string[] = [];
|
||||
let extensions: string[] = [];
|
||||
query = query.replace(tagRegex, (_, __, quotedTag, tag) => {
|
||||
tags.push(tag || quotedTag);
|
||||
return '';
|
||||
@@ -542,10 +566,19 @@ export function parseQuery(query: string): IParsedQuery {
|
||||
return '';
|
||||
});
|
||||
|
||||
query = query.replace(extensionRegex, (_, __, quotedExtensionId, extensionId) => {
|
||||
let extensionIdQuery: string = extensionId || quotedExtensionId;
|
||||
if (extensionIdQuery) {
|
||||
extensions.push(...extensionIdQuery.split(',').map(s => s.trim()).filter(s => !isFalsyOrWhitespace(s)));
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
query = query.trim();
|
||||
|
||||
return {
|
||||
tags,
|
||||
extensionFilters: extensions,
|
||||
query
|
||||
};
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export class TOCTreeModel {
|
||||
}
|
||||
|
||||
// Check everything that the SettingsFilter checks except whether it's filtered by a category
|
||||
return child.matchesScope(this._viewState.settingsTarget) && child.matchesAllTags(this._viewState.tagFilters);
|
||||
return child.matchesScope(this._viewState.settingsTarget) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyExtension(this._viewState.extensionFilters);
|
||||
}).length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,5 +108,6 @@ export const KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS = 'keybindings.editor.show
|
||||
export const DEFAULT_SETTINGS_EDITOR_SETTING = 'workbench.settings.openDefaultSettings';
|
||||
|
||||
export const MODIFIED_SETTING_TAG = 'modified';
|
||||
export const EXTENSION_SETTING_TAG = 'ext:';
|
||||
|
||||
export const SETTINGS_COMMAND_OPEN_SETTINGS = 'workbench.action.openSettings';
|
||||
|
||||
@@ -217,8 +217,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: null,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.US_COMMA,
|
||||
handler: (accessor, args: any) => {
|
||||
accessor.get(IPreferencesService).openSettings();
|
||||
handler: (accessor, args: string | undefined) => {
|
||||
accessor.get(IPreferencesService).openSettings(undefined, typeof args === 'string' ? args : undefined);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
|
||||
import * as collections from 'vs/base/common/collections';
|
||||
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { Iterator } from 'vs/base/common/iterator';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { isArray, withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import 'vs/css!./media/settingsEditor2';
|
||||
@@ -35,7 +36,7 @@ import { AbstractSettingRenderer, ISettingLinkClickEvent, ISettingOverrideClickE
|
||||
import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels';
|
||||
import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets';
|
||||
import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree';
|
||||
import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, EXTENSION_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
|
||||
@@ -69,7 +70,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
private static SETTING_UPDATE_SLOW_DEBOUNCE: number = 1000;
|
||||
|
||||
private static readonly SUGGESTIONS: string[] = [
|
||||
`@${MODIFIED_SETTING_TAG}`, '@tag:usesOnlineServices'
|
||||
`@${MODIFIED_SETTING_TAG}`, '@tag:usesOnlineServices', `@${EXTENSION_SETTING_TAG}`
|
||||
];
|
||||
|
||||
private static shouldSettingUpdateFast(type: SettingValueType | SettingValueType[]): boolean {
|
||||
@@ -149,7 +150,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this.delayedFilterLogging = new Delayer<void>(1000);
|
||||
this.localSearchDelayer = new Delayer(300);
|
||||
this.remoteSearchThrottle = new ThrottledDelayer(200);
|
||||
this.viewState = { settingsTarget: ConfigurationTarget.USER };
|
||||
this.viewState = { settingsTarget: ConfigurationTarget.USER_LOCAL };
|
||||
|
||||
this.settingFastUpdateDelayer = new Delayer<void>(SettingsEditor2.SETTING_UPDATE_FAST_DEBOUNCE);
|
||||
this.settingSlowUpdateDelayer = new Delayer<void>(SettingsEditor2.SETTING_UPDATE_SLOW_DEBOUNCE);
|
||||
@@ -212,10 +213,10 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
if (!options) {
|
||||
if (!this.viewState.settingsTarget) {
|
||||
// Persist?
|
||||
options = SettingsEditorOptions.create({ target: ConfigurationTarget.USER });
|
||||
options = SettingsEditorOptions.create({ target: ConfigurationTarget.USER_LOCAL });
|
||||
}
|
||||
} else if (!options.target) {
|
||||
options.target = ConfigurationTarget.USER;
|
||||
options.target = ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
this._setOptions(options);
|
||||
|
||||
@@ -371,7 +372,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this.searchWidget = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${SettingsEditor2.ID}.searchbox`, searchContainer, {
|
||||
triggerCharacters: ['@'],
|
||||
provideResults: (query: string) => {
|
||||
return SettingsEditor2.SUGGESTIONS.filter(tag => query.indexOf(tag) === -1).map(tag => tag + ' ');
|
||||
return SettingsEditor2.SUGGESTIONS.filter(tag => query.indexOf(tag) === -1).map(tag => strings.endsWith(tag, ':') ? tag : tag + ' ');
|
||||
}
|
||||
}, searchBoxLabel, 'settingseditor:searchinput' + SettingsEditor2.NUM_INSTANCES++, {
|
||||
placeholderText: searchBoxLabel,
|
||||
@@ -406,8 +407,8 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
|
||||
const headerControlsContainer = DOM.append(this.headerContainer, $('.settings-header-controls'));
|
||||
const targetWidgetContainer = DOM.append(headerControlsContainer, $('.settings-target-container'));
|
||||
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer));
|
||||
this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER;
|
||||
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer, { enableRemoteSettings: true }));
|
||||
this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER_LOCAL;
|
||||
this.settingsTargetsWidget.onDidTargetChange(target => this.onDidSettingsTargetChange(target));
|
||||
}
|
||||
|
||||
@@ -458,8 +459,10 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
const currentSettingsTarget = this.settingsTargetsWidget.settingsTarget;
|
||||
|
||||
const options: ISettingsEditorOptions = { query };
|
||||
if (currentSettingsTarget === ConfigurationTarget.USER) {
|
||||
if (currentSettingsTarget === ConfigurationTarget.USER_LOCAL) {
|
||||
return this.preferencesService.openGlobalSettings(true, options);
|
||||
} else if (currentSettingsTarget === ConfigurationTarget.USER_REMOTE) {
|
||||
return this.preferencesService.openRemoteSettings();
|
||||
} else if (currentSettingsTarget === ConfigurationTarget.WORKSPACE) {
|
||||
return this.preferencesService.openWorkspaceSettings(true, options);
|
||||
} else {
|
||||
@@ -615,8 +618,10 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this._register(this.settingRenderers.onDidClickOverrideElement((element: ISettingOverrideClickEvent) => {
|
||||
if (ConfigurationTargetToString(ConfigurationTarget.WORKSPACE) === element.scope.toUpperCase()) {
|
||||
this.settingsTargetsWidget.updateTarget(ConfigurationTarget.WORKSPACE);
|
||||
} else if (ConfigurationTargetToString(ConfigurationTarget.USER) === element.scope.toUpperCase()) {
|
||||
this.settingsTargetsWidget.updateTarget(ConfigurationTarget.USER);
|
||||
} else if (ConfigurationTargetToString(ConfigurationTarget.USER_LOCAL) === element.scope.toUpperCase()) {
|
||||
this.settingsTargetsWidget.updateTarget(ConfigurationTarget.USER_LOCAL);
|
||||
} else if (ConfigurationTargetToString(ConfigurationTarget.USER_REMOTE) === element.scope.toUpperCase()) {
|
||||
this.settingsTargetsWidget.updateTarget(ConfigurationTarget.USER_REMOTE);
|
||||
}
|
||||
|
||||
this.searchWidget.setValue(element.targetKey);
|
||||
@@ -792,9 +797,10 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
}
|
||||
}
|
||||
|
||||
const reportedTarget = props.settingsTarget === ConfigurationTarget.USER ? 'user' :
|
||||
props.settingsTarget === ConfigurationTarget.WORKSPACE ? 'workspace' :
|
||||
'folder';
|
||||
const reportedTarget = props.settingsTarget === ConfigurationTarget.USER_LOCAL ? 'user' :
|
||||
props.settingsTarget === ConfigurationTarget.USER_REMOTE ? 'user_remote' :
|
||||
props.settingsTarget === ConfigurationTarget.WORKSPACE ? 'workspace' :
|
||||
'folder';
|
||||
|
||||
const data = {
|
||||
key: props.key,
|
||||
@@ -1035,17 +1041,19 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
|
||||
private triggerSearch(query: string): Promise<void> {
|
||||
this.viewState.tagFilters = new Set<string>();
|
||||
this.viewState.extensionFilters = new Set<string>();
|
||||
if (query) {
|
||||
const parsedQuery = parseQuery(query);
|
||||
query = parsedQuery.query;
|
||||
parsedQuery.tags.forEach(tag => this.viewState.tagFilters!.add(tag));
|
||||
parsedQuery.extensionFilters.forEach(extensionId => this.viewState.extensionFilters!.add(extensionId));
|
||||
}
|
||||
|
||||
if (query && query !== '@') {
|
||||
query = this.parseSettingFromJSON(query) || query;
|
||||
return this.triggerFilterPreferences(query);
|
||||
} else {
|
||||
if (this.viewState.tagFilters && this.viewState.tagFilters.size) {
|
||||
if ((this.viewState.tagFilters && this.viewState.tagFilters.size) || (this.viewState.extensionFilters && this.viewState.extensionFilters.size)) {
|
||||
this.searchResultModel = this.createFilterModel();
|
||||
} else {
|
||||
this.searchResultModel = null;
|
||||
|
||||
@@ -116,6 +116,7 @@ suite('SettingsTree', () => {
|
||||
'',
|
||||
<IParsedQuery>{
|
||||
tags: [],
|
||||
extensionFilters: [],
|
||||
query: ''
|
||||
});
|
||||
|
||||
@@ -123,6 +124,7 @@ suite('SettingsTree', () => {
|
||||
'@modified',
|
||||
<IParsedQuery>{
|
||||
tags: ['modified'],
|
||||
extensionFilters: [],
|
||||
query: ''
|
||||
});
|
||||
|
||||
@@ -130,6 +132,7 @@ suite('SettingsTree', () => {
|
||||
'@tag:foo',
|
||||
<IParsedQuery>{
|
||||
tags: ['foo'],
|
||||
extensionFilters: [],
|
||||
query: ''
|
||||
});
|
||||
|
||||
@@ -137,6 +140,7 @@ suite('SettingsTree', () => {
|
||||
'@modified foo',
|
||||
<IParsedQuery>{
|
||||
tags: ['modified'],
|
||||
extensionFilters: [],
|
||||
query: 'foo'
|
||||
});
|
||||
|
||||
@@ -144,6 +148,7 @@ suite('SettingsTree', () => {
|
||||
'@tag:foo @modified',
|
||||
<IParsedQuery>{
|
||||
tags: ['foo', 'modified'],
|
||||
extensionFilters: [],
|
||||
query: ''
|
||||
});
|
||||
|
||||
@@ -151,6 +156,7 @@ suite('SettingsTree', () => {
|
||||
'@tag:foo @modified my query',
|
||||
<IParsedQuery>{
|
||||
tags: ['foo', 'modified'],
|
||||
extensionFilters: [],
|
||||
query: 'my query'
|
||||
});
|
||||
|
||||
@@ -158,6 +164,7 @@ suite('SettingsTree', () => {
|
||||
'test @modified query',
|
||||
<IParsedQuery>{
|
||||
tags: ['modified'],
|
||||
extensionFilters: [],
|
||||
query: 'test query'
|
||||
});
|
||||
|
||||
@@ -165,6 +172,7 @@ suite('SettingsTree', () => {
|
||||
'test @modified',
|
||||
<IParsedQuery>{
|
||||
tags: ['modified'],
|
||||
extensionFilters: [],
|
||||
query: 'test'
|
||||
});
|
||||
|
||||
@@ -172,7 +180,24 @@ suite('SettingsTree', () => {
|
||||
'query has @ for some reason',
|
||||
<IParsedQuery>{
|
||||
tags: [],
|
||||
extensionFilters: [],
|
||||
query: 'query has @ for some reason'
|
||||
});
|
||||
|
||||
testParseQuery(
|
||||
'@ext:github.vscode-pull-request-github',
|
||||
<IParsedQuery>{
|
||||
tags: [],
|
||||
extensionFilters: ['github.vscode-pull-request-github'],
|
||||
query: ''
|
||||
});
|
||||
|
||||
testParseQuery(
|
||||
'@ext:github.vscode-pull-request-github,vscode.git',
|
||||
<IParsedQuery>{
|
||||
tags: [],
|
||||
extensionFilters: ['github.vscode-pull-request-github', 'vscode.git'],
|
||||
query: ''
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -85,7 +85,8 @@ class PartsSplash {
|
||||
colorInfo,
|
||||
layoutInfo,
|
||||
baseTheme
|
||||
})
|
||||
}),
|
||||
{ encoding: 'utf8', overwriteEncoding: true }
|
||||
);
|
||||
|
||||
if (baseTheme !== this._lastBaseTheme || colorInfo.editorBackground !== this._lastBackground) {
|
||||
|
||||
@@ -533,7 +533,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
|
||||
// Handle top-level workspace files for local single folder workspace
|
||||
if (state === WorkbenchState.FOLDER && workspace.folders[0].uri.scheme === Schemas.file) {
|
||||
if (state === WorkbenchState.FOLDER) {
|
||||
const workspaceFiles = rootFiles.filter(hasWorkspaceFileExtension);
|
||||
if (workspaceFiles.length > 0) {
|
||||
this.doHandleWorkspaceFiles(workspace.folders[0].uri, workspaceFiles);
|
||||
|
||||
@@ -184,6 +184,9 @@ module.exports = function createWebviewManager(host) {
|
||||
|
||||
let isHandlingScroll = false;
|
||||
const handleInnerScroll = (event) => {
|
||||
if (!event.target || !event.target.body) {
|
||||
return;
|
||||
}
|
||||
if (isHandlingScroll) {
|
||||
return;
|
||||
}
|
||||
@@ -205,6 +208,10 @@ module.exports = function createWebviewManager(host) {
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (!document.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
host.onMessage('styles', (_event, variables, activeTheme) => {
|
||||
initData.styles = variables;
|
||||
initData.activeTheme = activeTheme;
|
||||
@@ -214,7 +221,9 @@ module.exports = function createWebviewManager(host) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyStyles(target.contentDocument, target.contentDocument.body);
|
||||
if (target.contentDocument) {
|
||||
applyStyles(target.contentDocument, target.contentDocument.body);
|
||||
}
|
||||
});
|
||||
|
||||
// propagate focus
|
||||
@@ -346,15 +355,15 @@ module.exports = function createWebviewManager(host) {
|
||||
return false;
|
||||
};
|
||||
|
||||
let onLoad = (contentDocument, contentWindow) => {
|
||||
if (contentDocument.body) {
|
||||
const onLoad = (contentDocument, contentWindow) => {
|
||||
if (contentDocument && contentDocument.body) {
|
||||
// Workaround for https://github.com/Microsoft/vscode/issues/12865
|
||||
// check new scrollY and reset if neccessary
|
||||
setInitialScrollPosition(contentDocument.body, contentWindow);
|
||||
}
|
||||
|
||||
const newFrame = getPendingFrame();
|
||||
if (newFrame && newFrame.contentDocument === contentDocument) {
|
||||
if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) {
|
||||
const oldActiveFrame = getActiveFrame();
|
||||
if (oldActiveFrame) {
|
||||
document.body.removeChild(oldActiveFrame);
|
||||
|
||||
@@ -46,7 +46,7 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
title: input.getName(),
|
||||
options: input.options,
|
||||
extensionLocation: input.extension ? input.extension.location : undefined,
|
||||
extensionId: input.extension ? input.extension.id.value : undefined,
|
||||
extensionId: input.extension && input.extension.id ? input.extension.id.value : undefined,
|
||||
state: input.state,
|
||||
iconPath: input.iconPath ? { light: input.iconPath.light, dark: input.iconPath.dark, } : undefined,
|
||||
group: input.group
|
||||
|
||||
Reference in New Issue
Block a user