diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index b9a6632244234..e1cc0dd3b22ac 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -175,6 +175,7 @@ export class MenuId { static readonly TerminalInlineTabContext = new MenuId('TerminalInlineTabContext'); static readonly WebviewContext = new MenuId('WebviewContext'); static readonly InlineCompletionsActions = new MenuId('InlineCompletionsActions'); + static readonly NewFile = new MenuId('NewFile'); readonly id: number; readonly _debugName: string; diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 3841403c9244d..bfd3d09b3dd52 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -238,6 +238,12 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.TunnelPortInline, description: localize('view.tunnelPortInline', "The Ports view item port inline menu") }, + { + key: 'file/newFile', + id: MenuId.NewFile, + description: localize('file.newFile', "The 'New File...' quick pick, shown on welcome page and File menu. Supports property `{0}` to override the default title if needed.)", 'title'), + supportsSubmenus: false, + }, { key: 'editor/inlineCompletions/actions', id: MenuId.InlineCompletionsActions, diff --git a/src/vs/workbench/contrib/welcome/common/newFile.contribution.ts b/src/vs/workbench/contrib/welcome/common/newFile.contribution.ts new file mode 100644 index 0000000000000..2bb73d5b0c3ba --- /dev/null +++ b/src/vs/workbench/contrib/welcome/common/newFile.contribution.ts @@ -0,0 +1,219 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { assertIsDefined } from 'vs/base/common/types'; +import { localize } from 'vs/nls'; +import { Action2, IMenuService, MenuId, registerAction2, IMenu, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; + +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; + + +const category = localize('Create', "Create"); + +export const HasMultipleNewFileEntries = new RawContextKey('hasMultipleNewFileEntries', false); + +registerAction2(class extends Action2 { + constructor() { + super({ + id: 'welcome.showNewFileEntries', + title: localize('welcome.newFile', "New File..."), + category, + f1: true, + keybinding: { + primary: KeyMod.Alt + KeyMod.CtrlCmd + KeyMod.WinCtrl + KeyCode.KEY_N, + weight: KeybindingWeight.WorkbenchContrib, + }, + menu: { + id: MenuId.MenubarFileMenu, + when: HasMultipleNewFileEntries, + group: '1_new', + order: 3 + } + }); + } + + run(accessor: ServicesAccessor) { + assertIsDefined(NewFileTemplatesManager.Instance).run(); + } +}); + +type NewFileItem = { commandID: string, title: string, from: string, group: string }; +class NewFileTemplatesManager extends Disposable { + static Instance: NewFileTemplatesManager | undefined; + + private menu: IMenu; + + private registry = new Map(); + + constructor( + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @ICommandService private readonly commandService: ICommandService, + @IKeybindingService private readonly keybindingService: IKeybindingService, + @IExtensionService private readonly extensionService: IExtensionService, + @IMenuService menuService: IMenuService, + ) { + super(); + + NewFileTemplatesManager.Instance = this; + + this._register({ dispose() { if (NewFileTemplatesManager.Instance === this) { NewFileTemplatesManager.Instance = undefined; } } }); + this._register(this.extensionService.onDidChangeExtensions(() => this.cacheRawContributionData())); + this.cacheRawContributionData(); + + this.menu = menuService.createMenu(MenuId.NewFile, contextKeyService); + this.updateContextKeys(); + this._register(this.menu.onDidChange(() => { this.updateContextKeys(); })); + } + + private async cacheRawContributionData() { + const allExts = await this.extensionService.getExtensions(); + for (const ext of allExts) { + const contribution = ext.contributes?.menus?.['file/newFile']; + if (contribution?.length) { + contribution.forEach(menu => this.registry.set(menu.command, { + commandID: menu.command, + from: ext.displayName ?? ext.name, + title: (menu as any).title, + group: menu.group?.toLowerCase() ?? '', + })); + } + } + } + + + private allEntries(): NewFileItem[] { + const items: NewFileItem[] = []; + for (const [group, actions] of this.menu.getActions()) { + for (const action of actions) { + const registered = this.registry.get(action.id); + if (registered) { + if (!registered.title) { registered.title = action.label; } + items.push(registered); + } + else { + items.push({ commandID: action.id, from: localize('Built-In', "Built-In"), title: action.label, group: group }); + } + } + } + return items; + } + + private updateContextKeys() { + HasMultipleNewFileEntries.bindTo(this.contextKeyService).set(this.allEntries().length > 1); + } + + run() { + const entries = this.allEntries(); + if (entries.length === 0) { + throw Error('Unexpected empty new items list'); + } + else if (entries.length === 1) { + this.commandService.executeCommand(entries[0].commandID); + } + else { + this.selectNewEntry(entries); + } + } + + private async selectNewEntry(entries: NewFileItem[]) { + const disposables = new DisposableStore(); + const qp = this.quickInputService.createQuickPick(); + qp.title = localize('createNew', "Create New..."); + qp.matchOnDetail = true; + qp.matchOnDescription = true; + + const sortCategories = (a: string, b: string): number => { + const categoryPriority: Record = { 'file': 1, 'notebook': 2 }; + if (categoryPriority[a] && categoryPriority[b]) { return categoryPriority[b] - categoryPriority[a]; } + if (categoryPriority[a]) { return 1; } + if (categoryPriority[b]) { return -1; } + return a.localeCompare(b); + }; + + const displayCategory: Record = { + 'file': localize('file', "File"), + 'notebook': localize('notebook', "Notebook"), + }; + + const refreshQp = (entries: NewFileItem[]) => { + const items: (((IQuickPickItem & NewFileItem) | IQuickPickSeparator))[] = []; + let lastSeparator: string | undefined; + entries + .sort((a, b) => -sortCategories(a.group, b.group)) + .forEach((entry) => { + const command = entry.commandID; + const keybinding = this.keybindingService.lookupKeybinding(command || '', this.contextKeyService); + if (lastSeparator !== entry.group) { + items.push({ + type: 'separator', + label: displayCategory[entry.group] ?? entry.group + }); + lastSeparator = entry.group; + } + items.push({ + ...entry, + label: entry.title, + type: 'item', + keybinding, + buttons: command ? [ + { + iconClass: 'codicon codicon-gear', + tooltip: localize('change keybinding', "Configure Keybinding") + } + ] : [], + detail: '', + description: entry.from, + }); + }); + qp.items = items; + }; + refreshQp(entries); + + disposables.add(this.menu.onDidChange(() => refreshQp(this.allEntries()))); + + disposables.add(qp.onDidAccept(async e => { + const selected = qp.selectedItems[0] as (IQuickPickItem & NewFileItem); + if (selected) { await this.commandService.executeCommand(selected.commandID); } + qp.hide(); + })); + + disposables.add(qp.onDidHide(() => { + qp.dispose(); + disposables.dispose(); + })); + + disposables.add(qp.onDidTriggerItemButton(e => { + qp.hide(); + this.commandService.executeCommand('workbench.action.openGlobalKeybindings', (e.item as any).action.runCommand); + })); + + qp.show(); + } + +} + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(NewFileTemplatesManager, LifecyclePhase.Restored); + +MenuRegistry.appendMenuItem(MenuId.NewFile, { + group: 'File', + command: { + id: 'workbench.action.files.newUntitledFile', + title: localize('miNewFile2', "Text File") + }, + order: 1 +}); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts index ca95fb8563e93..4ef047d726068 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts @@ -12,10 +12,10 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { ContextKeyEqualsExpr } from 'vs/platform/contextkey/common/contextkey'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { KeyCode } from 'vs/base/common/keyCodes'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { HasMultipleNewFileEntries, IGettingStartedNewMenuEntryDescriptorCategory, IGettingStartedService } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService'; +import { IGettingStartedService } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService'; import { GettingStartedInput } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -187,80 +187,6 @@ registerAction2(class extends Action2 { } }); -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'welcome.showNewFileEntries', - title: localize('welcome.newFile', "New File..."), - category, - f1: true, - keybinding: { - primary: KeyMod.Alt + KeyMod.CtrlCmd + KeyMod.WinCtrl + KeyCode.KEY_N, - weight: KeybindingWeight.WorkbenchContrib, - }, - menu: { - id: MenuId.MenubarFileMenu, - when: HasMultipleNewFileEntries, - group: '1_new', - order: 3 - } - }); - } - - run(accessor: ServicesAccessor) { - const gettingStartedService = accessor.get(IGettingStartedService); - gettingStartedService.selectNewEntry([ - IGettingStartedNewMenuEntryDescriptorCategory.file, - IGettingStartedNewMenuEntryDescriptorCategory.notebook]); - } -}); - -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'welcome.showNewFolderEntries', - title: localize('welcome.newFolder', "New Folder..."), - category, - // f1: true, - keybinding: { - primary: KeyMod.Alt + KeyMod.CtrlCmd + KeyMod.WinCtrl + KeyCode.KEY_F, - weight: KeybindingWeight.WorkbenchContrib, - }, - // menu: { - // id: MenuId.MenubarFileMenu, - // group: '1_new', - // order: 5 - // } - }); - } - - run(accessor: ServicesAccessor) { - const gettingStartedService = accessor.get(IGettingStartedService); - gettingStartedService.selectNewEntry([IGettingStartedNewMenuEntryDescriptorCategory.folder]); - } -}); - -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'welcome.showNewEntries', - title: localize('welcome.new', "New..."), - category, - f1: true, - }); - } - - run(accessor: ServicesAccessor, args?: ('file' | 'folder' | 'notebook')[]) { - const gettingStartedService = accessor.get(IGettingStartedService); - const filters: IGettingStartedNewMenuEntryDescriptorCategory[] = []; - (args ?? []).forEach(arg => { - if (IGettingStartedNewMenuEntryDescriptorCategory[arg]) { filters.push(IGettingStartedNewMenuEntryDescriptorCategory[arg]); } - }); - - gettingStartedService.selectNewEntry(filters); - } -}); - registerAction2(class extends Action2 { constructor() { super({ @@ -341,12 +267,6 @@ configurationRegistry.registerConfiguration({ type: 'boolean', default: true, description: localize('workbench.welcomePage.walkthroughs.openOnInstall', "When enabled, an extension's walkthrough will open upon install the extension. Walkthroughs are the items contributed the the 'Getting Started' section of the welcome page") - }, - 'workbench.welcome.experimental.startEntries': { - scope: ConfigurationScope.APPLICATION, - type: 'boolean', - default: false, - description: localize('workbench.welcome.experimental.startEntries', "Experimental. When enabled, extensions can use proposed API to contribute items to the New=>File... menu and welcome page item.") } } }); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts index e05abae64bc90..aae5231afa933 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts @@ -196,39 +196,9 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo } }); -export const startEntriesExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ +ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'startEntries', jsonSchema: { - description: localize('startEntries', "Contribute commands to the \"Welcome: Start...\" pickers and \"File => New X...\" menu entries."), - type: 'array', - items: { - type: 'object', - required: ['title', 'command', 'category'], - additionalProperties: false, - defaultSnippets: [{ body: { 'title': '$1', 'command': '$3' } }], - properties: { - title: { - type: 'string', - description: localize('startEntries.title', "Title of item.") - }, - command: { - type: 'string', - description: localize('startEntries.command', "Command to run.") - }, - category: { - type: 'string', - description: localize('startEntries.category', "Category of the new entry."), - enum: ['file', 'folder', 'notebook', 'other'], - }, - description: { - type: 'string', - description: localize('startEntries.description', "Description of item. We recommend leaving this blank unless the action is significantly nuanced in a way the title can not capture.") - }, - when: { - type: 'string', - description: localize('startEntries.when', "Context key expression to control the visibility of this item.") - }, - } - } + deprecationMessage: localize('removed', "Removed, use the menus => file/newFile contribution point instead"), } }); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts index 99a552f023caf..d7b1e1f601fac 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, IInstantiationService, optional, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, optional, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Emitter, Event } from 'vs/base/common/event'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Memento } from 'vs/workbench/common/memento'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, ContextKeyExpression, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; @@ -24,7 +24,7 @@ import { assertIsDefined } from 'vs/base/common/types'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILink, LinkedText, parseLinkedText } from 'vs/base/common/linkedText'; -import { walkthroughsExtensionPoint, startEntriesExtensionPoint } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint'; +import { walkthroughsExtensionPoint } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { dirname } from 'vs/base/common/path'; import { coalesce, flatten } from 'vs/base/common/arrays'; @@ -32,9 +32,6 @@ import { IViewsService } from 'vs/workbench/common/views'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { isLinux, isMacintosh, isWindows, OperatingSystem as OS } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; -import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import product from 'vs/platform/product/common/product'; export const WorkspacePlatform = new RawContextKey<'mac' | 'linux' | 'windows' | undefined>('workspacePlatform', undefined, localize('workspacePlatform', "The platform of the current workspace, which in remote contexts may be different from the platform of the UI")); export const HasMultipleNewFileEntries = new RawContextKey('hasMultipleNewFileEntries', false); @@ -87,25 +84,6 @@ export interface IGettingStartedWalkthroughDescriptor { | { type: 'steps' } } -export enum IGettingStartedNewMenuEntryDescriptorCategory { - 'file', - 'notebook', - 'folder', -} - - -export interface IGettingStartedNewMenuEntryDescriptor { - title: string - description?: string - when?: ContextKeyExpression - from: string - sourceExtensionId?: string - category: IGettingStartedNewMenuEntryDescriptorCategory - action: { runCommand: string, invokeFunction?: never } | { invokeFunction: (accessor: ServicesAccessor) => void, runCommand?: never } -} - -export const CoreNewEntryDisplayName = localize('builtinProviderDisplayName', "Built-in"); - export interface IGettingStartedStartEntryDescriptor { id: GettingStartedCategory | string title: string @@ -171,8 +149,6 @@ export interface IGettingStartedService { progressStep(id: string): void; deprogressStep(id: string): void; - selectNewEntry(categories: IGettingStartedNewMenuEntryDescriptorCategory[]): Promise; - markWalkthroughOpened(id: string): void; installedExtensionsRegistered: Promise; @@ -218,8 +194,6 @@ export class GettingStartedService extends Disposable implements IGettingStarted private stepCompletionContextKeyExpressions = new Set(); private stepCompletionContextKeys = new Set(); - private newMenuItems: IGettingStartedNewMenuEntryDescriptor[] = []; - private triggerInstalledExtensionsRegistered!: () => void; installedExtensionsRegistered: Promise; @@ -230,10 +204,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted @ICommandService private readonly commandService: ICommandService, @IContextKeyService private readonly contextService: IContextKeyService, @IUserDataAutoSyncEnablementService readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @IKeybindingService private readonly keybindingService: IKeybindingService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IInstantiationService private readonly instantiationService: IInstantiationService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IHostService private readonly hostService: IHostService, @IViewsService private readonly viewsService: IViewsService, @@ -248,32 +219,9 @@ export class GettingStartedService extends Disposable implements IGettingStarted JSON.parse( this.storageService.get(walkthroughMetadataConfigurationKey, StorageScope.GLOBAL, '[]'))); - const builtinNewMenuItems = [ - { - title: localize('newUntitledTitle', "Text File"), - action: { runCommand: 'workbench.action.files.newUntitledFile' }, - category: IGettingStartedNewMenuEntryDescriptorCategory.file, - from: CoreNewEntryDisplayName, - }, - { - title: localize('newGit', "Folder from Git Repo"), - action: { runCommand: 'git.clone' }, - when: ContextKeyExpr.deserialize('!git.missing'), - category: IGettingStartedNewMenuEntryDescriptorCategory.folder, - from: CoreNewEntryDisplayName, - } - ]; - - builtinNewMenuItems.forEach(item => this.registerNewMenuItem(item)); - this.memento = new Memento('gettingStartedService', this.storageService); this.stepProgress = this.memento.getMemento(StorageScope.GLOBAL, StorageTarget.USER); - startEntriesExtensionPoint.setHandler((_, { added, removed }) => { - added.forEach(e => this.registerExtensionNewContributions(e.description)); - removed.forEach(e => this.unregisterExtensionNewContributions(e.description)); - }); - walkthroughsExtensionPoint.setHandler((_, { added, removed }) => { added.forEach(e => this.registerExtensionWalkthroughContributions(e.description)); removed.forEach(e => this.unregisterExtensionWalkthroughContributions(e.description)); @@ -395,90 +343,6 @@ export class GettingStartedService extends Disposable implements IGettingStarted }); } - public async selectNewEntry(categories: IGettingStartedNewMenuEntryDescriptorCategory[]) { - const disposables = new DisposableStore(); - const qp = this.quickInputService.createQuickPick(); - qp.title = localize('createNew', "Create New..."); - qp.matchOnDetail = true; - qp.matchOnDescription = true; - - if (this.newMenuItems.filter(entry => categories.includes(entry.category)).length === 1 - && !(categories.length === 1 && categories[0] === IGettingStartedNewMenuEntryDescriptorCategory.folder)) { - const selection = this.newMenuItems - .filter(entry => categories.includes(entry.category))[0]; - - if (selection) { - if (selection.action.runCommand) { - await this.commandService.executeCommand(selection.action.runCommand); - } else if (selection.action.invokeFunction) { - await this.instantiationService.invokeFunction(selection.action.invokeFunction); - } - } - return; - } - - const refreshQp = () => { - const items: (((IQuickPickItem & IGettingStartedNewMenuEntryDescriptor) | IQuickPickSeparator))[] = []; - let lastSeparator: IGettingStartedNewMenuEntryDescriptorCategory | undefined; - this.newMenuItems - .filter(entry => categories.length === 0 || categories.includes(entry.category)) - .filter(entry => this.contextService.contextMatchesRules(entry.when)) - .forEach((entry) => { - const command = entry.action.runCommand; - const keybinding = this.keybindingService.lookupKeybinding(command || '', this.contextService); - if (lastSeparator !== entry.category && categories.length !== 1) { - items.push({ - type: 'separator', - label: displayCategory[entry.category] - }); - lastSeparator = entry.category; - } - items.push({ - ...entry, - label: entry.title, - type: 'item', - keybinding, - buttons: command ? [ - { - iconClass: 'codicon codicon-gear', - tooltip: localize('change keybinding', "Configure Keybinding") - } - ] : [], - detail: entry.description, - description: entry.from, - }); - }); - qp.items = items; - }; - refreshQp(); - - disposables.add(this.onDidAddNewEntry(() => refreshQp())); - - disposables.add(qp.onDidAccept(async e => { - const selected = qp.selectedItems[0] as (IQuickPickItem & IGettingStartedNewMenuEntryDescriptor); - if (selected) { - if (selected.action.runCommand) { - await this.commandService.executeCommand(selected.action.runCommand); - } else if (selected.action.invokeFunction) { - await this.instantiationService.invokeFunction(selected.action.invokeFunction); - } - } - qp.hide(); - })); - - disposables.add(qp.onDidHide(() => { - qp.dispose(); - disposables.dispose(); - })); - - disposables.add(qp.onDidTriggerItemButton(e => { - qp.hide(); - this.commandService.executeCommand('workbench.action.openGlobalKeybindings', (e.item as any).action.runCommand); - })); - - qp.show(); - } - private async getCategoryOverrides(category: BuiltinGettingStartedCategory | BuiltinGettingStartedStartEntry) { if (!this.tasExperimentService) { return; } @@ -516,24 +380,6 @@ export class GettingStartedService extends Disposable implements IGettingStarted this._onDidChangeStep.fire(this.getStepProgress(existingStep)); } - private async registerExtensionNewContributions(extension: IExtensionDescription) { - if (product.quality === 'stable' && !this.configurationService.getValue('workbench.welcome.experimental.startEntries')) { - console.warn('Warning: ignoring startEntries contributed by', extension.identifier, 'becuase this is a stable build and welcome.experimental.startEntries has not been set'); - return; - } - extension.contributes?.startEntries?.forEach(entry => { - this.registerNewMenuItem({ - sourceExtensionId: extension.identifier.value, - action: { runCommand: entry.command }, - description: entry.description, - title: entry.title, - category: IGettingStartedNewMenuEntryDescriptorCategory[entry.category], - when: ContextKeyExpr.deserialize(entry.when) ?? ContextKeyExpr.true(), - from: extension.displayName ?? extension.name, - }); - }); - } - markWalkthroughOpened(id: string) { const walkthrough = this.gettingStartedContributions.get(id); const prior = this.metadata.get(id); @@ -680,16 +526,6 @@ export class GettingStartedService extends Disposable implements IGettingStarted } } - private registerNewMenuItem(categoryDescriptor: IGettingStartedNewMenuEntryDescriptor) { - this.newMenuItems.push(categoryDescriptor); - this.newMenuItems.sort((a, b) => b.category - a.category); - if (categoryDescriptor.category === IGettingStartedNewMenuEntryDescriptorCategory.file || categoryDescriptor.category === IGettingStartedNewMenuEntryDescriptorCategory.notebook) { - HasMultipleNewFileEntries.bindTo(this.contextService).set(true); - } - - this._onDidAddNewEntry.fire(); - } - private unregisterExtensionWalkthroughContributions(extension: IExtensionDescription) { if (!(extension.contributes?.walkthroughs?.length)) { return; @@ -706,19 +542,6 @@ export class GettingStartedService extends Disposable implements IGettingStarted }); } - private unregisterExtensionNewContributions(extension: IExtensionDescription) { - if (!(extension.contributes?.startEntries?.length)) { - return; - } - - this.newMenuItems = this.newMenuItems.filter(entry => entry.sourceExtensionId !== extension.identifier.value); - HasMultipleNewFileEntries.bindTo(this.contextService).set( - this.newMenuItems.filter(entry => - entry.category === IGettingStartedNewMenuEntryDescriptorCategory.file - || entry.category === IGettingStartedNewMenuEntryDescriptorCategory.notebook).length > 1 - ); - } - private registerDoneListeners(step: IGettingStartedStep) { if (step.doneOn) { if (step.doneOn.commandExecuted) { step.completionEvents.push(`onCommand:${step.doneOn.commandExecuted}`); } @@ -1028,10 +851,4 @@ registerAction2(class extends Action2 { } }); -const displayCategory: Record = { - [IGettingStartedNewMenuEntryDescriptorCategory.file]: localize('file', "File"), - [IGettingStartedNewMenuEntryDescriptorCategory.folder]: localize('folder', "Folder"), - [IGettingStartedNewMenuEntryDescriptorCategory.notebook]: localize('notebook', "Notebook"), -}; - registerSingleton(IGettingStartedService, GettingStartedService); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index b9a20df585e07..73a268b2b40a5 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -286,6 +286,8 @@ import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; import 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution'; import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; +import 'vs/workbench/contrib/welcome/common/viewsWelcome.contribution'; +import 'vs/workbench/contrib/welcome/common/newFile.contribution'; // Call Hierarchy import 'vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution'; @@ -306,9 +308,6 @@ import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution'; // Code Actions import 'vs/workbench/contrib/codeActions/common/codeActions.contribution'; -// Welcome -import 'vs/workbench/contrib/welcome/common/viewsWelcome.contribution'; - // Timeline import 'vs/workbench/contrib/timeline/browser/timeline.contribution';