menus.ts 72.5 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

J
Joao Moreno 已提交
8
import * as nls from 'vs/nls';
9
import { isMacintosh, isLinux, isWindows, language } from 'vs/base/common/platform';
J
Joao Moreno 已提交
10
import * as arrays from 'vs/base/common/arrays';
11
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
B
Benjamin Pasero 已提交
12
import { app, shell, Menu, MenuItem, BrowserWindow } from 'electron';
J
Joao Moreno 已提交
13
import { OpenContext, IRunActionInWindowRequest, IWindowsService } from 'vs/platform/windows/common/windows';
14 15
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { AutoSaveConfiguration } from 'vs/platform/files/common/files';
J
Joao Moreno 已提交
16
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
17
import { IUpdateService, StateType } from 'vs/platform/update/common/update';
18
import product from 'vs/platform/node/product';
19
import { RunOnceScheduler } from 'vs/base/common/async';
20
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
J
Joao Moreno 已提交
21
import { mnemonicMenuLabel as baseMnemonicLabel, unmnemonicLabel, getPathLabel } from 'vs/base/common/labels';
22 23
import { KeybindingsResolver } from 'vs/code/electron-main/keyboard';
import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows';
B
Benjamin Pasero 已提交
24
import { IHistoryMainService } from 'vs/platform/history/common/history';
B
Benjamin Pasero 已提交
25
import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
E
Erich Gamma 已提交
26

27 28 29 30 31
interface IMenuItemClickHandler {
	inDevTools: (contents: Electron.WebContents) => void;
	inNoWindow: () => void;
}

32 33
const telemetryFrom = 'menu';

B
Benjamin Pasero 已提交
34
export class CodeMenu {
35

36
	private static readonly MAX_MENU_RECENT_ENTRIES = 10;
37

38 39 40 41 42 43 44 45 46
	private keys = [
		'files.autoSave',
		'editor.multiCursorModifier',
		'workbench.sideBar.location',
		'workbench.statusBar.visible',
		'workbench.activityBar.visible',
		'window.enableMenuBarMnemonics',
		'window.nativeTabs'
	];
B
Benjamin Pasero 已提交
47

B
Benjamin Pasero 已提交
48
	private isQuitting: boolean;
E
Erich Gamma 已提交
49 50
	private appMenuInstalled: boolean;

51 52
	private menuUpdater: RunOnceScheduler;

53
	private keybindingsResolver: KeybindingsResolver;
E
Erich Gamma 已提交
54

55 56 57
	private closeFolder: Electron.MenuItem;
	private closeWorkspace: Electron.MenuItem;

58 59
	private nativeTabMenuItems: Electron.MenuItem[];

J
Joao Moreno 已提交
60
	constructor(
B
Benjamin Pasero 已提交
61
		@IUpdateService private updateService: IUpdateService,
62
		@IInstantiationService instantiationService: IInstantiationService,
B
Benjamin Pasero 已提交
63
		@IConfigurationService private configurationService: IConfigurationService,
B
Benjamin Pasero 已提交
64
		@IWindowsMainService private windowsMainService: IWindowsMainService,
J
Joao Moreno 已提交
65
		@IWindowsService private windowsService: IWindowsService,
J
Joao Moreno 已提交
66
		@IEnvironmentService private environmentService: IEnvironmentService,
67
		@ITelemetryService private telemetryService: ITelemetryService,
I
isidor 已提交
68
		@IHistoryMainService private historyMainService: IHistoryMainService
J
Joao Moreno 已提交
69
	) {
70
		this.nativeTabMenuItems = [];
E
Erich Gamma 已提交
71

72
		this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0);
73
		this.keybindingsResolver = instantiationService.createInstance(KeybindingsResolver);
74

E
Erich Gamma 已提交
75
		this.install();
76 77

		this.registerListeners();
E
Erich Gamma 已提交
78 79 80 81 82 83
	}

	private registerListeners(): void {

		// Keep flag when app quits
		app.on('will-quit', () => {
B
Benjamin Pasero 已提交
84
			this.isQuitting = true;
E
Erich Gamma 已提交
85 86
		});

87
		// Listen to some events from window service to update menu
B
Benjamin Pasero 已提交
88 89 90 91 92
		this.historyMainService.onRecentlyOpenedChange(() => this.updateMenu());
		this.windowsMainService.onWindowsCountChanged(e => this.onWindowsCountChanged(e));
		this.windowsMainService.onActiveWindowChanged(() => this.updateWorkspaceMenuItems());
		this.windowsMainService.onWindowReady(() => this.updateWorkspaceMenuItems());
		this.windowsMainService.onWindowClose(() => this.updateWorkspaceMenuItems());
E
Erich Gamma 已提交
93

B
Benjamin Pasero 已提交
94
		// Update when auto save config changes
95
		this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e));
B
Benjamin Pasero 已提交
96

B
Benjamin Pasero 已提交
97
		// Listen to update service
98
		this.updateService.onStateChange(() => this.updateMenu());
99 100 101

		// Listen to keybindings change
		this.keybindingsResolver.onKeybindingsChanged(() => this.updateMenu());
E
Erich Gamma 已提交
102 103
	}

104 105 106
	private onConfigurationUpdated(event: IConfigurationChangeEvent): void {
		if (this.keys.some(key => event.affectsConfiguration(key))) {
			this.updateMenu();
B
Benjamin Pasero 已提交
107
		}
108
	}
B
Benjamin Pasero 已提交
109

110 111 112
	private get currentAutoSaveSetting(): string {
		return this.configurationService.getValue<string>('files.autoSave');
	}
113

114 115 116
	private get currentMultiCursorModifierSetting(): string {
		return this.configurationService.getValue<string>('editor.multiCursorModifier');
	}
B
Benjamin Pasero 已提交
117

118 119 120
	private get currentSidebarLocation(): string {
		return this.configurationService.getValue<string>('workbench.sideBar.location') || 'left';
	}
S
Sanders Lauture 已提交
121

122 123 124 125
	private get currentStatusbarVisible(): boolean {
		let statusbarVisible = this.configurationService.getValue<boolean>('workbench.statusBar.visible');
		if (typeof statusbarVisible !== 'boolean') {
			statusbarVisible = true;
B
Benjamin Pasero 已提交
126
		}
127 128
		return statusbarVisible;
	}
B
Benjamin Pasero 已提交
129

130 131 132 133
	private get currentActivityBarVisible(): boolean {
		let activityBarVisible = this.configurationService.getValue<boolean>('workbench.activityBar.visible');
		if (typeof activityBarVisible !== 'boolean') {
			activityBarVisible = true;
134
		}
135 136
		return activityBarVisible;
	}
137

138 139 140 141
	private get currentEnableMenuBarMnemonics(): boolean {
		let enableMenuBarMnemonics = this.configurationService.getValue<boolean>('window.enableMenuBarMnemonics');
		if (typeof enableMenuBarMnemonics !== 'boolean') {
			enableMenuBarMnemonics = true;
142
		}
143 144
		return enableMenuBarMnemonics;
	}
145

146 147 148 149
	private get currentEnableNativeTabs(): boolean {
		let enableNativeTabs = this.configurationService.getValue<boolean>('window.nativeTabs');
		if (typeof enableNativeTabs !== 'boolean') {
			enableNativeTabs = false;
B
Benjamin Pasero 已提交
150
		}
151
		return enableNativeTabs;
B
Benjamin Pasero 已提交
152 153
	}

E
Erich Gamma 已提交
154
	private updateMenu(): void {
155 156 157 158
		this.menuUpdater.schedule(); // buffer multiple attempts to update the menu
	}

	private doUpdateMenu(): void {
E
Erich Gamma 已提交
159 160 161

		// Due to limitations in Electron, it is not possible to update menu items dynamically. The suggested
		// workaround from Electron is to set the application menu again.
M
Martin Aeschlimann 已提交
162
		// See also https://github.com/electron/electron/issues/846
E
Erich Gamma 已提交
163 164 165 166 167 168 169 170 171 172 173
		//
		// Run delayed to prevent updating menu while it is open
		if (!this.isQuitting) {
			setTimeout(() => {
				if (!this.isQuitting) {
					this.install();
				}
			}, 10 /* delay this because there is an issue with updating a menu when it is open */);
		}
	}

B
Benjamin Pasero 已提交
174 175 176 177 178 179 180
	private onWindowsCountChanged(e: IWindowsCountChangedEvent): void {
		if (!isMacintosh) {
			return;
		}

		// Update menu if window count goes from N > 0 or 0 > N to update menu item enablement
		if ((e.oldCount === 0 && e.newCount > 0) || (e.oldCount > 0 && e.newCount === 0)) {
E
Erich Gamma 已提交
181 182
			this.updateMenu();
		}
183 184 185 186 187 188 189 190 191

		// Update specific items that are dependent on window count
		else if (this.currentEnableNativeTabs) {
			this.nativeTabMenuItems.forEach(item => {
				if (item) {
					item.enabled = e.newCount > 1;
				}
			});
		}
E
Erich Gamma 已提交
192 193
	}

194
	private updateWorkspaceMenuItems(): void {
B
Benjamin Pasero 已提交
195
		const window = this.windowsMainService.getLastActiveWindow();
196 197 198 199 200
		const isInWorkspaceContext = window && !!window.openedWorkspace;
		const isInFolderContext = window && !!window.openedFolderPath;

		this.closeWorkspace.visible = isInWorkspaceContext;
		this.closeFolder.visible = !isInWorkspaceContext;
B
Benjamin Pasero 已提交
201
		this.closeFolder.enabled = isInFolderContext || isLinux /* https://github.com/Microsoft/vscode/issues/36431 */;
202 203
	}

E
Erich Gamma 已提交
204 205 206
	private install(): void {

		// Menus
B
Benjamin Pasero 已提交
207
		const menubar = new Menu();
E
Erich Gamma 已提交
208 209

		// Mac: Application
B
Benjamin Pasero 已提交
210
		let macApplicationMenuItem: Electron.MenuItem;
211
		if (isMacintosh) {
B
Benjamin Pasero 已提交
212
			const applicationMenu = new Menu();
B
Benjamin Pasero 已提交
213
			macApplicationMenuItem = new MenuItem({ label: product.nameShort, submenu: applicationMenu });
E
Erich Gamma 已提交
214 215 216 217
			this.setMacApplicationMenu(applicationMenu);
		}

		// File
B
Benjamin Pasero 已提交
218
		const fileMenu = new Menu();
219
		const fileMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File")), submenu: fileMenu });
E
Erich Gamma 已提交
220 221 222
		this.setFileMenu(fileMenu);

		// Edit
B
Benjamin Pasero 已提交
223
		const editMenu = new Menu();
224
		const editMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit")), submenu: editMenu });
E
Erich Gamma 已提交
225 226
		this.setEditMenu(editMenu);

C
Christof Marti 已提交
227 228
		// Selection
		const selectionMenu = new Menu();
229
		const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu });
C
Christof Marti 已提交
230 231
		this.setSelectionMenu(selectionMenu);

E
Erich Gamma 已提交
232
		// View
B
Benjamin Pasero 已提交
233
		const viewMenu = new Menu();
234
		const viewMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View")), submenu: viewMenu });
E
Erich Gamma 已提交
235 236 237
		this.setViewMenu(viewMenu);

		// Goto
B
Benjamin Pasero 已提交
238
		const gotoMenu = new Menu();
239
		const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu });
E
Erich Gamma 已提交
240 241
		this.setGotoMenu(gotoMenu);

D
Daniel Imms 已提交
242
		// Terminal
D
Daniel Imms 已提交
243 244 245
		// const terminalMenu = new Menu();
		// const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu });
		// this.setTerminalMenu(terminalMenu);
D
Daniel Imms 已提交
246

I
isidor 已提交
247 248
		// Debug
		const debugMenu = new Menu();
249
		const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug")), submenu: debugMenu });
I
isidor 已提交
250 251
		this.setDebugMenu(debugMenu);

E
Erich Gamma 已提交
252
		// Mac: Window
B
Benjamin Pasero 已提交
253
		let macWindowMenuItem: Electron.MenuItem;
254
		if (isMacintosh) {
B
Benjamin Pasero 已提交
255
			const windowMenu = new Menu();
256
			macWindowMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize('mWindow', "Window")), submenu: windowMenu, role: 'window' });
E
Erich Gamma 已提交
257 258 259 260
			this.setMacWindowMenu(windowMenu);
		}

		// Help
B
Benjamin Pasero 已提交
261
		const helpMenu = new Menu();
262
		const helpMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help")), submenu: helpMenu, role: 'help' });
E
Erich Gamma 已提交
263 264
		this.setHelpMenu(helpMenu);

T
t-amqi 已提交
265 266
		// Tasks
		const taskMenu = new Menu();
267
		const taskMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTask', comment: ['&& denotes a mnemonic'] }, "&&Tasks")), submenu: taskMenu });
T
t-amqi 已提交
268 269
		this.setTaskMenu(taskMenu);

E
Erich Gamma 已提交
270 271 272 273 274 275 276
		// Menu Structure
		if (macApplicationMenuItem) {
			menubar.append(macApplicationMenuItem);
		}

		menubar.append(fileMenuItem);
		menubar.append(editMenuItem);
C
Christof Marti 已提交
277
		menubar.append(selectionMenuItem);
E
Erich Gamma 已提交
278 279
		menubar.append(viewMenuItem);
		menubar.append(gotoMenuItem);
D
Daniel Imms 已提交
280
		// menubar.append(terminalMenuItem);
I
isidor 已提交
281
		menubar.append(debugMenuItem);
T
t-amqi 已提交
282
		menubar.append(taskMenuItem);
E
Erich Gamma 已提交
283 284 285 286 287 288 289 290 291 292

		if (macWindowMenuItem) {
			menubar.append(macWindowMenuItem);
		}

		menubar.append(helpMenuItem);

		Menu.setApplicationMenu(menubar);

		// Dock Menu
293
		if (isMacintosh && !this.appMenuInstalled) {
E
Erich Gamma 已提交
294 295
			this.appMenuInstalled = true;

B
Benjamin Pasero 已提交
296
			const dockMenu = new Menu();
B
Benjamin Pasero 已提交
297
			dockMenu.append(new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")), click: () => this.windowsMainService.openNewWindow(OpenContext.DOCK) }));
E
Erich Gamma 已提交
298

299
			app.dock.setMenu(dockMenu);
E
Erich Gamma 已提交
300 301 302
		}
	}

B
Benjamin Pasero 已提交
303
	private setMacApplicationMenu(macApplicationMenu: Electron.Menu): void {
B
Benjamin Pasero 已提交
304
		const about = new MenuItem({ label: nls.localize('mAbout', "About {0}", product.nameLong), role: 'about' });
B
Benjamin Pasero 已提交
305 306
		const checkForUpdates = this.getUpdateMenuItems();
		const preferences = this.getPreferencesMenu();
307 308
		const servicesMenu = new Menu();
		const services = new MenuItem({ label: nls.localize('mServices', "Services"), role: 'services', submenu: servicesMenu });
B
Benjamin Pasero 已提交
309
		const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", product.nameLong), role: 'hide', accelerator: 'Command+H' });
B
Benjamin Pasero 已提交
310 311
		const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideothers', accelerator: 'Command+Alt+H' });
		const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' });
312 313
		const quit = new MenuItem(this.likeAction('workbench.action.quit', {
			label: nls.localize('miQuit', "Quit {0}", product.nameLong), click: () => {
314
				if (this.windowsMainService.getWindowCount() === 0 || !!BrowserWindow.getFocusedWindow()) {
315 316 317 318
					this.windowsMainService.quit(); // fix for https://github.com/Microsoft/vscode/issues/39191
				}
			}
		}));
B
Benjamin Pasero 已提交
319 320

		const actions = [about];
E
Erich Gamma 已提交
321 322 323 324 325
		actions.push(...checkForUpdates);
		actions.push(...[
			__separator__(),
			preferences,
			__separator__(),
326 327
			services,
			__separator__(),
E
Erich Gamma 已提交
328 329 330 331 332 333 334 335 336 337
			hide,
			hideOthers,
			showAll,
			__separator__(),
			quit
		]);

		actions.forEach(i => macApplicationMenu.append(i));
	}

B
Benjamin Pasero 已提交
338
	private setFileMenu(fileMenu: Electron.Menu): void {
B
Benjamin Pasero 已提交
339
		const hasNoWindows = (this.windowsMainService.getWindowCount() === 0);
E
Erich Gamma 已提交
340

B
Benjamin Pasero 已提交
341
		let newFile: Electron.MenuItem;
E
Erich Gamma 已提交
342
		if (hasNoWindows) {
B
Benjamin Pasero 已提交
343
			newFile = new MenuItem(this.likeAction('workbench.action.files.newUntitledFile', { label: this.mnemonicLabel(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File")), click: () => this.windowsMainService.openNewWindow(OpenContext.MENU) }));
E
Erich Gamma 已提交
344
		} else {
B
Benjamin Pasero 已提交
345
			newFile = this.createMenuItem(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File"), 'workbench.action.files.newUntitledFile');
E
Erich Gamma 已提交
346 347
		}

348 349
		let open: Electron.MenuItem;
		if (hasNoWindows) {
B
Benjamin Pasero 已提交
350
			open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: (menuItem, win, event) => this.windowsMainService.pickFileFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) }));
351 352 353 354 355 356
		} else {
			open = this.createMenuItem(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open..."), ['workbench.action.files.openFileFolder', 'workbench.action.files.openFileFolderInNewWindow']);
		}

		let openWorkspace: Electron.MenuItem;
		if (hasNoWindows) {
B
Benjamin Pasero 已提交
357
			openWorkspace = new MenuItem(this.likeAction('workbench.action.openWorkspace', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace...")), click: (menuItem, win, event) => this.windowsMainService.pickWorkspaceAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) }));
358
		} else {
I
isidor 已提交
359
			openWorkspace = this.createMenuItem(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace..."), ['workbench.action.openWorkspace', 'workbench.action.openWorkspaceInNewWindow']);
360 361 362 363
		}

		let openFolder: Electron.MenuItem;
		if (hasNoWindows) {
B
Benjamin Pasero 已提交
364
			openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: (menuItem, win, event) => this.windowsMainService.pickFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) }));
365 366 367
		} else {
			openFolder = this.createMenuItem(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder..."), ['workbench.action.files.openFolder', 'workbench.action.files.openFolderInNewWindow']);
		}
E
Erich Gamma 已提交
368

369 370
		let openFile: Electron.MenuItem;
		if (hasNoWindows) {
B
Benjamin Pasero 已提交
371
			openFile = new MenuItem(this.likeAction('workbench.action.files.openFile', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...")), click: (menuItem, win, event) => this.windowsMainService.pickFileAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) }));
372
		} else {
373
			openFile = this.createMenuItem(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File..."), ['workbench.action.files.openFile', 'workbench.action.files.openFileInNewWindow']);
374 375
		}

B
Benjamin Pasero 已提交
376
		const openRecentMenu = new Menu();
E
Erich Gamma 已提交
377
		this.setOpenRecentMenu(openRecentMenu);
378
		const openRecent = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent")), submenu: openRecentMenu, enabled: openRecentMenu.items.length > 0 });
E
Erich Gamma 已提交
379

380
		const saveWorkspaceAs = this.createMenuItem(nls.localize('miSaveWorkspaceAs', "Save Workspace As..."), 'workbench.action.saveWorkspaceAs');
I
isidor 已提交
381
		const addFolder = this.createMenuItem(nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace..."), 'workbench.action.addRootFolder');
B
Benjamin Pasero 已提交
382

B
Benjamin Pasero 已提交
383 384 385
		const saveFile = this.createMenuItem(nls.localize({ key: 'miSave', comment: ['&& denotes a mnemonic'] }, "&&Save"), 'workbench.action.files.save');
		const saveFileAs = this.createMenuItem(nls.localize({ key: 'miSaveAs', comment: ['&& denotes a mnemonic'] }, "Save &&As..."), 'workbench.action.files.saveAs');
		const saveAllFiles = this.createMenuItem(nls.localize({ key: 'miSaveAll', comment: ['&& denotes a mnemonic'] }, "Save A&&ll"), 'workbench.action.files.saveAll');
E
Erich Gamma 已提交
386

B
Benjamin Pasero 已提交
387
		const autoSaveEnabled = [AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => this.currentAutoSaveSetting === s);
B
Benjamin Pasero 已提交
388
		const autoSave = new MenuItem(this.likeAction('vscode.toggleAutoSave', { label: this.mnemonicLabel(nls.localize('miAutoSave', "Auto Save")), type: 'checkbox', checked: autoSaveEnabled, enabled: this.windowsMainService.getWindowCount() > 0, click: () => this.windowsMainService.sendToFocused('vscode.toggleAutoSave') }, false));
B
Benjamin Pasero 已提交
389

B
Benjamin Pasero 已提交
390
		const preferences = this.getPreferencesMenu();
E
Erich Gamma 已提交
391

B
Benjamin Pasero 已提交
392
		const newWindow = new MenuItem(this.likeAction('workbench.action.newWindow', { label: this.mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")), click: () => this.windowsMainService.openNewWindow(OpenContext.MENU) }));
B
Benjamin Pasero 已提交
393
		const revertFile = this.createMenuItem(nls.localize({ key: 'miRevert', comment: ['&& denotes a mnemonic'] }, "Re&&vert File"), 'workbench.action.files.revert');
B
Benjamin Pasero 已提交
394
		const closeWindow = new MenuItem(this.likeAction('workbench.action.closeWindow', { label: this.mnemonicLabel(nls.localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window")), click: () => this.windowsMainService.getLastActiveWindow().win.close(), enabled: this.windowsMainService.getWindowCount() > 0 }));
E
Erich Gamma 已提交
395

396 397 398
		this.closeWorkspace = this.createMenuItem(nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace"), 'workbench.action.closeFolder');
		this.closeFolder = this.createMenuItem(nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), 'workbench.action.closeFolder');

399
		const closeEditor = this.createMenuItem(nls.localize({ key: 'miCloseEditor', comment: ['&& denotes a mnemonic'] }, "&&Close Editor"), 'workbench.action.closeActiveEditor');
E
Erich Gamma 已提交
400

B
Benjamin Pasero 已提交
401
		const exit = new MenuItem(this.likeAction('workbench.action.quit', { label: this.mnemonicLabel(nls.localize({ key: 'miExit', comment: ['&& denotes a mnemonic'] }, "E&&xit")), click: () => this.windowsMainService.quit() }));
E
Erich Gamma 已提交
402

403 404
		this.updateWorkspaceMenuItems();

E
Erich Gamma 已提交
405 406 407 408
		arrays.coalesce([
			newFile,
			newWindow,
			__separator__(),
409 410 411
			isMacintosh ? open : null,
			!isMacintosh ? openFile : null,
			!isMacintosh ? openFolder : null,
412
			openWorkspace,
E
Erich Gamma 已提交
413
			openRecent,
414 415 416
			__separator__(),
			addFolder,
			saveWorkspaceAs,
E
Erich Gamma 已提交
417 418 419 420 421
			__separator__(),
			saveFile,
			saveFileAs,
			saveAllFiles,
			__separator__(),
B
Benjamin Pasero 已提交
422 423
			autoSave,
			__separator__(),
424 425
			!isMacintosh ? preferences : null,
			!isMacintosh ? __separator__() : null,
E
Erich Gamma 已提交
426 427
			revertFile,
			closeEditor,
428 429
			this.closeWorkspace,
			this.closeFolder,
B
Benjamin Pasero 已提交
430
			closeWindow,
431 432
			!isMacintosh ? __separator__() : null,
			!isMacintosh ? exit : null
B
Benjamin Pasero 已提交
433
		]).forEach(item => fileMenu.append(item));
E
Erich Gamma 已提交
434 435
	}

B
Benjamin Pasero 已提交
436
	private getPreferencesMenu(): Electron.MenuItem {
S
Sandeep Somavarapu 已提交
437
		const settings = this.createMenuItem(nls.localize({ key: 'miOpenSettings', comment: ['&& denotes a mnemonic'] }, "&&Settings"), 'workbench.action.openSettings');
B
Benjamin Pasero 已提交
438
		const kebindingSettings = this.createMenuItem(nls.localize({ key: 'miOpenKeymap', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts"), 'workbench.action.openGlobalKeybindings');
439
		const keymapExtensions = this.createMenuItem(nls.localize({ key: 'miOpenKeymapExtensions', comment: ['&& denotes a mnemonic'] }, "&&Keymap Extensions"), 'workbench.extensions.action.showRecommendedKeymapExtensions');
B
Benjamin Pasero 已提交
440 441 442 443 444
		const snippetsSettings = this.createMenuItem(nls.localize({ key: 'miOpenSnippets', comment: ['&& denotes a mnemonic'] }, "User &&Snippets"), 'workbench.action.openSnippets');
		const colorThemeSelection = this.createMenuItem(nls.localize({ key: 'miSelectColorTheme', comment: ['&& denotes a mnemonic'] }, "&&Color Theme"), 'workbench.action.selectTheme');
		const iconThemeSelection = this.createMenuItem(nls.localize({ key: 'miSelectIconTheme', comment: ['&& denotes a mnemonic'] }, "File &&Icon Theme"), 'workbench.action.selectIconTheme');

		const preferencesMenu = new Menu();
445
		preferencesMenu.append(settings);
E
Erich Gamma 已提交
446 447
		preferencesMenu.append(__separator__());
		preferencesMenu.append(kebindingSettings);
448
		preferencesMenu.append(keymapExtensions);
E
Erich Gamma 已提交
449 450 451
		preferencesMenu.append(__separator__());
		preferencesMenu.append(snippetsSettings);
		preferencesMenu.append(__separator__());
452 453
		preferencesMenu.append(colorThemeSelection);
		preferencesMenu.append(iconThemeSelection);
E
Erich Gamma 已提交
454

455
		return new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miPreferences', comment: ['&& denotes a mnemonic'] }, "&&Preferences")), submenu: preferencesMenu });
E
Erich Gamma 已提交
456 457
	}

B
Benjamin Pasero 已提交
458
	private setOpenRecentMenu(openRecentMenu: Electron.Menu): void {
459
		openRecentMenu.append(this.createMenuItem(nls.localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"), 'workbench.action.reopenClosedEditor'));
D
Daniel Imms 已提交
460

B
Benjamin Pasero 已提交
461
		const { workspaces, files } = this.historyMainService.getRecentlyOpened();
462 463 464 465 466 467

		// Workspaces
		if (workspaces.length > 0) {
			openRecentMenu.append(__separator__());

			for (let i = 0; i < CodeMenu.MAX_MENU_RECENT_ENTRIES && i < workspaces.length; i++) {
468
				openRecentMenu.append(this.createOpenRecentMenuItem(workspaces[i], 'openRecentWorkspace', false));
469 470
			}
		}
E
Erich Gamma 已提交
471 472

		// Files
473
		if (files.length > 0) {
474
			openRecentMenu.append(__separator__());
E
Erich Gamma 已提交
475

B
Benjamin Pasero 已提交
476
			for (let i = 0; i < CodeMenu.MAX_MENU_RECENT_ENTRIES && i < files.length; i++) {
477
				openRecentMenu.append(this.createOpenRecentMenuItem(files[i], 'openRecentFile', true));
478
			}
E
Erich Gamma 已提交
479 480
		}

481
		if (workspaces.length || files.length) {
482 483
			openRecentMenu.append(__separator__());
			openRecentMenu.append(this.createMenuItem(nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More..."), 'workbench.action.openRecent'));
E
Erich Gamma 已提交
484
			openRecentMenu.append(__separator__());
B
Benjamin Pasero 已提交
485
			openRecentMenu.append(new MenuItem(this.likeAction('workbench.action.clearRecentFiles', { label: this.mnemonicLabel(nls.localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened")), click: () => this.historyMainService.clearRecentlyOpened() })));
E
Erich Gamma 已提交
486 487 488
		}
	}

489
	private createOpenRecentMenuItem(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | string, commandId: string, isFile: boolean): Electron.MenuItem {
B
Benjamin Pasero 已提交
490 491
		let label: string;
		let path: string;
492
		if (isSingleFolderWorkspaceIdentifier(workspace) || typeof workspace === 'string') {
I
isidor 已提交
493
			label = unmnemonicLabel(getPathLabel(workspace, this.environmentService));
B
Benjamin Pasero 已提交
494 495
			path = workspace;
		} else {
B
Benjamin Pasero 已提交
496
			label = getWorkspaceLabel(workspace, this.environmentService, { verbose: true });
B
Benjamin Pasero 已提交
497 498
			path = workspace.configPath;
		}
499

500
		return new MenuItem(this.likeAction(commandId, {
501 502
			label,
			click: (menuItem, win, event) => {
503
				const openInNewWindow = this.isOptionClick(event);
B
Benjamin Pasero 已提交
504
				const success = this.windowsMainService.open({
505 506 507 508 509 510
					context: OpenContext.MENU,
					cli: this.environmentService.args,
					pathsToOpen: [path], forceNewWindow: openInNewWindow,
					forceOpenWorkspaceAsFile: isFile
				}).length > 0;

B
Benjamin Pasero 已提交
511
				if (!success) {
B
Benjamin Pasero 已提交
512
					this.historyMainService.removeFromRecentlyOpened([isSingleFolderWorkspaceIdentifier(workspace) ? workspace : workspace.configPath]);
B
Benjamin Pasero 已提交
513
				}
E
Erich Gamma 已提交
514
			}
515
		}, false));
E
Erich Gamma 已提交
516 517
	}

518
	private isOptionClick(event: Electron.Event): boolean {
519
		return event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey)));
520 521
	}

522
	private createRoleMenuItem(label: string, commandId: string, role: Electron.MenuItemRole): Electron.MenuItem {
523
		const options: Electron.MenuItemConstructorOptions = {
524
			label: this.mnemonicLabel(label),
B
Benjamin Pasero 已提交
525
			role,
526 527 528
			enabled: true
		};

529
		return new MenuItem(this.withKeybinding(commandId, options));
530 531
	}

B
Benjamin Pasero 已提交
532 533 534 535 536 537
	private setEditMenu(winLinuxEditMenu: Electron.Menu): void {
		let undo: Electron.MenuItem;
		let redo: Electron.MenuItem;
		let cut: Electron.MenuItem;
		let copy: Electron.MenuItem;
		let paste: Electron.MenuItem;
E
Erich Gamma 已提交
538

539
		if (isMacintosh) {
540 541 542 543 544 545 546 547
			undo = this.createContextAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', {
				inDevTools: devTools => devTools.undo(),
				inNoWindow: () => Menu.sendActionToFirstResponder('undo:')
			});
			redo = this.createContextAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', {
				inDevTools: devTools => devTools.redo(),
				inNoWindow: () => Menu.sendActionToFirstResponder('redo:')
			});
B
Benjamin Pasero 已提交
548 549
			cut = this.createRoleMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"), 'editor.action.clipboardCutAction', 'cut');
			copy = this.createRoleMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"), 'editor.action.clipboardCopyAction', 'copy');
550
			paste = this.createRoleMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction', 'paste');
E
Erich Gamma 已提交
551
		} else {
B
Benjamin Pasero 已提交
552 553
			undo = this.createMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo');
			redo = this.createMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo');
B
Benjamin Pasero 已提交
554 555
			cut = this.createMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"), 'editor.action.clipboardCutAction');
			copy = this.createMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"), 'editor.action.clipboardCopyAction');
B
Benjamin Pasero 已提交
556
			paste = this.createMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction');
E
Erich Gamma 已提交
557 558
		}

B
Benjamin Pasero 已提交
559 560
		const find = this.createMenuItem(nls.localize({ key: 'miFind', comment: ['&& denotes a mnemonic'] }, "&&Find"), 'actions.find');
		const replace = this.createMenuItem(nls.localize({ key: 'miReplace', comment: ['&& denotes a mnemonic'] }, "&&Replace"), 'editor.action.startFindReplaceAction');
S
Sandeep Somavarapu 已提交
561
		const findInFiles = this.createMenuItem(nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files"), 'workbench.action.findInFiles');
B
Benjamin Pasero 已提交
562
		const replaceInFiles = this.createMenuItem(nls.localize({ key: 'miReplaceInFiles', comment: ['&& denotes a mnemonic'] }, "Replace &&in Files"), 'workbench.action.replaceInFiles');
E
Erich Gamma 已提交
563

564 565
		const emmetExpandAbbreviation = this.createMenuItem(nls.localize({ key: 'miEmmetExpandAbbreviation', comment: ['&& denotes a mnemonic'] }, "Emmet: E&&xpand Abbreviation"), 'editor.emmet.action.expandAbbreviation');
		const showEmmetCommands = this.createMenuItem(nls.localize({ key: 'miShowEmmetCommands', comment: ['&& denotes a mnemonic'] }, "E&&mmet..."), 'workbench.action.showEmmetCommands');
566 567
		const toggleLineComment = this.createMenuItem(nls.localize({ key: 'miToggleLineComment', comment: ['&& denotes a mnemonic'] }, "&&Toggle Line Comment"), 'editor.action.commentLine');
		const toggleBlockComment = this.createMenuItem(nls.localize({ key: 'miToggleBlockComment', comment: ['&& denotes a mnemonic'] }, "Toggle &&Block Comment"), 'editor.action.blockComment');
568

E
Erich Gamma 已提交
569 570 571 572 573 574 575 576 577 578 579
		[
			undo,
			redo,
			__separator__(),
			cut,
			copy,
			paste,
			__separator__(),
			find,
			replace,
			__separator__(),
S
Sandeep Somavarapu 已提交
580
			findInFiles,
581 582
			replaceInFiles,
			__separator__(),
583 584
			toggleLineComment,
			toggleBlockComment,
585 586
			emmetExpandAbbreviation,
			showEmmetCommands
B
Benjamin Pasero 已提交
587
		].forEach(item => winLinuxEditMenu.append(item));
E
Erich Gamma 已提交
588 589
	}

C
Christof Marti 已提交
590
	private setSelectionMenu(winLinuxEditMenu: Electron.Menu): void {
591 592
		let multiCursorModifierLabel: string;
		if (this.currentMultiCursorModifierSetting === 'ctrlCmd') {
593
			multiCursorModifierLabel = nls.localize('miMultiCursorAlt', "Switch to Alt+Click for Multi-Cursor"); // The default has been overwritten
594 595 596
		} else {
			multiCursorModifierLabel = (
				isMacintosh
597 598
					? nls.localize('miMultiCursorCmd', "Switch to Cmd+Click for Multi-Cursor")
					: nls.localize('miMultiCursorCtrl', "Switch to Ctrl+Click for Multi-Cursor")
599 600 601 602
			);
		}

		const multicursorModifier = this.createMenuItem(multiCursorModifierLabel, 'workbench.action.toggleMultiCursorModifier');
C
Christof Marti 已提交
603 604
		const insertCursorAbove = this.createMenuItem(nls.localize({ key: 'miInsertCursorAbove', comment: ['&& denotes a mnemonic'] }, "&&Add Cursor Above"), 'editor.action.insertCursorAbove');
		const insertCursorBelow = this.createMenuItem(nls.localize({ key: 'miInsertCursorBelow', comment: ['&& denotes a mnemonic'] }, "A&&dd Cursor Below"), 'editor.action.insertCursorBelow');
605
		const insertCursorAtEndOfEachLineSelected = this.createMenuItem(nls.localize({ key: 'miInsertCursorAtEndOfEachLineSelected', comment: ['&& denotes a mnemonic'] }, "Add C&&ursors to Line Ends"), 'editor.action.insertCursorAtEndOfEachLineSelected');
C
Christof Marti 已提交
606 607 608
		const addSelectionToNextFindMatch = this.createMenuItem(nls.localize({ key: 'miAddSelectionToNextFindMatch', comment: ['&& denotes a mnemonic'] }, "Add &&Next Occurrence"), 'editor.action.addSelectionToNextFindMatch');
		const addSelectionToPreviousFindMatch = this.createMenuItem(nls.localize({ key: 'miAddSelectionToPreviousFindMatch', comment: ['&& denotes a mnemonic'] }, "Add P&&revious Occurrence"), 'editor.action.addSelectionToPreviousFindMatch');
		const selectHighlights = this.createMenuItem(nls.localize({ key: 'miSelectHighlights', comment: ['&& denotes a mnemonic'] }, "Select All &&Occurrences"), 'editor.action.selectHighlights');
C
Christof Marti 已提交
609 610 611 612 613 614

		const copyLinesUp = this.createMenuItem(nls.localize({ key: 'miCopyLinesUp', comment: ['&& denotes a mnemonic'] }, "&&Copy Line Up"), 'editor.action.copyLinesUpAction');
		const copyLinesDown = this.createMenuItem(nls.localize({ key: 'miCopyLinesDown', comment: ['&& denotes a mnemonic'] }, "Co&&py Line Down"), 'editor.action.copyLinesDownAction');
		const moveLinesUp = this.createMenuItem(nls.localize({ key: 'miMoveLinesUp', comment: ['&& denotes a mnemonic'] }, "Mo&&ve Line Up"), 'editor.action.moveLinesUpAction');
		const moveLinesDown = this.createMenuItem(nls.localize({ key: 'miMoveLinesDown', comment: ['&& denotes a mnemonic'] }, "Move &&Line Down"), 'editor.action.moveLinesDownAction');

615
		let selectAll: Electron.MenuItem;
616
		if (isMacintosh) {
617 618 619 620
			selectAll = this.createContextAwareMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll', {
				inDevTools: devTools => devTools.selectAll(),
				inNoWindow: () => Menu.sendActionToFirstResponder('selectAll:')
			});
621 622 623
		} else {
			selectAll = this.createMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll');
		}
C
Christof Marti 已提交
624 625 626 627
		const smartSelectGrow = this.createMenuItem(nls.localize({ key: 'miSmartSelectGrow', comment: ['&& denotes a mnemonic'] }, "&&Expand Selection"), 'editor.action.smartSelect.grow');
		const smartSelectshrink = this.createMenuItem(nls.localize({ key: 'miSmartSelectShrink', comment: ['&& denotes a mnemonic'] }, "&&Shrink Selection"), 'editor.action.smartSelect.shrink');

		[
628 629 630
			selectAll,
			smartSelectGrow,
			smartSelectshrink,
C
Christof Marti 已提交
631 632 633 634 635 636
			__separator__(),
			copyLinesUp,
			copyLinesDown,
			moveLinesUp,
			moveLinesDown,
			__separator__(),
637
			multicursorModifier,
638 639 640 641 642 643
			insertCursorAbove,
			insertCursorBelow,
			insertCursorAtEndOfEachLineSelected,
			addSelectionToNextFindMatch,
			addSelectionToPreviousFindMatch,
			selectHighlights,
C
Christof Marti 已提交
644 645 646
		].forEach(item => winLinuxEditMenu.append(item));
	}

B
Benjamin Pasero 已提交
647
	private setViewMenu(viewMenu: Electron.Menu): void {
B
Benjamin Pasero 已提交
648 649 650 651
		const commands = this.createMenuItem(nls.localize({ key: 'miCommandPalette', comment: ['&& denotes a mnemonic'] }, "&&Command Palette..."), 'workbench.action.showCommands');
		const openView = this.createMenuItem(nls.localize({ key: 'miOpenView', comment: ['&& denotes a mnemonic'] }, "&&Open View..."), 'workbench.action.openView');

		// Views
B
Benjamin Pasero 已提交
652 653
		const explorer = this.createMenuItem(nls.localize({ key: 'miViewExplorer', comment: ['&& denotes a mnemonic'] }, "&&Explorer"), 'workbench.view.explorer');
		const search = this.createMenuItem(nls.localize({ key: 'miViewSearch', comment: ['&& denotes a mnemonic'] }, "&&Search"), 'workbench.view.search');
J
Joao Moreno 已提交
654
		const scm = this.createMenuItem(nls.localize({ key: 'miViewSCM', comment: ['&& denotes a mnemonic'] }, "S&&CM"), 'workbench.view.scm');
B
Benjamin Pasero 已提交
655 656
		const debug = this.createMenuItem(nls.localize({ key: 'miViewDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug"), 'workbench.view.debug');
		const extensions = this.createMenuItem(nls.localize({ key: 'miViewExtensions', comment: ['&& denotes a mnemonic'] }, "E&&xtensions"), 'workbench.view.extensions');
B
Benjamin Pasero 已提交
657 658

		// Panels
B
Benjamin Pasero 已提交
659 660 661 662
		const output = this.createMenuItem(nls.localize({ key: 'miToggleOutput', comment: ['&& denotes a mnemonic'] }, "&&Output"), 'workbench.action.output.toggleOutput');
		const debugConsole = this.createMenuItem(nls.localize({ key: 'miToggleDebugConsole', comment: ['&& denotes a mnemonic'] }, "De&&bug Console"), 'workbench.debug.action.toggleRepl');
		const integratedTerminal = this.createMenuItem(nls.localize({ key: 'miToggleIntegratedTerminal', comment: ['&& denotes a mnemonic'] }, "&&Integrated Terminal"), 'workbench.action.terminal.toggleTerminal');
		const problems = this.createMenuItem(nls.localize({ key: 'miMarker', comment: ['&& denotes a mnemonic'] }, "&&Problems"), 'workbench.actions.view.problems');
B
Benjamin Pasero 已提交
663

B
Benjamin Pasero 已提交
664
		const fullscreen = new MenuItem(this.withKeybinding('workbench.action.toggleFullScreen', { label: this.mnemonicLabel(nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen")), click: () => this.windowsMainService.getLastActiveWindow().toggleFullScreen(), enabled: this.windowsMainService.getWindowCount() > 0 }));
B
Benjamin Pasero 已提交
665
		const toggleZenMode = this.createMenuItem(nls.localize('miToggleZenMode', "Toggle Zen Mode"), 'workbench.action.toggleZenMode');
666
		const toggleCenteredLayout = this.createMenuItem(nls.localize('miToggleCenteredLayout', "Toggle Centered Layout"), 'workbench.action.toggleCenteredLayout');
B
Benjamin Pasero 已提交
667
		const toggleMenuBar = this.createMenuItem(nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar"), 'workbench.action.toggleMenuBar');
B
Benjamin Pasero 已提交
668 669 670 671 672

		// Editor Layout

		const editorLayoutMenu = new Menu();

B
Benjamin Pasero 已提交
673 674 675 676
		const splitEditorUp = this.createMenuItem(nls.localize({ key: 'miSplitEditorUp', comment: ['&& denotes a mnemonic'] }, "Split &&Up"), 'workbench.action.splitEditorUp');
		const splitEditorDown = this.createMenuItem(nls.localize({ key: 'miSplitEditorDown', comment: ['&& denotes a mnemonic'] }, "Split &&Down"), 'workbench.action.splitEditorDown');
		const splitEditorLeft = this.createMenuItem(nls.localize({ key: 'miSplitEditorLeft', comment: ['&& denotes a mnemonic'] }, "Split &&Left"), 'workbench.action.splitEditorLeft');
		const splitEditorRight = this.createMenuItem(nls.localize({ key: 'miSplitEditorRight', comment: ['&& denotes a mnemonic'] }, "Split &&Right"), 'workbench.action.splitEditorRight');
B
Benjamin Pasero 已提交
677 678 679 680 681 682 683 684 685 686

		const singleColumnEditorLayout = this.createMenuItem(nls.localize({ key: 'miSingleColumnEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Single"), 'workbench.action.editorLayoutSingle');
		const twoColumnsEditorLayout = this.createMenuItem(nls.localize({ key: 'miTwoColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Two Columns"), 'workbench.action.editorLayoutTwoColumns');
		const threeColumnsEditorLayout = this.createMenuItem(nls.localize({ key: 'miThreeColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&hree Columns"), 'workbench.action.editorLayoutThreeColumns');
		const twoRowsEditorLayout = this.createMenuItem(nls.localize({ key: 'miTwoRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&wo Rows"), 'workbench.action.editorLayoutTwoRows');
		const threeRowsEditorLayout = this.createMenuItem(nls.localize({ key: 'miThreeRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "Three &&Rows"), 'workbench.action.editorLayoutThreeRows');
		const twoByTwoGridEditorLayout = this.createMenuItem(nls.localize({ key: 'miTwoByTwoGridEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Grid (2x2)"), 'workbench.action.editorLayoutTwoByTwoGrid');
		const twoColumnsRightEditorLayout = this.createMenuItem(nls.localize({ key: 'miTwoColumnsRightEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two C&&olumns Right"), 'workbench.action.editorLayoutTwoColumnsRight');
		const twoColumnsBottomEditorLayout = this.createMenuItem(nls.localize({ key: 'miTwoColumnsBottomEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two &&Columns Bottom"), 'workbench.action.editorLayoutTwoColumnsBottom');

B
Benjamin Pasero 已提交
687
		const toggleEditorLayout = this.createMenuItem(nls.localize({ key: 'miToggleEditorLayout', comment: ['&& denotes a mnemonic'] }, "Toggle Vertical/Horizontal &&Layout"), 'workbench.action.toggleEditorGroupLayout');
B
Benjamin Pasero 已提交
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709

		[
			splitEditorUp,
			splitEditorDown,
			splitEditorLeft,
			splitEditorRight,
			__separator__(),
			singleColumnEditorLayout,
			twoColumnsEditorLayout,
			threeColumnsEditorLayout,
			twoRowsEditorLayout,
			threeRowsEditorLayout,
			twoByTwoGridEditorLayout,
			twoColumnsRightEditorLayout,
			twoColumnsBottomEditorLayout,
			__separator__(),
			toggleEditorLayout
		].forEach(item => editorLayoutMenu.append(item));

		const editorLayout = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout")), submenu: editorLayoutMenu });

		// Workbench Layout
B
Benjamin Pasero 已提交
710
		const toggleSidebar = this.createMenuItem(nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar"), 'workbench.action.toggleSidebarVisibility');
B
Benjamin Pasero 已提交
711 712 713 714 715 716 717 718 719

		let moveSideBarLabel: string;
		if (this.currentSidebarLocation !== 'right') {
			moveSideBarLabel = nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right");
		} else {
			moveSideBarLabel = nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left");
		}

		const moveSidebar = this.createMenuItem(moveSideBarLabel, 'workbench.action.toggleSidebarPosition');
B
Benjamin Pasero 已提交
720
		const togglePanel = this.createMenuItem(nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel"), 'workbench.action.togglePanel');
B
Benjamin Pasero 已提交
721 722 723 724 725 726 727 728

		let statusBarLabel: string;
		if (this.currentStatusbarVisible) {
			statusBarLabel = nls.localize({ key: 'miHideStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Hide Status Bar");
		} else {
			statusBarLabel = nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Show Status Bar");
		}
		const toggleStatusbar = this.createMenuItem(statusBarLabel, 'workbench.action.toggleStatusbarVisibility');
E
Erich Gamma 已提交
729

S
Sanders Lauture 已提交
730 731
		let activityBarLabel: string;
		if (this.currentActivityBarVisible) {
B
Benjamin Pasero 已提交
732
			activityBarLabel = nls.localize({ key: 'miHideActivityBar', comment: ['&& denotes a mnemonic'] }, "Hide &&Activity Bar");
S
Sanders Lauture 已提交
733
		} else {
B
Benjamin Pasero 已提交
734
			activityBarLabel = nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar");
S
Sanders Lauture 已提交
735 736 737
		}
		const toggleActivtyBar = this.createMenuItem(activityBarLabel, 'workbench.action.toggleActivityBarVisibility');

B
Benjamin Pasero 已提交
738
		// Editor
B
Benjamin Pasero 已提交
739
		const toggleWordWrap = this.createMenuItem(nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Word Wrap"), 'editor.action.toggleWordWrap');
740
		const toggleMinimap = this.createMenuItem(nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap"), 'editor.action.toggleMinimap');
741
		const toggleRenderWhitespace = this.createMenuItem(nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"), 'editor.action.toggleRenderWhitespace');
A
Alex Dima 已提交
742
		const toggleRenderControlCharacters = this.createMenuItem(nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"), 'editor.action.toggleRenderControlCharacter');
743

B
Benjamin Pasero 已提交
744
		// Zoom
B
Benjamin Pasero 已提交
745 746 747
		const zoomIn = this.createMenuItem(nls.localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In"), 'workbench.action.zoomIn');
		const zoomOut = this.createMenuItem(nls.localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "Zoom O&&ut"), 'workbench.action.zoomOut');
		const resetZoom = this.createMenuItem(nls.localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom"), 'workbench.action.zoomReset');
C
Chris Dias 已提交
748

B
Benjamin Pasero 已提交
749
		arrays.coalesce([
750
			commands,
751
			openView,
752
			__separator__(),
753 754
			explorer,
			search,
J
Joao Moreno 已提交
755
			scm,
756
			debug,
J
Joao Moreno 已提交
757
			extensions,
758 759 760 761 762
			__separator__(),
			output,
			problems,
			debugConsole,
			integratedTerminal,
C
Chris Dias 已提交
763
			__separator__(),
E
Erich Gamma 已提交
764
			fullscreen,
I
isidor 已提交
765
			toggleZenMode,
S
SrTobi 已提交
766
			toggleCenteredLayout,
767
			isWindows || isLinux ? toggleMenuBar : void 0,
E
Erich Gamma 已提交
768
			__separator__(),
B
Benjamin Pasero 已提交
769 770
			editorLayout,
			__separator__(),
E
Erich Gamma 已提交
771
			moveSidebar,
B
Benjamin Pasero 已提交
772 773 774
			toggleSidebar,
			togglePanel,
			toggleStatusbar,
S
Sanders Lauture 已提交
775
			toggleActivtyBar,
E
Erich Gamma 已提交
776
			__separator__(),
J
Joao Moreno 已提交
777
			toggleWordWrap,
778
			toggleMinimap,
779
			toggleRenderWhitespace,
780
			toggleRenderControlCharacters,
J
Joao Moreno 已提交
781
			__separator__(),
E
Erich Gamma 已提交
782
			zoomIn,
783 784
			zoomOut,
			resetZoom
B
Benjamin Pasero 已提交
785
		]).forEach(item => viewMenu.append(item));
E
Erich Gamma 已提交
786 787
	}

B
Benjamin Pasero 已提交
788
	private setGotoMenu(gotoMenu: Electron.Menu): void {
B
Benjamin Pasero 已提交
789 790
		const back = this.createMenuItem(nls.localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"), 'workbench.action.navigateBack');
		const forward = this.createMenuItem(nls.localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"), 'workbench.action.navigateForward');
B
Benjamin Pasero 已提交
791

B
Benjamin Pasero 已提交
792
		const switchEditorMenu = new Menu();
B
Benjamin Pasero 已提交
793

B
Benjamin Pasero 已提交
794 795 796 797
		const nextEditor = this.createMenuItem(nls.localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor"), 'workbench.action.nextEditor');
		const previousEditor = this.createMenuItem(nls.localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor"), 'workbench.action.previousEditor');
		const nextEditorInGroup = this.createMenuItem(nls.localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group"), 'workbench.action.openNextRecentlyUsedEditorInGroup');
		const previousEditorInGroup = this.createMenuItem(nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group"), 'workbench.action.openPreviousRecentlyUsedEditorInGroup');
B
Benjamin Pasero 已提交
798 799 800 801 802

		[
			nextEditor,
			previousEditor,
			__separator__(),
803
			nextEditorInGroup,
B
Benjamin Pasero 已提交
804 805 806
			previousEditorInGroup
		].forEach(item => switchEditorMenu.append(item));

807
		const switchEditor = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor")), submenu: switchEditorMenu, enabled: true });
B
Benjamin Pasero 已提交
808

B
Benjamin Pasero 已提交
809
		const switchGroupMenu = new Menu();
B
Benjamin Pasero 已提交
810

811 812 813 814 815
		const focusFirstGroup = this.createMenuItem(nls.localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1"), 'workbench.action.focusFirstEditorGroup');
		const focusSecondGroup = this.createMenuItem(nls.localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2"), 'workbench.action.focusSecondEditorGroup');
		const focusThirdGroup = this.createMenuItem(nls.localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3"), 'workbench.action.focusThirdEditorGroup');
		const focusFourthGroup = this.createMenuItem(nls.localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4"), 'workbench.action.focusFourthEditorGroup');
		const focusFifthGroup = this.createMenuItem(nls.localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5"), 'workbench.action.focusFifthEditorGroup');
B
Benjamin Pasero 已提交
816 817
		const nextGroup = this.createMenuItem(nls.localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group"), 'workbench.action.focusNextGroup');
		const previousGroup = this.createMenuItem(nls.localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group"), 'workbench.action.focusPreviousGroup');
B
Benjamin Pasero 已提交
818

B
Benjamin Pasero 已提交
819 820 821 822
		const focusLeftGroup = this.createMenuItem(nls.localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left"), 'workbench.action.focusLeftGroup');
		const focusRightGroup = this.createMenuItem(nls.localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right"), 'workbench.action.focusRightGroup');
		const focusAboveGroup = this.createMenuItem(nls.localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above"), 'workbench.action.focusAboveGroup');
		const focusBelowGroup = this.createMenuItem(nls.localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below"), 'workbench.action.focusBelowGroup');
823

B
Benjamin Pasero 已提交
824 825 826 827
		[
			focusFirstGroup,
			focusSecondGroup,
			focusThirdGroup,
828 829
			focusFourthGroup,
			focusFifthGroup,
B
Benjamin Pasero 已提交
830 831
			__separator__(),
			nextGroup,
832 833 834 835 836 837
			previousGroup,
			__separator__(),
			focusAboveGroup,
			focusBelowGroup,
			focusLeftGroup,
			focusRightGroup
B
Benjamin Pasero 已提交
838 839
		].forEach(item => switchGroupMenu.append(item));

840
		const switchGroup = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group")), submenu: switchGroupMenu, enabled: true });
B
Benjamin Pasero 已提交
841

B
Benjamin Pasero 已提交
842
		const gotoFile = this.createMenuItem(nls.localize({ key: 'miGotoFile', comment: ['&& denotes a mnemonic'] }, "Go to &&File..."), 'workbench.action.quickOpen');
843 844
		const gotoSymbolInFile = this.createMenuItem(nls.localize({ key: 'miGotoSymbolInFile', comment: ['&& denotes a mnemonic'] }, "Go to &&Symbol in File..."), 'workbench.action.gotoSymbol');
		const gotoSymbolInWorkspace = this.createMenuItem(nls.localize({ key: 'miGotoSymbolInWorkspace', comment: ['&& denotes a mnemonic'] }, "Go to Symbol in &&Workspace..."), 'workbench.action.showAllSymbols');
B
Benjamin Pasero 已提交
845
		const gotoDefinition = this.createMenuItem(nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition"), 'editor.action.goToDeclaration');
846 847
		const gotoTypeDefinition = this.createMenuItem(nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition"), 'editor.action.goToTypeDefinition');
		const goToImplementation = this.createMenuItem(nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementation"), 'editor.action.goToImplementation');
B
Benjamin Pasero 已提交
848
		const gotoLine = this.createMenuItem(nls.localize({ key: 'miGotoLine', comment: ['&& denotes a mnemonic'] }, "Go to &&Line..."), 'workbench.action.gotoLine');
E
Erich Gamma 已提交
849 850 851 852 853

		[
			back,
			forward,
			__separator__(),
B
Benjamin Pasero 已提交
854 855
			switchEditor,
			switchGroup,
E
Erich Gamma 已提交
856 857
			__separator__(),
			gotoFile,
858 859
			gotoSymbolInFile,
			gotoSymbolInWorkspace,
E
Erich Gamma 已提交
860
			gotoDefinition,
861 862
			gotoTypeDefinition,
			goToImplementation,
E
Erich Gamma 已提交
863
			gotoLine
B
Benjamin Pasero 已提交
864
		].forEach(item => gotoMenu.append(item));
E
Erich Gamma 已提交
865 866
	}

D
Daniel Imms 已提交
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
	// private setTerminalMenu(terminalMenu: Electron.Menu): void {
	// 	const newTerminal = this.createMenuItem(nls.localize({ key: 'miNewTerminal', comment: ['&& denotes a mnemonic'] }, "&&New Terminal"), 'workbench.action.terminal.new');
	// 	const splitTerminal = this.createMenuItem(nls.localize({ key: 'miSplitTerminal', comment: ['&& denotes a mnemonic'] }, "&&Split Terminal"), 'workbench.action.terminal.split');
	// 	const killTerminal = this.createMenuItem(nls.localize({ key: 'miKillTerminal', comment: ['&& denotes a mnemonic'] }, "&&Kill Terminal"), 'workbench.action.terminal.kill');

	// 	const clear = this.createMenuItem(nls.localize({ key: 'miClear', comment: ['&& denotes a mnemonic'] }, "&&Clear"), 'workbench.action.terminal.clear');
	// 	// const deleteWordLeft = this.createMenuItem(nls.localize({ key: 'miDeleteWordLeft', comment: ['&& denotes a mnemonic'] }, "Delete Word To &&Left"), 'workbench.action.terminal.deleteWordLeft');
	// 	// const deleteWordRight = this.createMenuItem(nls.localize({ key: 'miDeleteWordRight', comment: ['&& denotes a mnemonic'] }, "Delete Word To &&Right"), 'workbench.action.terminal.deleteWordRight');
	// 	// const moveToLineStart = this.createMenuItem(nls.localize({ key: 'miMoveToLineStart', comment: ['&& denotes a mnemonic'] }, "Move to Line Start"), 'workbench.action.terminal.moveToLineStart');
	// 	// const moveToLineEnd = this.createMenuItem(nls.localize({ key: 'miMoveToLineEnd', comment: ['&& denotes a mnemonic'] }, "Move to Line &&End"), 'workbench.action.terminal.moveToLineEnd');

	// 	const runActiveFile = this.createMenuItem(nls.localize({ key: 'miRunActiveFile', comment: ['&& denotes a mnemonic'] }, "Run &&Active File"), 'workbench.action.terminal.runActiveFile');
	// 	const runSelectedText = this.createMenuItem(nls.localize({ key: 'miRunSelectedText', comment: ['&& denotes a mnemonic'] }, "Run &&Selected Text"), 'workbench.action.terminal.runSelectedText');

	// 	// const scrollUp = this.createMenuItem(nls.localize({ key: 'miScrollUp', comment: ['&& denotes a mnemonic'] }, "Scroll Up"), 'workbench.action.terminal.scrollUp');
	// 	// const scrollDown = this.createMenuItem(nls.localize({ key: 'miScrollDown', comment: ['&& denotes a mnemonic'] }, "Scroll Down"), 'workbench.action.terminal.scrollDown');
	// 	// const scrollUpPage = this.createMenuItem(nls.localize({ key: 'miScrollUpPage', comment: ['&& denotes a mnemonic'] }, "Scroll Up Page"), 'workbench.action.terminal.scrollUpPage');
	// 	// const scrollDownPage = this.createMenuItem(nls.localize({ key: 'miScrollDownPage', comment: ['&& denotes a mnemonic'] }, "Scroll Down Page"), 'workbench.action.terminal.scrollDownPage');
	// 	// const scrollToTop = this.createMenuItem(nls.localize({ key: 'miScrollToTop', comment: ['&& denotes a mnemonic'] }, "Scroll To Top"), 'workbench.action.terminal.scrollToTop');
	// 	// const scrollToBottom = this.createMenuItem(nls.localize({ key: 'miScrollToBottom', comment: ['&& denotes a mnemonic'] }, "Scroll To Bottom"), 'workbench.action.terminal.scrollToBottom');
	// 	const scrollToPreviousCommand = this.createMenuItem(nls.localize({ key: 'miScrollToPreviousCommand', comment: ['&& denotes a mnemonic'] }, "Scroll To Previous Command"), 'workbench.action.terminal.scrollToPreviousCommand');
	// 	const scrollToNextCommand = this.createMenuItem(nls.localize({ key: 'miScrollToNextCommand', comment: ['&& denotes a mnemonic'] }, "Scroll To Next Command"), 'workbench.action.terminal.scrollToNextCommand');

	// 	const selectToPreviousCommand = this.createMenuItem(nls.localize({ key: 'miSelectToPreviousCommand', comment: ['&& denotes a mnemonic'] }, "Select To Previous Command"), 'workbench.action.terminal.selectToPreviousCommand');
	// 	const selectToNextCommand = this.createMenuItem(nls.localize({ key: 'miSelectToNextCommand', comment: ['&& denotes a mnemonic'] }, "Select To Next Command"), 'workbench.action.terminal.selectToNextCommand');

	// 	const menuItems: MenuItem[] = [
	// 		newTerminal,
	// 		splitTerminal,
	// 		killTerminal,
	// 		__separator__(),
	// 		clear,
	// 	];
	// 	// if (!isWindows) {
	// 	// 	menuItems.push(
	// 	// 		deleteWordLeft,
	// 	// 		deleteWordRight,
	// 	// 	);

	// 	// }
	// 	// if (isMacintosh) {
	// 	// 	menuItems.push(
	// 	// 		moveToLineStart,
	// 	// 		moveToLineEnd
	// 	// 	);
	// 	// }
	// 	menuItems.push(
	// 		runActiveFile,
	// 		runSelectedText,
	// 		__separator__(),
	// 		// scrollUp,
	// 		// scrollDown,
	// 		// scrollUpPage,
	// 		// scrollDownPage,
	// 		// scrollToTop,
	// 		// scrollToBottom,
	// 		scrollToPreviousCommand,
	// 		scrollToNextCommand,
	// 		// __separator__(),
	// 		selectToPreviousCommand,
	// 		selectToNextCommand
	// 	);

	// 	menuItems.forEach(item => terminalMenu.append(item));
	// }
D
Daniel Imms 已提交
932

I
isidor 已提交
933 934 935 936 937 938
	private setDebugMenu(debugMenu: Electron.Menu): void {
		const start = this.createMenuItem(nls.localize({ key: 'miStartDebugging', comment: ['&& denotes a mnemonic'] }, "&&Start Debugging"), 'workbench.action.debug.start');
		const startWithoutDebugging = this.createMenuItem(nls.localize({ key: 'miStartWithoutDebugging', comment: ['&& denotes a mnemonic'] }, "Start &&Without Debugging"), 'workbench.action.debug.run');
		const stop = this.createMenuItem(nls.localize({ key: 'miStopDebugging', comment: ['&& denotes a mnemonic'] }, "&&Stop Debugging"), 'workbench.action.debug.stop');
		const restart = this.createMenuItem(nls.localize({ key: 'miRestart Debugging', comment: ['&& denotes a mnemonic'] }, "&&Restart Debugging"), 'workbench.action.debug.restart');

I
isidor 已提交
939 940
		const openConfigurations = this.createMenuItem(nls.localize({ key: 'miOpenConfigurations', comment: ['&& denotes a mnemonic'] }, "Open &&Configurations"), 'workbench.action.debug.configure');
		const addConfiguration = this.createMenuItem(nls.localize({ key: 'miAddConfiguration', comment: ['&& denotes a mnemonic'] }, "Add Configuration..."), 'debug.addConfiguration');
I
isidor 已提交
941 942 943 944 945 946 947 948 949

		const stepOver = this.createMenuItem(nls.localize({ key: 'miStepOver', comment: ['&& denotes a mnemonic'] }, "Step &&Over"), 'workbench.action.debug.stepOver');
		const stepInto = this.createMenuItem(nls.localize({ key: 'miStepInto', comment: ['&& denotes a mnemonic'] }, "Step &&Into"), 'workbench.action.debug.stepInto');
		const stepOut = this.createMenuItem(nls.localize({ key: 'miStepOut', comment: ['&& denotes a mnemonic'] }, "Step O&&ut"), 'workbench.action.debug.stepOut');
		const continueAction = this.createMenuItem(nls.localize({ key: 'miContinue', comment: ['&& denotes a mnemonic'] }, "&&Continue"), 'workbench.action.debug.continue');

		const toggleBreakpoint = this.createMenuItem(nls.localize({ key: 'miToggleBreakpoint', comment: ['&& denotes a mnemonic'] }, "Toggle &&Breakpoint"), 'editor.debug.action.toggleBreakpoint');
		const breakpointsMenu = new Menu();
		breakpointsMenu.append(this.createMenuItem(nls.localize({ key: 'miConditionalBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Conditional Breakpoint..."), 'editor.debug.action.conditionalBreakpoint'));
950
		breakpointsMenu.append(this.createMenuItem(nls.localize({ key: 'miInlineBreakpoint', comment: ['&& denotes a mnemonic'] }, "Inline Breakp&&oint"), 'editor.debug.action.toggleInlineBreakpoint'));
I
isidor 已提交
951
		breakpointsMenu.append(this.createMenuItem(nls.localize({ key: 'miFunctionBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Function Breakpoint..."), 'workbench.debug.viewlet.action.addFunctionBreakpointAction'));
I
isidor 已提交
952
		breakpointsMenu.append(this.createMenuItem(nls.localize({ key: 'miLogPoint', comment: ['&& denotes a mnemonic'] }, "&&Logpoint..."), 'editor.debug.action.toggleLogPoint'));
953
		const newBreakpoints = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miNewBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&New Breakpoint")), submenu: breakpointsMenu });
I
isidor 已提交
954
		const enableAllBreakpoints = this.createMenuItem(nls.localize({ key: 'miEnableAllBreakpoints', comment: ['&& denotes a mnemonic'] }, "Enable All Breakpoints"), 'workbench.debug.viewlet.action.enableAllBreakpoints');
I
isidor 已提交
955
		const disableAllBreakpoints = this.createMenuItem(nls.localize({ key: 'miDisableAllBreakpoints', comment: ['&& denotes a mnemonic'] }, "Disable A&&ll Breakpoints"), 'workbench.debug.viewlet.action.disableAllBreakpoints');
I
isidor 已提交
956
		const removeAllBreakpoints = this.createMenuItem(nls.localize({ key: 'miRemoveAllBreakpoints', comment: ['&& denotes a mnemonic'] }, "Remove &&All Breakpoints"), 'workbench.debug.viewlet.action.removeAllBreakpoints');
I
isidor 已提交
957

I
isidor 已提交
958
		const installAdditionalDebuggers = this.createMenuItem(nls.localize({ key: 'miInstallAdditionalDebuggers', comment: ['&& denotes a mnemonic'] }, "&&Install Additional Debuggers..."), 'debug.installAdditionalDebuggers');
I
isidor 已提交
959 960 961 962 963 964
		[
			start,
			startWithoutDebugging,
			stop,
			restart,
			__separator__(),
I
isidor 已提交
965 966
			openConfigurations,
			addConfiguration,
I
isidor 已提交
967 968 969 970 971 972 973 974
			__separator__(),
			stepOver,
			stepInto,
			stepOut,
			continueAction,
			__separator__(),
			toggleBreakpoint,
			newBreakpoints,
I
isidor 已提交
975
			enableAllBreakpoints,
I
isidor 已提交
976 977 978
			disableAllBreakpoints,
			removeAllBreakpoints,
			__separator__(),
I
isidor 已提交
979
			installAdditionalDebuggers
I
isidor 已提交
980 981 982
		].forEach(item => debugMenu.append(item));
	}

B
Benjamin Pasero 已提交
983
	private setMacWindowMenu(macWindowMenu: Electron.Menu): void {
B
Benjamin Pasero 已提交
984 985 986
		const minimize = new MenuItem({ label: nls.localize('mMinimize', "Minimize"), role: 'minimize', accelerator: 'Command+M', enabled: this.windowsMainService.getWindowCount() > 0 });
		const zoom = new MenuItem({ label: nls.localize('mZoom', "Zoom"), role: 'zoom', enabled: this.windowsMainService.getWindowCount() > 0 });
		const bringAllToFront = new MenuItem({ label: nls.localize('mBringToFront', "Bring All to Front"), role: 'front', enabled: this.windowsMainService.getWindowCount() > 0 });
B
Benjamin Pasero 已提交
987
		const switchWindow = this.createMenuItem(nls.localize({ key: 'miSwitchWindow', comment: ['&& denotes a mnemonic'] }, "Switch &&Window..."), 'workbench.action.switchWindow');
E
Erich Gamma 已提交
988

989
		this.nativeTabMenuItems = [];
990 991
		const nativeTabMenuItems: Electron.MenuItem[] = [];
		if (this.currentEnableNativeTabs) {
B
Benjamin Pasero 已提交
992
			const hasMultipleWindows = this.windowsMainService.getWindowCount() > 1;
993

994 995 996 997
			this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowPreviousTab', "Show Previous Tab"), 'workbench.action.showPreviousWindowTab', hasMultipleWindows));
			this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowNextTab', "Show Next Tab"), 'workbench.action.showNextWindowTab', hasMultipleWindows));
			this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mMoveTabToNewWindow', "Move Tab to New Window"), 'workbench.action.moveWindowTabToNewWindow', hasMultipleWindows));
			this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mMergeAllWindows', "Merge All Windows"), 'workbench.action.mergeAllWindowTabs', hasMultipleWindows));
998 999 1000 1001 1002 1003

			nativeTabMenuItems.push(__separator__(), ...this.nativeTabMenuItems);
		} else {
			this.nativeTabMenuItems = [];
		}

E
Erich Gamma 已提交
1004 1005
		[
			minimize,
B
Benjamin Pasero 已提交
1006 1007
			zoom,
			switchWindow,
1008
			...nativeTabMenuItems,
E
Erich Gamma 已提交
1009 1010
			__separator__(),
			bringAllToFront
B
Benjamin Pasero 已提交
1011
		].forEach(item => macWindowMenu.append(item));
E
Erich Gamma 已提交
1012 1013
	}

J
fix npe  
Joao Moreno 已提交
1014
	private toggleDevTools(): void {
B
Benjamin Pasero 已提交
1015
		const w = this.windowsMainService.getFocusedWindow();
J
fix npe  
Joao Moreno 已提交
1016
		if (w && w.win) {
1017 1018 1019 1020 1021 1022
			const contents = w.win.webContents;
			if (w.hasHiddenTitleBarStyle() && !w.win.isFullScreen() && !contents.isDevToolsOpened()) {
				contents.openDevTools({ mode: 'undocked' }); // due to https://github.com/electron/electron/issues/3647
			} else {
				contents.toggleDevTools();
			}
J
fix npe  
Joao Moreno 已提交
1023 1024 1025
		}
	}

B
Benjamin Pasero 已提交
1026
	private setHelpMenu(helpMenu: Electron.Menu): void {
1027
		const toggleDevToolsItem = new MenuItem(this.likeAction('workbench.action.toggleDevTools', {
1028
			label: this.mnemonicLabel(nls.localize({ key: 'miToggleDevTools', comment: ['&& denotes a mnemonic'] }, "&&Toggle Developer Tools")),
J
fix npe  
Joao Moreno 已提交
1029
			click: () => this.toggleDevTools(),
B
Benjamin Pasero 已提交
1030
			enabled: (this.windowsMainService.getWindowCount() > 0)
1031
		}));
E
Erich Gamma 已提交
1032

1033
		const showAccessibilityOptions = new MenuItem(this.likeAction('accessibilityOptions', {
1034
			label: this.mnemonicLabel(nls.localize({ key: 'miAccessibilityOptions', comment: ['&& denotes a mnemonic'] }, "Accessibility &&Options")),
1035 1036
			accelerator: null,
			click: () => {
1037
				this.openAccessibilityOptions();
1038
			}
1039
		}, false));
1040

1041 1042
		const openProcessExplorer = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer")), click: () => this.runActionInRenderer('workbench.action.openProcessExplorer') });

B
Benjamin Pasero 已提交
1043
		let reportIssuesItem: Electron.MenuItem = null;
B
Benjamin Pasero 已提交
1044
		if (product.reportIssueUrl) {
I
isidor 已提交
1045
			const label = nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue");
B
Benjamin Pasero 已提交
1046

B
Benjamin Pasero 已提交
1047
			if (this.windowsMainService.getWindowCount() > 0) {
1048
				reportIssuesItem = this.createMenuItem(label, 'workbench.action.openIssueReporter');
B
Benjamin Pasero 已提交
1049
			} else {
1050
				reportIssuesItem = new MenuItem({ label: this.mnemonicLabel(label), click: () => this.openUrl(product.reportIssueUrl, 'openReportIssues') });
B
Benjamin Pasero 已提交
1051 1052
			}
		}
J
Joao Moreno 已提交
1053

1054
		const keyboardShortcutsUrl = isLinux ? product.keyboardShortcutsUrlLinux : isMacintosh ? product.keyboardShortcutsUrlMac : product.keyboardShortcutsUrlWin;
E
Erich Gamma 已提交
1055
		arrays.coalesce([
B
Benjamin Pasero 已提交
1056 1057 1058 1059
			new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")), click: () => this.runActionInRenderer('workbench.action.showWelcomePage'), enabled: (this.windowsMainService.getWindowCount() > 0) }),
			new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")), click: () => this.runActionInRenderer('workbench.action.showInteractivePlayground'), enabled: (this.windowsMainService.getWindowCount() > 0) }),
			product.documentationUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.runActionInRenderer('workbench.action.openDocumentationUrl'), enabled: (this.windowsMainService.getWindowCount() > 0) }) : null,
			product.releaseNotesUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.runActionInRenderer('update.showCurrentReleaseNotes'), enabled: (this.windowsMainService.getWindowCount() > 0) }) : null,
1060
			__separator__(),
B
Benjamin Pasero 已提交
1061 1062 1063
			keyboardShortcutsUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")), click: () => this.runActionInRenderer('workbench.action.keybindingsReference'), enabled: (this.windowsMainService.getWindowCount() > 0) }) : null,
			product.introductoryVideosUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")), click: () => this.runActionInRenderer('workbench.action.openIntroductoryVideosUrl'), enabled: (this.windowsMainService.getWindowCount() > 0) }) : null,
			product.tipsAndTricksUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")), click: () => this.runActionInRenderer('workbench.action.openTipsAndTricksUrl'), enabled: (this.windowsMainService.getWindowCount() > 0) }) : null,
I
isidor 已提交
1064
			(product.introductoryVideosUrl || keyboardShortcutsUrl) ? __separator__() : null,
1065 1066
			product.twitterUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(product.twitterUrl, 'openTwitterUrl') }) : null,
			product.requestFeatureUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(product.requestFeatureUrl, 'openUserVoiceUrl') }) : null,
B
Benjamin Pasero 已提交
1067
			reportIssuesItem,
B
Benjamin Pasero 已提交
1068 1069
			(product.twitterUrl || product.requestFeatureUrl || product.reportIssueUrl) ? __separator__() : null,
			product.licenseUrl ? new MenuItem({
1070
				label: this.mnemonicLabel(nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License")), click: () => {
1071
					if (language) {
B
Benjamin Pasero 已提交
1072
						const queryArgChar = product.licenseUrl.indexOf('?') > 0 ? '&' : '?';
1073
						this.openUrl(`${product.licenseUrl}${queryArgChar}lang=${language}`, 'openLicenseUrl');
B
Benjamin Pasero 已提交
1074
					} else {
B
Benjamin Pasero 已提交
1075
						this.openUrl(product.licenseUrl, 'openLicenseUrl');
B
Benjamin Pasero 已提交
1076
					}
1077
				}
B
Benjamin Pasero 已提交
1078
			}) : null,
B
Benjamin Pasero 已提交
1079
			product.privacyStatementUrl ? new MenuItem({
1080
				label: this.mnemonicLabel(nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "&&Privacy Statement")), click: () => {
1081
					if (language) {
B
Benjamin Pasero 已提交
1082
						const queryArgChar = product.licenseUrl.indexOf('?') > 0 ? '&' : '?';
1083
						this.openUrl(`${product.privacyStatementUrl}${queryArgChar}lang=${language}`, 'openPrivacyStatement');
1084
					} else {
B
Benjamin Pasero 已提交
1085
						this.openUrl(product.privacyStatementUrl, 'openPrivacyStatement');
1086 1087 1088
					}
				}
			}) : null,
B
Benjamin Pasero 已提交
1089
			(product.licenseUrl || product.privacyStatementUrl) ? __separator__() : null,
E
Erich Gamma 已提交
1090
			toggleDevToolsItem,
1091 1092
			openProcessExplorer,
			isWindows && product.quality !== 'stable' ? showAccessibilityOptions : null,
B
Benjamin Pasero 已提交
1093
		]).forEach(item => helpMenu.append(item));
E
Erich Gamma 已提交
1094

1095
		if (!isMacintosh) {
E
Erich Gamma 已提交
1096 1097 1098 1099 1100 1101 1102
			const updateMenuItems = this.getUpdateMenuItems();
			if (updateMenuItems.length) {
				helpMenu.append(__separator__());
				updateMenuItems.forEach(i => helpMenu.append(i));
			}

			helpMenu.append(__separator__());
J
Joao Moreno 已提交
1103
			helpMenu.append(new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")), click: () => this.windowsService.openAboutDialog() }));
E
Erich Gamma 已提交
1104 1105 1106
		}
	}

T
t-amqi 已提交
1107
	private setTaskMenu(taskMenu: Electron.Menu): void {
1108
		const runTask = this.createMenuItem(nls.localize({ key: 'miRunTask', comment: ['&& denotes a mnemonic'] }, "&&Run Task..."), 'workbench.action.tasks.runTask');
1109 1110
		const buildTask = this.createMenuItem(nls.localize({ key: 'miBuildTask', comment: ['&& denotes a mnemonic'] }, "Run &&Build Task..."), 'workbench.action.tasks.build');
		const showTasks = this.createMenuItem(nls.localize({ key: 'miRunningTask', comment: ['&& denotes a mnemonic'] }, "Show Runnin&&g Tasks..."), 'workbench.action.tasks.showTasks');
1111
		const restartTask = this.createMenuItem(nls.localize({ key: 'miRestartTask', comment: ['&& denotes a mnemonic'] }, "R&&estart Running Task..."), 'workbench.action.tasks.restartTask');
1112
		const terminateTask = this.createMenuItem(nls.localize({ key: 'miTerminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task..."), 'workbench.action.tasks.terminate');
1113 1114
		const configureTask = this.createMenuItem(nls.localize({ key: 'miConfigureTask', comment: ['&& denotes a mnemonic'] }, "&&Configure Tasks..."), 'workbench.action.tasks.configureTaskRunner');
		const configureBuildTask = this.createMenuItem(nls.localize({ key: 'miConfigureBuildTask', comment: ['&& denotes a mnemonic'] }, "Configure De&&fault Build Task..."), 'workbench.action.tasks.configureDefaultBuildTask');
T
t-amqi 已提交
1115 1116

		[
1117 1118
			//__separator__(),
			runTask,
D
Dirk Baeumer 已提交
1119
			buildTask,
T
t-amqi 已提交
1120 1121 1122
			__separator__(),
			terminateTask,
			restartTask,
1123
			showTasks,
T
t-amqi 已提交
1124 1125
			__separator__(),
			configureTask,
1126
			configureBuildTask
T
t-amqi 已提交
1127 1128 1129
		].forEach(item => taskMenu.append(item));
	}

1130
	private openAccessibilityOptions(): void {
1131
		const win = new BrowserWindow({
1132 1133 1134 1135 1136 1137
			alwaysOnTop: true,
			skipTaskbar: true,
			resizable: false,
			width: 450,
			height: 300,
			show: true,
B
Benjamin Pasero 已提交
1138 1139 1140 1141
			title: nls.localize('accessibilityOptionsWindowTitle', "Accessibility Options"),
			webPreferences: {
				disableBlinkFeatures: 'Auxclick'
			}
1142 1143 1144 1145 1146 1147 1148
		});

		win.setMenuBarVisibility(false);

		win.loadURL('chrome://accessibility');
	}

B
Benjamin Pasero 已提交
1149
	private getUpdateMenuItems(): Electron.MenuItem[] {
1150 1151 1152 1153
		const state = this.updateService.state;

		switch (state.type) {
			case StateType.Uninitialized:
E
Erich Gamma 已提交
1154 1155
				return [];

1156 1157 1158 1159
			case StateType.Idle:
				return [new MenuItem({
					label: nls.localize('miCheckForUpdates', "Check for Updates..."), click: () => setTimeout(() => {
						this.reportMenuActionTelemetry('CheckForUpdate');
J
Joao Moreno 已提交
1160 1161 1162 1163

						const focusedWindow = this.windowsMainService.getFocusedWindow();
						const context = focusedWindow ? { windowId: focusedWindow.id } : null;
						this.updateService.checkForUpdates(context);
1164 1165 1166 1167 1168 1169
					}, 0)
				})];

			case StateType.CheckingForUpdates:
				return [new MenuItem({ label: nls.localize('miCheckingForUpdates', "Checking For Updates..."), enabled: false })];

J
Joao Moreno 已提交
1170
			case StateType.AvailableForDownload:
1171 1172
				return [new MenuItem({
					label: nls.localize('miDownloadUpdate', "Download Available Update"), click: () => {
1173
						this.updateService.downloadUpdate();
1174 1175 1176 1177 1178 1179 1180
					}
				})];

			case StateType.Downloading:
				return [new MenuItem({ label: nls.localize('miDownloadingUpdate', "Downloading Update..."), enabled: false })];

			case StateType.Downloaded:
J
Joao Moreno 已提交
1181 1182 1183 1184 1185 1186 1187
				return [new MenuItem({
					label: nls.localize('miInstallUpdate', "Install Update..."), click: () => {
						this.reportMenuActionTelemetry('InstallUpdate');
						this.updateService.applyUpdate();
					}
				})];

1188
			case StateType.Updating:
J
Joao Moreno 已提交
1189 1190
				return [new MenuItem({ label: nls.localize('miInstallingUpdate', "Installing Update..."), enabled: false })];

1191
			case StateType.Ready:
B
Benjamin Pasero 已提交
1192
				return [new MenuItem({
J
Joao Moreno 已提交
1193
					label: nls.localize('miRestartToUpdate', "Restart to Update..."), click: () => {
J
fix npe  
Joao Moreno 已提交
1194
						this.reportMenuActionTelemetry('RestartToUpdate');
J
Joao Moreno 已提交
1195
						this.updateService.quitAndInstall();
B
Benjamin Pasero 已提交
1196 1197
					}
				})];
E
Erich Gamma 已提交
1198 1199 1200
		}
	}

1201
	private createMenuItem(label: string, commandId: string | string[], enabled?: boolean, checked?: boolean): Electron.MenuItem;
B
Benjamin Pasero 已提交
1202 1203
	private createMenuItem(label: string, click: () => void, enabled?: boolean, checked?: boolean): Electron.MenuItem;
	private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): Electron.MenuItem {
1204
		const label = this.mnemonicLabel(arg1);
1205
		const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: Electron.MenuItem, win: Electron.BrowserWindow, event: Electron.Event) => {
1206
			let commandId = arg2;
1207
			if (Array.isArray(arg2)) {
1208
				commandId = this.isOptionClick(event) ? arg2[1] : arg2[0]; // support alternative action if we got multiple action Ids and the option key was pressed while invoking
1209 1210
			}

1211
			this.runActionInRenderer(commandId);
1212
		};
B
Benjamin Pasero 已提交
1213
		const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsMainService.getWindowCount() > 0;
B
Benjamin Pasero 已提交
1214
		const checked = typeof arg4 === 'boolean' ? arg4 : false;
E
Erich Gamma 已提交
1215

1216
		const options: Electron.MenuItemConstructorOptions = {
B
Benjamin Pasero 已提交
1217 1218 1219
			label,
			click,
			enabled
E
Erich Gamma 已提交
1220 1221
		};

B
Benjamin Pasero 已提交
1222 1223 1224 1225 1226
		if (checked) {
			options['type'] = 'checkbox';
			options['checked'] = checked;
		}

1227 1228 1229 1230 1231 1232 1233
		let commandId: string;
		if (typeof arg2 === 'string') {
			commandId = arg2;
		} else if (Array.isArray(arg2)) {
			commandId = arg2[0];
		}

1234
		return new MenuItem(this.withKeybinding(commandId, options));
E
Erich Gamma 已提交
1235 1236
	}

1237
	private createContextAwareMenuItem(label: string, commandId: string, clickHandler: IMenuItemClickHandler): Electron.MenuItem {
1238
		return new MenuItem(this.withKeybinding(commandId, {
1239
			label: this.mnemonicLabel(label),
B
Benjamin Pasero 已提交
1240
			enabled: this.windowsMainService.getWindowCount() > 0,
1241
			click: () => {
1242 1243

				// No Active Window
B
Benjamin Pasero 已提交
1244
				const activeWindow = this.windowsMainService.getFocusedWindow();
1245 1246
				if (!activeWindow) {
					return clickHandler.inNoWindow();
1247 1248
				}

1249 1250 1251
				// DevTools focused
				if (activeWindow.win.webContents.isDevToolsFocused()) {
					return clickHandler.inDevTools(activeWindow.win.webContents.devToolsWebContents);
1252
				}
1253 1254

				// Finally execute command in Window
1255
				this.runActionInRenderer(commandId);
1256
			}
1257
		}));
1258 1259
	}

1260
	private runActionInRenderer(id: string): void {
1261 1262 1263
		// We make sure to not run actions when the window has no focus, this helps
		// for https://github.com/Microsoft/vscode/issues/25907 and specifically for
		// https://github.com/Microsoft/vscode/issues/11928
B
Benjamin Pasero 已提交
1264
		const activeWindow = this.windowsMainService.getFocusedWindow();
1265
		if (activeWindow) {
B
Benjamin Pasero 已提交
1266
			this.windowsMainService.sendToFocused('vscode:runAction', { id, from: 'menu' } as IRunActionInWindowRequest);
1267
		}
1268 1269
	}

1270
	private withKeybinding(commandId: string, options: Electron.MenuItemConstructorOptions): Electron.MenuItemConstructorOptions {
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
		const binding = this.keybindingsResolver.getKeybinding(commandId);

		// Apply binding if there is one
		if (binding && binding.label) {

			// if the binding is native, we can just apply it
			if (binding.isNative) {
				options.accelerator = binding.label;
			}

			// the keybinding is not native so we cannot show it as part of the accelerator of
			// the menu item. we fallback to a different strategy so that we always display it
			else {
B
Benjamin Pasero 已提交
1284
				const bindingIndex = options.label.indexOf('[');
1285
				if (bindingIndex >= 0) {
B
Benjamin Pasero 已提交
1286
					options.label = `${options.label.substr(0, bindingIndex)} [${binding.label}]`;
1287
				} else {
B
Benjamin Pasero 已提交
1288
					options.label = `${options.label} [${binding.label}]`;
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
				}
			}
		}

		// Unset bindings if there is none
		else {
			options.accelerator = void 0;
		}

		return options;
	}

1301
	private likeAction(commandId: string, options: Electron.MenuItemConstructorOptions, setAccelerator = !options.accelerator): Electron.MenuItemConstructorOptions {
1302
		if (setAccelerator) {
1303
			options = this.withKeybinding(commandId, options);
1304
		}
1305

1306 1307
		const originalClick = options.click;
		options.click = (item, window, event) => {
1308
			this.reportMenuActionTelemetry(commandId);
1309 1310 1311 1312 1313
			if (originalClick) {
				originalClick(item, window, event);
			}
		};

1314
		return options;
E
Erich Gamma 已提交
1315 1316
	}

J
fix npe  
Joao Moreno 已提交
1317 1318 1319
	private openUrl(url: string, id: string): void {
		shell.openExternal(url);
		this.reportMenuActionTelemetry(id);
E
Erich Gamma 已提交
1320 1321
	}

J
fix npe  
Joao Moreno 已提交
1322
	private reportMenuActionTelemetry(id: string): void {
K
kieferrm 已提交
1323
		/* __GDPR__
K
kieferrm 已提交
1324
			"workbenchActionExecuted" : {
K
kieferrm 已提交
1325 1326 1327 1328
				"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
			}
		*/
1329
		this.telemetryService.publicLog('workbenchActionExecuted', { id, from: telemetryFrom });
J
fix npe  
Joao Moreno 已提交
1330
	}
E
Erich Gamma 已提交
1331

1332
	private mnemonicLabel(label: string): string {
1333
		return baseMnemonicLabel(label, !this.currentEnableMenuBarMnemonics);
1334
	}
1335
}
1336

1337 1338
function __separator__(): Electron.MenuItem {
	return new MenuItem({ type: 'separator' });
1339
}