mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Merge pull request #107215 from microsoft/aeschli/welcomeViewGroups
groups for viewsWelcome
This commit is contained in:
commit
2ef6c258b0
|
@ -2083,27 +2083,32 @@
|
||||||
{
|
{
|
||||||
"view": "scm",
|
"view": "scm",
|
||||||
"contents": "%view.workbench.scm.empty%",
|
"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",
|
"view": "scm",
|
||||||
"contents": "%view.workbench.scm.folder%",
|
"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",
|
"view": "scm",
|
||||||
"contents": "%view.workbench.scm.workspace%",
|
"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",
|
"view": "scm",
|
||||||
"contents": "%view.workbench.scm.emptyWorkspace%",
|
"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",
|
"view": "explorer",
|
||||||
"contents": "%view.workbench.cloneRepository%",
|
"contents": "%view.workbench.cloneRepository%",
|
||||||
"when": "config.git.enabled && git.state == initialized"
|
"when": "config.git.enabled && git.state == initialized",
|
||||||
|
"group": "5_scm@1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -278,16 +278,18 @@ export interface IViewContainerModel {
|
||||||
move(from: string, to: string): void;
|
move(from: string, to: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ViewContentPriority {
|
export enum ViewContentGroups {
|
||||||
Normal = 0,
|
Open = '2_open',
|
||||||
Low = 1,
|
Debug = '4_debug',
|
||||||
Lowest = 2
|
SCM = '5_scm',
|
||||||
|
More = '9_more'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IViewContentDescriptor {
|
export interface IViewContentDescriptor {
|
||||||
readonly content: string;
|
readonly content: string;
|
||||||
readonly when?: ContextKeyExpression | 'default';
|
readonly when?: ContextKeyExpression | 'default';
|
||||||
readonly priority?: ViewContentPriority;
|
readonly group?: string;
|
||||||
|
readonly order?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ordered preconditions for each button in the content
|
* ordered preconditions for each button in the content
|
||||||
|
@ -323,15 +325,12 @@ export interface IViewsRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareViewContentDescriptors(a: IViewContentDescriptor, b: IViewContentDescriptor): number {
|
function compareViewContentDescriptors(a: IViewContentDescriptor, b: IViewContentDescriptor): number {
|
||||||
const aPriority = a.priority ?? ViewContentPriority.Normal;
|
const aGroup = a.group ?? ViewContentGroups.More;
|
||||||
const bPriority = b.priority ?? ViewContentPriority.Normal;
|
const bGroup = b.group ?? ViewContentGroups.More;
|
||||||
|
if (aGroup !== bGroup) {
|
||||||
if (aPriority !== bPriority) {
|
return aGroup.localeCompare(bGroup);
|
||||||
return aPriority - bPriority;
|
|
||||||
}
|
}
|
||||||
|
return (a.order ?? 5) - (b.order ?? 5);
|
||||||
// No priroity, keep views sorted in the order they got registered
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewsRegistry extends Disposable implements IViewsRegistry {
|
class ViewsRegistry extends Disposable implements IViewsRegistry {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { IDebugService, CONTEXT_DEBUGGERS_AVAILABLE } from 'vs/workbench/contrib
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
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 { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
|
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
|
||||||
|
@ -109,7 +109,8 @@ const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||||
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
|
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'] },
|
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),
|
"[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 = '';
|
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'] },
|
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),
|
"[Run and Debug{0}](command:{1})", debugKeybindingLabel, StartAction.ID),
|
||||||
preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR],
|
preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR],
|
||||||
when: CONTEXT_DEBUGGERS_AVAILABLE
|
when: CONTEXT_DEBUGGERS_AVAILABLE,
|
||||||
|
group: ViewContentGroups.Debug
|
||||||
});
|
});
|
||||||
|
|
||||||
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
|
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'] },
|
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),
|
"[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, {
|
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'] },
|
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),
|
"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, {
|
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'] },
|
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),
|
"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
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
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 { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
|
@ -273,18 +273,24 @@ const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
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'] },
|
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),
|
"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;
|
const commandId = isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID;
|
||||||
viewsRegistry.registerViewWelcomeContent(EmptyView.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'] },
|
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),
|
"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, {
|
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'] },
|
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),
|
"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
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* 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 { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
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 { ViewsWelcomeExtensionPoint, ViewWelcome, ViewIdentifierMap } from './viewsWelcomeExtensionPoint';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
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);
|
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 contribution of added) {
|
||||||
for (const welcome of contribution.value) {
|
for (const welcome of contribution.value) {
|
||||||
const id = ViewIdentifierMap[welcome.view] ?? welcome.view;
|
const id = ViewIdentifierMap[welcome.view] ?? welcome.view;
|
||||||
|
const { group, order } = parseGroupAndOrder(welcome, contribution);
|
||||||
const disposable = viewsRegistry.registerViewWelcomeContent(id, {
|
const disposable = viewsRegistry.registerViewWelcomeContent(id, {
|
||||||
content: welcome.contents,
|
content: welcome.contents,
|
||||||
when: ContextKeyExpr.deserialize(welcome.when),
|
when: ContextKeyExpr.deserialize(welcome.when),
|
||||||
priority: contribution.description.isBuiltin ? ViewContentPriority.Low : ViewContentPriority.Lowest
|
group,
|
||||||
|
order
|
||||||
});
|
});
|
||||||
|
|
||||||
this.viewWelcomeContents.set(welcome, disposable);
|
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 };
|
||||||
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ export enum ViewsWelcomeExtensionPointFields {
|
||||||
view = 'view',
|
view = 'view',
|
||||||
contents = 'contents',
|
contents = 'contents',
|
||||||
when = 'when',
|
when = 'when',
|
||||||
|
group = 'group',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewWelcome {
|
export interface ViewWelcome {
|
||||||
readonly [ViewsWelcomeExtensionPointFields.view]: string;
|
readonly [ViewsWelcomeExtensionPointFields.view]: string;
|
||||||
readonly [ViewsWelcomeExtensionPointFields.contents]: string;
|
readonly [ViewsWelcomeExtensionPointFields.contents]: string;
|
||||||
readonly [ViewsWelcomeExtensionPointFields.when]: string;
|
readonly [ViewsWelcomeExtensionPointFields.when]: string;
|
||||||
|
readonly [ViewsWelcomeExtensionPointFields.group]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ViewsWelcomeExtensionPoint = ViewWelcome[];
|
export type ViewsWelcomeExtensionPoint = ViewWelcome[];
|
||||||
|
@ -58,6 +60,10 @@ const viewsWelcomeExtensionPointSchema = Object.freeze<IConfigurationPropertySch
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: nls.localize('contributes.viewsWelcome.view.when', "Condition when the welcome content should be displayed."),
|
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."),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue