mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-26 01:38:40 +01:00
875 lines
40 KiB
TypeScript
875 lines
40 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
'use strict';
|
|
|
|
import * as nls from 'vs/nls';
|
|
import * as os from 'os';
|
|
import * as platform from 'vs/base/common/platform';
|
|
import * as arrays from 'vs/base/common/arrays';
|
|
import * as env from 'vs/code/electron-main/env';
|
|
import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem } from 'electron';
|
|
import { IWindowsService, WindowsManager, IOpenedPathsList } from 'vs/code/electron-main/windows';
|
|
import { IPath, VSCodeWindow } from 'vs/code/electron-main/window';
|
|
import { IStorageService } from 'vs/code/electron-main/storage';
|
|
import { IUpdateService, State as UpdateState } from 'vs/code/electron-main/update-manager';
|
|
import { Keybinding } from 'vs/base/common/keyCodes';
|
|
import product from 'vs/platform/product';
|
|
import pkg from 'vs/platform/package';
|
|
|
|
export function generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string): string {
|
|
const osVersion = `${os.type()} ${os.arch()} ${os.release()}`;
|
|
const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&';
|
|
const body = encodeURIComponent(
|
|
`- VSCode Version: ${name} ${version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})
|
|
- OS Version: ${osVersion}
|
|
|
|
Steps to Reproduce:
|
|
|
|
1.
|
|
2.`
|
|
);
|
|
|
|
return `${baseUrl}${queryStringPrefix}body=${body}`;
|
|
}
|
|
|
|
interface IResolvedKeybinding {
|
|
id: string;
|
|
binding: number;
|
|
}
|
|
|
|
export class VSCodeMenu {
|
|
|
|
private static lastKnownKeybindingsMapStorageKey = 'lastKnownKeybindings';
|
|
|
|
private static MAX_MENU_RECENT_ENTRIES = 10;
|
|
private static MAX_TOTAL_RECENT_ENTRIES = 100;
|
|
|
|
private isQuitting: boolean;
|
|
private appMenuInstalled: boolean;
|
|
|
|
private actionIdKeybindingRequests: string[];
|
|
private mapLastKnownKeybindingToActionId: { [id: string]: string; };
|
|
private mapResolvedKeybindingToActionId: { [id: string]: string; };
|
|
private keybindingsResolved: boolean;
|
|
|
|
constructor(
|
|
@IStorageService private storageService: IStorageService,
|
|
@IUpdateService private updateService: IUpdateService,
|
|
@IWindowsService private windowsService: IWindowsService,
|
|
@env.IEnvService private envService: env.IEnvService
|
|
) {
|
|
this.actionIdKeybindingRequests = [];
|
|
|
|
this.mapResolvedKeybindingToActionId = Object.create(null);
|
|
this.mapLastKnownKeybindingToActionId = this.storageService.getItem<{ [id: string]: string; }>(VSCodeMenu.lastKnownKeybindingsMapStorageKey) || Object.create(null);
|
|
}
|
|
|
|
public ready(): void {
|
|
this.registerListeners();
|
|
this.install();
|
|
}
|
|
|
|
private registerListeners(): void {
|
|
|
|
// Keep flag when app quits
|
|
app.on('will-quit', () => {
|
|
this.isQuitting = true;
|
|
});
|
|
|
|
// Listen to "open" & "close" event from window service
|
|
this.windowsService.onOpen((paths) => this.onOpen(paths));
|
|
this.windowsService.onClose(_ => this.onClose(this.windowsService.getWindowCount()));
|
|
|
|
// Resolve keybindings when any first workbench is loaded
|
|
this.windowsService.onReady((win) => this.resolveKeybindings(win));
|
|
|
|
// Listen to resolved keybindings
|
|
ipc.on('vscode:keybindingsResolved', (event, rawKeybindings) => {
|
|
let keybindings: IResolvedKeybinding[] = [];
|
|
try {
|
|
keybindings = JSON.parse(rawKeybindings);
|
|
} catch (error) {
|
|
// Should not happen
|
|
}
|
|
|
|
// Fill hash map of resolved keybindings
|
|
let needsMenuUpdate = false;
|
|
keybindings.forEach((keybinding) => {
|
|
const accelerator = new Keybinding(keybinding.binding)._toElectronAccelerator();
|
|
if (accelerator) {
|
|
this.mapResolvedKeybindingToActionId[keybinding.id] = accelerator;
|
|
if (this.mapLastKnownKeybindingToActionId[keybinding.id] !== accelerator) {
|
|
needsMenuUpdate = true; // we only need to update when something changed!
|
|
}
|
|
}
|
|
});
|
|
|
|
// A keybinding might have been unassigned, so we have to account for that too
|
|
if (Object.keys(this.mapLastKnownKeybindingToActionId).length !== Object.keys(this.mapResolvedKeybindingToActionId).length) {
|
|
needsMenuUpdate = true;
|
|
}
|
|
|
|
if (needsMenuUpdate) {
|
|
this.storageService.setItem(VSCodeMenu.lastKnownKeybindingsMapStorageKey, this.mapResolvedKeybindingToActionId); // keep to restore instantly after restart
|
|
this.mapLastKnownKeybindingToActionId = this.mapResolvedKeybindingToActionId; // update our last known map
|
|
|
|
this.updateMenu();
|
|
}
|
|
});
|
|
|
|
// Listen to update service
|
|
this.updateService.on('change', () => this.updateMenu());
|
|
}
|
|
|
|
private resolveKeybindings(win: VSCodeWindow): void {
|
|
if (this.keybindingsResolved) {
|
|
return; // only resolve once
|
|
}
|
|
|
|
this.keybindingsResolved = true;
|
|
|
|
// Resolve keybindings when workbench window is up
|
|
if (this.actionIdKeybindingRequests.length) {
|
|
win.send('vscode:resolveKeybindings', JSON.stringify(this.actionIdKeybindingRequests));
|
|
}
|
|
}
|
|
|
|
private updateMenu(): void {
|
|
|
|
// 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.
|
|
// See also https://github.com/electron/electron/issues/846
|
|
//
|
|
// 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 */);
|
|
}
|
|
}
|
|
|
|
private onOpen(path: IPath): void {
|
|
this.addToOpenedPathsList(path.filePath || path.workspacePath, !!path.filePath);
|
|
this.updateMenu();
|
|
}
|
|
|
|
private onClose(remainingWindowCount: number): void {
|
|
if (remainingWindowCount === 0 && platform.isMacintosh) {
|
|
this.updateMenu();
|
|
}
|
|
}
|
|
|
|
private install(): void {
|
|
|
|
// Menus
|
|
const menubar = new Menu();
|
|
|
|
// Mac: Application
|
|
let macApplicationMenuItem: Electron.MenuItem;
|
|
if (platform.isMacintosh) {
|
|
const applicationMenu = new Menu();
|
|
macApplicationMenuItem = new MenuItem({ label: this.envService.product.nameShort, submenu: applicationMenu });
|
|
this.setMacApplicationMenu(applicationMenu);
|
|
}
|
|
|
|
// File
|
|
const fileMenu = new Menu();
|
|
const fileMenuItem = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File")), submenu: fileMenu });
|
|
this.setFileMenu(fileMenu);
|
|
|
|
// Edit
|
|
const editMenu = new Menu();
|
|
const editMenuItem = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit")), submenu: editMenu });
|
|
this.setEditMenu(editMenu);
|
|
|
|
// View
|
|
const viewMenu = new Menu();
|
|
const viewMenuItem = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View")), submenu: viewMenu });
|
|
this.setViewMenu(viewMenu);
|
|
|
|
// Goto
|
|
const gotoMenu = new Menu();
|
|
const gotoMenuItem = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu });
|
|
this.setGotoMenu(gotoMenu);
|
|
|
|
// Mac: Window
|
|
let macWindowMenuItem: Electron.MenuItem;
|
|
if (platform.isMacintosh) {
|
|
const windowMenu = new Menu();
|
|
macWindowMenuItem = new MenuItem({ label: mnemonicLabel(nls.localize('mWindow', "Window")), submenu: windowMenu, role: 'window' });
|
|
this.setMacWindowMenu(windowMenu);
|
|
}
|
|
|
|
// Help
|
|
const helpMenu = new Menu();
|
|
const helpMenuItem = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help")), submenu: helpMenu, role: 'help' });
|
|
this.setHelpMenu(helpMenu);
|
|
|
|
// Menu Structure
|
|
if (macApplicationMenuItem) {
|
|
menubar.append(macApplicationMenuItem);
|
|
}
|
|
|
|
menubar.append(fileMenuItem);
|
|
menubar.append(editMenuItem);
|
|
menubar.append(viewMenuItem);
|
|
menubar.append(gotoMenuItem);
|
|
|
|
if (macWindowMenuItem) {
|
|
menubar.append(macWindowMenuItem);
|
|
}
|
|
|
|
menubar.append(helpMenuItem);
|
|
|
|
Menu.setApplicationMenu(menubar);
|
|
|
|
// Dock Menu
|
|
if (platform.isMacintosh && !this.appMenuInstalled) {
|
|
this.appMenuInstalled = true;
|
|
|
|
const dockMenu = new Menu();
|
|
dockMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "&&New Window")), click: () => this.windowsService.openNewWindow() }));
|
|
|
|
app.dock.setMenu(dockMenu);
|
|
}
|
|
}
|
|
|
|
private addToOpenedPathsList(path?: string, isFile?: boolean): void {
|
|
if (!path) {
|
|
return;
|
|
}
|
|
|
|
const mru = this.getOpenedPathsList();
|
|
if (isFile) {
|
|
mru.files.unshift(path);
|
|
mru.files = arrays.distinct(mru.files, (f) => platform.isLinux ? f : f.toLowerCase());
|
|
} else {
|
|
mru.folders.unshift(path);
|
|
mru.folders = arrays.distinct(mru.folders, (f) => platform.isLinux ? f : f.toLowerCase());
|
|
}
|
|
|
|
// Make sure its bounded
|
|
mru.folders = mru.folders.slice(0, VSCodeMenu.MAX_TOTAL_RECENT_ENTRIES);
|
|
mru.files = mru.files.slice(0, VSCodeMenu.MAX_TOTAL_RECENT_ENTRIES);
|
|
|
|
this.storageService.setItem(WindowsManager.openedPathsListStorageKey, mru);
|
|
}
|
|
|
|
private removeFromOpenedPathsList(path: string): void {
|
|
const mru = this.getOpenedPathsList();
|
|
|
|
let index = mru.files.indexOf(path);
|
|
if (index >= 0) {
|
|
mru.files.splice(index, 1);
|
|
}
|
|
|
|
index = mru.folders.indexOf(path);
|
|
if (index >= 0) {
|
|
mru.folders.splice(index, 1);
|
|
}
|
|
|
|
this.storageService.setItem(WindowsManager.openedPathsListStorageKey, mru);
|
|
}
|
|
|
|
private clearOpenedPathsList(): void {
|
|
this.storageService.setItem(WindowsManager.openedPathsListStorageKey, { folders: [], files: [] });
|
|
app.clearRecentDocuments();
|
|
|
|
this.updateMenu();
|
|
}
|
|
|
|
private getOpenedPathsList(): IOpenedPathsList {
|
|
let mru = this.storageService.getItem<IOpenedPathsList>(WindowsManager.openedPathsListStorageKey);
|
|
if (!mru) {
|
|
mru = { folders: [], files: [] };
|
|
}
|
|
|
|
return mru;
|
|
}
|
|
|
|
private setMacApplicationMenu(macApplicationMenu: Electron.Menu): void {
|
|
const about = new MenuItem({ label: nls.localize('mAbout', "About {0}", this.envService.product.nameLong), role: 'about' });
|
|
const checkForUpdates = this.getUpdateMenuItems();
|
|
const preferences = this.getPreferencesMenu();
|
|
const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", this.envService.product.nameLong), role: 'hide', accelerator: 'Command+H' });
|
|
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' });
|
|
const quit = new MenuItem({ label: nls.localize('miQuit', "Quit {0}", this.envService.product.nameLong), click: () => this.quit(), accelerator: 'Command+Q' });
|
|
|
|
const actions = [about];
|
|
actions.push(...checkForUpdates);
|
|
actions.push(...[
|
|
__separator__(),
|
|
preferences,
|
|
__separator__(),
|
|
hide,
|
|
hideOthers,
|
|
showAll,
|
|
__separator__(),
|
|
quit
|
|
]);
|
|
|
|
actions.forEach(i => macApplicationMenu.append(i));
|
|
}
|
|
|
|
private setFileMenu(fileMenu: Electron.Menu): void {
|
|
const hasNoWindows = (this.windowsService.getWindowCount() === 0);
|
|
|
|
let newFile: Electron.MenuItem;
|
|
if (hasNoWindows) {
|
|
newFile = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File")), accelerator: this.getAccelerator('workbench.action.files.newUntitledFile'), click: () => this.windowsService.openNewWindow() });
|
|
} else {
|
|
newFile = this.createMenuItem(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File"), 'workbench.action.files.newUntitledFile');
|
|
}
|
|
|
|
const open = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), accelerator: this.getAccelerator('workbench.action.files.openFileFolder'), click: () => this.windowsService.openFileFolderPicker() });
|
|
const openFolder = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), accelerator: this.getAccelerator('workbench.action.files.openFolder'), click: () => this.windowsService.openFolderPicker() });
|
|
|
|
let openFile: Electron.MenuItem;
|
|
if (hasNoWindows) {
|
|
openFile = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...")), accelerator: this.getAccelerator('workbench.action.files.openFile'), click: () => this.windowsService.openFilePicker() });
|
|
} else {
|
|
openFile = this.createMenuItem(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File..."), 'workbench.action.files.openFile');
|
|
}
|
|
|
|
const openRecentMenu = new Menu();
|
|
this.setOpenRecentMenu(openRecentMenu);
|
|
const openRecent = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent")), submenu: openRecentMenu, enabled: openRecentMenu.items.length > 0 });
|
|
|
|
const saveFile = this.createMenuItem(nls.localize({ key: 'miSave', comment: ['&& denotes a mnemonic'] }, "&&Save"), 'workbench.action.files.save', this.windowsService.getWindowCount() > 0);
|
|
const saveFileAs = this.createMenuItem(nls.localize({ key: 'miSaveAs', comment: ['&& denotes a mnemonic'] }, "Save &&As..."), 'workbench.action.files.saveAs', this.windowsService.getWindowCount() > 0);
|
|
const saveAllFiles = this.createMenuItem(nls.localize({ key: 'miSaveAll', comment: ['&& denotes a mnemonic'] }, "Save A&&ll"), 'workbench.action.files.saveAll', this.windowsService.getWindowCount() > 0);
|
|
|
|
const preferences = this.getPreferencesMenu();
|
|
|
|
const newWindow = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "&&New Window")), accelerator: this.getAccelerator('workbench.action.newWindow'), click: () => this.windowsService.openNewWindow() });
|
|
const revertFile = this.createMenuItem(nls.localize({ key: 'miRevert', comment: ['&& denotes a mnemonic'] }, "Revert F&&ile"), 'workbench.action.files.revert', this.windowsService.getWindowCount() > 0);
|
|
const closeWindow = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Close &&Window")), accelerator: this.getAccelerator('workbench.action.closeWindow'), click: () => this.windowsService.getLastActiveWindow().win.close(), enabled: this.windowsService.getWindowCount() > 0 });
|
|
|
|
const closeFolder = this.createMenuItem(nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), 'workbench.action.closeFolder');
|
|
const closeEditor = this.createMenuItem(nls.localize({ key: 'miCloseEditor', comment: ['&& denotes a mnemonic'] }, "Close &&Editor"), 'workbench.action.closeActiveEditor');
|
|
|
|
const exit = this.createMenuItem(nls.localize({ key: 'miExit', comment: ['&& denotes a mnemonic'] }, "E&&xit"), () => this.quit());
|
|
|
|
arrays.coalesce([
|
|
newFile,
|
|
newWindow,
|
|
__separator__(),
|
|
platform.isMacintosh ? open : null,
|
|
!platform.isMacintosh ? openFile : null,
|
|
!platform.isMacintosh ? openFolder : null,
|
|
openRecent,
|
|
__separator__(),
|
|
saveFile,
|
|
saveFileAs,
|
|
saveAllFiles,
|
|
__separator__(),
|
|
!platform.isMacintosh ? preferences : null,
|
|
!platform.isMacintosh ? __separator__() : null,
|
|
revertFile,
|
|
closeEditor,
|
|
closeFolder,
|
|
!platform.isMacintosh ? closeWindow : null,
|
|
!platform.isMacintosh ? __separator__() : null,
|
|
!platform.isMacintosh ? exit : null
|
|
]).forEach((item) => fileMenu.append(item));
|
|
}
|
|
|
|
private getPreferencesMenu(): Electron.MenuItem {
|
|
const userSettings = this.createMenuItem(nls.localize({ key: 'miOpenSettings', comment: ['&& denotes a mnemonic'] }, "&&User Settings"), 'workbench.action.openGlobalSettings');
|
|
const workspaceSettings = this.createMenuItem(nls.localize({ key: 'miOpenWorkspaceSettings', comment: ['&& denotes a mnemonic'] }, "&&Workspace Settings"), 'workbench.action.openWorkspaceSettings');
|
|
const kebindingSettings = this.createMenuItem(nls.localize({ key: 'miOpenKeymap', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts"), 'workbench.action.openGlobalKeybindings');
|
|
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();
|
|
preferencesMenu.append(userSettings);
|
|
preferencesMenu.append(workspaceSettings);
|
|
preferencesMenu.append(__separator__());
|
|
preferencesMenu.append(kebindingSettings);
|
|
preferencesMenu.append(__separator__());
|
|
preferencesMenu.append(snippetsSettings);
|
|
preferencesMenu.append(__separator__());
|
|
preferencesMenu.append(colorThemeSelection);
|
|
preferencesMenu.append(iconThemeSelection);
|
|
|
|
return new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miPreferences', comment: ['&& denotes a mnemonic'] }, "&&Preferences")), submenu: preferencesMenu });
|
|
}
|
|
|
|
private quit(): void {
|
|
|
|
// If the user selected to exit from an extension development host window, do not quit, but just
|
|
// close the window unless this is the last window that is opened.
|
|
const vscodeWindow = this.windowsService.getFocusedWindow();
|
|
if (vscodeWindow && vscodeWindow.isPluginDevelopmentHost && this.windowsService.getWindowCount() > 1) {
|
|
vscodeWindow.win.close();
|
|
}
|
|
|
|
// Otherwise: normal quit
|
|
else {
|
|
setTimeout(() => {
|
|
this.isQuitting = true;
|
|
|
|
app.quit();
|
|
}, 10 /* delay this because there is an issue with quitting while the menu is open */);
|
|
}
|
|
}
|
|
|
|
private setOpenRecentMenu(openRecentMenu: Electron.Menu): void {
|
|
openRecentMenu.append(this.createMenuItem(nls.localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"), 'workbench.action.reopenClosedEditor'));
|
|
|
|
const {folders, files} = this.getOpenedPathsList();
|
|
|
|
// Folders
|
|
if (folders.length > 0) {
|
|
openRecentMenu.append(__separator__());
|
|
|
|
for (let i = 0; i < VSCodeMenu.MAX_MENU_RECENT_ENTRIES && i < folders.length; i++) {
|
|
openRecentMenu.append(this.createOpenRecentMenuItem(folders[i]));
|
|
}
|
|
}
|
|
|
|
// Files
|
|
if (files.length > 0) {
|
|
openRecentMenu.append(__separator__());
|
|
|
|
for (let i = 0; i < VSCodeMenu.MAX_MENU_RECENT_ENTRIES && i < files.length; i++) {
|
|
openRecentMenu.append(this.createOpenRecentMenuItem(files[i]));
|
|
}
|
|
}
|
|
|
|
if (folders.length || files.length) {
|
|
openRecentMenu.append(__separator__());
|
|
openRecentMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miClearItems', comment: ['&& denotes a mnemonic'] }, "&&Clear Items")), click: () => this.clearOpenedPathsList() }));
|
|
}
|
|
}
|
|
|
|
private createOpenRecentMenuItem(path: string): Electron.MenuItem {
|
|
return new MenuItem({
|
|
label: unMnemonicLabel(path), click: () => {
|
|
const success = !!this.windowsService.open({ cli: this.envService.cliArgs, pathsToOpen: [path] });
|
|
if (!success) {
|
|
this.removeFromOpenedPathsList(path);
|
|
this.updateMenu();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private createRoleMenuItem(label: string, actionId: string, role: Electron.MenuItemRole): Electron.MenuItem {
|
|
const options: Electron.MenuItemOptions = {
|
|
label: mnemonicLabel(label),
|
|
accelerator: this.getAccelerator(actionId),
|
|
role,
|
|
enabled: true
|
|
};
|
|
|
|
return new MenuItem(options);
|
|
}
|
|
|
|
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;
|
|
let selectAll: Electron.MenuItem;
|
|
|
|
if (platform.isMacintosh) {
|
|
undo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', (devTools) => devTools.undo());
|
|
redo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', (devTools) => devTools.redo());
|
|
cut = this.createRoleMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "&&Cut"), 'editor.action.clipboardCutAction', 'cut');
|
|
copy = this.createRoleMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "C&&opy"), 'editor.action.clipboardCopyAction', 'copy');
|
|
paste = this.createRoleMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction', 'paste');
|
|
selectAll = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll', (devTools) => devTools.selectAll());
|
|
} else {
|
|
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');
|
|
cut = this.createMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "&&Cut"), 'editor.action.clipboardCutAction');
|
|
copy = this.createMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "C&&opy"), 'editor.action.clipboardCopyAction');
|
|
paste = this.createMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction');
|
|
selectAll = this.createMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll');
|
|
}
|
|
|
|
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');
|
|
const findInFiles = this.createMenuItem(nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files"), 'workbench.view.search');
|
|
const replaceInFiles = this.createMenuItem(nls.localize({ key: 'miReplaceInFiles', comment: ['&& denotes a mnemonic'] }, "Replace &&in Files"), 'workbench.action.replaceInFiles');
|
|
|
|
[
|
|
undo,
|
|
redo,
|
|
__separator__(),
|
|
cut,
|
|
copy,
|
|
paste,
|
|
selectAll,
|
|
__separator__(),
|
|
find,
|
|
replace,
|
|
__separator__(),
|
|
findInFiles,
|
|
replaceInFiles
|
|
].forEach(item => winLinuxEditMenu.append(item));
|
|
}
|
|
|
|
private setViewMenu(viewMenu: Electron.Menu): void {
|
|
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');
|
|
const git = this.createMenuItem(nls.localize({ key: 'miViewGit', comment: ['&& denotes a mnemonic'] }, "&&Git"), 'workbench.view.git');
|
|
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');
|
|
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');
|
|
|
|
const commands = this.createMenuItem(nls.localize({ key: 'miCommandPalette', comment: ['&& denotes a mnemonic'] }, "&&Command Palette..."), 'workbench.action.showCommands');
|
|
|
|
const fullscreen = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen")), accelerator: this.getAccelerator('workbench.action.toggleFullScreen'), click: () => this.windowsService.getLastActiveWindow().toggleFullScreen(), enabled: this.windowsService.getWindowCount() > 0 });
|
|
const toggleMenuBar = this.createMenuItem(nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar"), 'workbench.action.toggleMenuBar');
|
|
const splitEditor = this.createMenuItem(nls.localize({ key: 'miSplitEditor', comment: ['&& denotes a mnemonic'] }, "Split &&Editor"), 'workbench.action.splitEditor');
|
|
const toggleSidebar = this.createMenuItem(nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar"), 'workbench.action.toggleSidebarVisibility');
|
|
const moveSidebar = this.createMenuItem(nls.localize({ key: 'miMoveSidebar', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar"), 'workbench.action.toggleSidebarPosition');
|
|
const togglePanel = this.createMenuItem(nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel"), 'workbench.action.togglePanel');
|
|
const toggleStatusbar = this.createMenuItem(nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar"), 'workbench.action.toggleStatusbarVisibility');
|
|
|
|
const toggleWordWrap = this.createMenuItem(nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Word Wrap"), 'editor.action.toggleWordWrap');
|
|
const toggleRenderWhitespace = this.createMenuItem(nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"), 'editor.action.toggleRenderWhitespace');
|
|
const toggleRenderControlCharacters = this.createMenuItem(nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"), 'editor.action.toggleRenderControlCharacter');
|
|
|
|
|
|
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');
|
|
|
|
arrays.coalesce([
|
|
commands,
|
|
__separator__(),
|
|
explorer,
|
|
search,
|
|
git,
|
|
debug,
|
|
extensions,
|
|
__separator__(),
|
|
output,
|
|
problems,
|
|
debugConsole,
|
|
integratedTerminal,
|
|
__separator__(),
|
|
fullscreen,
|
|
platform.isWindows || platform.isLinux ? toggleMenuBar : void 0,
|
|
__separator__(),
|
|
splitEditor,
|
|
moveSidebar,
|
|
toggleSidebar,
|
|
togglePanel,
|
|
toggleStatusbar,
|
|
__separator__(),
|
|
toggleWordWrap,
|
|
toggleRenderWhitespace,
|
|
toggleRenderControlCharacters,
|
|
__separator__(),
|
|
zoomIn,
|
|
zoomOut,
|
|
resetZoom
|
|
]).forEach((item) => viewMenu.append(item));
|
|
}
|
|
|
|
private setGotoMenu(gotoMenu: Electron.Menu): void {
|
|
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');
|
|
|
|
const switchEditorMenu = new Menu();
|
|
|
|
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');
|
|
|
|
[
|
|
nextEditor,
|
|
previousEditor,
|
|
__separator__(),
|
|
nextEditorInGroup,
|
|
previousEditorInGroup
|
|
].forEach(item => switchEditorMenu.append(item));
|
|
|
|
const switchEditor = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor")), submenu: switchEditorMenu, enabled: true });
|
|
|
|
const switchGroupMenu = new Menu();
|
|
|
|
const focusFirstGroup = this.createMenuItem(nls.localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "&&Left Group"), 'workbench.action.focusFirstEditorGroup');
|
|
const focusSecondGroup = this.createMenuItem(nls.localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "&&Center Group"), 'workbench.action.focusSecondEditorGroup');
|
|
const focusThirdGroup = this.createMenuItem(nls.localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "&&Right Group"), 'workbench.action.focusThirdEditorGroup');
|
|
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');
|
|
|
|
[
|
|
focusFirstGroup,
|
|
focusSecondGroup,
|
|
focusThirdGroup,
|
|
__separator__(),
|
|
nextGroup,
|
|
previousGroup
|
|
].forEach(item => switchGroupMenu.append(item));
|
|
|
|
const switchGroup = new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group")), submenu: switchGroupMenu, enabled: true });
|
|
|
|
const gotoFile = this.createMenuItem(nls.localize({ key: 'miGotoFile', comment: ['&& denotes a mnemonic'] }, "Go to &&File..."), 'workbench.action.quickOpen');
|
|
const gotoSymbol = this.createMenuItem(nls.localize({ key: 'miGotoSymbol', comment: ['&& denotes a mnemonic'] }, "Go to &&Symbol..."), 'workbench.action.gotoSymbol');
|
|
const gotoDefinition = this.createMenuItem(nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition"), 'editor.action.goToDeclaration');
|
|
const gotoLine = this.createMenuItem(nls.localize({ key: 'miGotoLine', comment: ['&& denotes a mnemonic'] }, "Go to &&Line..."), 'workbench.action.gotoLine');
|
|
|
|
[
|
|
back,
|
|
forward,
|
|
__separator__(),
|
|
switchEditor,
|
|
switchGroup,
|
|
__separator__(),
|
|
gotoFile,
|
|
gotoSymbol,
|
|
gotoDefinition,
|
|
gotoLine
|
|
].forEach(item => gotoMenu.append(item));
|
|
}
|
|
|
|
private setMacWindowMenu(macWindowMenu: Electron.Menu): void {
|
|
const minimize = new MenuItem({ label: nls.localize('mMinimize', "Minimize"), role: 'minimize', accelerator: 'Command+M', enabled: this.windowsService.getWindowCount() > 0 });
|
|
const close = new MenuItem({ label: nls.localize('mClose', "Close"), role: 'close', accelerator: 'Command+W', enabled: this.windowsService.getWindowCount() > 0 });
|
|
const bringAllToFront = new MenuItem({ label: nls.localize('mBringToFront', "Bring All to Front"), role: 'front', enabled: this.windowsService.getWindowCount() > 0 });
|
|
|
|
[
|
|
minimize,
|
|
close,
|
|
__separator__(),
|
|
bringAllToFront
|
|
].forEach(item => macWindowMenu.append(item));
|
|
}
|
|
|
|
private toggleDevTools(): void {
|
|
const w = this.windowsService.getFocusedWindow();
|
|
if (w && w.win) {
|
|
w.win.webContents.toggleDevTools();
|
|
}
|
|
}
|
|
|
|
private setHelpMenu(helpMenu: Electron.Menu): void {
|
|
const toggleDevToolsItem = new MenuItem({
|
|
label: mnemonicLabel(nls.localize({ key: 'miToggleDevTools', comment: ['&& denotes a mnemonic'] }, "&&Toggle Developer Tools")),
|
|
accelerator: this.getAccelerator('workbench.action.toggleDevTools'),
|
|
click: () => this.toggleDevTools(),
|
|
enabled: (this.windowsService.getWindowCount() > 0)
|
|
});
|
|
|
|
const issueUrl = generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date);
|
|
|
|
arrays.coalesce([
|
|
this.envService.product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.openUrl(this.envService.product.documentationUrl, 'openDocumentationUrl') }) : null,
|
|
this.envService.product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.openUrl(this.envService.product.releaseNotesUrl, 'openReleaseNotesUrl') }) : null,
|
|
(this.envService.product.documentationUrl || this.envService.product.releaseNotesUrl) ? __separator__() : null,
|
|
this.envService.product.twitterUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(this.envService.product.twitterUrl, 'openTwitterUrl') }) : null,
|
|
this.envService.product.requestFeatureUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(this.envService.product.requestFeatureUrl, 'openUserVoiceUrl') }) : null,
|
|
this.envService.product.reportIssueUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReportIssues', comment: ['&& denotes a mnemonic'] }, "Report &&Issues")), click: () => this.openUrl(issueUrl, 'openReportIssues') }) : null,
|
|
(this.envService.product.twitterUrl || this.envService.product.requestFeatureUrl || this.envService.product.reportIssueUrl) ? __separator__() : null,
|
|
this.envService.product.licenseUrl ? new MenuItem({
|
|
label: mnemonicLabel(nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "&&View License")), click: () => {
|
|
if (platform.language) {
|
|
const queryArgChar = this.envService.product.licenseUrl.indexOf('?') > 0 ? '&' : '?';
|
|
this.openUrl(`${this.envService.product.licenseUrl}${queryArgChar}lang=${platform.language}`, 'openLicenseUrl');
|
|
} else {
|
|
this.openUrl(this.envService.product.licenseUrl, 'openLicenseUrl');
|
|
}
|
|
}
|
|
}) : null,
|
|
this.envService.product.privacyStatementUrl ? new MenuItem({
|
|
label: mnemonicLabel(nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "&&Privacy Statement")), click: () => {
|
|
if (platform.language) {
|
|
const queryArgChar = this.envService.product.licenseUrl.indexOf('?') > 0 ? '&' : '?';
|
|
this.openUrl(`${this.envService.product.privacyStatementUrl}${queryArgChar}lang=${platform.language}`, 'openPrivacyStatement');
|
|
} else {
|
|
this.openUrl(this.envService.product.privacyStatementUrl, 'openPrivacyStatement');
|
|
}
|
|
}
|
|
}) : null,
|
|
(this.envService.product.licenseUrl || this.envService.product.privacyStatementUrl) ? __separator__() : null,
|
|
toggleDevToolsItem,
|
|
]).forEach((item) => helpMenu.append(item));
|
|
|
|
if (!platform.isMacintosh) {
|
|
const updateMenuItems = this.getUpdateMenuItems();
|
|
if (updateMenuItems.length) {
|
|
helpMenu.append(__separator__());
|
|
updateMenuItems.forEach(i => helpMenu.append(i));
|
|
}
|
|
|
|
helpMenu.append(__separator__());
|
|
helpMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")), click: () => this.openAboutDialog() }));
|
|
}
|
|
}
|
|
|
|
private getUpdateMenuItems(): Electron.MenuItem[] {
|
|
switch (this.updateService.state) {
|
|
case UpdateState.Uninitialized:
|
|
return [];
|
|
|
|
case UpdateState.UpdateDownloaded:
|
|
const update = this.updateService.availableUpdate;
|
|
return [new MenuItem({
|
|
label: nls.localize('miRestartToUpdate', "Restart To Update..."), click: () => {
|
|
this.reportMenuActionTelemetry('RestartToUpdate');
|
|
update.quitAndUpdate();
|
|
}
|
|
})];
|
|
|
|
case UpdateState.CheckingForUpdate:
|
|
return [new MenuItem({ label: nls.localize('miCheckingForUpdates', "Checking For Updates..."), enabled: false })];
|
|
|
|
case UpdateState.UpdateAvailable:
|
|
if (platform.isLinux) {
|
|
const update = this.updateService.availableUpdate;
|
|
return [new MenuItem({
|
|
label: nls.localize('miDownloadUpdate', "Download Available Update"), click: () => {
|
|
update.quitAndUpdate();
|
|
}
|
|
})];
|
|
}
|
|
|
|
const updateAvailableLabel = platform.isWindows
|
|
? nls.localize('miDownloadingUpdate', "Downloading Update...")
|
|
: nls.localize('miInstallingUpdate', "Installing Update...");
|
|
|
|
return [new MenuItem({ label: updateAvailableLabel, enabled: false })];
|
|
|
|
default:
|
|
const result = [new MenuItem({
|
|
label: nls.localize('miCheckForUpdates', "Check For Updates..."), click: () => setTimeout(() => {
|
|
this.reportMenuActionTelemetry('CheckForUpdate');
|
|
this.updateService.checkForUpdates(true);
|
|
}, 0)
|
|
})];
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
private createMenuItem(label: string, actionId: string, enabled?: boolean): Electron.MenuItem;
|
|
private createMenuItem(label: string, click: () => void, enabled?: boolean): Electron.MenuItem;
|
|
private createMenuItem(arg1: string, arg2: any, arg3?: boolean): Electron.MenuItem {
|
|
const label = mnemonicLabel(arg1);
|
|
const click: () => void = (typeof arg2 === 'function') ? arg2 : () => this.windowsService.sendToFocused('vscode:runAction', arg2);
|
|
const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsService.getWindowCount() > 0;
|
|
|
|
let actionId: string;
|
|
if (typeof arg2 === 'string') {
|
|
actionId = arg2;
|
|
}
|
|
|
|
const options: Electron.MenuItemOptions = {
|
|
label: label,
|
|
accelerator: this.getAccelerator(actionId),
|
|
click: click,
|
|
enabled: enabled
|
|
};
|
|
|
|
return new MenuItem(options);
|
|
}
|
|
|
|
private createDevToolsAwareMenuItem(label: string, actionId: string, devToolsFocusedFn: (contents: Electron.WebContents) => void): Electron.MenuItem {
|
|
return new MenuItem({
|
|
label: mnemonicLabel(label),
|
|
accelerator: this.getAccelerator(actionId),
|
|
enabled: this.windowsService.getWindowCount() > 0,
|
|
click: () => {
|
|
const windowInFocus = this.windowsService.getFocusedWindow();
|
|
if (!windowInFocus) {
|
|
return;
|
|
}
|
|
|
|
if (windowInFocus.win.webContents.isDevToolsFocused()) {
|
|
devToolsFocusedFn(windowInFocus.win.webContents.devToolsWebContents);
|
|
} else {
|
|
this.windowsService.sendToFocused('vscode:runAction', actionId);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private getAccelerator(actionId: string): string {
|
|
if (actionId) {
|
|
const resolvedKeybinding = this.mapResolvedKeybindingToActionId[actionId];
|
|
if (resolvedKeybinding) {
|
|
return resolvedKeybinding; // keybinding is fully resolved
|
|
}
|
|
|
|
if (!this.keybindingsResolved) {
|
|
this.actionIdKeybindingRequests.push(actionId); // keybinding needs to be resolved
|
|
}
|
|
|
|
const lastKnownKeybinding = this.mapLastKnownKeybindingToActionId[actionId];
|
|
|
|
return lastKnownKeybinding; // return the last known keybining (chance of mismatch is very low unless it changed)
|
|
}
|
|
|
|
return void (0);
|
|
}
|
|
|
|
private openAboutDialog(): void {
|
|
const lastActiveWindow = this.windowsService.getFocusedWindow() || this.windowsService.getLastActiveWindow();
|
|
|
|
dialog.showMessageBox(lastActiveWindow && lastActiveWindow.win, {
|
|
title: this.envService.product.nameLong,
|
|
type: 'info',
|
|
message: this.envService.product.nameLong,
|
|
detail: nls.localize('aboutDetail',
|
|
"\nVersion {0}\nCommit {1}\nDate {2}\nShell {3}\nRenderer {4}\nNode {5}",
|
|
app.getVersion(),
|
|
this.envService.product.commit || 'Unknown',
|
|
this.envService.product.date || 'Unknown',
|
|
process.versions['electron'],
|
|
process.versions['chrome'],
|
|
process.versions['node']
|
|
),
|
|
buttons: [nls.localize('okButton', "OK")],
|
|
noLink: true
|
|
}, (result) => null);
|
|
|
|
this.reportMenuActionTelemetry('showAboutDialog');
|
|
}
|
|
|
|
private openUrl(url: string, id: string): void {
|
|
shell.openExternal(url);
|
|
this.reportMenuActionTelemetry(id);
|
|
}
|
|
|
|
private reportMenuActionTelemetry(id: string): void {
|
|
this.windowsService.sendToFocused('vscode:telemetry', { eventName: 'workbenchActionExecuted', data: { id, from: 'menu' } });
|
|
}
|
|
}
|
|
|
|
function __separator__(): Electron.MenuItem {
|
|
return new MenuItem({ type: 'separator' });
|
|
}
|
|
|
|
function mnemonicLabel(label: string): string {
|
|
if (platform.isMacintosh) {
|
|
return label.replace(/\(&&\w\)|&&/g, ''); // no mnemonic support on mac
|
|
}
|
|
|
|
return label.replace(/&&/g, '&');
|
|
}
|
|
|
|
function unMnemonicLabel(label: string): string {
|
|
if (platform.isMacintosh) {
|
|
return label; // no mnemonic support on mac
|
|
}
|
|
|
|
return label.replace(/&/g, '&&');
|
|
} |