Skip to content

Commit

Permalink
#92038 Move output view from get*Actions to use menus
Browse files Browse the repository at this point in the history
  • Loading branch information
sandy081 committed Mar 9, 2020
1 parent ab35bc5 commit 849aadb
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 331 deletions.
4 changes: 2 additions & 2 deletions src/vs/workbench/browser/parts/views/viewMenuActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class ViewMenuActions extends Disposable {
const updateActions = () => {
this.primaryActions = [];
this.secondaryActions = [];
this.titleActionsDisposable.value = createAndFillInActionBarActions(menu, undefined, { primary: this.primaryActions, secondary: this.secondaryActions });
this.titleActionsDisposable.value = createAndFillInActionBarActions(menu, { shouldForwardArgs: true }, { primary: this.primaryActions, secondary: this.secondaryActions });
this._onDidChangeTitle.fire();
};
this._register(menu.onDidChange(updateActions));
Expand All @@ -45,7 +45,7 @@ export class ViewMenuActions extends Disposable {
const contextMenu = this._register(this.menuService.createMenu(contextMenuId, scopedContextKeyService));
const updateContextMenuActions = () => {
this.contextMenuActions = [];
this.titleActionsDisposable.value = createAndFillInActionBarActions(contextMenu, undefined, { primary: [], secondary: this.contextMenuActions });
this.titleActionsDisposable.value = createAndFillInActionBarActions(contextMenu, { shouldForwardArgs: true }, { primary: [], secondary: this.contextMenuActions });
};
this._register(contextMenu.onDidChange(updateContextMenuActions));
updateContextMenuActions();
Expand Down
246 changes: 206 additions & 40 deletions src/vs/workbench/contrib/output/browser/output.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
*--------------------------------------------------------------------------------------------*/

import * as nls from 'vs/nls';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { MenuId, MenuRegistry, SyncActionDescriptor, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { OutputService, LogContentProvider } from 'vs/workbench/contrib/output/browser/outputServices';
import { ToggleOutputAction, ClearOutputAction, OpenLogOutputFile, ShowLogsOutputChannelAction, OpenOutputLogFileAction } from 'vs/workbench/contrib/output/browser/outputActions';
import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, LOG_MODE_ID, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT } from 'vs/workbench/contrib/output/common/output';
import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, LOG_MODE_ID, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK } from 'vs/workbench/contrib/output/common/output';
import { OutputViewPane } from 'vs/workbench/contrib/output/browser/outputView';
import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor';
import { LogViewer, LogViewerInput } from 'vs/workbench/contrib/output/browser/logViewer';
Expand All @@ -21,9 +20,18 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWo
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views';
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService } from 'vs/workbench/common/views';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/services/output/common/output';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { assertIsDefined } from 'vs/base/common/types';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';

// Register Service
registerSingleton(IOutputService, OutputService);
Expand All @@ -43,18 +51,18 @@ ModesRegistry.registerLanguage({
});

// register output container
const toggleOutputAcitonId = 'workbench.action.output.toggleOutput';
const toggleOutputActionKeybindings = {
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U,
linux: {
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command
}
};
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({
id: OUTPUT_VIEW_ID,
name: nls.localize('output', "Output"),
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [OUTPUT_VIEW_ID, OUTPUT_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
focusCommand: {
id: ToggleOutputAction.ID, keybindings: {
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U,
linux: {
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command
}
}
}
focusCommand: { id: toggleOutputAcitonId, keybindings: toggleOutputActionKeybindings }
}, ViewContainerLocation.Panel);

Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry).registerViews([{
Expand Down Expand Up @@ -86,62 +94,220 @@ class OutputContribution implements IWorkbenchContribution {

Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(OutputContribution, LifecyclePhase.Restored);

// register toggle output action globally
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleOutputAction, ToggleOutputAction.ID, ToggleOutputAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U,
linux: {
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command
registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.output.action.switchBetweenOutputs`,
title: nls.localize('switchToOutput.label', "Switch to Output"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID),
group: 'navigation',
order: 1
},
});
}
}), 'View: Toggle Output', nls.localize('viewCategory', "View"));

actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClearOutputAction, ClearOutputAction.ID, ClearOutputAction.LABEL),
'View: Clear Output', nls.localize('viewCategory', "View"));

const devCategory = nls.localize('developer', "Developer");
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ShowLogsOutputChannelAction, ShowLogsOutputChannelAction.ID, ShowLogsOutputChannelAction.LABEL), 'Developer: Show Logs...', devCategory);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(OpenOutputLogFileAction, OpenOutputLogFileAction.ID, OpenOutputLogFileAction.LABEL), 'Developer: Open Log File...', devCategory);

// Define clear command, contribute to editor context menu
async run(accessor: ServicesAccessor, channelId: string): Promise<void> {
accessor.get(IOutputService).showChannel(channelId);
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'editor.action.clearoutput',
id: `workbench.output.action.clearOutput`,
title: { value: nls.localize('clearOutput.label', "Clear Output"), original: 'Clear Output' },
menu: {
category: nls.localize('viewCategory', "View"),
menu: [{
id: MenuId.ViewTitle,
when: ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID),
group: 'navigation',
order: 2
}, {
id: MenuId.CommandPalette
}, {
id: MenuId.EditorContext,
when: CONTEXT_IN_OUTPUT
},
}],
icon: { id: 'codicon/clear-all' }
});
}
run(accessor: ServicesAccessor) {
const activeChannel = accessor.get(IOutputService).getActiveChannel();
async run(accessor: ServicesAccessor): Promise<void> {
const outputService = accessor.get(IOutputService);
const activeChannel = outputService.getActiveChannel();
if (activeChannel) {
activeChannel.clear();
aria.status(nls.localize('outputCleared', "Output was cleared"));
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.output.action.turnOffAutoScroll`,
title: nls.localize('outputScrollOff', "Turn Auto Scrolling Off"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID), CONTEXT_OUTPUT_SCROLL_LOCK.negate()),
group: 'navigation',
order: 3,
},
icon: { id: 'codicon/unlock' }
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const outputView = accessor.get(IViewsService).getActiveViewWithId<OutputViewPane>(OUTPUT_VIEW_ID)!;
outputView.scrollLock = true;
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.output.action.turnOnAutoScroll`,
title: nls.localize('outputScrollOn', "Turn Auto Scrolling On"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID), CONTEXT_OUTPUT_SCROLL_LOCK),
group: 'navigation',
order: 3,
},
icon: { id: 'codicon/lock' },
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const outputView = accessor.get(IViewsService).getActiveViewWithId<OutputViewPane>(OUTPUT_VIEW_ID)!;
outputView.scrollLock = false;
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.action.openActiveLogOutputFile`,
title: { value: nls.localize('openActiveLogOutputFile', "Open Log Output File"), original: 'Open Log Output File' },
menu: [{
id: MenuId.ViewTitle,
when: ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID),
group: 'navigation',
order: 4
}, {
id: MenuId.CommandPalette,
when: CONTEXT_ACTIVE_LOG_OUTPUT,
}],
icon: { id: 'codicon/go-to-file' },
precondition: CONTEXT_ACTIVE_LOG_OUTPUT
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const outputService = accessor.get(IOutputService);
const editorService = accessor.get(IEditorService);
const instantiationService = accessor.get(IInstantiationService);
const logFileOutputChannelDescriptor = this.getLogFileOutputChannelDescriptor(outputService);
if (logFileOutputChannelDescriptor) {
await editorService.openEditor(instantiationService.createInstance(LogViewerInput, logFileOutputChannelDescriptor));
}
}
private getLogFileOutputChannelDescriptor(outputService: IOutputService): IFileOutputChannelDescriptor | null {
const channel = outputService.getActiveChannel();
if (channel) {
const descriptor = outputService.getChannelDescriptors().filter(c => c.id === channel.id)[0];
if (descriptor && descriptor.file && descriptor.log) {
return <IFileOutputChannelDescriptor>descriptor;
}
}
return null;
}
});

// register toggle output action globally
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.openActiveLogOutputFile',
title: { value: nls.localize('openActiveLogOutputFile', "Open Active Log Output File"), original: 'Open Active Log Output File' },
id: toggleOutputAcitonId,
title: { value: nls.localize('toggleOutput', "Toggle Output"), original: 'Toggle Output' },
category: { value: nls.localize('viewCategory', "View"), original: 'View' },
menu: {
id: MenuId.CommandPalette,
when: CONTEXT_ACTIVE_LOG_OUTPUT
},
keybinding: {
...toggleOutputActionKeybindings,
...{
weight: KeybindingWeight.WorkbenchContrib,
when: undefined
}
},
});
}
run(accessor: ServicesAccessor) {
accessor.get(IInstantiationService).createInstance(OpenLogOutputFile).run();
async run(accessor: ServicesAccessor): Promise<void> {
const panelService = accessor.get(IPanelService);
const layoutService = accessor.get(IWorkbenchLayoutService);
return new class ToggleOutputAction extends TogglePanelAction {
constructor() {
super(toggleOutputAcitonId, 'Toggle Output', OUTPUT_VIEW_ID, panelService, layoutService);
}
}().run();
}
});

const devCategory = { value: nls.localize('developer', "Developer"), original: 'Developer' };
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.showLogs',
title: { value: nls.localize('showLogs', "Show Logs..."), original: 'Show Logs...' },
category: devCategory,
menu: {
id: MenuId.CommandPalette,
},
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const outputService = accessor.get(IOutputService);
const quickInputService = accessor.get(IQuickInputService);
const entries: { id: string, label: string }[] = outputService.getChannelDescriptors().filter(c => c.file && c.log)
.map(({ id, label }) => ({ id, label }));

const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") });
if (entry) {
return outputService.showChannel(entry.id);
}
}
});

interface IOutputChannelQuickPickItem extends IQuickPickItem {
channel: IOutputChannelDescriptor;
}

registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.openLogFile',
title: { value: nls.localize('openLogFile', "Open Log File..."), original: 'Open Log File...' },
category: devCategory,
menu: {
id: MenuId.CommandPalette,
},
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const outputService = accessor.get(IOutputService);
const quickInputService = accessor.get(IQuickInputService);
const instantiationService = accessor.get(IInstantiationService);
const editorService = accessor.get(IEditorService);

const entries: IOutputChannelQuickPickItem[] = outputService.getChannelDescriptors().filter(c => c.file && c.log)
.map(channel => (<IOutputChannelQuickPickItem>{ id: channel.id, label: channel.label, channel }));

const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log file") });
if (entry) {
assertIsDefined(entry.channel.file);
await editorService.openEditor(instantiationService.createInstance(LogViewerInput, (entry.channel as IFileOutputChannelDescriptor)));
}
}
});

MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '4_panels',
command: {
id: ToggleOutputAction.ID,
id: toggleOutputAcitonId,
title: nls.localize({ key: 'miToggleOutput', comment: ['&& denotes a mnemonic'] }, "&&Output")
},
order: 1
Expand Down

0 comments on commit 849aadb

Please sign in to comment.