SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- // {{SQL CARBON EDIT}} -->
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
</head>
<body class="monaco-shell vs-dark" aria-label="">
<script src="preload.js"></script>
</body>
<!-- // {{SQL CARBON EDIT}} -->
<script src="../../../../sql/parts/grid/load/loadJquery.js"></script>
<script src="../../../../../node_modules/slickgrid/lib/jquery.event.drag-2.2.js"></script>
<script src="../../../../../node_modules/slickgrid/lib/jquery-ui-1.9.2.js"></script>
<!-- Startup via index.js -->
<script src="index.js"></script>
</html>

View File

@@ -0,0 +1,268 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Warning: Do not use the `let` declarator in this file, it breaks our minification
'use strict';
if (window.location.search.indexOf('prof-startup') >= 0) {
var profiler = require('v8-profiler');
profiler.startProfiling('renderer', true);
}
/*global window,document,define,Monaco_Loader_Init*/
const startTimer = require('../../../base/node/startupTimers').startTimer;
const path = require('path');
const electron = require('electron');
const remote = electron.remote;
const ipc = electron.ipcRenderer;
process.lazyEnv = new Promise(function (resolve) {
const handle = setTimeout(function () {
resolve();
console.warn('renderer did not receive lazyEnv in time');
}, 10000);
ipc.once('vscode:acceptShellEnv', function (event, shellEnv) {
clearTimeout(handle);
assign(process.env, shellEnv);
resolve(process.env);
});
ipc.send('vscode:fetchShellEnv', remote.getCurrentWindow().id);
});
function onError(error, enableDeveloperTools) {
if (enableDeveloperTools) {
remote.getCurrentWebContents().openDevTools();
}
console.error('[uncaught exception]: ' + error);
if (error.stack) {
console.error(error.stack);
}
}
function assign(destination, source) {
return Object.keys(source)
.reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
}
function parseURLQueryArgs() {
const search = window.location.search || '';
return search.split(/[?&]/)
.filter(function (param) { return !!param; })
.map(function (param) { return param.split('='); })
.filter(function (param) { return param.length === 2; })
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
}
function createScript(src, onload) {
const script = document.createElement('script');
script.src = src;
script.addEventListener('load', onload);
const head = document.getElementsByTagName('head')[0];
head.insertBefore(script, head.lastChild);
}
function uriFromPath(_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/');
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName;
}
return encodeURI('file://' + pathName);
}
function registerListeners(enableDeveloperTools) {
// Devtools & reload support
var listener;
if (enableDeveloperTools) {
const extractKey = function (e) {
return [
e.ctrlKey ? 'ctrl-' : '',
e.metaKey ? 'meta-' : '',
e.altKey ? 'alt-' : '',
e.shiftKey ? 'shift-' : '',
e.keyCode
].join('');
};
const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
listener = function (e) {
const key = extractKey(e);
if (key === TOGGLE_DEV_TOOLS_KB) {
remote.getCurrentWebContents().toggleDevTools();
} else if (key === RELOAD_KB) {
remote.getCurrentWindow().reload();
}
};
window.addEventListener('keydown', listener);
}
process.on('uncaughtException', function (error) { onError(error, enableDeveloperTools); });
return function () {
if (listener) {
window.removeEventListener('keydown', listener);
listener = void 0;
}
};
}
// {{SQL CARBON EDIT}}
/* eslint-disable */
// SQL global imports
require('slickgrid/slick.core');
const Slick = window.Slick;
require('slickgrid/slick.grid');
require('slickgrid/slick.editors');;
require('reflect-metadata');
require('zone.js');
const _ = require('underscore')._;
/* eslint-enable */
function main() {
const webFrame = require('electron').webFrame;
const args = parseURLQueryArgs();
const configuration = JSON.parse(args['config'] || '{}') || {};
// Correctly inherit the parent's environment
assign(process.env, configuration.userEnv);
// Get the nls configuration into the process.env as early as possible.
var nlsConfig = { availableLanguages: {} };
const config = process.env['VSCODE_NLS_CONFIG'];
if (config) {
process.env['VSCODE_NLS_CONFIG'] = config;
try {
nlsConfig = JSON.parse(config);
} catch (e) { /*noop*/ }
}
var locale = nlsConfig.availableLanguages['*'] || 'en';
if (locale === 'zh-tw') {
locale = 'zh-Hant';
} else if (locale === 'zh-cn') {
locale = 'zh-Hans';
}
window.document.documentElement.setAttribute('lang', locale);
const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath;
const unbind = registerListeners(enableDeveloperTools);
// disable pinch zoom & apply zoom level early to avoid glitches
const zoomLevel = configuration.zoomLevel;
webFrame.setVisualZoomLevelLimits(1, 1);
if (typeof zoomLevel === 'number' && zoomLevel !== 0) {
webFrame.setZoomLevel(zoomLevel);
}
// {{SQL CARBON EDIT}}
// Load the loader and start loading the workbench
const appRoot = uriFromPath(configuration.appRoot);
const rootUrl = appRoot + '/out';
createScript(appRoot + '/node_modules/chart.js/dist/Chart.js', undefined);
function onLoader() {
window.nodeRequire = require.__$__nodeRequire;
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
loaderTimer.stop();
window.MonacoEnvironment = {};
const onNodeCachedData = window.MonacoEnvironment.onNodeCachedData = [];
// {{SQL CARBON EDIT}}
require.config({
baseUrl: rootUrl,
'vs/nls': nlsConfig,
recordStats: !!configuration.performance,
nodeCachedDataDir: configuration.nodeCachedDataDir,
onNodeCachedData: function () { onNodeCachedData.push(arguments); },
nodeModules: [
'@angular/common',
'@angular/core',
'@angular/forms',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/router',
'angular2-grid',
'pretty-data',
'html-query-plan',
'ng2-charts/ng2-charts',
'rangy',
'rangy/lib/rangy-textrange',
'rxjs/Observable',
'rxjs/Subject',
'rxjs/Observer'
]
});
if (nlsConfig.pseudo) {
require(['vs/nls'], function (nlsPlugin) {
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
});
}
// Perf Counters
const timers = window.MonacoEnvironment.timers = {
isInitialStartup: !!configuration.isInitialStartup,
hasAccessibilitySupport: !!configuration.accessibilitySupport,
start: configuration.perfStartTime,
appReady: configuration.perfAppReady,
windowLoad: configuration.perfWindowLoadTime,
beforeLoadWorkbenchMain: Date.now()
};
const workbenchMainTimer = startTimer('load:workbench.main');
require([
'vs/workbench/workbench.main',
'vs/nls!vs/workbench/workbench.main',
'vs/css!vs/workbench/workbench.main'
], function () {
workbenchMainTimer.stop();
timers.afterLoadWorkbenchMain = Date.now();
process.lazyEnv.then(function () {
require('vs/workbench/electron-browser/main')
.startup(configuration)
.done(function () {
unbind(); // since the workbench is running, unbind our developer related listeners and let the workbench handle them
}, function (error) {
onError(error, enableDeveloperTools);
});
});
});
}
// In the bundled version the nls plugin is packaged with the loader so the NLS Plugins
// loads as soon as the loader loads. To be able to have pseudo translation
const loaderTimer = startTimer('load:loader');
if (typeof Monaco_Loader_Init === 'function') {
const loader = Monaco_Loader_Init();
//eslint-disable-next-line no-global-assign
define = loader.define; require = loader.require;
onLoader();
} else {
createScript(rootUrl + '/vs/loader.js', onLoader);
}
}
main();

View File

@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
(function() {
function getConfig() {
const queryParams = window.location.search.substring(1).split('&');
for (var i = 0; i < queryParams.length; i++) {
var kv = queryParams[i].split('=');
if (kv[0] === 'config' && kv[1]) {
return JSON.parse(decodeURIComponent(kv[1]));
}
}
return {};
}
try {
const config = getConfig();
const document = window.document;
// sets the base theme class ('vs', 'vs-dark', 'hc-black')
const baseTheme = config.baseTheme || 'vs';
document.body.className = 'monaco-shell ' + baseTheme;
// adds a stylesheet with the backgrdound color
var backgroundColor = config.backgroundColor;
if (!backgroundColor) {
backgroundColor = baseTheme === 'hc-black' ? '#000000' : (baseTheme === 'vs' ? '#FFFFFF' : '#1E1E1E');
}
const foregroundColor = baseTheme === 'hc-black' ? '#FFFFFF' : (baseTheme === 'vs' ? '#6C6C6C' : '#CCCCCC');
const style = document.createElement('style');
style.innerHTML = '.monaco-shell { background-color:' + backgroundColor + '; color:' + foregroundColor + '; }';
document.head.appendChild(style);
} catch (error) {
console.error(error);
}
})();

View File

@@ -0,0 +1,423 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions';
import { NoEditorsVisibleContext, InZenModeContext } from 'vs/workbench/electron-browser/workbench';
import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows';
import { IListService, ListFocusContext } from 'vs/platform/list/browser/listService';
import { List } from 'vs/base/browser/ui/list/listWidget';
import errors = require('vs/base/common/errors');
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import URI from 'vs/base/common/uri';
import { IEditorOptions, Position as EditorPosition } from 'vs/platform/editor/common/editor';
// --- List Commands
export function registerCommands(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusDown',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.DownArrow,
mac: {
primary: KeyCode.DownArrow,
secondary: [KeyMod.WinCtrl | KeyCode.KEY_N]
},
handler: (accessor, arg2) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
const count = typeof arg2 === 'number' ? arg2 : 1;
// List
if (focused instanceof List) {
const list = focused;
list.focusNext(count);
list.reveal(list.getFocus()[0]);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusNext(count, { origin: 'keyboard' });
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusUp',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.UpArrow,
mac: {
primary: KeyCode.UpArrow,
secondary: [KeyMod.WinCtrl | KeyCode.KEY_P]
},
handler: (accessor, arg2) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
const count = typeof arg2 === 'number' ? arg2 : 1;
// List
if (focused instanceof List) {
const list = focused;
list.focusPrevious(count);
list.reveal(list.getFocus()[0]);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusPrevious(count, { origin: 'keyboard' });
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.collapse',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.LeftArrow,
mac: {
primary: KeyCode.LeftArrow,
secondary: [KeyMod.CtrlCmd | KeyCode.UpArrow]
},
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// Tree only
if (focused && !(focused instanceof List)) {
const tree = focused;
const focus = tree.getFocus();
tree.collapse(focus).then(didCollapse => {
if (focus && !didCollapse) {
tree.focusParent({ origin: 'keyboard' });
return tree.reveal(tree.getFocus());
}
return void 0;
}).done(null, errors.onUnexpectedError);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.expand',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.RightArrow,
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// Tree only
if (focused && !(focused instanceof List)) {
const tree = focused;
const focus = tree.getFocus();
tree.expand(focus).then(didExpand => {
if (focus && !didExpand) {
tree.focusFirstChild({ origin: 'keyboard' });
return tree.reveal(tree.getFocus());
}
return void 0;
}).done(null, errors.onUnexpectedError);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusPageUp',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.PageUp,
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// List
if (focused instanceof List) {
const list = focused;
list.focusPreviousPage();
list.reveal(list.getFocus()[0]);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusPreviousPage({ origin: 'keyboard' });
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusPageDown',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.PageDown,
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// List
if (focused instanceof List) {
const list = focused;
list.focusNextPage();
list.reveal(list.getFocus()[0]);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusNextPage({ origin: 'keyboard' });
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusFirst',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.Home,
handler: accessor => listFocusFirst(accessor)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusFirstChild',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: null,
handler: accessor => listFocusFirst(accessor, { fromFocused: true })
});
function listFocusFirst(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// List
if (focused instanceof List) {
const list = focused;
list.setFocus([0]);
list.reveal(0);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusFirst({ origin: 'keyboard' }, options && options.fromFocused ? tree.getFocus() : void 0);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusLast',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.End,
handler: accessor => listFocusLast(accessor)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusLastChild',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: null,
handler: accessor => listFocusLast(accessor, { fromFocused: true })
});
function listFocusLast(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// List
if (focused instanceof List) {
const list = focused;
list.setFocus([list.length - 1]);
list.reveal(list.length - 1);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusLast({ origin: 'keyboard' }, options && options.fromFocused ? tree.getFocus() : void 0);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.select',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.Enter,
secondary: [KeyMod.CtrlCmd | KeyCode.Enter],
mac: {
primary: KeyCode.Enter,
secondary: [KeyMod.CtrlCmd | KeyCode.Enter, KeyMod.CtrlCmd | KeyCode.DownArrow]
},
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// List
if (focused instanceof List) {
const list = focused;
list.setSelection(list.getFocus());
list.open(list.getFocus());
}
// Tree
else if (focused) {
const tree = focused;
const focus = tree.getFocus();
if (focus) {
tree.setSelection([focus], { origin: 'keyboard' });
}
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.toggleExpand',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.Space,
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// Tree only
if (focused && !(focused instanceof List)) {
const tree = focused;
const focus = tree.getFocus();
if (focus) {
tree.toggleExpansion(focus);
}
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.clear',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ListFocusContext,
primary: KeyCode.Escape,
handler: (accessor) => {
const listService = accessor.get(IListService);
const focused = listService.getFocused();
// Tree only
if (focused && !(focused instanceof List)) {
const tree = focused;
if (tree.getSelection().length) {
tree.clearSelection({ origin: 'keyboard' });
return void 0;
}
if (tree.getFocus()) {
tree.clearFocus({ origin: 'keyboard' });
return void 0;
}
}
}
});
// --- commands
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.closeWindow', // close the window when the last editor is closed by reusing the same keybinding
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: NoEditorsVisibleContext,
primary: KeyMod.CtrlCmd | KeyCode.KEY_W,
handler: accessor => {
const windowService = accessor.get(IWindowService);
windowService.closeWindow();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.exitZenMode',
weight: CommonEditorRegistry.commandWeight(-1000),
handler(accessor: ServicesAccessor, configurationOrName: any) {
const partService = accessor.get(IPartService);
partService.toggleZenMode();
},
when: InZenModeContext,
primary: KeyChord(KeyCode.Escape, KeyCode.Escape)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.quit',
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
handler(accessor: ServicesAccessor) {
const windowsService = accessor.get(IWindowsService);
windowsService.quit();
},
when: void 0,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Q,
win: { primary: void 0 }
});
CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string, string, IEditorOptions, EditorPosition]) {
const editorService = accessor.get(IWorkbenchEditorService);
let [leftResource, rightResource, label, description, options, position] = args;
if (!options || typeof options !== 'object') {
options = {
preserveFocus: false
};
}
if (!label) {
label = nls.localize('diffLeftRightLabel', "{0} ⟷ {1}", leftResource.toString(true), rightResource.toString(true));
}
return editorService.openEditor({ leftResource, rightResource, label, description, options }, position).then(() => {
return void 0;
});
});
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, number]) {
const editorService = accessor.get(IWorkbenchEditorService);
const [resource, column] = args;
return editorService.openEditor({ resource }, column).then(() => {
return void 0;
});
});
}

View File

@@ -0,0 +1,398 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Registry } from 'vs/platform/registry/common/platform';
import nls = require('vs/nls');
import product from 'vs/platform/node/product';
import * as os from 'os';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction } from 'vs/workbench/electron-browser/actions';
import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { registerCommands } from 'vs/workbench/electron-browser/commands';
import { AddRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction } from 'vs/workbench/browser/actions/workspaceActions';
// Contribute Commands
registerCommands();
// Contribute Global Actions
const viewCategory = nls.localize('view', "View");
const helpCategory = nls.localize('help', "Help");
const fileCategory = nls.localize('file', "File");
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: null, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory);
if (!!product.reportIssueUrl) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportIssueAction, ReportIssueAction.ID, ReportIssueAction.LABEL), 'Help: Report Issues', helpCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueAction, ReportPerformanceIssueAction.ID, ReportPerformanceIssueAction.LABEL), 'Help: Report Performance Issue', helpCategory);
}
if (KeybindingsReferenceAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory);
}
if (OpenDocumentationUrlAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory);
}
if (OpenIntroductoryVideosUrlAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIntroductoryVideosUrlAction, OpenIntroductoryVideosUrlAction.ID, OpenIntroductoryVideosUrlAction.LABEL), 'Help: Introductory Videos', helpCategory);
}
if (OpenTipsAndTricksUrlAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory);
}
workbenchActionsRegistry.registerWorkbenchAction(
new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD]
}), 'View: Zoom In', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(
new SyncActionDescriptor(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.US_MINUS,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT],
linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] }
}), 'View: Zoom Out', viewCategory
);
workbenchActionsRegistry.registerWorkbenchAction(
new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0
}), 'View: Reset Zoom', viewCategory
);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseMessagesAction, CloseMessagesAction.ID, CloseMessagesAction.LABEL, { primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] }, MessagesVisibleContext), 'Close Notification Messages');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseEditorAction, CloseEditorAction.ID, CloseEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_W, win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_W] } }), 'View: Close Editor', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory);
if (isWindows || isLinux) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory);
}
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, null), 'View: Move to the View Above', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, null), 'View: Move to the View Below', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, null), 'View: Move to the View on the Left', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, null), 'View: Move to the View on the Right', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(IncreaseViewSizeAction, IncreaseViewSizeAction.ID, IncreaseViewSizeAction.LABEL, null), 'View: Increase Current View Size', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(DecreaseViewSizeAction, DecreaseViewSizeAction.ID, DecreaseViewSizeAction.LABEL, null), 'View: Decrease Current View Size', viewCategory);
// TODO@Ben multi root
if (product.quality !== 'stable') {
const workspacesCategory = nls.localize('workspaces', "Workspaces");
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace...', workspacesCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL), 'Workspaces: Open Workspace Configuration File', workspacesCategory);
}
// Developer related actions
const developerCategory = nls.localize('developer', "Developer");
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowStartupPerformance, ShowStartupPerformance.ID, ShowStartupPerformance.LABEL), 'Developer: Startup Performance', developerCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory);
// Configuration: Workbench
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
let workbenchProperties: { [path: string]: IJSONSchema; } = {
'workbench.editor.showTabs': {
'type': 'boolean',
'description': nls.localize('showEditorTabs', "Controls if opened editors should show in tabs or not."),
'default': true
},
'workbench.editor.tabCloseButton': {
'type': 'string',
'enum': ['left', 'right', 'off'],
'default': 'right',
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons or disables them when set to 'off'.")
},
'workbench.editor.showIcons': {
'type': 'boolean',
'description': nls.localize('showIcons', "Controls if opened editors should show with an icon or not. This requires an icon theme to be enabled as well."),
'default': true
},
'workbench.editor.enablePreview': {
'type': 'boolean',
'description': nls.localize('enablePreview', "Controls if opened editors show as preview. Preview editors are reused until they are kept (e.g. via double click or editing)."),
'default': true
},
'workbench.editor.enablePreviewFromQuickOpen': {
'type': 'boolean',
'description': nls.localize('enablePreviewFromQuickOpen', "Controls if opened editors from Quick Open show as preview. Preview editors are reused until they are kept (e.g. via double click or editing)."),
'default': true
},
'workbench.editor.openPositioning': {
'type': 'string',
'enum': ['left', 'right', 'first', 'last'],
'default': 'right',
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select 'left' or 'right' to open editors to the left or right of the current active one. Select 'first' or 'last' to open editors independently from the currently active one.")
},
'workbench.editor.revealIfOpen': {
'type': 'boolean',
'description': nls.localize('revealIfOpen', "Controls if an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, e.g. when forcing an editor to open in a specific group or to the side of the currently active group."),
'default': false
},
'workbench.commandPalette.history': {
'type': 'number',
'description': nls.localize('commandHistory', "Controls if the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."),
'default': 50
},
'workbench.commandPalette.preserveInput': {
'type': 'boolean',
'description': nls.localize('preserveInput', "Controls if the last typed input to the command palette should be restored when opening it the next time."),
'default': false
},
'workbench.quickOpen.closeOnFocusLost': {
'type': 'boolean',
'description': nls.localize('closeOnFocusLost', "Controls if Quick Open should close automatically once it loses focus."),
'default': true
},
'workbench.settings.openDefaultSettings': {
'type': 'boolean',
'description': nls.localize('openDefaultSettings', "Controls if opening settings also opens an editor showing all default settings."),
'default': true
},
'workbench.sideBar.location': {
'type': 'string',
'enum': ['left', 'right'],
'default': 'left',
'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.")
},
'workbench.statusBar.visible': {
'type': 'boolean',
'default': true,
'description': nls.localize('statusBarVisibility', "Controls the visibility of the status bar at the bottom of the workbench.")
},
'workbench.activityBar.visible': {
'type': 'boolean',
'default': true,
'description': nls.localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.")
},
'workbench.editor.closeOnFileDelete': {
'type': 'boolean',
'description': nls.localize('closeOnFileDelete', "Controls if editors showing a file should close automatically when the file is deleted or renamed by some other process. Disabling this will keep the editor open as dirty on such an event. Note that deleting from within the application will always close the editor and that dirty files will never close to preserve your data."),
'default': true
}
};
if (isMacintosh) {
workbenchProperties['workbench.fontAliasing'] = {
'type': 'string',
'enum': ['default', 'antialiased', 'none'],
'default': 'default',
'description':
nls.localize('fontAliasing',
`Controls font aliasing method in the workbench.
- default: Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text
- antialiased: Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall
- none: Disables font smoothing. Text will show with jagged sharp edges`),
'enumDescriptions': [
nls.localize('workbench.fontAliasing.default', "Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text."),
nls.localize('workbench.fontAliasing.antialiased', "Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall."),
nls.localize('workbench.fontAliasing.none', "Disables font smoothing. Text will show with jagged sharp edges.")
],
};
workbenchProperties['workbench.editor.swipeToNavigate'] = {
'type': 'boolean',
'description': nls.localize('swipeToNavigate', "Navigate between open files using three-finger swipe horizontally."),
'default': false
};
}
configurationRegistry.registerConfiguration({
'id': 'workbench',
'order': 7,
'title': nls.localize('workbenchConfigurationTitle', "Workbench"),
'type': 'object',
'properties': workbenchProperties
});
// Configuration: Window
let properties: { [path: string]: IJSONSchema; } = {
'window.openFilesInNewWindow': {
'type': 'string',
'enum': ['on', 'off', 'default'],
'enumDescriptions': [
nls.localize('window.openFilesInNewWindow.on', "Files will open in a new window"),
nls.localize('window.openFilesInNewWindow.off', "Files will open in the window with the files' folder open or the last active window"),
nls.localize('window.openFilesInNewWindow.default', "Files will open in the window with the files' folder open or the last active window unless opened via the dock or from finder (macOS only)")
],
'default': 'off',
'description':
nls.localize('openFilesInNewWindow',
`Controls if files should open in a new window.
- default: files will open in the window with the files' folder open or the last active window unless opened via the dock or from finder (macOS only)
- on: files will open in a new window
- off: files will open in the window with the files' folder open or the last active window
Note that there can still be cases where this setting is ignored (e.g. when using the -new-window or -reuse-window command line option).`
)
},
'window.openFoldersInNewWindow': {
'type': 'string',
'enum': ['on', 'off', 'default'],
'enumDescriptions': [
nls.localize('window.openFoldersInNewWindow.on', "Folders will open in a new window"),
nls.localize('window.openFoldersInNewWindow.off', "Folders will replace the last active window"),
nls.localize('window.openFoldersInNewWindow.default', "Folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu)")
],
'default': 'default',
'description': nls.localize('openFoldersInNewWindow',
`Controls if folders should open in a new window or replace the last active window.
- default: folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu)
- on: folders will open in a new window
- off: folders will replace the last active window
Note that there can still be cases where this setting is ignored (e.g. when using the -new-window or -reuse-window command line option).`
)
},
'window.restoreWindows': {
'type': 'string',
'enum': ['all', 'folders', 'one', 'none'],
'enumDescriptions': [
nls.localize('window.reopenFolders.all', "Reopen all windows."),
nls.localize('window.reopenFolders.folders', "Reopen all folders. Empty workspaces will not be restored."),
nls.localize('window.reopenFolders.one', "Reopen the last active window."),
nls.localize('window.reopenFolders.none', "Never reopen a window. Always start with an empty one.")
],
'default': 'one',
'description': nls.localize('restoreWindows', "Controls how windows are being reopened after a restart. Select 'none' to always start with an empty workspace, 'one' to reopen the last window you worked on, 'folders' to reopen all windows that had folders opened or 'all' to reopen all windows of your last session.")
},
'window.restoreFullscreen': {
'type': 'boolean',
'default': false,
'description': nls.localize('restoreFullscreen', "Controls if a window should restore to full screen mode if it was exited in full screen mode.")
},
'window.zoomLevel': {
'type': 'number',
'default': 0,
'description': nls.localize('zoomLevel', "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.")
},
'window.title': {
'type': 'string',
'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}',
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'title' },
`Controls the window title based on the active editor. Variables are substituted based on the context:
\${activeEditorShort}: e.g. myFile.txt
\${activeEditorMedium}: e.g. myFolder/myFile.txt
\${activeEditorLong}: e.g. /Users/Development/myProject/myFolder/myFile.txt
\${folderName}: e.g. myFolder
\${folderPath}: e.g. /Users/Development/myFolder
\${rootName}: e.g. myFolder1, myFolder2, myFolder3
\${rootPath}: e.g. /Users/Development/myWorkspace
\${appName}: e.g. VS Code
\${dirty}: a dirty indicator if the active editor is dirty
\${separator}: a conditional separator (" - ") that only shows when surrounded by variables with values`)
},
'window.newWindowDimensions': {
'type': 'string',
'enum': ['default', 'inherit', 'maximized', 'fullscreen'],
'enumDescriptions': [
nls.localize('window.newWindowDimensions.default', "Open new windows in the center of the screen."),
nls.localize('window.newWindowDimensions.inherit', "Open new windows with same dimension as last active one."),
nls.localize('window.newWindowDimensions.maximized', "Open new windows maximized."),
nls.localize('window.newWindowDimensions.fullscreen', "Open new windows in full screen mode.")
],
'default': 'default',
'description': nls.localize('newWindowDimensions', "Controls the dimensions of opening a new window when at least one window is already opened. By default, a new window will open in the center of the screen with small dimensions. When set to 'inherit', the window will get the same dimensions as the last window that was active. When set to 'maximized', the window will open maximized and fullscreen if configured to 'fullscreen'. Note that this setting does not have an impact on the first window that is opened. The first window will always restore the size and location as you left it before closing.")
},
'window.closeWhenEmpty': {
'type': 'boolean',
'default': false,
'description': nls.localize('closeWhenEmpty', "Controls if closing the last editor should also close the window. This setting only applies for windows that do not show folders.")
}
};
if (isWindows || isLinux) {
properties['window.menuBarVisibility'] = {
'type': 'string',
'enum': ['default', 'visible', 'toggle', 'hidden'],
'enumDescriptions': [
nls.localize('window.menuBarVisibility.default', "Menu is only hidden in full screen mode."),
nls.localize('window.menuBarVisibility.visible', "Menu is always visible even in full screen mode."),
nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed via Alt key."),
nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden.")
],
'default': 'default',
'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. By default, the menu bar will be visible, unless the window is full screen.")
};
properties['window.enableMenuBarMnemonics'] = {
'type': 'boolean',
'default': true,
'description': nls.localize('enableMenuBarMnemonics', "If enabled, the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead.")
};
}
if (isWindows) {
properties['window.autoDetectHighContrast'] = {
'type': 'boolean',
'default': true,
'description': nls.localize('autoDetectHighContrast', "If enabled, will automatically change to high contrast theme if Windows is using a high contrast theme, and to dark theme when switching away from a Windows high contrast theme."),
};
}
if (isMacintosh) {
properties['window.titleBarStyle'] = {
'type': 'string',
'enum': ['native', 'custom'],
'default': 'custom',
'description': nls.localize('titleBarStyle', "Adjust the appearance of the window title bar. Changes require a full restart to apply.")
};
// macOS Sierra (10.12.x = darwin 16.x) and electron > 1.4.6 only
if (os.release().indexOf('16.') === 0 && process.versions.electron !== '1.4.6') {
properties['window.nativeTabs'] = {
'type': 'boolean',
'default': false,
'description': nls.localize('window.nativeTabs', "Enables macOS Sierra window tabs. Note that changes require a full restart to apply and that native tabs will disable a custom title bar style if configured.")
};
}
}
configurationRegistry.registerConfiguration({
'id': 'window',
'order': 8,
'title': nls.localize('windowConfigurationTitle', "Window"),
'type': 'object',
'properties': properties
});
// Configuration: Zen Mode
configurationRegistry.registerConfiguration({
'id': 'zenMode',
'order': 9,
'title': nls.localize('zenModeConfigurationTitle', "Zen Mode"),
'type': 'object',
'properties': {
'zenMode.fullScreen': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.fullScreen', "Controls if turning on Zen Mode also puts the workbench into full screen mode.")
},
'zenMode.hideTabs': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideTabs', "Controls if turning on Zen Mode also hides workbench tabs.")
},
'zenMode.hideStatusBar': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideStatusBar', "Controls if turning on Zen Mode also hides the status bar at the bottom of the workbench.")
},
'zenMode.hideActivityBar': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideActivityBar', "Controls if turning on Zen Mode also hides the activity bar at the left of the workbench.")
},
'zenMode.restore': {
'type': 'boolean',
'default': false,
'description': nls.localize('zenMode.restore', "Controls if a window should restore to zen mode if it was exited in zen mode.")
}
}
});

View File

@@ -0,0 +1,238 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import { TPromise } from 'vs/base/common/winjs.base';
import { WorkbenchShell } from 'vs/workbench/electron-browser/shell';
import * as browser from 'vs/base/browser/browser';
import { domContentLoaded } from 'vs/base/browser/dom';
import errors = require('vs/base/common/errors');
import comparer = require('vs/base/common/comparers');
import platform = require('vs/base/common/platform');
import paths = require('vs/base/common/paths');
import uri from 'vs/base/common/uri';
import strings = require('vs/base/common/strings');
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { EmptyWorkspaceServiceImpl, WorkspaceServiceImpl, WorkspaceService } from 'vs/workbench/services/configuration/node/configuration';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { realpath, readFile, writeFile } from 'vs/base/node/pfs';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import path = require('path');
import gracefulFs = require('graceful-fs');
import { IInitData } from 'vs/workbench/services/timer/common/timerService';
import { TimerService } from 'vs/workbench/services/timer/node/timerService';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { IWindowConfiguration, IWindowsService } from 'vs/platform/windows/common/windows';
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { StorageService, inMemoryLocalStorageInstance } from 'vs/platform/storage/common/storageService';
import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser';
import { webFrame, remote } from 'electron';
import { UpdateChannelClient } from 'vs/platform/update/common/updateIpc';
import { IUpdateService } from 'vs/platform/update/common/update';
import { URLChannelClient } from 'vs/platform/url/common/urlIpc';
import { IURLService } from 'vs/platform/url/common/url';
import { WorkspacesChannelClient } from 'vs/platform/workspaces/common/workspacesIpc';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { CredentialsChannelClient } from 'vs/platform/credentials/node/credentialsIpc';
import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration';
import fs = require('fs');
gracefulFs.gracefulify(fs); // enable gracefulFs
const currentWindowId = remote.getCurrentWindow().id;
export function startup(configuration: IWindowConfiguration): TPromise<void> {
// Ensure others can listen to zoom level changes
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Can be trusted because we are not setting it ourselves.
browser.setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */);
browser.setFullscreen(!!configuration.fullscreen);
KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(configuration.isISOKeyboard);
browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
// Setup Intl
comparer.setFileNameComparer(new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }));
// Open workbench
return openWorkbench(configuration);
}
function openWorkbench(configuration: IWindowConfiguration): TPromise<void> {
const mainProcessClient = new ElectronIPCClient(String(`window${currentWindowId}`));
const mainServices = createMainProcessServices(mainProcessClient);
const environmentService = new EnvironmentService(configuration, configuration.execPath);
// Since the configuration service is one of the core services that is used in so many places, we initialize it
// right before startup of the workbench shell to have its data ready for consumers
return createAndInitializeWorkspaceService(configuration, environmentService, <IWorkspacesService>mainServices.get(IWorkspacesService)).then(workspaceService => {
const timerService = new TimerService((<any>window).MonacoEnvironment.timers as IInitData, !workspaceService.hasWorkspace());
const storageService = createStorageService(configuration, workspaceService, environmentService);
timerService.beforeDOMContentLoaded = Date.now();
return domContentLoaded().then(() => {
timerService.afterDOMContentLoaded = Date.now();
// Open Shell
timerService.beforeWorkbenchOpen = Date.now();
const shell = new WorkbenchShell(document.body, {
contextService: workspaceService,
configurationService: workspaceService,
environmentService,
timerService,
storageService
}, mainServices, configuration);
shell.open();
// Inform user about loading issues from the loader
(<any>self).require.config({
onError: (err: any) => {
if (err.errorCode === 'load') {
shell.onUnexpectedError(loaderError(err));
}
}
});
});
});
}
function createAndInitializeWorkspaceService(configuration: IWindowConfiguration, environmentService: EnvironmentService, workspacesService: IWorkspacesService): TPromise<WorkspaceService> {
return migrateWorkspaceId(configuration).then(() => {
return validateWorkspacePath(configuration).then(() => {
let workspaceService: WorkspaceServiceImpl | EmptyWorkspaceServiceImpl;
if (configuration.workspace || configuration.folderPath) {
workspaceService = new WorkspaceServiceImpl(configuration.workspace || configuration.folderPath, environmentService, workspacesService);
} else {
workspaceService = new EmptyWorkspaceServiceImpl(environmentService);
}
return workspaceService.initialize().then(() => workspaceService, error => new EmptyWorkspaceServiceImpl(environmentService));
});
});
}
// TODO@Ben migration
function migrateWorkspaceId(configuration: IWindowConfiguration): TPromise<void> {
if (!configuration.workspace || !configuration.workspace.configPath) {
return TPromise.as(null);
}
return readFile(configuration.workspace.configPath).then(data => {
try {
const raw = JSON.parse(data.toString());
if (raw.id) {
const previousWorkspaceId = raw.id;
delete raw.id;
migrateStorageToMultiRootWorkspace(uri.from({ path: previousWorkspaceId, scheme: 'root' }).toString(), configuration.workspace, window.localStorage);
return writeFile(configuration.workspace.configPath, JSON.stringify(raw, null, '\t'));
}
} catch (error) { };
return void 0;
}).then(() => void 0, () => void 0);
}
function validateWorkspacePath(configuration: IWindowConfiguration): TPromise<void> {
if (!configuration.folderPath) {
return TPromise.as(null);
}
return realpath(configuration.folderPath).then(realFolderPath => {
// for some weird reason, node adds a trailing slash to UNC paths
// we never ever want trailing slashes as our workspace path unless
// someone opens root ("/").
// See also https://github.com/nodejs/io.js/issues/1765
if (paths.isUNC(realFolderPath) && strings.endsWith(realFolderPath, paths.nativeSep)) {
realFolderPath = strings.rtrim(realFolderPath, paths.nativeSep);
}
// update config
configuration.folderPath = realFolderPath;
}, error => {
errors.onUnexpectedError(error);
return null; // treat invalid paths as empty workspace
});
}
function createStorageService(configuration: IWindowConfiguration, workspaceService: IWorkspaceContextService, environmentService: IEnvironmentService): IStorageService {
const workspace = workspaceService.getWorkspace();
let workspaceId: string;
let secondaryWorkspaceId: number;
// in multi root workspace mode we use the provided ID as key for workspace storage
if (workspaceService.hasMultiFolderWorkspace()) {
workspaceId = uri.from({ path: workspace.id, scheme: 'root' }).toString();
}
// in single folder mode we use the path of the opened folder as key for workspace storage
// the ctime is used as secondary workspace id to clean up stale UI state if necessary
else if (workspaceService.hasFolderWorkspace()) {
const legacyWorkspace = workspaceService.getLegacyWorkspace();
workspaceId = legacyWorkspace.resource.toString();
secondaryWorkspaceId = legacyWorkspace.ctime;
}
// finaly, if we do not have a workspace open, we need to find another identifier for the window to store
// workspace UI state. if we have a backup path in the configuration we can use that because this
// will be a unique identifier per window that is stable between restarts as long as there are
// dirty files in the workspace.
// We use basename() to produce a short identifier, we do not need the full path. We use a custom
// scheme so that we can later distinguish these identifiers from the workspace one.
else if (configuration.backupPath) {
workspaceId = uri.from({ path: path.basename(configuration.backupPath), scheme: 'empty' }).toString();
}
const disableStorage = !!environmentService.extensionTestsPath; // never keep any state when running extension tests!
const storage = disableStorage ? inMemoryLocalStorageInstance : window.localStorage;
return new StorageService(storage, storage, workspaceId, secondaryWorkspaceId);
}
function createMainProcessServices(mainProcessClient: ElectronIPCClient): ServiceCollection {
const serviceCollection = new ServiceCollection();
const windowsChannel = mainProcessClient.getChannel('windows');
serviceCollection.set(IWindowsService, new WindowsChannelClient(windowsChannel));
const updateChannel = mainProcessClient.getChannel('update');
serviceCollection.set(IUpdateService, new SyncDescriptor(UpdateChannelClient, updateChannel));
const urlChannel = mainProcessClient.getChannel('url');
serviceCollection.set(IURLService, new SyncDescriptor(URLChannelClient, urlChannel, currentWindowId));
const workspacesChannel = mainProcessClient.getChannel('workspaces');
serviceCollection.set(IWorkspacesService, new WorkspacesChannelClient(workspacesChannel));
const credentialsChannel = mainProcessClient.getChannel('credentials');
serviceCollection.set(ICredentialsService, new CredentialsChannelClient(credentialsChannel));
return serviceCollection;
}
function loaderError(err: Error): Error {
if (platform.isWeb) {
return new Error(nls.localize('loaderError', "Failed to load a required file. Either you are no longer connected to the internet or the server you are connected to is offline. Please refresh the browser to try again."));
}
return new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err)));
}

View File

@@ -0,0 +1,13 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.vs .action-remove-from-recently-opened {
background: url("remove.svg") center center no-repeat;
}
.vs-dark .action-remove-from-recently-opened,
.hc-black .action-remove-from-recently-opened {
background: url("remove-dark.svg") center center no-repeat;
}

View File

@@ -0,0 +1 @@
<svg width="13" height="13" viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M6.5 0C2.91 0 0 2.91 0 6.5S2.91 13 6.5 13 13 10.09 13 6.5 10.09 0 6.5 0zm3.9 9.1l-1.3 1.3-2.6-2.6-2.6 2.6-1.3-1.3 2.6-2.635L2.6 3.9l1.3-1.3 2.6 2.6 2.6-2.6 1.3 1.3-2.6 2.565L10.4 9.1z" fill="#aaa"/></g></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#e8e8e8" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#424242" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1,173 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-shell {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
font-size: 11px;
-webkit-user-select: none;
}
/* Font Families (with CJK support) */
.monaco-shell { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Ubuntu", "Droid Sans", sans-serif; }
.monaco-shell:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
.monaco-shell:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Microsoft Jhenghei", "PingFang TC", "Source Han Sans TC", "Source Han Sans", "Source Han Sans TW", sans-serif; }
.monaco-shell:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Meiryo", "Hiragino Kaku Gothic Pro", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", "Sazanami Gothic", "IPA Gothic", sans-serif; }
.monaco-shell:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Malgun Gothic", "Nanum Gothic", "Dotom", "Apple SD Gothic Neo", "AppleGothic", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
@-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.monaco-shell img {
border: 0;
}
.monaco-shell label {
cursor: pointer;
}
.monaco-shell a {
text-decoration: none;
}
.monaco-shell a:active {
color: inherit;
background-color: inherit;
}
.monaco-shell a.plain {
color: inherit;
text-decoration: none;
}
.monaco-shell a.plain:hover,
.monaco-shell a.plain.hover {
color: inherit;
text-decoration: none;
}
.monaco-shell input {
color: inherit;
font-family: inherit;
font-size: 100%;
}
.monaco-shell select {
font-family: inherit;
}
.monaco-shell .pointer {
cursor: pointer;
}
.monaco-shell input[type="search"]::-webkit-search-decoration,
.monaco-shell input[type="search"]::-webkit-search-results-button,
.monaco-shell input[type="search"]::-webkit-search-results-decoration {
display: none;
}
.monaco-shell input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
height: 18px;
width: 18px;
background-image: url('clear.svg');
background-repeat: no-repeat;
background-position: center center;
}
/* START Keyboard Focus Indication Styles */
.monaco-shell [tabindex="0"]:focus,
.monaco-shell .synthetic-focus,
.monaco-shell select:focus,
.monaco-shell input[type="button"]:focus,
.monaco-shell input[type="submit"]:focus,
.monaco-shell input[type="search"]:focus,
.monaco-shell input[type="text"]:focus,
.monaco-shell textarea:focus,
.monaco-shell input[type="checkbox"]:focus {
outline-width: 1px;
outline-style: solid;
outline-offset: -1px;
opacity: 1 !important;
}
.monaco-shell .mac select:focus {
border: none; /* outline is a square, but border has a radius, so we avoid this glitch when focused (https://github.com/Microsoft/vscode/issues/26045) */
}
.monaco-shell.hc-black [tabindex="0"]:focus,
.monaco-shell.hc-black .synthetic-focus,
.monaco-shell.hc-black select:focus,
.monaco-shell.hc-black input[type="button"]:focus,
.monaco-shell.hc-black input[type="text"]:focus,
.monaco-shell.hc-black textarea:focus,
.monaco-shell.hc-black input[type="search"]:focus,
.monaco-shell.hc-black input[type="checkbox"]:focus {
outline-style: solid;
outline-width: 1px;
}
.monaco-shell.hc-black .synthetic-focus input {
background: transparent; /* Search input focus fix when in high contrast */
}
.monaco-shell.vs .monaco-tree.focused .monaco-tree-row.focused [tabindex="0"]:focus,
.monaco-shell.vs-dark .monaco-tree.focused .monaco-tree-row.focused [tabindex="0"]:focus {
outline-width: 1px; /* higher contrast color for focusable elements in a row that shows focus feedback */
outline-style: solid;
}
.monaco-shell .monaco-tree.focused.no-focused-item:focus:before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 5; /* make sure we are on top of the tree items */
content: "";
pointer-events: none; /* enable click through */
outline: 1px solid; /* we still need to handle the empty tree or no focus item case */
outline-width: 1px;
outline-style: solid;
outline-offset: -1px;
}
.monaco-shell.hc-black .monaco-tree.focused.no-focused-item:focus:before {
outline-width: 1px;
outline-offset: -2px;
}
.monaco-shell .synthetic-focus :focus {
outline: 0 !important; /* elements within widgets that draw synthetic-focus should never show focus */
}
.monaco-shell .monaco-inputbox.info.synthetic-focus,
.monaco-shell .monaco-inputbox.warning.synthetic-focus,
.monaco-shell .monaco-inputbox.error.synthetic-focus,
.monaco-shell .monaco-inputbox.info input[type="text"]:focus,
.monaco-shell .monaco-inputbox.warning input[type="text"]:focus,
.monaco-shell .monaco-inputbox.error input[type="text"]:focus {
outline: 0 !important; /* outline is not going well with decoration */
}
.monaco-shell .monaco-tree.focused:focus {
outline: 0 !important; /* tree indicates focus not via outline but through the focused item */
}
.monaco-shell [tabindex="0"]:active,
.monaco-shell select:active,
.monaco-shell input[type="button"]:active,
.monaco-shell input[type="submit"]:active,
.monaco-shell input[type="checkbox"]:active,
.monaco-shell .monaco-tree .monaco-tree-row
.monaco-action-bar .action-item [tabindex="0"]:hover,
.monaco-shell .monaco-tree.focused.no-focused-item:active:before {
outline: 0 !important; /* fixes some flashing outlines from showing up when clicking */
}

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench-container {
position: absolute;
}
.monaco-workbench {
font-size: 13px;
line-height: 1.4em;
position: relative;
z-index: 1;
overflow: hidden;
}
.monaco-workbench > .part {
position: absolute;
box-sizing: border-box;
}
.monaco-workbench .monaco-action-bar .select-box {
margin-top: 8px; /* Center the select box */
}
.monaco-workbench.windows .monaco-action-bar .select-box {
margin-top: 7px; /* Center the select box */
}

View File

@@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { join, basename } from 'path';
import { readdir, rimraf, stat } from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import product from 'vs/platform/node/product';
declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }];
declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] };
export class NodeCachedDataManager {
private static _DataMaxAge = product.nameLong.indexOf('Insiders') >= 0
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months
private _telemetryService: ITelemetryService;
private _environmentService: IEnvironmentService;
private _disposables: IDisposable[] = [];
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IEnvironmentService environmentService: IEnvironmentService
) {
this._telemetryService = telemetryService;
this._environmentService = environmentService;
this._handleCachedDataInfo();
this._manageCachedDataSoon();
}
dispose(): void {
this._disposables = dispose(this._disposables);
}
private _handleCachedDataInfo(): void {
let didRejectCachedData = false;
let didProduceCachedData = false;
for (const [err, data] of MonacoEnvironment.onNodeCachedData) {
// build summary
didRejectCachedData = didRejectCachedData || Boolean(err);
didProduceCachedData = didProduceCachedData || Boolean(data);
// log each failure separately
if (err) {
this._telemetryService.publicLog('cachedDataError', {
errorCode: err.errorCode,
path: basename(err.path)
});
}
}
// log summary
this._telemetryService.publicLog('cachedDataInfo', {
didRequestCachedData: Boolean(global.require.getConfig().nodeCachedDataDir),
didRejectCachedData,
didProduceCachedData
});
global.require.config({ onNodeCachedData: undefined });
delete MonacoEnvironment.onNodeCachedData;
}
private _manageCachedDataSoon(): void {
// Cached data is stored as user data and we run a cleanup task everytime
// the editor starts. The strategy is to delete all files that are older than
// 3 months
const { nodeCachedDataDir } = this._environmentService;
if (!nodeCachedDataDir) {
return;
}
let handle = setTimeout(() => {
handle = undefined;
readdir(nodeCachedDataDir).then(entries => {
const now = Date.now();
const deletes = entries.map(entry => {
const path = join(nodeCachedDataDir, entry);
return stat(path).then(stats => {
const diff = now - stats.mtime.getTime();
if (diff > NodeCachedDataManager._DataMaxAge) {
return rimraf(path);
}
return undefined;
});
});
return TPromise.join(deletes);
}).done(undefined, onUnexpectedError);
}, 30 * 1000);
this._disposables.push({
dispose() { clearTimeout(handle); }
});
}
}

View File

@@ -0,0 +1,567 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/shell';
import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import * as platform from 'vs/base/common/platform';
import { Dimension, Builder, $ } from 'vs/base/browser/builder';
import dom = require('vs/base/browser/dom');
import aria = require('vs/base/browser/ui/aria/aria');
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import errors = require('vs/base/common/errors');
import { toErrorMessage } from 'vs/base/common/errorMessage';
import product from 'vs/platform/node/product';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import pkg from 'vs/platform/node/package';
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
import { Workbench, IWorkbenchStartedInfo } from 'vs/workbench/electron-browser/workbench';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService, configurationTelemetry, lifecycleTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { IExperimentService, ExperimentService } from 'vs/platform/telemetry/common/experiments';
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { IdleMonitor, UserStatus } from 'vs/platform/telemetry/browser/idleMonitor';
import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
import { ElectronWindow } from 'vs/workbench/electron-browser/window';
import { resolveWorkbenchCommonProperties, getOrCreateMachineId } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { machineIdIpcChannel } from 'vs/platform/telemetry/node/commonProperties';
import { WorkspaceStats } from 'vs/workbench/services/telemetry/common/workspaceStats';
import { IWindowsService, IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { WindowService } from 'vs/platform/windows/electron-browser/windowService';
import { MessageService } from 'vs/workbench/services/message/electron-browser/messageService';
import { IRequestService } from 'vs/platform/request/node/request';
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { SearchService } from 'vs/workbench/services/search/node/searchService';
import { LifecycleService } from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { CodeEditorServiceImpl } from 'vs/editor/browser/services/codeEditorServiceImpl';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { IntegrityServiceImpl } from 'vs/platform/integrity/node/integrityServiceImpl';
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IMessageService, IChoiceService, Severity } from 'vs/platform/message/common/message';
import { ChoiceChannel } from 'vs/platform/message/common/messageIpc';
import { ISearchService } from 'vs/platform/search/common/search';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/platform/commands/common/commandService';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { ICrashReporterService, NullCrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService';
import { CrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService';
import { NodeCachedDataManager } from 'vs/workbench/electron-browser/nodeCachedDataManager';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { IExtensionManagementChannel, ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
import { ITimerService } from 'vs/workbench/services/timer/common/timerService';
import { remote, ipcRenderer as ipc } from 'electron';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration';
import * as browser from 'vs/base/browser/browser';
import 'vs/platform/opener/browser/opener.contribution';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl';
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry';
import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax';
import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService';
import { IBroadcastService, BroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService';
/**
* Services that we require for the Shell
*/
export interface ICoreServices {
contextService: IWorkspaceContextService;
configurationService: IConfigurationService;
environmentService: IEnvironmentService;
timerService: ITimerService;
storageService: IStorageService;
}
const currentWindow = remote.getCurrentWindow();
/**
* The workbench shell contains the workbench with a rich header containing navigation and the activity bar.
* With the Shell being the top level element in the page, it is also responsible for driving the layouting.
*/
export class WorkbenchShell {
private storageService: IStorageService;
private messageService: MessageService;
private environmentService: IEnvironmentService;
private contextViewService: ContextViewService;
private configurationService: IConfigurationService;
private contextService: IWorkspaceContextService;
private telemetryService: ITelemetryService;
private experimentService: IExperimentService;
private extensionService: ExtensionService;
private broadcastService: IBroadcastService;
private timerService: ITimerService;
private themeService: WorkbenchThemeService;
private lifecycleService: LifecycleService;
private mainProcessServices: ServiceCollection;
private container: HTMLElement;
private toUnbind: IDisposable[];
private previousErrorValue: string;
private previousErrorTime: number;
private content: HTMLElement;
private contentsContainer: Builder;
private configuration: IWindowConfiguration;
private workbench: Workbench;
constructor(container: HTMLElement, coreServices: ICoreServices, mainProcessServices: ServiceCollection, configuration: IWindowConfiguration) {
this.container = container;
this.configuration = configuration;
this.contextService = coreServices.contextService;
this.configurationService = coreServices.configurationService;
this.environmentService = coreServices.environmentService;
this.timerService = coreServices.timerService;
this.storageService = coreServices.storageService;
this.mainProcessServices = mainProcessServices;
this.toUnbind = [];
this.previousErrorTime = 0;
}
private createContents(parent: Builder): Builder {
// ARIA
aria.setARIAContainer(document.body);
// Workbench Container
const workbenchContainer = $(parent).div();
// Instantiation service with services
const [instantiationService, serviceCollection] = this.initServiceCollection(parent.getHTMLElement());
// Workbench
this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.configuration, serviceCollection);
this.workbench.startup({
onWorkbenchStarted: (info: IWorkbenchStartedInfo) => {
// run workbench started logic
this.onWorkbenchStarted(info);
// start cached data manager
instantiationService.createInstance(NodeCachedDataManager);
// Set lifecycle phase to `Runnning` so that other contributions
// can now do something
this.lifecycleService.phase = LifecyclePhase.Running;
}
});
// Window
this.workbench.getInstantiationService().createInstance(ElectronWindow, this.container);
// Handle case where workbench is not starting up properly
const timeoutHandle = setTimeout(() => {
console.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.');
}, 10000);
this.workbench.joinCreation().then(() => {
clearTimeout(timeoutHandle);
});
return workbenchContainer;
}
private onWorkbenchStarted(info: IWorkbenchStartedInfo): void {
// Telemetry: workspace info
const { filesToOpen, filesToCreate, filesToDiff } = this.configuration;
this.telemetryService.publicLog('workspaceLoad', {
userAgent: navigator.userAgent,
windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth },
emptyWorkbench: !this.contextService.hasWorkspace(),
'workbench.filesToOpen': filesToOpen && filesToOpen.length || void 0,
'workbench.filesToCreate': filesToCreate && filesToCreate.length || void 0,
'workbench.filesToDiff': filesToDiff && filesToDiff.length || void 0,
customKeybindingsCount: info.customKeybindingsCount,
theme: this.themeService.getColorTheme().id,
language: platform.language,
experiments: this.experimentService.getExperiments(),
pinnedViewlets: info.pinnedViewlets,
restoredViewlet: info.restoredViewlet,
restoredEditors: info.restoredEditors.length,
startupKind: this.lifecycleService.startupKind
});
// Telemetry: startup metrics
this.timerService.workbenchStarted = Date.now();
this.timerService.restoreEditorsDuration = info.restoreEditorsDuration;
this.timerService.restoreViewletDuration = info.restoreViewletDuration;
this.extensionService.onReady().done(() => {
this.telemetryService.publicLog('startupTime', this.timerService.startupMetrics);
});
// Telemetry: workspace tags
const workspaceStats: WorkspaceStats = <WorkspaceStats>this.workbench.getInstantiationService().createInstance(WorkspaceStats);
workspaceStats.reportWorkspaceTags(this.configuration);
workspaceStats.reportCloudStats();
if ((platform.isLinux || platform.isMacintosh) && process.getuid() === 0) {
this.messageService.show(Severity.Warning, nls.localize('runningAsRoot', "It is recommended not to run Code as 'root'."));
}
}
private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] {
const disposables: IDisposable[] = [];
const serviceCollection = new ServiceCollection();
serviceCollection.set(IWorkspaceContextService, this.contextService);
serviceCollection.set(IConfigurationService, this.configurationService);
serviceCollection.set(IEnvironmentService, this.environmentService);
serviceCollection.set(ITimerService, this.timerService);
serviceCollection.set(IStorageService, this.storageService);
this.mainProcessServices.forEach((serviceIdentifier, serviceInstance) => {
serviceCollection.set(serviceIdentifier, serviceInstance);
});
const instantiationService: IInstantiationService = new InstantiationService(serviceCollection, true);
this.broadcastService = new BroadcastService(currentWindow.id);
serviceCollection.set(IBroadcastService, this.broadcastService);
serviceCollection.set(IWindowService, new SyncDescriptor(WindowService, currentWindow.id));
const sharedProcess = (<IWindowsService>serviceCollection.get(IWindowsService)).whenSharedProcessReady()
.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${currentWindow.id}`));
sharedProcess
.done(client => client.registerChannel('choice', instantiationService.createInstance(ChoiceChannel)));
// Warm up font cache information before building up too many dom elements
restoreFontInfo(this.storageService);
readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getConfiguration('editor'), browser.getZoomLevel()));
// Experiments
this.experimentService = instantiationService.createInstance(ExperimentService);
serviceCollection.set(IExperimentService, this.experimentService);
// Telemetry
this.sendMachineIdToMain(this.storageService);
if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !!product.enableTelemetry) {
const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const commit = product.commit;
const version = pkg.version;
const config: ITelemetryServiceConfig = {
appender: new TelemetryAppenderClient(channel),
commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version),
piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath]
};
const telemetryService = instantiationService.createInstance(TelemetryService, config);
this.telemetryService = telemetryService;
const errorTelemetry = new ErrorTelemetry(telemetryService);
const idleMonitor = new IdleMonitor(2 * 60 * 1000); // 2 minutes
const listener = idleMonitor.onStatusChange(status =>
this.telemetryService.publicLog(status === UserStatus.Active
? TelemetryService.IDLE_STOP_EVENT_NAME
: TelemetryService.IDLE_START_EVENT_NAME
));
disposables.push(telemetryService, errorTelemetry, listener, idleMonitor);
} else {
this.telemetryService = NullTelemetryService;
}
serviceCollection.set(ITelemetryService, this.telemetryService);
disposables.push(configurationTelemetry(this.telemetryService, this.configurationService));
let crashReporterService = NullCrashReporterService;
if (product.crashReporter && product.hockeyApp) {
crashReporterService = instantiationService.createInstance(CrashReporterService);
}
serviceCollection.set(ICrashReporterService, crashReporterService);
this.messageService = instantiationService.createInstance(MessageService, container);
serviceCollection.set(IMessageService, this.messageService);
serviceCollection.set(IChoiceService, this.messageService);
const lifecycleService = instantiationService.createInstance(LifecycleService);
this.toUnbind.push(lifecycleService.onShutdown(reason => dispose(disposables)));
this.toUnbind.push(lifecycleService.onShutdown(reason => saveFontInfo(this.storageService)));
serviceCollection.set(ILifecycleService, lifecycleService);
disposables.push(lifecycleTelemetry(this.telemetryService, lifecycleService));
this.lifecycleService = lifecycleService;
const extensionManagementChannel = getDelayedChannel<IExtensionManagementChannel>(sharedProcess.then(c => c.getChannel('extensions')));
serviceCollection.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementChannelClient, extensionManagementChannel));
const extensionEnablementService = instantiationService.createInstance(ExtensionEnablementService);
serviceCollection.set(IExtensionEnablementService, extensionEnablementService);
disposables.push(extensionEnablementService);
this.extensionService = instantiationService.createInstance(ExtensionService);
serviceCollection.set(IExtensionService, this.extensionService);
this.timerService.beforeExtensionLoad = Date.now();
this.extensionService.onReady().done(() => {
this.timerService.afterExtensionLoad = Date.now();
});
this.themeService = instantiationService.createInstance(WorkbenchThemeService, document.body);
serviceCollection.set(IWorkbenchThemeService, this.themeService);
serviceCollection.set(ICommandService, new SyncDescriptor(CommandService));
this.contextViewService = instantiationService.createInstance(ContextViewService, this.container);
serviceCollection.set(IContextViewService, this.contextViewService);
serviceCollection.set(IRequestService, new SyncDescriptor(RequestService));
serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService));
serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl));
serviceCollection.set(IModelService, new SyncDescriptor(ModelServiceImpl));
serviceCollection.set(ITextResourceConfigurationService, new SyncDescriptor(TextResourceConfigurationService));
serviceCollection.set(IEditorWorkerService, new SyncDescriptor(EditorWorkerServiceImpl));
serviceCollection.set(IUntitledEditorService, new SyncDescriptor(UntitledEditorService));
serviceCollection.set(ITextMateService, new SyncDescriptor(TextMateService));
serviceCollection.set(ISearchService, new SyncDescriptor(SearchService));
serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorServiceImpl));
serviceCollection.set(IIntegrityService, new SyncDescriptor(IntegrityServiceImpl));
return [instantiationService, serviceCollection];
}
private sendMachineIdToMain(storageService: IStorageService) {
getOrCreateMachineId(storageService).then(machineId => {
ipc.send(machineIdIpcChannel, machineId);
}).then(null, errors.onUnexpectedError);
}
public open(): void {
// Listen on unexpected errors
errors.setUnexpectedErrorHandler((error: any) => {
this.onUnexpectedError(error);
});
// Shell Class for CSS Scoping
$(this.container).addClass('monaco-shell');
// Controls
this.content = $('.monaco-shell-content').appendTo(this.container).getHTMLElement();
// Create Contents
this.contentsContainer = this.createContents($(this.content));
// Layout
this.layout();
// Listeners
this.registerListeners();
}
private registerListeners(): void {
// Resize
$(window).on(dom.EventType.RESIZE, () => this.layout(), this.toUnbind);
}
public onUnexpectedError(error: any): void {
const errorMsg = toErrorMessage(error, true);
if (!errorMsg) {
return;
}
const now = Date.now();
if (errorMsg === this.previousErrorValue && now - this.previousErrorTime <= 1000) {
return; // Return if error message identical to previous and shorter than 1 second
}
this.previousErrorTime = now;
this.previousErrorValue = errorMsg;
// Log to console
console.error(errorMsg);
// Show to user if friendly message provided
if (error && error.friendlyMessage && this.messageService) {
this.messageService.show(Severity.Error, error.friendlyMessage);
}
}
private layout(): void {
const clArea = $(this.container).getClientArea();
const contentsSize = new Dimension(clArea.width, clArea.height);
this.contentsContainer.size(contentsSize.width, contentsSize.height);
this.contextViewService.layout();
this.workbench.layout();
}
public joinCreation(): TPromise<boolean> {
return this.workbench.joinCreation();
}
public dispose(): void {
// Workbench
if (this.workbench) {
this.workbench.dispose();
}
this.contextViewService.dispose();
// Listeners
this.toUnbind = dispose(this.toUnbind);
// Container
$(this.container).empty();
}
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
// Foreground
const windowForeground = theme.getColor(foreground);
if (windowForeground) {
collector.addRule(`.monaco-shell { color: ${windowForeground}; }`);
}
// Selection
const windowSelectionBackground = theme.getColor(selectionBackground);
if (windowSelectionBackground) {
collector.addRule(`.monaco-shell ::selection { background-color: ${windowSelectionBackground}; }`);
}
// Input placeholder
const placeholderForeground = theme.getColor(inputPlaceholderForeground);
if (placeholderForeground) {
collector.addRule(`.monaco-shell input::-webkit-input-placeholder { color: ${placeholderForeground}; }`);
collector.addRule(`.monaco-shell textarea::-webkit-input-placeholder { color: ${placeholderForeground}; }`);
}
// List highlight
const listHighlightForegroundColor = theme.getColor(listHighlightForeground);
if (listHighlightForegroundColor) {
collector.addRule(`
.monaco-shell .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight,
.monaco-shell .monaco-list .monaco-list-row .monaco-highlighted-label .highlight {
color: ${listHighlightForegroundColor};
}
`);
}
// We need to set the workbench background color so that on Windows we get subpixel-antialiasing.
let workbenchBackground: string;
switch (theme.type) {
case 'dark':
workbenchBackground = '#252526';
break;
case 'light':
workbenchBackground = '#F3F3F3';
break;
default:
workbenchBackground = '#000000';
}
collector.addRule(`.monaco-workbench { background-color: ${workbenchBackground}; }`);
// Scrollbars
const scrollbarShadowColor = theme.getColor(scrollbarShadow);
if (scrollbarShadowColor) {
collector.addRule(`
.monaco-shell .monaco-scrollable-element > .shadow.top {
box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset;
}
.monaco-shell .monaco-scrollable-element > .shadow.left {
box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset;
}
.monaco-shell .monaco-scrollable-element > .shadow.top.left {
box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset;
}
`);
}
const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground);
if (scrollbarSliderBackgroundColor) {
collector.addRule(`
.monaco-shell .monaco-scrollable-element > .scrollbar > .slider {
background: ${scrollbarSliderBackgroundColor};
}
`);
}
const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground);
if (scrollbarSliderHoverBackgroundColor) {
collector.addRule(`
.monaco-shell .monaco-scrollable-element > .scrollbar > .slider:hover {
background: ${scrollbarSliderHoverBackgroundColor};
}
`);
}
const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground);
if (scrollbarSliderActiveBackgroundColor) {
collector.addRule(`
.monaco-shell .monaco-scrollable-element > .scrollbar > .slider.active {
background: ${scrollbarSliderActiveBackgroundColor};
}
`);
}
// Focus outline
const focusOutline = theme.getColor(focusBorder);
if (focusOutline) {
collector.addRule(`
.monaco-shell [tabindex="0"]:focus,
.monaco-shell .synthetic-focus,
.monaco-shell select:focus,
.monaco-shell .monaco-tree.focused.no-focused-item:focus:before,
.monaco-shell input[type="button"]:focus,
.monaco-shell input[type="text"]:focus,
.monaco-shell button:focus,
.monaco-shell textarea:focus,
.monaco-shell input[type="search"]:focus,
.monaco-shell input[type="checkbox"]:focus {
outline-color: ${focusOutline};
}
`);
}
});

View File

@@ -0,0 +1,394 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import platform = require('vs/base/common/platform');
import URI from 'vs/base/common/uri';
import errors = require('vs/base/common/errors');
import types = require('vs/base/common/types');
import { TPromise } from 'vs/base/common/winjs.base';
import arrays = require('vs/base/common/arrays');
import DOM = require('vs/base/browser/dom');
import Severity from 'vs/base/common/severity';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, Action } from 'vs/base/common/actions';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { AutoSaveConfiguration } from 'vs/platform/files/common/files';
import { toResource } from 'vs/workbench/common/editor';
import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { IMessageService } from 'vs/platform/message/common/message';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IWindowsService, IWindowService, IWindowSettings, IPath, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest } from 'vs/platform/windows/common/windows';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
import { IWorkbenchThemeService, VS_HC_THEME, VS_DARK_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
import * as browser from 'vs/base/browser/browser';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { Position, IResourceInput, IUntitledResourceInput, IEditor } from 'vs/platform/editor/common/editor';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { Themable } from 'vs/workbench/common/theme';
import { ipcRenderer as ipc, webFrame } from 'electron';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
const TextInputActions: IAction[] = [
new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)),
new Action('redo', nls.localize('redo', "Redo"), null, true, () => document.execCommand('redo') && TPromise.as(true)),
new Separator(),
new Action('editor.action.clipboardCutAction', nls.localize('cut', "Cut"), null, true, () => document.execCommand('cut') && TPromise.as(true)),
new Action('editor.action.clipboardCopyAction', nls.localize('copy', "Copy"), null, true, () => document.execCommand('copy') && TPromise.as(true)),
new Action('editor.action.clipboardPasteAction', nls.localize('paste', "Paste"), null, true, () => document.execCommand('paste') && TPromise.as(true)),
new Separator(),
new Action('editor.action.selectAll', nls.localize('selectAll', "Select All"), null, true, () => document.execCommand('selectAll') && TPromise.as(true))
];
export class ElectronWindow extends Themable {
private static AUTO_SAVE_SETTING = 'files.autoSave';
constructor(
shellContainer: HTMLElement,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@IPartService private partService: IPartService,
@IWindowsService private windowsService: IWindowsService,
@IWindowService private windowService: IWindowService,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
@ITitleService private titleService: ITitleService,
@IWorkbenchThemeService protected themeService: IWorkbenchThemeService,
@IMessageService private messageService: IMessageService,
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService,
@ICommandService private commandService: ICommandService,
@IExtensionService private extensionService: IExtensionService,
@IViewletService private viewletService: IViewletService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IKeybindingService private keybindingService: IKeybindingService,
@IEnvironmentService private environmentService: IEnvironmentService,
@ITelemetryService private telemetryService: ITelemetryService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService
) {
super(themeService);
this.registerListeners();
this.setup();
}
private registerListeners(): void {
// React to editor input changes
this.editorGroupService.onEditorsChanged(() => {
const file = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
this.titleService.setRepresentedFilename(file ? file.fsPath : '');
});
// prevent opening a real URL inside the shell
[DOM.EventType.DRAG_OVER, DOM.EventType.DROP].forEach(event => {
window.document.body.addEventListener(event, (e: DragEvent) => {
DOM.EventHelper.stop(e);
});
});
// Handle window.open() calls
const $this = this;
(<any>window).open = function (url: string, target: string, features: string, replace: boolean) {
$this.windowsService.openExternal(url);
return null;
};
}
private setup(): void {
// Support runAction event
ipc.on('vscode:runAction', (event, actionId: string) => {
this.commandService.executeCommand(actionId, { from: 'menu' }).done(_ => {
this.telemetryService.publicLog('commandExecuted', { id: actionId, from: 'menu' });
}, err => {
this.messageService.show(Severity.Error, err);
});
});
// Support resolve keybindings event
ipc.on('vscode:resolveKeybindings', (event, rawActionIds: string) => {
let actionIds: string[] = [];
try {
actionIds = JSON.parse(rawActionIds);
} catch (error) {
// should not happen
}
// Resolve keys using the keybinding service and send back to browser process
this.resolveKeybindings(actionIds).done(keybindings => {
if (keybindings.length) {
ipc.send('vscode:keybindingsResolved', JSON.stringify(keybindings));
}
}, () => errors.onUnexpectedError);
});
// Send over all extension viewlets when extensions are ready
this.extensionService.onReady().then(() => {
ipc.send('vscode:extensionViewlets', JSON.stringify(this.viewletService.getViewlets().filter(v => !!v.extensionId).map(v => { return { id: v.id, label: v.name }; })));
});
ipc.on('vscode:reportError', (event, error) => {
if (error) {
const errorParsed = JSON.parse(error);
errorParsed.mainProcess = true;
errors.onUnexpectedError(errorParsed);
}
});
// Support openFiles event for existing and new files
ipc.on('vscode:openFiles', (event, request: IOpenFileRequest) => this.onOpenFiles(request));
// Support addFolders event if we have a workspace opened
ipc.on('vscode:addFolders', (event, request: IAddFoldersRequest) => this.onAddFolders(request));
// Emit event when vscode has loaded
this.partService.joinCreation().then(() => {
ipc.send('vscode:workbenchLoaded', this.windowService.getCurrentWindowId());
});
// Message support
ipc.on('vscode:showInfoMessage', (event, message: string) => {
this.messageService.show(Severity.Info, message);
});
// Support toggling auto save
ipc.on('vscode.toggleAutoSave', event => {
this.toggleAutoSave();
});
// Fullscreen Events
ipc.on('vscode:enterFullScreen', event => {
this.partService.joinCreation().then(() => {
browser.setFullscreen(true);
});
});
ipc.on('vscode:leaveFullScreen', event => {
this.partService.joinCreation().then(() => {
browser.setFullscreen(false);
});
});
// High Contrast Events
ipc.on('vscode:enterHighContrast', event => {
const windowConfig = this.configurationService.getConfiguration<IWindowSettings>('window');
if (windowConfig && windowConfig.autoDetectHighContrast) {
this.partService.joinCreation().then(() => {
this.themeService.setColorTheme(VS_HC_THEME, null);
});
}
});
ipc.on('vscode:leaveHighContrast', event => {
const windowConfig = this.configurationService.getConfiguration<IWindowSettings>('window');
if (windowConfig && windowConfig.autoDetectHighContrast) {
this.partService.joinCreation().then(() => {
this.themeService.setColorTheme(VS_DARK_THEME, null);
});
}
});
// keyboard layout changed event
ipc.on('vscode:keyboardLayoutChanged', (event, isISOKeyboard: boolean) => {
KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(isISOKeyboard);
});
// keyboard layout changed event
ipc.on('vscode:accessibilitySupportChanged', (event, accessibilitySupportEnabled: boolean) => {
browser.setAccessibilitySupport(accessibilitySupportEnabled ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
});
// Configuration changes
let previousConfiguredZoomLevel: number;
this.configurationService.onDidUpdateConfiguration(e => {
const windowConfig: IWindowsConfiguration = this.configurationService.getConfiguration<IWindowsConfiguration>();
let newZoomLevel = 0;
if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') {
newZoomLevel = windowConfig.window.zoomLevel;
// Leave early if the configured zoom level did not change (https://github.com/Microsoft/vscode/issues/1536)
if (previousConfiguredZoomLevel === newZoomLevel) {
return;
}
previousConfiguredZoomLevel = newZoomLevel;
}
if (webFrame.getZoomLevel() !== newZoomLevel) {
webFrame.setZoomLevel(newZoomLevel);
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Cannot be trusted because the webFrame might take some time
// until it really applies the new zoom level
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
}
});
// Context menu support in input/textarea
window.document.addEventListener('contextmenu', e => {
if (e.target instanceof HTMLElement) {
const target = <HTMLElement>e.target;
if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) {
e.preventDefault();
e.stopPropagation();
this.contextMenuService.showContextMenu({
getAnchor: () => e,
getActions: () => TPromise.as(TextInputActions)
});
}
}
});
}
private resolveKeybindings(actionIds: string[]): TPromise<{ id: string; label: string, isNative: boolean; }[]> {
return TPromise.join([this.partService.joinCreation(), this.extensionService.onReady()]).then(() => {
return arrays.coalesce(actionIds.map(id => {
const binding = this.keybindingService.lookupKeybinding(id);
if (!binding) {
return null;
}
// first try to resolve a native accelerator
const electronAccelerator = binding.getElectronAccelerator();
if (electronAccelerator) {
return { id, label: electronAccelerator, isNative: true };
}
// we need this fallback to support keybindings that cannot show in electron menus (e.g. chords)
const acceleratorLabel = binding.getLabel();
if (acceleratorLabel) {
return { id, label: acceleratorLabel, isNative: false };
}
return null;
}));
});
}
private onAddFolders(request: IAddFoldersRequest): void {
const foldersToAdd = request.foldersToAdd.map(folderToAdd => URI.file(folderToAdd.filePath));
// Workspace: just add to workspace config
if (this.contextService.hasMultiFolderWorkspace()) {
this.workspaceEditingService.addRoots(foldersToAdd).done(null, errors.onUnexpectedError);
}
// Single folder or no workspace: create workspace and open
else {
let workspaceFolders: URI[] = [];
// Folder of workspace is the first of multi root workspace, so add it
if (this.contextService.hasFolderWorkspace()) {
workspaceFolders.push(...this.contextService.getWorkspace().roots);
}
// Fill in remaining ones from request
workspaceFolders.push(...request.foldersToAdd.map(folderToAdd => URI.file(folderToAdd.filePath)));
// Create workspace and open (ensure no duplicates)
this.windowService.createAndOpenWorkspace(arrays.distinct(workspaceFolders.map(folder => folder.fsPath), folder => platform.isLinux ? folder : folder.toLowerCase()));
}
}
private onOpenFiles(request: IOpenFileRequest): void {
let inputs: IResourceInputType[] = [];
let diffMode = (request.filesToDiff.length === 2);
if (!diffMode && request.filesToOpen) {
inputs.push(...this.toInputs(request.filesToOpen, false));
}
if (!diffMode && request.filesToCreate) {
inputs.push(...this.toInputs(request.filesToCreate, true));
}
if (diffMode) {
inputs.push(...this.toInputs(request.filesToDiff, false));
}
if (inputs.length) {
this.openResources(inputs, diffMode).done(null, errors.onUnexpectedError);
}
}
private openResources(resources: (IResourceInput | IUntitledResourceInput)[], diffMode: boolean): TPromise<IEditor | IEditor[]> {
return this.partService.joinCreation().then((): TPromise<IEditor | IEditor[]> => {
// In diffMode we open 2 resources as diff
if (diffMode && resources.length === 2) {
return this.editorService.openEditor({ leftResource: resources[0].resource, rightResource: resources[1].resource, options: { pinned: true } });
}
// For one file, just put it into the current active editor
if (resources.length === 1) {
return this.editorService.openEditor(resources[0]);
}
// Otherwise open all
const activeEditor = this.editorService.getActiveEditor();
return this.editorService.openEditors(resources.map((r, index) => {
return {
input: r,
position: activeEditor ? activeEditor.position : Position.ONE
};
}));
});
}
private toInputs(paths: IPath[], isNew: boolean): IResourceInputType[] {
return paths.map(p => {
const resource = URI.file(p.filePath);
let input: IResourceInput | IUntitledResourceInput;
if (isNew) {
input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
} else {
input = { resource, options: { pinned: true } } as IResourceInput;
}
if (!isNew && p.lineNumber) {
input.options.selection = {
startLineNumber: p.lineNumber,
startColumn: p.columnNumber
};
}
return input;
});
}
private toggleAutoSave(): void {
const setting = this.configurationService.lookup(ElectronWindow.AUTO_SAVE_SETTING);
let userAutoSaveConfig = setting.user;
if (types.isUndefinedOrNull(userAutoSaveConfig)) {
userAutoSaveConfig = setting.default; // use default if setting not defined
}
let newAutoSaveValue: string;
if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) {
newAutoSaveValue = AutoSaveConfiguration.OFF;
} else {
newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY;
}
this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ElectronWindow.AUTO_SAVE_SETTING, value: newAutoSaveValue });
}
}

File diff suppressed because it is too large Load Diff