Merge pull request #107215 from microsoft/aeschli/welcomeViewGroups

groups for viewsWelcome
This commit is contained in:
Martin Aeschlimann 2020-09-28 14:10:06 -07:00 committed by GitHub
commit 2ef6c258b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 32 deletions

View file

@ -2083,27 +2083,32 @@
{
"view": "scm",
"contents": "%view.workbench.scm.empty%",
"when": "config.git.enabled && git.state == initialized && workbenchState == empty"
"when": "config.git.enabled && git.state == initialized && workbenchState == empty",
"group": "2_open@1"
},
{
"view": "scm",
"contents": "%view.workbench.scm.folder%",
"when": "config.git.enabled && git.state == initialized && workbenchState == folder"
"when": "config.git.enabled && git.state == initialized && workbenchState == folder",
"group": "5_scm@1"
},
{
"view": "scm",
"contents": "%view.workbench.scm.workspace%",
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0"
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0",
"group": "5_scm@1"
},
{
"view": "scm",
"contents": "%view.workbench.scm.emptyWorkspace%",
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount == 0"
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount == 0",
"group": "2_open@1"
},
{
"view": "explorer",
"contents": "%view.workbench.cloneRepository%",
"when": "config.git.enabled && git.state == initialized"
"when": "config.git.enabled && git.state == initialized",
"group": "5_scm@1"
}
]
},

View file

@ -278,16 +278,18 @@ export interface IViewContainerModel {
move(from: string, to: string): void;
}
export enum ViewContentPriority {
Normal = 0,
Low = 1,
Lowest = 2
export enum ViewContentGroups {
Open = '2_open',
Debug = '4_debug',
SCM = '5_scm',
More = '9_more'
}
export interface IViewContentDescriptor {
readonly content: string;
readonly when?: ContextKeyExpression | 'default';
readonly priority?: ViewContentPriority;
readonly group?: string;
readonly order?: number;
/**
* ordered preconditions for each button in the content
@ -323,15 +325,12 @@ export interface IViewsRegistry {
}
function compareViewContentDescriptors(a: IViewContentDescriptor, b: IViewContentDescriptor): number {
const aPriority = a.priority ?? ViewContentPriority.Normal;
const bPriority = b.priority ?? ViewContentPriority.Normal;
if (aPriority !== bPriority) {
return aPriority - bPriority;
const aGroup = a.group ?? ViewContentGroups.More;
const bGroup = b.group ?? ViewContentGroups.More;
if (aGroup !== bGroup) {
return aGroup.localeCompare(bGroup);
}
// No priroity, keep views sorted in the order they got registered
return 0;
return (a.order ?? 5) - (b.order ?? 5);
}
class ViewsRegistry extends Disposable implements IViewsRegistry {

View file

@ -15,7 +15,7 @@ import { IDebugService, CONTEXT_DEBUGGERS_AVAILABLE } from 'vs/workbench/contrib
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IViewDescriptorService, IViewsRegistry, Extensions, ViewContentPriority } from 'vs/workbench/common/views';
import { IViewDescriptorService, IViewsRegistry, Extensions, ViewContentGroups } from 'vs/workbench/common/views';
import { Registry } from 'vs/platform/registry/common/platform';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
@ -109,7 +109,8 @@ const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
content: localize({ key: 'openAFileWhichCanBeDebugged', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"[Open a file](command:{0}) which can be debugged or run.", isMacintosh ? OpenFileFolderAction.ID : OpenFileAction.ID),
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR.toNegated())
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR.toNegated()),
group: ViewContentGroups.Open
});
let debugKeybindingLabel = '';
@ -117,24 +118,28 @@ viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
content: localize({ key: 'runAndDebugAction', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"[Run and Debug{0}](command:{1})", debugKeybindingLabel, StartAction.ID),
preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR],
when: CONTEXT_DEBUGGERS_AVAILABLE
when: CONTEXT_DEBUGGERS_AVAILABLE,
group: ViewContentGroups.Debug
});
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
content: localize({ key: 'detectThenRunAndDebug', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"[Show](command:{0}) all automatic debug configurations.", SelectAndStartAction.ID),
priority: ViewContentPriority.Lowest,
when: CONTEXT_DEBUGGERS_AVAILABLE
when: CONTEXT_DEBUGGERS_AVAILABLE,
group: ViewContentGroups.Debug,
order: 10
});
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
content: localize({ key: 'customizeRunAndDebug', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"To customize Run and Debug [create a launch.json file](command:{0}).", ConfigureAction.ID),
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.notEqualsTo('empty'))
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.notEqualsTo('empty')),
group: ViewContentGroups.Debug
});
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
content: localize({ key: 'customizeRunAndDebugOpenFolder', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"To customize Run and Debug, [open a folder](command:{0}) and create a launch.json file.", isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID),
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.isEqualTo('empty'))
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.isEqualTo('empty')),
group: ViewContentGroups.Debug
});

View file

@ -19,7 +19,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IViewsRegistry, IViewDescriptor, Extensions, ViewContainer, IViewContainersRegistry, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
import { IViewsRegistry, IViewDescriptor, Extensions, ViewContainer, IViewContainersRegistry, ViewContainerLocation, IViewDescriptorService, ViewContentGroups } from 'vs/workbench/common/views';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
@ -273,18 +273,24 @@ const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
content: localize({ key: 'noWorkspaceHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"You have not yet added a folder to the workspace.\n[Add Folder](command:{0})", AddRootFolderAction.ID),
when: WorkbenchStateContext.isEqualTo('workspace')
when: WorkbenchStateContext.isEqualTo('workspace'),
group: ViewContentGroups.Open,
order: 1
});
const commandId = isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID;
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
content: localize({ key: 'remoteNoFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"Connected to remote.\n[Open Folder](command:{0})", commandId),
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.notEqualsTo(''), IsWebContext.toNegated())
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.notEqualsTo(''), IsWebContext.toNegated()),
group: ViewContentGroups.Open,
order: 1
});
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
content: localize({ key: 'noFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
"You have not yet opened a folder.\n[Open Folder](command:{0})", commandId),
when: ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext))
when: ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext)),
group: ViewContentGroups.Open,
order: 1
});

View file

@ -3,13 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ViewsWelcomeExtensionPoint, ViewWelcome, ViewIdentifierMap } from './viewsWelcomeExtensionPoint';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as ViewContainerExtensions, IViewsRegistry, ViewContentPriority } from 'vs/workbench/common/views';
import { Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views';
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
@ -34,10 +35,12 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo
for (const contribution of added) {
for (const welcome of contribution.value) {
const id = ViewIdentifierMap[welcome.view] ?? welcome.view;
const { group, order } = parseGroupAndOrder(welcome, contribution);
const disposable = viewsRegistry.registerViewWelcomeContent(id, {
content: welcome.contents,
when: ContextKeyExpr.deserialize(welcome.when),
priority: contribution.description.isBuiltin ? ViewContentPriority.Low : ViewContentPriority.Lowest
group,
order
});
this.viewWelcomeContents.set(welcome, disposable);
@ -46,3 +49,24 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo
});
}
}
function parseGroupAndOrder(welcome: ViewWelcome, contribution: IExtensionPointUser<ViewsWelcomeExtensionPoint>): { group: string | undefined, order: number | undefined } {
let group: string | undefined;
let order: number | undefined;
if (welcome.group) {
if (!contribution.description.enableProposedApi) {
contribution.collector.warn(nls.localize('ViewsWelcomeExtensionPoint.proposedAPI', "The viewsWelcome contribution in '{0}' requires 'enableProposedApi' to be enabled.", contribution.description.identifier.value));
return { group, order };
}
const idx = welcome.group.lastIndexOf('@');
if (idx > 0) {
group = welcome.group.substr(0, idx);
order = Number(welcome.group.substr(idx + 1)) || undefined;
} else {
group = welcome.group;
}
}
return { group, order };
}

View file

@ -10,12 +10,14 @@ export enum ViewsWelcomeExtensionPointFields {
view = 'view',
contents = 'contents',
when = 'when',
group = 'group',
}
export interface ViewWelcome {
readonly [ViewsWelcomeExtensionPointFields.view]: string;
readonly [ViewsWelcomeExtensionPointFields.contents]: string;
readonly [ViewsWelcomeExtensionPointFields.when]: string;
readonly [ViewsWelcomeExtensionPointFields.group]: string;
}
export type ViewsWelcomeExtensionPoint = ViewWelcome[];
@ -58,6 +60,10 @@ const viewsWelcomeExtensionPointSchema = Object.freeze<IConfigurationPropertySch
type: 'string',
description: nls.localize('contributes.viewsWelcome.view.when', "Condition when the welcome content should be displayed."),
},
[ViewsWelcomeExtensionPointFields.group]: {
type: 'string',
description: nls.localize('contributes.viewsWelcome.view.group', "Group to which this welcome content belongs."),
},
}
}
});