Skip to content

Commit 849aadb

Browse files
committed
microsoft#92038 Move output view from get*Actions to use menus
1 parent ab35bc5 commit 849aadb

5 files changed

Lines changed: 289 additions & 331 deletions

File tree

src/vs/workbench/browser/parts/views/viewMenuActions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class ViewMenuActions extends Disposable {
3636
const updateActions = () => {
3737
this.primaryActions = [];
3838
this.secondaryActions = [];
39-
this.titleActionsDisposable.value = createAndFillInActionBarActions(menu, undefined, { primary: this.primaryActions, secondary: this.secondaryActions });
39+
this.titleActionsDisposable.value = createAndFillInActionBarActions(menu, { shouldForwardArgs: true }, { primary: this.primaryActions, secondary: this.secondaryActions });
4040
this._onDidChangeTitle.fire();
4141
};
4242
this._register(menu.onDidChange(updateActions));
@@ -45,7 +45,7 @@ export class ViewMenuActions extends Disposable {
4545
const contextMenu = this._register(this.menuService.createMenu(contextMenuId, scopedContextKeyService));
4646
const updateContextMenuActions = () => {
4747
this.contextMenuActions = [];
48-
this.titleActionsDisposable.value = createAndFillInActionBarActions(contextMenu, undefined, { primary: [], secondary: this.contextMenuActions });
48+
this.titleActionsDisposable.value = createAndFillInActionBarActions(contextMenu, { shouldForwardArgs: true }, { primary: [], secondary: this.contextMenuActions });
4949
};
5050
this._register(contextMenu.onDidChange(updateContextMenuActions));
5151
updateContextMenuActions();

src/vs/workbench/contrib/output/browser/output.contribution.ts

Lines changed: 206 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as nls from 'vs/nls';
7+
import * as aria from 'vs/base/browser/ui/aria/aria';
78
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
89
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
910
import { Registry } from 'vs/platform/registry/common/platform';
10-
import { MenuId, MenuRegistry, SyncActionDescriptor, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
11+
import { MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
1112
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
12-
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
1313
import { OutputService, LogContentProvider } from 'vs/workbench/contrib/output/browser/outputServices';
14-
import { ToggleOutputAction, ClearOutputAction, OpenLogOutputFile, ShowLogsOutputChannelAction, OpenOutputLogFileAction } from 'vs/workbench/contrib/output/browser/outputActions';
15-
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';
14+
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';
1615
import { OutputViewPane } from 'vs/workbench/contrib/output/browser/outputView';
1716
import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor';
1817
import { LogViewer, LogViewerInput } from 'vs/workbench/contrib/output/browser/logViewer';
@@ -21,9 +20,18 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWo
2120
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
2221
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
2322
import { ITextModelService } from 'vs/editor/common/services/resolverService';
24-
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views';
23+
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService } from 'vs/workbench/common/views';
2524
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
2625
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
26+
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
27+
import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
28+
import { IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/services/output/common/output';
29+
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
30+
import { assertIsDefined } from 'vs/base/common/types';
31+
import { TogglePanelAction } from 'vs/workbench/browser/panel';
32+
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
33+
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
34+
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
2735

2836
// Register Service
2937
registerSingleton(IOutputService, OutputService);
@@ -43,18 +51,18 @@ ModesRegistry.registerLanguage({
4351
});
4452

4553
// register output container
54+
const toggleOutputAcitonId = 'workbench.action.output.toggleOutput';
55+
const toggleOutputActionKeybindings = {
56+
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U,
57+
linux: {
58+
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command
59+
}
60+
};
4661
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({
4762
id: OUTPUT_VIEW_ID,
4863
name: nls.localize('output', "Output"),
4964
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [OUTPUT_VIEW_ID, OUTPUT_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
50-
focusCommand: {
51-
id: ToggleOutputAction.ID, keybindings: {
52-
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U,
53-
linux: {
54-
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command
55-
}
56-
}
57-
}
65+
focusCommand: { id: toggleOutputAcitonId, keybindings: toggleOutputActionKeybindings }
5866
}, ViewContainerLocation.Panel);
5967

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

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

89-
// register toggle output action globally
90-
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
91-
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleOutputAction, ToggleOutputAction.ID, ToggleOutputAction.LABEL, {
92-
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U,
93-
linux: {
94-
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command
97+
registerAction2(class extends Action2 {
98+
constructor() {
99+
super({
100+
id: `workbench.output.action.switchBetweenOutputs`,
101+
title: nls.localize('switchToOutput.label', "Switch to Output"),
102+
menu: {
103+
id: MenuId.ViewTitle,
104+
when: ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID),
105+
group: 'navigation',
106+
order: 1
107+
},
108+
});
95109
}
96-
}), 'View: Toggle Output', nls.localize('viewCategory', "View"));
97-
98-
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClearOutputAction, ClearOutputAction.ID, ClearOutputAction.LABEL),
99-
'View: Clear Output', nls.localize('viewCategory', "View"));
100-
101-
const devCategory = nls.localize('developer', "Developer");
102-
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ShowLogsOutputChannelAction, ShowLogsOutputChannelAction.ID, ShowLogsOutputChannelAction.LABEL), 'Developer: Show Logs...', devCategory);
103-
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(OpenOutputLogFileAction, OpenOutputLogFileAction.ID, OpenOutputLogFileAction.LABEL), 'Developer: Open Log File...', devCategory);
104-
105-
// Define clear command, contribute to editor context menu
110+
async run(accessor: ServicesAccessor, channelId: string): Promise<void> {
111+
accessor.get(IOutputService).showChannel(channelId);
112+
}
113+
});
106114
registerAction2(class extends Action2 {
107115
constructor() {
108116
super({
109-
id: 'editor.action.clearoutput',
117+
id: `workbench.output.action.clearOutput`,
110118
title: { value: nls.localize('clearOutput.label', "Clear Output"), original: 'Clear Output' },
111-
menu: {
119+
category: nls.localize('viewCategory', "View"),
120+
menu: [{
121+
id: MenuId.ViewTitle,
122+
when: ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID),
123+
group: 'navigation',
124+
order: 2
125+
}, {
126+
id: MenuId.CommandPalette
127+
}, {
112128
id: MenuId.EditorContext,
113129
when: CONTEXT_IN_OUTPUT
114-
},
130+
}],
131+
icon: { id: 'codicon/clear-all' }
115132
});
116133
}
117-
run(accessor: ServicesAccessor) {
118-
const activeChannel = accessor.get(IOutputService).getActiveChannel();
134+
async run(accessor: ServicesAccessor): Promise<void> {
135+
const outputService = accessor.get(IOutputService);
136+
const activeChannel = outputService.getActiveChannel();
119137
if (activeChannel) {
120138
activeChannel.clear();
139+
aria.status(nls.localize('outputCleared', "Output was cleared"));
140+
}
141+
}
142+
});
143+
registerAction2(class extends Action2 {
144+
constructor() {
145+
super({
146+
id: `workbench.output.action.turnOffAutoScroll`,
147+
title: nls.localize('outputScrollOff', "Turn Auto Scrolling Off"),
148+
menu: {
149+
id: MenuId.ViewTitle,
150+
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID), CONTEXT_OUTPUT_SCROLL_LOCK.negate()),
151+
group: 'navigation',
152+
order: 3,
153+
},
154+
icon: { id: 'codicon/unlock' }
155+
});
156+
}
157+
async run(accessor: ServicesAccessor): Promise<void> {
158+
const outputView = accessor.get(IViewsService).getActiveViewWithId<OutputViewPane>(OUTPUT_VIEW_ID)!;
159+
outputView.scrollLock = true;
160+
}
161+
});
162+
registerAction2(class extends Action2 {
163+
constructor() {
164+
super({
165+
id: `workbench.output.action.turnOnAutoScroll`,
166+
title: nls.localize('outputScrollOn', "Turn Auto Scrolling On"),
167+
menu: {
168+
id: MenuId.ViewTitle,
169+
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID), CONTEXT_OUTPUT_SCROLL_LOCK),
170+
group: 'navigation',
171+
order: 3,
172+
},
173+
icon: { id: 'codicon/lock' },
174+
});
175+
}
176+
async run(accessor: ServicesAccessor): Promise<void> {
177+
const outputView = accessor.get(IViewsService).getActiveViewWithId<OutputViewPane>(OUTPUT_VIEW_ID)!;
178+
outputView.scrollLock = false;
179+
}
180+
});
181+
registerAction2(class extends Action2 {
182+
constructor() {
183+
super({
184+
id: `workbench.action.openActiveLogOutputFile`,
185+
title: { value: nls.localize('openActiveLogOutputFile', "Open Log Output File"), original: 'Open Log Output File' },
186+
menu: [{
187+
id: MenuId.ViewTitle,
188+
when: ContextKeyEqualsExpr.create('view', OUTPUT_VIEW_ID),
189+
group: 'navigation',
190+
order: 4
191+
}, {
192+
id: MenuId.CommandPalette,
193+
when: CONTEXT_ACTIVE_LOG_OUTPUT,
194+
}],
195+
icon: { id: 'codicon/go-to-file' },
196+
precondition: CONTEXT_ACTIVE_LOG_OUTPUT
197+
});
198+
}
199+
async run(accessor: ServicesAccessor): Promise<void> {
200+
const outputService = accessor.get(IOutputService);
201+
const editorService = accessor.get(IEditorService);
202+
const instantiationService = accessor.get(IInstantiationService);
203+
const logFileOutputChannelDescriptor = this.getLogFileOutputChannelDescriptor(outputService);
204+
if (logFileOutputChannelDescriptor) {
205+
await editorService.openEditor(instantiationService.createInstance(LogViewerInput, logFileOutputChannelDescriptor));
206+
}
207+
}
208+
private getLogFileOutputChannelDescriptor(outputService: IOutputService): IFileOutputChannelDescriptor | null {
209+
const channel = outputService.getActiveChannel();
210+
if (channel) {
211+
const descriptor = outputService.getChannelDescriptors().filter(c => c.id === channel.id)[0];
212+
if (descriptor && descriptor.file && descriptor.log) {
213+
return <IFileOutputChannelDescriptor>descriptor;
214+
}
121215
}
216+
return null;
122217
}
123218
});
124219

220+
// register toggle output action globally
125221
registerAction2(class extends Action2 {
126222
constructor() {
127223
super({
128-
id: 'workbench.action.openActiveLogOutputFile',
129-
title: { value: nls.localize('openActiveLogOutputFile', "Open Active Log Output File"), original: 'Open Active Log Output File' },
224+
id: toggleOutputAcitonId,
225+
title: { value: nls.localize('toggleOutput', "Toggle Output"), original: 'Toggle Output' },
226+
category: { value: nls.localize('viewCategory', "View"), original: 'View' },
130227
menu: {
131228
id: MenuId.CommandPalette,
132-
when: CONTEXT_ACTIVE_LOG_OUTPUT
229+
},
230+
keybinding: {
231+
...toggleOutputActionKeybindings,
232+
...{
233+
weight: KeybindingWeight.WorkbenchContrib,
234+
when: undefined
235+
}
133236
},
134237
});
135238
}
136-
run(accessor: ServicesAccessor) {
137-
accessor.get(IInstantiationService).createInstance(OpenLogOutputFile).run();
239+
async run(accessor: ServicesAccessor): Promise<void> {
240+
const panelService = accessor.get(IPanelService);
241+
const layoutService = accessor.get(IWorkbenchLayoutService);
242+
return new class ToggleOutputAction extends TogglePanelAction {
243+
constructor() {
244+
super(toggleOutputAcitonId, 'Toggle Output', OUTPUT_VIEW_ID, panelService, layoutService);
245+
}
246+
}().run();
247+
}
248+
});
249+
250+
const devCategory = { value: nls.localize('developer', "Developer"), original: 'Developer' };
251+
registerAction2(class extends Action2 {
252+
constructor() {
253+
super({
254+
id: 'workbench.action.showLogs',
255+
title: { value: nls.localize('showLogs', "Show Logs..."), original: 'Show Logs...' },
256+
category: devCategory,
257+
menu: {
258+
id: MenuId.CommandPalette,
259+
},
260+
});
261+
}
262+
async run(accessor: ServicesAccessor): Promise<void> {
263+
const outputService = accessor.get(IOutputService);
264+
const quickInputService = accessor.get(IQuickInputService);
265+
const entries: { id: string, label: string }[] = outputService.getChannelDescriptors().filter(c => c.file && c.log)
266+
.map(({ id, label }) => ({ id, label }));
267+
268+
const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") });
269+
if (entry) {
270+
return outputService.showChannel(entry.id);
271+
}
272+
}
273+
});
274+
275+
interface IOutputChannelQuickPickItem extends IQuickPickItem {
276+
channel: IOutputChannelDescriptor;
277+
}
278+
279+
registerAction2(class extends Action2 {
280+
constructor() {
281+
super({
282+
id: 'workbench.action.openLogFile',
283+
title: { value: nls.localize('openLogFile', "Open Log File..."), original: 'Open Log File...' },
284+
category: devCategory,
285+
menu: {
286+
id: MenuId.CommandPalette,
287+
},
288+
});
289+
}
290+
async run(accessor: ServicesAccessor): Promise<void> {
291+
const outputService = accessor.get(IOutputService);
292+
const quickInputService = accessor.get(IQuickInputService);
293+
const instantiationService = accessor.get(IInstantiationService);
294+
const editorService = accessor.get(IEditorService);
295+
296+
const entries: IOutputChannelQuickPickItem[] = outputService.getChannelDescriptors().filter(c => c.file && c.log)
297+
.map(channel => (<IOutputChannelQuickPickItem>{ id: channel.id, label: channel.label, channel }));
298+
299+
const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log file") });
300+
if (entry) {
301+
assertIsDefined(entry.channel.file);
302+
await editorService.openEditor(instantiationService.createInstance(LogViewerInput, (entry.channel as IFileOutputChannelDescriptor)));
303+
}
138304
}
139305
});
140306

141307
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
142308
group: '4_panels',
143309
command: {
144-
id: ToggleOutputAction.ID,
310+
id: toggleOutputAcitonId,
145311
title: nls.localize({ key: 'miToggleOutput', comment: ['&& denotes a mnemonic'] }, "&&Output")
146312
},
147313
order: 1

0 commit comments

Comments
 (0)